Redis 也支持全文搜索?这也太强了

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Redis 也支持全文搜索?这也太强了

在 2021 年我就了解到 RediSearch 这个项目,并已经把它用于我的开源项目 newbee-mall-pro 中。

就我的使用体验来说,简单场景下,用来平替 Elasticsearch 的使用场景已经足够。像是 Elasticsearch 中常用中文分词插件可以用 RediSearch 替代,但是拼音转中文插件在 RediSearch 中还没有功能替代,只能通过个人手段处理。

在 newbee-mall-pro 项目中,拼音搜索我是通过先将中文转拼音后作为拼音字段存入 Redis 中,再通过 RediSearch 查询拼音字段来实现的。

RediSearch 对于我来说相比 Elasticsearch 的最大优点就是 内存占用非常低,查询性能也足够高😂。

在我的低配 2 核 4g 内存的服务器上,通过官方提供的 Redis Stack 镜像部署 Redis 以及自带模块 RediSearch 后,内存占用才不到 100m。

相比部署一个 Elasticsearch 起码需要 1g 内存来说,我更愿意部署 RediSearch。本文大纲如下,

图片

RediSearch 简介

RediSearch 是一个 Redis 模块,为 Redis 提供查询、二级索引和全文搜索功能。

要使用 RediSearch 的功能,我们需要要先声明一个 index(类似于 Elasticsearch 的索引)。然后就可以使用 RediSearch 的查询语言来查询该索引下的数据。

RediSearch 内部使用压缩的倒排索引,所以可以用较低的内存占用来实现索引的快速构建。

目前 RediSearch 最新版支持的查询功能也比较丰富了,除了基本的文本分词还支持聚合统计、停用词、同义词、拼写检查、结果排序、标签查询、向量相似度查询以及中文分词等。

对比 Elasticsearch

基本硬件

数据源

RediSearch 配置

Elasticsearch 配置

版本

索引构建测试

在官方提供的索引构建测试中,RediSearch 用 221 秒的速度超过了 Elasticsearch 的 349 秒,领先 58%,

查询性能测试

通过数据集导入索引数据后,官方使用运行在专用负载生成器服务器上的 32 个客户端启动了两个词的搜索查询。

如下图所示,RediSearch 的吞吐量达到了 12.5K ops/sec,而 Elasticsearch 的吞吐量只有了 3.1K ops/sec,快了 4 倍。此外 RediSearch 的延迟稍好一些,平均为 8 毫秒,而 Elasticsearch 为 10 毫秒。(ops/sec 每秒操作数)

由此可见,RediSearch 在性能上对比 RediSearch 有比较大的优势。


目前 RediSearch 已经更新到 2.0+ 版本,根据官方对于 RediSearch 2.0 版本介绍,与 RediSearch 1.6 相比,吞吐量和延迟相关的指标都提高了 2.4 倍。

RediSearch 安装

对于目前最新的 RediSearch 2.0 版本来说,官方推荐直接使用 redis-stack-server 镜像进行进行部署,也比较简单,

复制

docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest• 1.

设置登录

复制

// 设置登录
docker run -e REDIS_ARGS="--requirepass redis-stack" redis/redis-stack:latest• 1.
• 2.

通过 redis-cli 连接查看 RediSearch 是否安装了 search 模块,

复制

redis-cli -h localhost
module list
> MODULE list
...
3) 1) "name"
   2) "search"
   3) "ver"
   4) "20809"
   5) "path"
   6) "/opt/redis-stack/lib/redisearch.so"
   7) "args"
   8) 1) "MAXSEARCHRESULTS"
      2) "10000"
      3) "MAXAGGREGATERESULTS"
      4) "10000"
...• 1.
• 2.
• 3.
• 4.
• 5.
• 6.
• 7.
• 8.
• 9.
• 10.
• 11.
• 12.
• 13.
• 14.
• 15.
• 16.

索引操作

FT.CREATE 创建索引命令

复制

