mod unified_hybrid;
mod full_flow;
use langchainrust::retrieval::bm25::{
AutoMergingConfig, ChunkedBM25Retriever, ChunkedSearchResult,
};
use langchainrust::vector_stores::document_store::{ChunkedDocumentStore, ChunkedDocumentStoreTrait};
use langchainrust::Document;
use tempfile::NamedTempFile;
use std::sync::Arc;
#[test]
fn test_chunked_retriever_basic() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store);
retriever.add_documents(vec![
Document::new("Rust是一门系统编程语言,注重安全和性能。由Mozilla开发,于2010年首次发布。")
.with_id("rust_doc"),
Document::new("Python是一门高级编程语言,适合数据科学、机器学习和Web开发。")
.with_id("python_doc"),
Document::new("JavaScript是一门脚本语言,主要用于前端开发和Node.js后端开发。")
.with_id("js_doc"),
]);
println!("索引是否为空: {}", retriever.is_empty());
println!("索引文档数量: {}", retriever.len());
}
#[test]
fn test_chunked_retriever_search() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store);
retriever.add_documents(vec![
Document::new("Rust是一门系统编程语言,注重安全和性能。由Mozilla开发。")
.with_id("rust_doc"),
Document::new("Python是一门脚本语言,适合数据科学。").with_id("python_doc"),
Document::new("Go语言由Google开发,是一门并发编程语言。").with_id("go_doc"),
]);
let results = retriever.search("系统编程", 2);
println!("搜索关键词: 系统编程");
println!("返回结果数: {}", results.len());
for (i, result) in results.iter().enumerate() {
println!(
"结果 {}: 分数={}, 内容={}",
i,
result.score,
result.content()
);
}
}
#[test]
fn test_chunked_retriever_chinese_search() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store);
retriever.add_documents(vec![
Document::new("机器学习是人工智能的一个分支,通过算法让计算机从数据中学习。")
.with_id("ml_doc"),
Document::new("深度学习使用神经网络进行特征学习和模式识别。").with_id("dl_doc"),
Document::new("自然语言处理让计算机理解和生成人类语言。").with_id("nlp_doc"),
]);
let results: Vec<ChunkedSearchResult> = retriever.search("机器学习算法", 3);
println!("搜索关键词: 机器学习算法");
println!("返回结果数: {}", results.len());
for (i, result) in results.iter().enumerate() {
println!(
"结果 {}: 分数={}, 是否合并={}, 内容={}",
i,
result.score,
result.is_merged(),
result.content()
);
}
}
#[test]
fn test_auto_merging_config() {
let config = AutoMergingConfig::new()
.with_threshold(0.6)
.with_leaf_size(300)
.with_parent_size(1500);
println!("合并阈值: {}", config.merge_threshold);
println!("Leaf大小: {}", config.leaf_chunk_size);
println!("Parent大小: {}", config.parent_chunk_size);
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::with_config(store, config);
let doc = Document::new(
"这是一段很长的测试文本,用于验证自定义配置是否正常工作。我们需要确保文档能够被正确拆分。",
)
.with_id("test_doc");
retriever.add_document(doc);
println!("索引文档数量: {}", retriever.len());
}
#[test]
fn test_auto_merging_high_match_ratio() {
let config = AutoMergingConfig::new()
.with_leaf_size(30)
.with_threshold(0.5);
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::with_config(store, config);
let long_doc = Document::new(
"Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust Rust"
).with_id("rust_repeat");
retriever.add_document(long_doc);
let results: Vec<ChunkedSearchResult> = retriever.search("Rust", 1);
println!("搜索关键词: Rust");
println!("Leaf大小配置: 30");
println!("合并阈值: 0.5");
for (i, result) in results.iter().enumerate() {
println!(
"结果 {}: 是否合并={}, 分数={}, 内容长度={}",
i,
result.is_merged(),
result.score,
result.content().len()
);
}
}
#[test]
fn test_auto_merging_low_match_ratio() {
let config = AutoMergingConfig::new()
.with_leaf_size(30)
.with_threshold(0.8);
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::with_config(store, config);
retriever.add_documents(vec![
Document::new("Rust是一门系统编程语言。Python是一门脚本语言。JavaScript是一门前端语言。")
.with_id("multi_lang"),
Document::new("Go是一门并发编程语言。").with_id("go_doc"),
]);
let results: Vec<ChunkedSearchResult> = retriever.search("Rust", 2);
println!("搜索关键词: Rust");
println!("合并阈值: 0.8 (高阈值,不易触发合并)");
for (i, result) in results.iter().enumerate() {
println!(
"结果 {}: 是否合并={}, Leaf数量={}, 分数={}",
i,
result.is_merged(),
result.leaf_chunks.len(),
result.score
);
}
}
#[test]
fn test_persistence_save_load() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store.clone());
retriever.add_documents(vec![
Document::new("Rust是一门系统编程语言,注重安全。").with_id("rust_doc"),
Document::new("Python适合数据科学和机器学习。").with_id("python_doc"),
Document::new("JavaScript用于Web前端开发。").with_id("js_doc"),
]);
let original_len = retriever.len();
let temp_file = NamedTempFile::new().expect("Failed to create temp file");
retriever.save(temp_file.path()).expect("Failed to save");
println!("保存路径: {}", temp_file.path().display());
println!("原始索引文档数: {}", original_len);
let loaded = ChunkedBM25Retriever::load(store, temp_file.path()).expect("Failed to load");
println!("加载后文档数: {}", loaded.len());
println!(
"rust_doc 存在: {}",
loaded.get_parent_document("rust_doc").is_some()
);
println!(
"python_doc 存在: {}",
loaded.get_parent_document("python_doc").is_some()
);
println!(
"js_doc 存在: {}",
loaded.get_parent_document("js_doc").is_some()
);
}
#[test]
fn test_persistence_with_search() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store.clone());
retriever.add_documents(vec![
Document::new("人工智能是计算机科学的一个分支。").with_id("ai_doc"),
Document::new("机器学习是人工智能的核心技术。").with_id("ml_doc"),
]);
let temp_file = NamedTempFile::new().expect("Failed to create temp file");
retriever.save(temp_file.path()).expect("Failed to save");
let mut loaded = ChunkedBM25Retriever::load(store, temp_file.path()).expect("Failed to load");
let results: Vec<ChunkedSearchResult> = loaded.search("人工智能", 2);
println!("加载后搜索关键词: 人工智能");
println!("返回结果数: {}", results.len());
for (i, result) in results.iter().enumerate() {
println!("结果 {}: 内容={}", i, result.content());
}
}
#[test]
fn test_get_parent_document() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store);
let doc = Document::new("这是一个测试文档的内容。").with_id("test_doc");
retriever.add_document(doc);
let parent = retriever.get_parent_document("test_doc");
println!("获取 test_doc: {}", parent.is_some());
if let Some(p) = parent {
println!("Parent ID: {:?}", p.id);
println!("Parent 内容: {}", p.content);
}
let not_found = retriever.get_parent_document("nonexistent");
println!("获取 nonexistent: {}", not_found.is_some());
}
#[test]
fn test_clear() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store);
retriever.add_documents(vec![
Document::new("文档一").with_id("doc1"),
Document::new("文档二").with_id("doc2"),
]);
println!("清空前文档数: {}", retriever.len());
retriever.clear();
println!("清空后文档数: {}", retriever.len());
println!("清空后是否为空: {}", retriever.is_empty());
}
#[test]
fn test_empty_search() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store);
let results = retriever.search("测试查询", 5);
println!("空索引搜索结果数: {}", results.len());
}
#[test]
fn test_large_document_chunking() {
let config = AutoMergingConfig::new()
.with_leaf_size(100)
.with_threshold(0.5);
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::with_config(store, config);
let large_doc = Document::new(
"这是一个很长的文档,包含了很多内容。我们需要测试文档拆分功能是否正常工作。\
文档拆分是将长文档切分成多个小块的过程,这样可以提高检索的精确度。\
BM25算法会在每个小块上进行搜索,然后通过AutoMerging机制将相关的小块合并。\
这种方法结合了精确性和完整性,既能够精确定位到相关内容,又能够提供完整的上下文。\
用户可以根据需要调整合并阈值和chunk大小,以适应不同的应用场景。",
)
.with_id("large_doc");
retriever.add_document(large_doc);
println!("Leaf大小配置: 100");
println!("索引文档数 (Leaf chunks): {}", retriever.len());
let results: Vec<ChunkedSearchResult> = retriever.search("文档拆分", 2);
println!("搜索关键词: 文档拆分");
println!("返回结果数: {}", results.len());
for (i, result) in results.iter().enumerate() {
println!(
"结果 {}: 是否合并={}, 内容长度={}",
i,
result.is_merged(),
result.content().len()
);
}
}
#[test]
fn test_multiple_keywords_search() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store);
retriever.add_documents(vec![
Document::new("Rust是一门系统编程语言,注重安全和并发。").with_id("rust_doc"),
Document::new("Python是一门高级语言,适合数据科学。").with_id("python_doc"),
Document::new("Go是一门并发语言,由Google开发。").with_id("go_doc"),
]);
let results: Vec<ChunkedSearchResult> = retriever.search("系统编程 安全", 2);
println!("搜索关键词: 系统编程 安全 (多关键词)");
println!("返回结果数: {}", results.len());
for (i, result) in results.iter().enumerate() {
println!(
"结果 {}: 分数={}, 内容={}",
i,
result.score,
result.content()
);
}
}
#[test]
fn test_search_result_properties() {
let store = Arc::new(ChunkedDocumentStore::new());
let mut retriever = ChunkedBM25Retriever::new(store);
retriever.add_document(Document::new("测试文档用于验证搜索结果的属性。").with_id("test_doc"));
let results: Vec<ChunkedSearchResult> = retriever.search("测试", 1);
if !results.is_empty() {
let result: &ChunkedSearchResult = &results[0];
println!("结果分数: {}", result.score);
println!("结果内容长度: {}", result.content().len());
println!("Parent ID: {}", result.parent_id);
println!("是否合并: {}", result.is_merged());
println!("Leaf数量: {}", result.leaf_chunks.len());
println!("匹配词: {:?}", result.matched_terms);
}
}