登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

Redis 向量查询怎样组合标签过滤与距离排序

来源:17golang原创

时间:2026-10-09 22:15:35 290浏览 收藏

做 Redis 向量检索时,业务条件往往不是“全库找最像”,而是“只在某个标签范围内找最像”。例如知识库要先限定 category=manual,再按 embedding 距离取前 5 条。稳定的写法是把标签条件放进 FT.SEARCH 的括号过滤表达式,再接 KNN,用 PARAMS 传入二进制查询向量,最后用距离别名和 SORTBY ... ASC 固定排序。

官方地址:https://redis.io/docs/latest/develop/ai/search-and-query/query/vector-search/

要点速览
  • 标签过滤放在 (...) 中,=> 后连接向量查询,避免把业务范围交给应用层再过滤。
  • KNN 解决固定 top-k;需要距离上限时改用 VECTOR_RANGE,两者都使用 DIALECT 2。
  • 距离字段必须显式命名并参与排序;$SHARD_K_RATIO 只对 Redis Cluster 有意义。

先把标签和向量放进同一个索引

本文假设文档至少包含三个字段:业务标签 category、可选的标题或摘要,以及向量字段 embedding。标签要按 TAG 方式建索引,向量的维度、类型和距离度量必须与生成 embedding 的模型保持一致。下面的命令只是一个最小结构示意,向量字节由应用生成,不要把示例中的占位串当成真实向量。

# 创建一个同时支持标签过滤和向量检索的索引
FT.CREATE idx:docs ON HASH PREFIX 1 "doc:" SCHEMA \
  category TAG SEPARATOR "," \
  title TEXT \
  embedding VECTOR HNSW 6 TYPE FLOAT32 DIM 768 DISTANCE_METRIC COSINE

# 写入文档时,embedding 应是模型输出的 FLOAT32 二进制内容
HSET doc:001 category "manual" title "Redis 查询手册" embedding ""

这里的重点不是索引参数越多越好,而是让过滤字段与向量字段属于同一查询模型。若标签没有按 TAG 建模,查询语法就不能按标签精确缩小候选;若 DIM 或距离度量不匹配,结果即使能返回,也没有可靠的业务含义。

先用标签缩小候选,再执行 KNN

KNN 适合“在满足条件的文档中固定取前 k 个”。Redis 的组合查询可以把 (@category:{manual}) 放在前面,=> 后接 [KNN 5 @embedding $query_vector AS distance]。这样标签是搜索范围,向量距离才是排序依据。

# 只在 manual 标签内找最相近的 5 条文档
FT.SEARCH idx:docs \
  "(@category:{manual})=>[KNN 5 @embedding $query_vector AS distance]" \
  PARAMS 2 query_vector "" \
  SORTBY distance ASC \
  RETURN 3 distance title category \
  DIALECT 2

PARAMS 2 后面是参数名和参数值,数量写错会导致查询无法正确绑定。AS distance 给向量分数起了稳定名字,随后才能用 SORTBY distance ASC 排序。返回字段也尽量收窄,先拿距离、标题和标签,正文或大字段按需二次读取。

Redis 向量查询中标签过滤、embedding 向量字段、PARAMS 查询向量与 KNN 结果的关系说明图
图1:Redis 向量查询的标签预过滤与 KNN 关系说明图,不是截图或运行证据。

距离字段、排序与验收边界

“返回了 5 条”并不等于查询正确,至少要核对三件事:结果是否都带目标标签、距离是否按升序排列、返回数量是否受 top-k 控制。还要分清两种需求:

需求查询方式判断重点
固定返回前 k 条KNN关注 top-k、距离排序与候选范围
只接受距离不超过阈值的结果VECTOR_RANGE关注半径、距离别名与分页
Redis Cluster 下调节召回与性能SHARD_K_RATIO只在集群环境有作用

当业务是“相似度至少达到某个标准”,不要先取很大的 KNN 再在应用层猜阈值,可以使用 VECTOR_RANGE,并通过 $YIELD_DISTANCE_AS 导出距离:

# 只返回 manual 标签中距离不超过 0.35 的结果,并按距离升序
FT.SEARCH idx:docs \
  "@category:{manual} @embedding:[VECTOR_RANGE 0.35 $query_vector]=>{$YIELD_DISTANCE_AS: distance}" \
  PARAMS 2 query_vector "" \
  SORTBY distance ASC RETURN 3 distance title category DIALECT 2

如果部署在 Redis Cluster,可以在 KNN 后设置 $SHARD_K_RATIO,让每个分片多取一些候选再汇总;它是召回与性能之间的调节旋钮,单机 Redis 不会因为写上它就获得额外效果。

Redis 向量距离别名、SORTBY ASC、RETURN 字段以及 KNN 和 VECTOR_RANGE 选择边界说明图
图2:距离字段与查询边界的静态结构说明图,不是截图或运行证据。

用一张清单验收组合查询

  1. 先用一个已知标签过滤,确认结果不会混入其他类别。
  2. 把 KNN 5 改成 KNN 1,确认返回数量和距离字段仍然存在。
  3. 固定同一个查询向量重复请求,确认距离排序稳定;不要用文档返回顺序代替显式排序。
  4. 将半径调小,确认 VECTOR_RANGE 会自然减少结果,而不是由应用层静默截断。
  5. 只有在 Cluster 场景下再比较 SHARD_K_RATIO,同时记录召回变化和延迟。

常见误区是把“标签过滤”和“向量排序”拆成两次查询:这样应用层可能先拿到过大的候选集,再承担过滤、排序和分页成本。把范围、距离和返回字段都写进 FT.SEARCH,查询意图更明确,也更容易排查参数错误。

常见问题

KNN 为什么必须写 DIALECT 2?

Redis 官方向量查询示例使用查询方言 2;组合 KNN、参数绑定和后续向量表达式时,应显式写出,避免环境默认值不同。

距离越小一定越相似吗?

只能在同一向量模型和同一距离度量下比较。本文按距离升序示例,实际含义仍取决于索引的 DISTANCE_METRIC 和模型输出。

为什么过滤条件写了却混入其他标签?

先检查字段是否按 TAG 建索引、标签值是否包含分隔符,再确认过滤表达式和向量查询位于同一条 FT.SEARCH 语句中。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>