> FT.CREATE idx:goods on hash prefix 1 "goods:" language chinese schema goodsName text sortable
"OK"• 1.
• 2.
  • FT.CREATE:创建索引命令
  • idx:goods:索引名称
  • on hash:索引关联的数据类型,这里指定索引基于 hash 类型的源数据构建
  • prefix 1 "goods:":表示索引关联的 hash 类型源数据前缀是 goods:
  • language chinese:表示支持中文语言分词
  • schema goodsName text sortable:表示字段定义,goodsName 表示元数据属性名,text 表示字段类型 sortable 表示该字段可以用于排序

添加索引时,直接使用 hset 命令添加一个 key 前缀是 "goods:" 的源数据。如下,

复制

hset goods:1001 goodsName 小米手机
hset goods:1002 goodsName 华为手机• 1.
• 2.

FT.SEARCH 查询索引

复制

> FT.SEARCH idx:goods1 "手机"
1) "2"
2) "goods:1001"
3) 1) "goodsName"
   2) "\xe5\xb0\x8f\xe7\xb1\xb3\xe6\x89\x8b\xe6\x9c\xba"
4) "goods:1002"
5) 1) "goodsName"
   2) "\xe5\x8d\x8e\xe4\xb8\xba\xe6\x89\x8b\xe6\x9c\xba"• 1.
• 2.
• 3.
• 4.
• 5.
• 6.
• 7.
• 8.

FT.INFO 查询指定名称索引信息

复制

> FT.INFO idx:goods
1) "index_name"
2) "idx:goods1"
3) "index_options"
4) (empty list or set)
5) "index_definition"
6) 1) "key_type"
   2) "HASH"
   3) "prefixes"
   4) 1) "goods:"
   5) "default_language"
   6) "chinese"
   7) "default_score"
   8) "1"
7) "attributes"
8) 1) 1) "identifier"
      2) "goodsName"
      3) "attribute"
      4) "goodsName"
      5) "type"
      6) "TEXT"
      7) "WEIGHT"
      8) "1"
      9) "SORTABLE"
...• 1.
• 2.
• 3.
• 4.
• 5.
• 6.
• 7.
• 8.
• 9.
• 10.
• 11.
• 12.
• 13.
• 14.
• 15.
• 16.
• 17.
• 18.
• 19.
• 20.
• 21.
• 22.
• 23.
• 24.
• 25.
  • FT.INFO 查询指定名称的索引信息

FT.DROPINDEX 删除索引名称

复制

> FT.DROPINDEX idx:goods1
"OK"• 1.
• 2.
  • FT.DROPINDEX 删除指定名称索引,不会删除 hash 类型的源数据

如果需要删除索引数据,直接使用 del 命令删除索引关联的源数据即可。

Java 使用 RediSearch

对于 Java 项目直接选用 Jedis4.0 以上版本就可以使用 RediSearch 提供的搜索功能,Jedis 在 4.0 以上版本自动支持 RediSearch,编写 Jedis 连接 RedisSearch 测试用例,用 RedisSearch 命令创建如下,

Jedis 创建 RediSearch 客户端

复制

@Bean
public UnifiedJedis unifiedJedis(GenericObjectPoolConfig jedisPoolConfig) {
    UnifiedJedis client;
    if (StringUtils.isNotEmpty(password)) {
        client = new JedisPooled(jedisPoolConfig, host, port, timeout, password, database);
    } else {
        client = new JedisPooled(jedisPoolConfig, host, port, timeout, null, database);
    }
    return client;
}• 1.
• 2.
• 3.
• 4.
• 5.
• 6.
• 7.
• 8.
• 9.
• 10.

Jedis 创建索引

复制

Schema schema = new Schema()
        .addSortableTextField("goodsName", 1.0)
        .addSortableTagField("tag", "|");
IndexDefinition rule = new IndexDefinition(IndexDefinition.Type.HASH)
        .setPrefixes("idx:goods")
        .setLanguage("chinese"); # 设置支持中文分词
client.ftCreate(idxName,
        IndexOptions.defaultOptions().setDefinition(rule),
        schema);• 1.
• 2.
• 3.
• 4.
• 5.
• 6.
• 7.
• 8.
• 9.

Jedis 添加索引源数据

复制

public boolean addGoodsIndex(String keyPrefix, Goods goods) {
    Map<String, String> hash = MyBeanUtil.toMap(goods);
    hash.put("_language", "chinese");
    client.hset("idx:goods" + goods.getGoodsId(), MyBeanUtil.toMap(goods));
    return true;
}• 1.
• 2.
• 3.
• 4.
• 5.
• 6.

