Python中使用Langchain与OpenSearch多索引查询的问题求助
解决Langchain跨OpenSearch多索引查询问题
问题原因
你当前代码里虽然指定了index_name="index-*"通配符,但默认检索器只会返回Top K个最相关文档(默认k=4),而你需要的是所有文档标题,自然会出现结果不全的情况;另外部分场景下通配符索引的检索逻辑存在限制,可能只返回单个索引的结果。
解决方案
方案1:调整检索器参数,获取足够多的相关文档
通过修改检索器的search_kwargs,设置足够大的k值(覆盖所有文档数量),确保能获取到所有索引中的文档,再让LLM提取标题:
from langchain.vectorstores import OpenSearchVectorSearch from langchain.chains import ConversationalRetrievalChain from langchain.embeddings import OpenAIEmbeddings from langchain.chat_models import ChatOpenAI embeddings = OpenAIEmbeddings() def get_llm(model): llm = ChatOpenAI(model_name=model.lower(), verbose=False, temperature=0) return llm # 初始化OpenSearch向量存储,使用通配符索引名 docsearch = OpenSearchVectorSearch( opensearch_url="http://localhost:9200", index_name="index-*", embedding_function=embeddings ) # 创建检索器,设置足够大的k值(根据总文档数调整,比如设为1000) retriever = docsearch.as_retriever( search_kwargs={"k": 1000} ) chain = ConversationalRetrievalChain.from_llm( llm=get_llm("gpt-3.5-turbo"), retriever=retriever, # 开启原始文档返回,方便调试结果是否完整 return_source_documents=True ) result = chain({'question': '列出所有文档的标题,每个标题单独一行', "chat_history": []}) print(result['answer']) # 调试用:查看返回的原始文档 # print(result['source_documents'])
方案2:手动遍历所有目标索引,合并检索结果
如果通配符索引的检索不稳定,可以手动列出所有index-开头的索引,分别创建向量存储实例,合并所有文档后再提取标题:
from langchain.vectorstores import OpenSearchVectorSearch from langchain.chat_models import ChatOpenAI from langchain.embeddings import OpenAIEmbeddings embeddings = OpenAIEmbeddings() def get_llm(model): llm = ChatOpenAI(model_name=model.lower(), verbose=False, temperature=0) return llm # 手动指定所有目标索引 target_indices = ["index-pdf", "index-html"] # 根据实际索引名补充 all_documents = [] for idx in target_indices: vs = OpenSearchVectorSearch( opensearch_url="http://localhost:9200", index_name=idx, embedding_function=embeddings ) # 获取当前索引的所有文档 docs = vs.get()["documents"] all_documents.extend(docs) # 让LLM提取并整理所有文档标题 llm = get_llm("gpt-3.5-turbo") prompt = f"请从以下文档中提取所有文档的标题,每个标题单独一行:\n{[doc.page_content for doc in all_documents]}" response = llm.predict(prompt) print(response)
方案3:直接调用OpenSearch API查询元数据
如果文档标题存储在元数据(比如metadata['title'])中,直接通过OpenSearch客户端查询元数据字段,效率更高:
from opensearchpy import OpenSearch from langchain.chat_models import ChatOpenAI # 初始化OpenSearch客户端 client = OpenSearch( hosts=[{'host': 'localhost', 'port': 9200}], http_compress=True, use_ssl=False, verify_certs=False, ssl_show_warn=False ) # 查询所有index-*索引的文档,提取title元数据 query = { "query": {"match_all": {}}, "_source": ["metadata.title"] # 假设标题存在于metadata.title字段 } response = client.search( index="index-*", body=query, size=1000 # 根据总文档数调整 ) # 提取所有标题 titles = [hit['_source']['metadata']['title'] for hit in response['hits']['hits'] if 'title' in hit['_source']['metadata']] # 让LLM整理输出 llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0) formatted_response = llm.predict(f"请将以下标题整理成清晰的列表,每个标题单独一行:\n{titles}") print(formatted_response)
注意事项
- 如果文档数量极大,方案1和2中的全量获取文档方式可能导致内存占用过高,此时推荐方案3直接查询元数据。
- 确保OpenSearch集群允许跨索引查询,且所有索引的结构一致(比如元数据字段名相同)。
内容的提问来源于stack exchange,提问作者user2966197
相关产品推荐
相关产品推荐

