Redis 全文搜索依赖官方提供的 RediSearch 模块来实现。RediSearch 可以对 hash 或 json 类型数据的任意字段建立二级索引,索引建立后,就能对相关字段执行搜索和聚合操作。
这里我们把被索引的 hash 或者 json 类型数据叫做源数据。
本文大纲如下:

使用体验
在简单场景下,用 RediSearch 平替 Elasticsearch 完全够用。Elasticsearch 中常见的查询语法,比如 AND、OR、IN、NOT IN、>、<、=、like 等,RediSearch 均能支持。
此外 RediSearch 还提供了聚合统计、停用词、文本标记和转义、同义词、标签、排序、向量查询、中文分词等能力。
就我个人体验来说,个人项目用 RediSearch 做全文搜索引擎已经足够,它的优势很明显:内存占用低、索引建立快、查询性能足够优秀。
后续发展
从官方对 RediSearch 的更新维护来看,活跃度相当不错:

最近一次提交记录在 12 月 17 号。
可以看到 RediSearch 的更新频率还是比较高的,而且是官方主导维护的模块,不用担心后续无人接手。
虽然 Redis 天生支持分布式集群,但 RediSearch 对 Redis 集群的支持还不完善。引用官方说明:

官方针对 RediSearch 的集群支持问题,提供了一个集群版本,但该版本只能在 Redis 企业版或者 Redis Cloud 上使用,开源版本暂未提供,这一点需要大家留意。
遇到 bug
在使用 RediSearch 的过程中,如果碰到了 bug 并且定位到问题来源于 RediSearch,不用慌,也不必抱怨难用——毕竟是开源项目,问题总是可以一起解决的。

大家可以看到 issue 列表中还有不少 bug 待处理。
本着开源共进的精神,希望大家发现 bug 后,第一时间到 RediSearch 官方 GitHub 上提 issue,帮助官方更快定位和修复问题。
RediSearch Github 仓库地址:https://github.com/RediSearch/RediSearch
下面我用 newbee-mall-pro 项目作为样本,介绍如何创建索引并关联源数据。
newbee-mall-pro 项目地址:https://github.com/wayn111/newbee-mall-pro
添加源数据
在 newbee-mall-pro 项目中,商品数据已经以 hash 类型存入了 Redis。
其中,key 名称的定义规则是 newbee_mall:goods: + 商品ID。
这里的 key 名称定义规则很重要,RediSearch 创建索引会基于 key 名称前缀来生成。
hash 类型的 value 包含以下属性:
goodsId : 商品 ID,唯一属性,由数据库商品表主键生成
goodsName : 商品名称
goodsIntro : 商品简介
goodsCategoryId : 商品分类 ID,唯一属性,由数据库商品分类表主键生成
goodsSellStatus : 商品上架状态,0 代表下架,1 代表上架
sellingPrice : 商品售价
originalPrice : 商品原价
tag : 商品标签
在 newbee-mall-pro 中,添加源数据的方法已经封装好了,核心逻辑在 JedisSearch.addGoodsListIndex() 方法里:
public boolean addGoodsListIndex(String keyPrefix, List<Goods> list) {
int chunk = 200;
List<List<Goods>> partition = ListUtil.partition(list, chunk);
AbstractPipeline pipelined = client.pipelined();
for (List<Goods> goodsList : partition) {
for (Goods goods : goodsList) {
RsGoodsDTO target = new RsGoodsDTO();
MyBeanUtil.copyProperties(goods, target);
Map<String, String> hash = MyBeanUtil.toMap(target);
// 支持中文
hash.put("_language", Constants.GOODS_IDX_LANGUAGE);
pipelined.hset(keyPrefix + goods.getGoodsId(), hash);
}
}
pipelined.sync();
return true;
}
上述代码就是把商品列表以 hash 类型写入 Redis,为了提升写入速度,还使用了 Redis 的管道(pipeline)操作。
需要注意,hash 结构中额外加了一个 _language 字段,用来告诉 RediSearch:这个源数据关联的索引要使用中文分词查询。
建立索引
RediSearch 提供了一种简单且自动的方式,在 Redis hash 结构上创建二级索引,内部实现极大简化了这一过程(后续还会支持更多数据结构)。

