如何基于Pinecone等向量数据库实现自动合并检索器(父文档检索器)
实现Auto-merging Retriever对接Pinecone的解决方案
1. 用LlamaIndex将向量数据直接存入Pinecone
LlamaIndex提供官方Pinecone集成,无需手动处理元数据,直接替换默认存储即可完成对接:
步骤与代码示例
- 先安装依赖:
pip install llama-index-vector-stores-pinecone pinecone-client - 初始化Pinecone并创建关联Pinecone的索引:
import pinecone from llama_index import VectorStoreIndex, ServiceContext from llama_index.vector_stores import PineconeVectorStore from llama_index.retrievers import RecursiveRetriever # 初始化Pinecone客户端 pinecone.init(api_key="你的Pinecone密钥", environment="你的环境名") # 关联已创建的Pinecone索引(无索引需先在Pinecone控制台创建) pinecone_index = pinecone.Index("你的索引名称") # 创建Pinecone专属的VectorStore实例 vector_store = PineconeVectorStore(pinecone_index=pinecone_index) # 基于Pinecone存储创建VectorStoreIndex vector_index_chunk = VectorStoreIndex( all_nodes, service_context=service_context, vector_store=vector_store, show_progress=True ) # 获取指向Pinecone的向量检索器 vector_retriever_metadata = vector_index_chunk.as_retriever(similarity_top_k=5) # 初始化RecursiveRetriever(逻辑与原示例一致,检索器已关联Pinecone) retriever_metadata = RecursiveRetriever( "vector", retriever_dict={"vector": vector_retriever_metadata}, node_dict=all_nodes_dict, verbose=True, ) - 说明:LlamaIndex会自动处理节点的元数据(包括父/子文档关联ID、节点类型等),无需手动编写额外映射逻辑。
2. 非Python微服务使用Auto-merging检索逻辑
RecursiveRetriever是Python专属实现,非Python服务需要拆解其核心逻辑,通过Pinecone官方SDK实现等价功能:
核心逻辑拆解
Auto-merging Retriever的本质是**"检索子节点→通过元数据关联父节点→获取完整父文档"**的递归流程,对应非Python服务的实现步骤:
- 存储阶段(用Python完成):将所有子节点、父节点的向量存入Pinecone,同时在元数据中添加:
node_id:节点唯一标识node_type:标记为child或parentparent_node_id:子节点关联的父节点ID(父节点可省略)
- 检索阶段(非Python代码实现):
- 用查询向量检索Pinecone中
node_type=child的相似节点 - 从结果元数据中提取所有父节点ID,去重后检索
node_type=parent的对应节点 - 若有多层递归(父节点还有上层节点),重复上述步骤,最终返回完整的父文档内容
- 用查询向量检索Pinecone中
非Python示例(以JavaScript为例)
import { Pinecone } from "@pinecone-database/pinecone"; const pinecone = new Pinecone({ apiKey: "你的Pinecone密钥", environment: "你的环境名" }); const index = pinecone.Index("你的索引名称"); async function autoMergeRetrieve(queryEmbedding) { // 1. 检索相关子节点 const childMatches = await index.query({ vector: queryEmbedding, topK: 5, filter: { node_type: "child" }, includeMetadata: true }); // 2. 提取并去重父节点ID const parentIds = [...new Set( childMatches.matches.map(match => match.metadata.parent_node_id) )]; // 3. 检索对应父节点 const parentMatches = await index.query({ vector: queryEmbedding, topK: parentIds.length, filter: { node_id: { $in: parentIds }, node_type: "parent" }, includeMetadata: true, includeValues: false // 无需返回向量,只取内容 }); // 4. 返回父文档内容(若有多层递归可在此扩展逻辑) return parentMatches.matches.map(match => match.metadata.content); }
- 补充:如果父文档内容过大,可将内容存储在专门的文档库(如PostgreSQL、S3),Pinecone仅存储向量和关联ID,检索到ID后再去文档库拉取内容。
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

