Haystack 如何应用 metadata 过滤器在检索阶段缩小 Retriever 返回的文档范围
2026/9/13 1:44:23 网站建设 项目流程

Haystack 如何应用 metadata 过滤器在检索阶段缩小 Retriever 返回的文档范围

【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack

当你把带 metadata 的文档写入 Document Store 后,常见的诉求是:查询时只从某个子集里取文档,比如只要 2019 年的年报、只要某几家公司的报告。Haystack 的做法是给过滤器定义一套统一语法,然后把它传给 Retriever 的filters参数——可以在组件初始化时写死,也可以在运行时通过Pipeline.run()动态传入,管道会自动把它路由给 Retriever 组件(见 metadata-filtering)。下面以InMemoryDocumentStore为主路径,给出可直接运行的完整流程,并用断言验证过滤是否生效。

先弄清过滤器的两种字典结构

过滤器是一个字典(或嵌套字典),只允许两种类型(定义见 metadata-filtering):

Comparison(比较),必须包含三个键:

  • field:文档 meta 字段名,如meta.type
  • operator==!=>>=<<=innot in
  • value:单个值,in/not in时为列表。
filters = {"field": "meta.type", "operator": "==", "value": "article"}

Logic(逻辑),用于嵌套组合多个条件,必须包含:

  • operatorNOTORAND
  • conditions:Comparison 或 Logic 字典的列表。

一个组合示例:type为 article、date落在某时间戳区间内、rating≥ 3,且(genre属于 economy/politics 或publisher为 nytimes):

filters = { "operator": "AND", "conditions": [ {"field": "meta.type", "operator": "==", "value": "article"}, {"field": "meta.date", "operator": ">=", "value": 1420066800}, {"field": "meta.date", "operator": "<", "value": 1609455600}, {"field": "meta.rating", "operator": ">=", "value": 3}, { "operator": "OR", "conditions": [ { "field": "meta.genre", "operator": "in", "value": ["economy", "politics"], }, {"field": "meta.publisher", "operator": "==", "value": "nytimes"}, ], }, ], }

注意:具体支持哪些算子取决于 Document Store 集成。例如ChromaDocumentStore额外支持containsnot contains,但不支持NOT,细节要查对应集成的 API reference。

最小路径:用 FilterRetriever 过滤并断言结果

FilterRetriever可以配合任意 Document Store 工作,专门按过滤器取文档(见 FilterRetriever)。下面的示例自带断言,运行无报错即说明过滤命中了预期那一篇:

from haystack import Document from haystack.components.retrievers import FilterRetriever from haystack.document_stores.in_memory import InMemoryDocumentStore docs = [ Document(content="Python is a popular programming language", meta={"lang": "en"}), Document( content="python ist eine beliebte Programmiersprache", meta={"lang": "de"}, ), ] doc_store = InMemoryDocumentStore() doc_store.write_documents(docs) retriever = FilterRetriever(doc_store) result = retriever.run(filters={"field": "lang", "operator": "==", "value": "en"}) assert "documents" in result assert len(result["documents"]) == 1 assert result["documents"][0].content == "Python is a popular programming language"

这里 filters 在run()里传入,也可以放在初始化参数里。两点来自该文档的注意事项:FilterRetriever返回所有命中过滤器且不去重、不排序的文档,对文档量大的 Store 直接filter_retriever.run({})(不传 filters)会把全部文档推给下游组件;它也不计算相似度分数,需要按查询排序时应另配 Ranker 组件。

在 pipeline 里给 embedding 检索缩小范围

embedding-based 检索走InMemoryEmbeddingRetriever,它除query_embedding外接受可选的top_kfilters参数用于"narrow down the search space"(见 InMemoryEmbeddingRetriever)。示例使用sentence-transformers-haystack包的 embedder,运行前需要:

