首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >向量检索中的过滤:让结果保持相关

向量检索中的过滤:让结果保持相关

原创
作者头像
点火三周
发布2025-09-13 08:20:11
发布2025-09-13 08:20:11
1260
举报
文章被收录于专栏:Elastic Stack专栏Elastic Stack专栏

Vector search(向量检索)能够帮助我们在海量数据中找到语义相似的内容,但要想真正获得「有用」的结果,仅靠向量相似度还不够——我们还需要过滤(filtering)。正确理解在向量检索中如何应用过滤,可以帮助你在「性能-召回」之间取得平衡,同时也能了解 Elasticsearch / Lucene 在过滤场景下做了哪些优化。

为什么需要过滤?

向量检索让我们能快速在大规模数据中找到与查询语义相近的条目。然而,「相似」并不代表「满足需求」。在很多场景中,我们还希望基于特定属性进一步缩小结果范围。

想象一下在一个 电商 网站上搜商品:纯粹的向量检索可能找到一堆外观相似的商品,但你还想按价格区间、品牌、库存、评分等条件筛选。如果没有过滤,你会被淹没在海量相似商品里,难以快速定位目标。

过滤让我们对检索结果拥有精细的控制权——不仅语义相关,还完全符合业务约束,从而带来更准确、更高效、更友好的检索体验。也正因为此,Elasticsearch 与 Apache Lucene 在「跨多类型数据高效过滤」这一点上,比许多专用向量数据库更具优势。


精确(Exact)向量检索中的过滤

执行精确向量检索有两种主要方式:

  1. dense_vector 字段映射为 flat 索引类型。此时 knn 查询会走「精确」而非「近似」路径。
  2. 使用 script_score query 结合向量函数自行计算分值,此方式不受索引类型限制。

在精确检索中,系统会把查询向量与索引中所有向量逐一比较。如果先应用过滤,就只需要比较满足过滤条件的向量,大大节省计算量。

因此,只要过滤条件足够严格,精确检索可能比近似检索还快。经验法则:

• 过滤后命中文档 < 10k 时,用精确检索更合适。

• 如果使用 BBQ(Better Binary Quantization)索引,由于比较更快,过滤后文档 < 100k 也推荐走精确检索。

更多细节可参考这篇博客:KNN Exact vs Approximate Search

如果你的过滤条件几乎总是很严格,可以直接把向量字段映射为 flat 类型;具体可查看 index_options 参数


近似(Approximate)向量检索中的过滤

近似向量检索(如 HNSW)牺牲一定精度来换取性能,它通过最小化昂贵的「向量比较」操作来快速定位近邻。向量字段之外的其他属性(数值、关键词等)各自拥有专用索引结构:terms 字典、posting list、doc values……

这些结构与向量索引彼此独立,所以我们有两种给向量检索加过滤的策略:

  1. 后过滤(post-filtering):先做向量检索,再按过滤条件剔除不符文档。
  2. 预过滤(pre-filtering):先得到满足过滤的文档集合,再在其中做向量检索。

下面分别介绍两者的优缺点。

后过滤(Postfiltering)

后过滤在拿到「最相似的 k 个向量」之后再应用过滤条件,所以最终结果数≤k。我们可以把 k 设大一些,但仍无法保证最后一定返回 k 条。

优点:

• 对向量检索本身零侵入,运行时逻辑完全不变。

缺点:

• 最终结果数不可控;如果过滤掉太多,可能得到的结果不足 k 条。

示例(knn query + bool.filter):

代码语言:json
复制
{
  "query": {
    "bool": {
      "must": {
        "knn": {
          "field": "image-vector",
          "query_vector": [54, 10, -2],
          "k": 5,
          "num_candidates": 50
        }
      },
      "filter": {
        "term": {
          "file-type": "png"
        }
      }
    }
  }
}

knn search 也支持用 post_filter

代码语言:json
复制
{
  "knn": {
    "field": "image-vector",
    "query_vector": [54, 10, 2],
    "k": 5,
    "num_candidates": 50
  },
  "post_filter": {
    "term": {
      "file-type": "png"
    }
  }
}

注意:如果在 knn search 中不显式使用 post_filter,系统会把过滤条件与 KNN 结果合并,行为等同预过滤。


预过滤(Prefiltering)

预过滤会先用普通倒排/列式结构把「满足过滤条件的文档 ID」存进 BitSet。随后在遍历 HNSW 图时,每找到一个候选文档,先检查它是否在 BitSet 中;若不在就丢弃。

关键点:即便候选被丢弃,其邻居节点仍需继续探索,否则会破坏 HNSW 的图遍历特性——就像开车去加油站,即便当前道路没有加油站,你也得沿路开下去,因为它可能连通着目的地。

因此,预过滤一定比「无过滤」慢。但它能确保返回的 k 条结果全部符合过滤条件

示例(过滤写在 knn 内部):

代码语言:json
复制
{
  "knn": {
    "field": "image-vector",
    "query_vector": [54, 10, -2],
    "k": 5,
    "num_candidates": 50,
    "filter": {
      "term": {
        "file-type": "png"
      }
    }
  }
}

同样可用于 knn search

代码语言:json
复制
{
  "query": {
    "knn": {
      "field": "image-vector",
      "query_vector": [-5, 9, -12],
      "k": 5,
      "filter": {
        "term": {
          "file-type": "png"
        }
      }
    }
  }
}
预过滤的优化手段
  1. 自动切换到精确检索undefined如果过滤极其严格(命中文档很少),直接做精确检索更快。Lucene 与 Elasticsearch 都内置了此优化。
  2. ACORN-1 算法undefined该算法跳过不符合过滤条件的节点,只探索符合条件节点的邻居,大幅减少比较次数。详见官方博客

使用 DLS(Document Level Security)做过滤

Document Level Security 允许基于角色定义可见文档范围。本质上,DLS 会为角色配置一条查询,该查询过滤出的文档集合被缓存为 BitSet,并包裹到底层 Lucene Reader,使「不可见」文档对用户仿佛不存在。

在向量检索里:

• 对近似检索来说,DLS 与预过滤效果一致,具有相同的性能影响与优化策略。

• 对精确检索来说,DLS 像一般过滤一样:命中文档越少,性能越好。若 DLS 限制非常严格,可考虑直接使用精确检索。


基准测试(Benchmarking)

为了确保过滤场景下的向量检索性能,Elasticsearch 官方维护了一套专门的过滤基准

例如,在 ACORN-1 引入后,当仅 2% 向量通过过滤时,查询延迟降到了原来的 55%:

Benchmark 图示
Benchmark 图示

结论

过滤是搜索系统不可或缺的一环。理解它在向量检索中的实现与取舍,是打造高效、准确搜索体验的关键。

• 当过滤非常严格时,精确检索可能更快(Elasticsearch 会自动优化)。

• 近似检索 + 预过滤会变慢,但能保证返回的 k 条结果均符合过滤条件

• 后过滤对向量检索零侵入,但无法保证最终结果数达到 k。

祝你过滤愉快!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要过滤?
  • 精确(Exact)向量检索中的过滤
  • 近似(Approximate)向量检索中的过滤
    • 后过滤(Postfiltering)
    • 预过滤(Prefiltering)
      • 预过滤的优化手段
  • 使用 DLS(Document Level Security)做过滤
  • 基准测试(Benchmarking)
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档