如果要使用 RediSearch 查询商品 hash 结构里的 goodsName 字段,就必须先对该字段建立索引。
Jedis 新建索引
在 newbee-mall-pro 项目中,建立索引的逻辑在 GoodsServiceImpl.syncRs() 方法中:
// 定义索引结构
public boolean syncRs() {
jedisSearch.dropIndex("idx:goods");
Schema schema = new Schema()
.addSortableTextField("goodsName", 1.0)
.addSortableTextField("goodsIntro", 0.5)
.addSortableNumericField("goodsId")
.addSortableNumericField("goodsCategoryId")
.addSortableNumericField("goodsSellStatus")
.addSortableNumericField("sellingPrice")
.addSortableNumericField("originalPrice")
.addSortableTagField("tag", "|");
jedisSearch.createIndex(Constants.GOODS_IDX_NAME, Constants.GOODS_IDX_PREFIX, schema);
}
上述代码对商品 hash 结构中的以下字段建立了索引:
goodsName:文本类型,可排序,权重 1.0
goodsIntro:文本类型,可排序,权重 0.5
goodsId:数字类型,可排序
goodsCategoryId:数字类型,可排序
goodsSellStatus:数字类型,可排序
sellingPrice:数字类型,可排序
originalPrice:数字类型,可排序
tag:标签类型,可排序,分隔符为 |
在 RediSearch 中,可添加的字段类型包括 text、numeric、tag 等,也可以设置字段是否排序。
权重系数的设置也很实用:它表示该字段已加权,在搜索操作完成后进入打分排序阶段时,可以对不同字段赋予不同的重要性级别,从而提升或降低某些字段对最终排名的影响。
Redis 中的新建索引语法
当把上面的 Jedis 新建索引代码转换为 Redis 原生语法后,如下所示:
> FT.CREATE idx:goods ON hash PREFIX 1 "newbeemall:goods:" \
SCHEMA goodsName TEXT SORTABLE WEIGHT 1.0 \
SCHEMA goodsIntro TEXT SORTABLE WEIGHT 0.5 \
goodsId NUMERIC SORTABLE \
goodsCategoryId NUMERIC SORTABLE \
goodsSellStatus NUMERIC SORTABLE \
sellingPrice NUMERIC SORTABLE \
originalPrice NUMERIC SORTABLE \
tag TAG SORTABLE SEPARATOR "|"
下面详细拆解这条命令:
FT.CREATE:RediSearch 中创建索引的语法。
idx:goods:指定索引名称。索引名称会出现在所有键名中,建议保持简短。
ON hash:指定索引关联的结构类型。需要注意的是,RediSearch 2.0 仅支持哈希结构,随着版本更新,后续有望支持更多数据结构。
PREFIX 1 "newbeemall:goods:":指定索引关联的源数据 key 前缀,可以同时指定多个前缀。
SCHEMA ...:字段定义,用于声明字段名称、类型、是否排序、权重等,可以定义多个字段。
如果想深入了解 FT.SEARCH 的语法以及字段定义相关知识,可以查阅官方文档:
https://redis.io/docs/interact/search-and-query/basic-constructs/schema-definition
Redis 中查询索引定义
要查询已存在的索引详情同样很简单,官方提供了 FT.INFO 索引名称 语法,用于打印索引详情:
> FT.INFO idx:goods
最后聊两句
本文以开源项目 newbee-mall-pro 为样本,详细拆解了 RediSearch 在项目实战中创建索引与关联源数据的完整流程,希望能给你带来一些启发。如果你对 Redis 全文搜索还有疑问,或者想交流更多 Java 项目实战经验,欢迎来云栈社区一起聊聊。