pip install sentence-transformers-haystack
from haystack import Document, Pipeline from haystack.document_stores.in_memory import InMemoryDocumentStore from haystack_integrations.components.embedders.sentence_transformers import ( SentenceTransformersTextEmbedder, SentenceTransformersDocumentEmbedder, ) from haystack.components.retrievers import InMemoryEmbeddingRetriever document_store = InMemoryDocumentStore(embedding_similarity_function="cosine") documents = [ Document( content="There are over 7,000 languages spoken around the world today.", meta={"type": "article"}, ), Document( content="Elephants have been observed to behave in a way that indicates a high level of self-awareness, such as recognizing themselves in mirrors.", meta={"type": "article"}, ), Document( content="In certain parts of the world, like the Maldives, Puerto Rico, and San Diego, you can witness the phenomenon of bioluminescent waves.", meta={"type": "report"}, ), ] document_embedder = SentenceTransformersDocumentEmbedder() documents_with_embeddings = document_embedder.run(documents)["documents"] document_store.write_documents(documents_with_embeddings) query_pipeline = Pipeline() query_pipeline.add_component("text_embedder", SentenceTransformersTextEmbedder()) query_pipeline.add_component( "retriever", InMemoryEmbeddingRetriever(document_store=document_store), ) query_pipeline.connect("text_embedder.embedding", "retriever.query_embedding") query = "How many languages are there?" # filters 通过 Pipeline.run 传入,管道会把它路由到 retriever 组件 result = query_pipeline.run( { "text_embedder": {"text": query}, "retriever": { "filters": {"field": "meta.type", "operator": "==", "value": "article"} }, } ) print(result["retriever"]["documents"])

文档中filters经由Pipeline.run()路由给 Retriever 的原始写法(来自 metadata-filtering):

pipeline.run( data={ "retriever": { "query": "Why did the revenue increase?", "filters": { "operator": "AND", "conditions": [ {"field": "meta.years", "operator": "==", "value": "2019"}, { "field": "meta.companies", "operator": "in", "value": ["BMW", "Mercedes"], }, ], }, }, }, )

判断过滤是否生效:检查result["retriever"]["documents"]里的每条 Document,其meta.type都应为"article"。文档未给出固定输出结果,上面print的实际内容以你的 embedder 模型计算出的相似度排序为准。BM25侧的InMemoryBM25Retriever同样接受top_kfilters可选参数(见 InMemoryBM25Retriever),传法一致。

不经过 Retriever 直接验证过滤器

Document Store 的协议方法filter_documents用来按 filters 返回命中文档(见 Document Store),适合在接入 pipeline 前先确认数据本身能被过滤。metadata-filtering 给出的QdrantDocumentStore示例:

filters = { "operator": "AND", "conditions": [ {"field": "meta.type", "operator": "==", "value": "article"}, {"field": "meta.genre", "operator": "in", "value": ["economy", "politics"]}, ], } results = QdrantDocumentStore.filter_documents(filters=filters)

关于field的写法:文档示例以meta.前缀为主,而FilterRetriever文档中的示例直接写field: "lang"不带前缀;InMemoryDocumentStore的元数据辅助方法(见 in_memory/document_store.py 中get_metadata_fields_info等方法的说明)接受带或不带"meta."前缀的字段名,两种写法在 InMemory store 上都可以用。

初始化 filters 与运行时 filters 的取舍

Retriever 的FilterPolicy决定静态 filters(init 时设置)和动态 filters(run 时传入)如何合并,取值见 Retrievers:

  • REPLACE(默认):运行时 filters 完全覆盖初始化时的 filters,适合让每次查询动态改变过滤范围;
  • MERGE:运行时 filters 与初始化 filters 合并,进一步收窄结果。

filters在 init 和 run 两处都可设置,filter_policy在所选 Retriever 的 init 方法中设置。以InMemoryBM25Retriever为例,源码 中 init 签名为filters: dict[str, Any] | None = Nonefilter_policy: FilterPolicy = FilterPolicy.REPLACE,run 时通过apply_filter_policy(self.filter_policy, self.filters, filters)合并,行为与文档描述一致。

限制与不适用场景

  • InMemoryDocumentStore无外部依赖、适合实验,官方文档不推荐用于生产环境;换成其他 Store 时,算子支持范围以该集成文档为准。
  • 过滤器只能缩小候选范围,不改变相似度排序;FilterRetriever本身不打分,需要排序时另接 Ranker。
  • 文档中引用的外部 tutorial(如 "Filtering Documents with Metadata")不在本仓库内,仓库内的语法依据以上述页面为准。

【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询