Webman集成RediSearch做全文索引,关键在于索引结构、源数据绑定、查询语义三处;需严格匹配PREFIX、显式指定TEXT字段WEIGHT、doc_id与HSET key一致、显式RETURN字段并避免重复建索引。

Webman 集成 Redisearch 做全文索引,关键不在“能不能连上”,而在于索引结构、源数据绑定、查询语义这三处不设防就崩。Redisearch 本身不支持动态 mapping,字段类型一旦错配(比如把数字当文本建索引),后续写入直接失败且无明确报错;更隐蔽的是 prefix 规则写错或 hash key 不对齐,会导致 FT.ADD 手动加的数据进不了倒排索引,查不到还找不到原因。
FT.CREATE 的 PREFIX 必须严格匹配源数据 key
Redisearch 不自动扫描所有 hash,它只监听你声明的 prefix 下的 key 变更。如果你存商品用 HSET goods:1001 title "iPhone" price 5999,那创建索引时 FT.CREATE idx:goods ON HASH PREFIX 1 "goods:" 就必须带结尾冒号,少一个字符(如写成 "goods")或漏掉引号,索引就收不到任何变更。
常见错误现象:数据明明存在,FT.SEARCH idx:goods "@title:iphone" 返回空数组,但 FT.INFO idx:goods 显示 num_docs: 0。
- 确认源数据 key 格式:用
KEYS goods:*或SCAN 0 MATCH goods:* COUNT 10实际看一遍 - PREFIX 参数是字符串字面量,不是 glob 模式,不支持
*或? - 多个 prefix 要写成
PREFIX 2 "goods:" "user:",不能合并成一个字符串
TEXT 字段必须显式指定 WEIGHT,否则中文权重归零
Redisearch 对 TEXT 字段默认 weight 是 1.0,但实测在中文场景下,若不显式写 WEIGHT 5.0,match 算分极低,哪怕完全匹配也排不到前面。这不是 bug,是 TF-IDF 权重计算对单字分词敏感导致的副作用。
示例错误写法:FT.CREATE idx ON HASH SCHEMA title TEXT content TEXT → 中文搜索结果混乱,高相关文档靠后。
- 标题类字段建议
WEIGHT 5.0,正文类WEIGHT 1.0,标签类可用TAG替代 - 不要给同一个字段重复定义(如
title TEXT title TAG),会触发ERR Schema is invalid - 字段名区分大小写,
title和Title是两个字段
PHP 客户端调用 FT.ADD 时 doc_id 必须与 HSET key 一致
Webman 是常驻进程,不能依赖 Redisearch 自动同步(它只监听模块加载后的变更)。很多同学先 HSET goods:1001 ...,再用 PHP 客户端 $client->addDocument('doc_1001', [...]),结果查不到——因为 doc_1001 和 goods:1001 不同,索引根本没关联到源数据。
正确做法是:doc_id 必须等于你存 hash 的完整 key,且类型必须是 string(不能是 int)。
- 写入时统一用
$redis->hSet('goods:'.$id, [...]),然后$client->addDocument('goods:'.$id, [...]) - 如果源数据是 JSON,改用
ON JSON PREFIX 1 "goods:",doc_id 就是 JSON key,如goods:1001 - weight 参数传
1.0即可,别传0或空字符串,否则被当成无效文档丢弃
搜索时不用 RETURN 就默认返回全部字段,性能雪崩
Redisearch 默认返回所有 indexed 字段 + score,但 Webman 常驻进程下,每个请求都扛着 10+ 字段的完整 payload,内存和网络开销翻倍。更麻烦的是,如果你建索引时用了 SORTABLE 字段(如 price NUMERIC SORTABLE),不加 RETURN 会让 Redisearch 强制加载这些字段做排序预处理,哪怕你根本不需要排序。
错误示例:FT.SEARCH idx:goods "@title:手机" LIMIT 0 20 → 返回每条记录含 title/content/price/category 全部内容。
- 务必显式写
RETURN 2 title price,只取前端真正要展示的字段 - 需要高亮就加
HIGHLIGHT FIELDS 1 title,不加则不触发分词高亮逻辑 -
LIMIT必须有,且首参数不能大于 1000;超长分页用SEARCH_AFTER,Redisearch 不支持from/size深度分页
最易被忽略的一点:Redisearch 的 SCHEMA 一旦创建就不能修改字段类型。Webman 启动时若执行 FT.CREATE 两次(比如开发环境反复 reload),第二次会报错并中断初始化——得先 FT.DROPINDEX idx:goods DD 再重建,但线上严禁这么做。稳妥做法是启动前用 FT.INFO 检查索引是否存在,仅不存在时才建。


