Jedis 中文查询

复制

public SearchResult search(String goodsIdxName, SearchObjVO searchObjVO, Page<SearchPageGoodsVO> page) {
    // 查询关键字
    String keyword = searchObjVO.getKeyword();
    String queryKey = String.format("@goodsName:(%s)", keyword);
    Query q = new Query(queryKey);
    String sort = searchObjVO.getSidx();
    String order = searchObjVO.getOrder();
    // 查询是否排序
    if (StringUtils.isNotBlank(sort)) {
        q.setSortBy(sort, Constants.SORT_ASC.equals(order));
    }
    // 设置中文分词查询
    q.setLanguage("chinese");
    // 设置分页
    q.limit((int) page.offset(), (int) page.getSize());
    // 返回查询结果
    return client.ftSearch(goodsIdxName, q);
}• 1.
• 2.
• 3.
• 4.
• 5.
• 6.
• 7.
• 8.
• 9.
• 10.
• 11.
• 12.
• 13.
• 14.
• 15.
• 16.
• 17.
• 18.
• 19.

最后聊两句

RediSearch 是这几年新出的一个全文搜索引擎,借助于 Redis 的成功,RediSearch 一出场就获得了较高的关注度。

目前来看,我个人使用 RediSearch 作为 newbee-mall-pro 项目的全文搜索引擎已经够用了,它有易于安装、索引占用内存低、查询速度快等许多优点。不过在对 Redis 集群的支持上,RediSearch 目前只针对 Redis 企业版有解决方案,开源版还没有,这一点需要告诉大家。

如果想要在生产环境大规模使用,我还是不太建议的。

最后本文使用的 Jedis 操作 RediSearch 相关代码,都在 newbee-mall-pro 项目的 JedisSearchTest 类有体现。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
缓存 NoSQL 架构师
Redis 三种批量查询技巧,高并发场景下的利器
在高并发场景下,巧妙地利用缓存批量查询技巧能够显著提高系统性能。 在笔者看来,熟练掌握细粒度的缓存使用是每位架构师必备的技能。因此,在本文中,我们将深入探讨 Redis 中批量查询的一些技巧,希望能够给你带来一些启发。
1026 0
Redis 三种批量查询技巧,高并发场景下的利器
|
存储 缓存 NoSQL
Redis点赞业务的设计与实现(Redis键值设计)
案例分享Redis点赞业务实现!
1384 2
Redis点赞业务的设计与实现(Redis键值设计)
|
1月前
|
存储 NoSQL 关系型数据库
Redis 实战篇:巧用数据类型实现亿级数据统计
Redis 实战篇:巧用数据类型实现亿级数据统计
98 0
|
1月前
|
存储 NoSQL Java
Redis高级技巧:性能提升100%不是梦
Redis,作为一种广泛使用的高性能键值对数据库,已成为现代应用架构不可或缺的组成部分。其快速的数据处理能力使其在处理大量数据时显得尤为重要。
171 2
Redis的高性能怎么做到的?
Redis的高性能怎么做到的? Redis这个NOSQL数据库在计算机界可谓是无人不知,无人不晓。只要涉及到数据那么就需要数据库,数据库类型很多,但是NOSQL的kv内存数据库也很多,redis作为其中一个是怎么做到行业天花板的呢?是怎么做到高性能的呢?怎么做到高可用的呢?今天这篇八股文我就整理一些redis的设计写写,本篇还是偏关于高性能这一块。
|
负载均衡 NoSQL 网络协议
Redis Plus 来了,性能炸裂!
Redis Plus 来了,性能炸裂!
为什么 Redis 的查询很快,Redis 如何保证查询的高效
Redis 如何保证高效的查询效率 为什么 Redis 比较快 Redis 中的查询速度为什么那么快呢?
|
存储 NoSQL JavaScript
实战!Redis 巧用数据类型实现亿级数据统计!
实战!Redis 巧用数据类型实现亿级数据统计!
|
存储 NoSQL 算法
Redis源码剖析之GEO——Redis是如何高效检索地理位置的?
Redis源码剖析之GEO——Redis是如何高效检索地理位置的?
169 0