数据库
在 Redis 上设计搜索索引、编写…
为 Redis Search 从建索引、字段类型选择、查询/聚合/向量/混合检索到 RAG 与运维排障提供完整可执行指南。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Redis 上设计搜索索引、编写 F特定
解决思路
- 命令选择:优先用最窄可满足需求的查询命令;FT.SEARCH 用于文档检索、排序/排名,返回匹配文档,是默认选择;最低 Redis 2.0(模块)/8.0(内置)。
- 需要分面、计算字段、自定义输出结构或分析时用 FT.AGGREGATE,把它当作声明式管道:LOAD、APPLY、GROUPBY、REDUCE、SORTBY;最低 Redis 2.0/8.0。
- 需要将词法(BM25)与向量相似度融合且可配置融合方式时用 FT.HYBRID,显式包含 SEARCH + VSIM 两条腿和 COMBINE 融合阶段;最低 Redis 8.4.0。
- 若 Redis < 8.4,用 FT.SEARCH 预过滤 + `=>[KNN ...]` 近似词法+向量混合。
- 创建、修改或审查搜索索引时使用 `FT.CREATE`/`FT.ALTER`;修改现有索引结构用 `FT.ALTER`,零停机变更优先用别名方案。
- `FT.CREATE` 可为匹配 `PREFIX` 的 Hash 或 JSON 文档建索引;始终设置 `PREFIX`。
- 使用 `DIALECT 2`;它是 Redis 8 起默认值,且向量查询必需。
- 字段类型选最窄满足访问模式:`TEXT` 用于全文搜索;会分词和词干化;不要用于精确匹配。
- 字段类型选最窄满足访问模式:`TAG` 用于精确匹配/过滤;加 `SORTABLE UNF` 以获得最快 TAG 查询。
- 字段类型选最窄满足访问模式:`NUMERIC` 用于范围查询和排序,如价格、计数、时间戳。
- 字段类型选最窄满足访问模式:`GEO` 用于经纬度点,如商店、用户。
- 字段类型选最窄满足访问模式:`GEOSHAPE` 用于多边形/区域查询,如配送区域、地区。
- 字段类型选最窄满足访问模式:`VECTOR` 用于相似度搜索,选 HNSW 或 FLAT。
- 字段类型选最窄满足访问模式:JSON 嵌套字段用 `$.path AS alias`,并在 `ON JSON` 上建索引。
- 避免经典错误:因为 category/status 是字符串就用 `TEXT`;精确匹配过滤用 `TAG` 约快 10 倍。
- 查询时用过滤条件收窄,并只返回需要的字段;示例 `FT.SEARCH idx:products "@category:{electronics} @price:[100 500]" SORTBY price ASC LIMIT 0 20 RETURN 3 name price category`。
- 组合文本和标签过滤:示例 `FT.SEARCH idx:products "wireless headphones @category:{audio}"`。
- 使用否定、OR 和可选/加权:空格=AND,`|`=OR,`-`=NOT,`~`=可选(评分提升),`=>{$weight: N}`=加权。
- TAG 值中的连字符和特殊字符要转义,例如 `@sku:{ABC\-123}`。
- 处理分词问题:留意词干化、停用词、语言。
- 控制结果形态:使用 `SORTBY`、`RETURN`、`HIGHLIGHT`、`SUMMARIZE`、`NOCONTENT`。
- 查询性能优化:使用预过滤器、`SORTABLE` 字段、收紧 `RETURN`,并用 `FT.PROFILE` 分析。
- 向量索引必须让 `DIM` 与嵌入模型完全匹配:例如 OpenAI `text-embedding-3-small` 为 1536;不匹配会产生静默垃圾结果。
- 向量索引必须让 `DISTANCE_METRIC` 与嵌入模型完全匹配:归一化文本嵌入常用 `COSINE`;未归一化内积用 `IP`;原始欧氏距离用 `L2`。
- 向量索引必须让 `TYPE` 与嵌入模型完全匹配:通常 `FLOAT32`;只有内存是瓶颈时才用 `FLOAT16` 或量化变体。
- 建向量索引示例:`FT.CREATE idx:docs ON HASH PREFIX 1 doc: SCHEMA content TEXT embedding VECTOR HNSW 6 TYPE FLOAT32 DIM 1536 DISTANCE_METRIC COSINE`。
- 纯 KNN 查询示例:`FT.SEARCH idx:docs "*=>[KNN 5 @embedding $vec AS score]" PARAMS 2 vec "..." SORTBY score DIALECT 2`。
- 选向量算法:HNSW 快、近似、约 95%+ 召回可调、内存更高,用于生产、>10k 向量、延迟敏感场景。
- 选向量算法:FLAT 慢、精确、100% 召回、内存更低,用于小语料(<10k)或必须精确匹配场景。
- 调 HNSW 参数 `M`:取 16–64,表示每节点连接数。
- 调 HNSW 参数 `EF_CONSTRUCTION`:取 100–500,控制构建质量。
- 调 HNSW 参数 `EF_RUNTIME`:控制查询时候选列表。
- 混合检索模式一:filter-then-vector(任意 Redis 版本)——先应用属性过滤,让引擎在向量比较前收窄搜索空间。
- filter-then-vector 示例:`FT.SEARCH idx:docs "(@category:{tech} @date:[2024 +inf])=>[KNN 10 @embedding $vec AS score]" PARAMS 2 vec "..." SORTBY score DIALECT 2`。
- 混合检索模式二:lexical + vector fusion(Redis ≥ 8.4)——将 BM25 文本评分与向量相似度混合,用 RRF 或 LINEAR 融合,使用 FT.HYBRID。
- 不要获取宽泛未过滤结果后在客户端过滤——更慢且更不准确。
- 聚合与结果塑形使用 FT.AGGREGATE 声明式管道;按阶段组装。
- 聚合示例:`FT.AGGREGATE idx:orders "@status:{shipped}" LOAD 2 @category @amount GROUPBY 1 @category REDUCE SUM 1 @amount AS revenue SORTBY 2 @revenue DESC LIMIT 0 5`。
- 常用聚合阶段:`LOAD`、`APPLY`(计算字段)、`FILTER`(查询后过滤)、`GROUPBY` + `REDUCE`(`SUM`、`COUNT`、`AVG`、`FIRST_VALUE`、`TOLIST`)、`SORTBY`、`LIMIT`。
- 对长时间运行的结果集使用 `WITHCURSOR` + `FT.CURSOR READ` 做服务端分页。
- RAG 标准流水线:嵌入查询 → 在 Redis 中向量搜索 → 将 top-K 上下文传给 LLM。
- RAG 实操:将距离度量与嵌入模型匹配(归一化文本模型几乎总是 `COSINE`)。
- RAG 实操:对长文档分块,200–500 token 块通常优于整页索引。
- RAG 实操:批量插入,不要每条记录一次调用。
- RAG 实操:在向量搜索前用属性(租户、时效、文档类型)预过滤。
- RAG 实操:如果精确率比召回率更重要,在漏斗顶部重排。
- 零停机模式变更:应用查询指向别名,替换底层索引。
- 零停机示例:`FT.CREATE idx:products_v2 ON HASH PREFIX 1 product: SCHEMA ...`;`FT.ALIASUPDATE products idx:products_v2`;应用查询保持 `FT.SEARCH products "@category:{electronics}"`。
- 管理命令:`FT.INFO`、`FT.DROPINDEX`、`FT._LIST`、`FT.ALIASADD/UPDATE/DEL`。
- 调试空结果或慢查询:用 `FT.EXPLAIN` 查看查询如何被解析,用 `FT.PROFILE` 查看执行统计,用 `FT.INFO` 查看索引信息。
- 客户端示例以 CLI/RESP 形式给出;这是所有客户端序列化到的 wire protocol。
- 具体客户端惯用写法参考 redis-py、Jedis、RedisVL;其他客户端(Lettuce、node-redis、go-redis、NRedisStack、.NET)转换相同 CLI 形式。
适用边界 · 注意事项
- 未部署 Redis 或目标版本/模块不支持 Redis Search(FT.HYBRID 需 Redis ≥ 8.4)且无法安装或使用托管服务时,不适用。
- 需要在向量检索中获得 100% 精确召回且语料很小(<10k)时,不要选 HNSW;应改用 FLAT(仍属于 Redis Search)。
- 只需要简单键值缓存、不需要全文/标签/数值/地理/向量检索时,不要为它引入 Redis Search 索引。