RedisJSON + RediSearch

发现一个好玩且性能很高的数据查询方式,可以进行数据查询筛选聚合,也具备全文搜索引擎的功能

准备

使用docker快速搭建,镜像为redis/redis-stack:7.0.2-RC1,其中RedisJSON版本为2.2.0,RediSearch版本为2.4.11

1
2
3
docker run -d --name redis-stack -p 6379:6379 --restart=always \
-e REDIS_ARGS="--requirepass 7Fbvh0EMaN0Ieovgj2N7Y3MmKhf0lOTZ" \
redis/redis-stack:7.0.2-RC1

准备数据

1
2
3
4
5
JSON.SET phone:1 $ '{"name": "锤子8plus","description": "锤子手机-5G-128G","brandName":"锤子","price": 3299, "keyword":["锤子","plus","锤子8"]}'
JSON.SET phone:2 $ '{"name": "华为Mate40 pro","description": "HuaWei-5G-128G","brandName":"华为","price": 6499, "keyword":["华为","Mate","40","pro","华为Mate","Mate40","Mate40 pro","华为Mate40"]}'
JSON.SET phone:3 $ '{"name": "华为Mate30 pro","description": "HuaWei-5G-128G","brandName":"华为","price": 4499, "keyword":["华为","Mate","30","pro","华为Mate","Mate30","Mate30 pro","华为Mate30"]}'
JSON.SET phone:4 $ '{"name": "华为Nova10","description": "HuaWei-5G-128G","brandName":"华为","price": 2999, "keyword":["华为","Nova","10","pro","华为Nova","Nova10"]}'
JSON.SET phone:5 $ '{"name": "vivoS15","description": "vivo-S15-5G-128G","brandName":"vivo","price": 2569, "keyword":["vivo","S15"]}'

建立索引

1
FT.CREATE idx_test ON JSON PREFIX 1 'phone:' LANGUAGE chinese SCHEMA $.name AS name TEXT $.description as description TEXT $.brandName AS brandName TAG $.price AS price NUMERIC SORTABLE $.keyword.* as keyword TAG

搜索

RediSearch搜索中TEXT内容会全文搜索,以关键词的形式进行搜索。如‘@name:华为’能搜索到3条记录,但如果进行‘@name:华为Mate40’的搜索却一条也搜索不到,因为RediSearch认为“华为”和“Mate40”是两个词。

查询所有数据

1
FT.SEARCH idx_test *

搜索name字段中包含“华为”关键词的数据

1
FT.SEARCH idx_test '@name:华为'

搜索name字段中包含“华为”和“Mate40”关键词的数据

1
FT.SEARCH idx_test '@name:(华为 Mate40)'

搜索name字段中包含“华为”或“锤子”关键词的数据

1
FT.SEARCH idx_test '@name:(华为|锤子)'

搜索name字段中包含“华为”关键词且价格在3000到6000的数据

1
FT.SEARCH idx_test '@name:华为 @price:[3000, 6000]'

模糊搜索

搜索name字段中包含开头为“华”的数据(但默认情况下不能使用“*为”进行前缀匹配,需要修改配置)

1
FT.SEARCH idx_test '@name:华*'

搜索name字段中包含“Mate50”的数据,对LD为1的所有关键词进行模糊匹配,所以这里能搜索到Mate40和Mate30的数据

1
FT.SEARCH idx_test '@name:%Mate50%'

搜索name字段中包含“Qate51”的数据,对LD为3的所有关键词进行模糊匹配,所以这里能搜索到Mate40和Mate30的数据

1
FT.SEARCH idx_test '@name:%%%Qate51%%%'

使用通配符,目前版本感觉存在问题

1
FT.SEARCH idx_test @description:w'vivo?128G'

聚合查询

每千元一个挡位进行分组

1
2
3
FT.AGGREGATE idx_test *
APPLY '@price - (@price % 1000)' AS level
GROUPBY 1 @level REDUCE COUNT_DISTINCT 1 @name AS num

排序分页

按价格排序,只查询出name和price字段

1
FT.SEARCH idx_test * RETURN 2 name price name SORTBY price DESC

按价格排序,只查询出name和price字段,从第3条开始,查询2条数据

1
FT.SEARCH idx_test * RETURN 2 name price LIMIT 3 2 SORTBY price DESC

分词

rediSearch会将TEXT类型内容进行简单的分词(且忽略大小写),比如搜索“华为”或“Mate40”或“mate40”都能出现“华为Mate40 pro”这条数据,但分词效果一般,用“Mate”或“华为Mate40”搜索不到数据。

1.可以自定义词库的方法进行优化,这里就不介绍了。

2.使用空格或横线等方式让rediSearch对内容进行分词,从而达到想要的搜索效果,比如本次测试数据中的description字段

搜索description字段中包含“5G”关键词的数据

1
FT.SEARCH idx_test '@description:5G'

3.使用数组搜索,将分好的关键词放入其中数组中

测试使用的是TAG类型进行数组搜索,TAG类型搜索时并不会分词(但同样忽略大小写),必须完全相等才能匹配。

搜索keyword数组中包含“华为”和“Mate”的数据

1
FT.SEARCH idx_test '@keyword:{华为} @keyword:{Mate}'

搜索keyword数组中包含“华为”或“Mate”的数据

1
FT.SEARCH idx_test '@keyword:{华为|Mate}'

参考文献