在 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

设置登录密码

// 设置登录密码
docker run -e REDIS_ARGS="--requirepass redis-stack" redis/redis-stack:latest

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

redis-cli -h localhost

> 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"
...

索引操作

FT.CREATE 创建索引命令

> FT.CREATE idx:goods on hash prefix 1 "goods:" language chinese schema goodsName text sortable
"OK"
  • 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 华为手机

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"

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"
...
  • FT.INFO 查询指定名称的索引信息

FT.DROPINDEX 删除索引名称

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

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

Java 使用 RediSearch

对于 Java 项目直接选用 Jedis4.0 以上版本就可以使用 RediSearch 提供的搜索功能,Jedis 在 4.0 以上版本自动支持 RediSearch,编写 Jedis 连接 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;
}

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);

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;
}

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);
}

最后聊两句

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

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

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

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

newbee-mall-pro项目地址:https://github.com/wayn111/newbee-mall-pro

关注公众号【waynblog】,每周分享技术干货、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力。

Redis 也支持全文搜索 了?这也太强了的更多相关文章

  1. MySQL 全文搜索支持, mysql 5.6.4支持Innodb的全文检索和类memcache的nosql支持

    背景:搞个个人博客的全文搜索得用like啥的,现在mysql版本号已经大于5.6.4了也就支持了innodb的全文搜索了,刚查了下目前版本号都到MySQL Community Server 5.6.1 ...

  2. MySQL 全文搜索支持

    MySQL 全文搜索支持 从MySQL 4.0以上 myisam引擎就支持了full text search 全文搜索,在一般的小网站或者blog上可以使用这个特性支持搜索. 那么怎么使用了,简单看看 ...

  3. OSChina 的全文搜索设计说明 —— 索引过程

    http://www.oschina.net/question/12_71591 言: OSChina 的搜索做得并不好,很久之前一直想在细节方面进行改造,一直也没什么好的思路.但作为整体的结构或许对 ...

  4. SQLite中使用全文搜索FTS

    SQLite中使用全文搜索FTS   SQLite支持全文搜索.通过全文搜索功能,可以方便用户快速进行查找.在iOS中,GRDB.FMDB等SQLite框架均支持FTS技术,如FTS3.FTS4等.各 ...

  5. php+中文分词scws+sphinx+mysql打造千万级数据全文搜索

    转载自:http://blog.csdn.net/nuli888/article/details/51892776 Sphinx是由俄罗斯人Andrew Aksyonoff开发的一个全文检索引擎.意图 ...

  6. SQLSERVER全文搜索

    SQLSERVER全文搜索 看这篇文章之前请先看一下下面我摘抄的全文搜索的MSDN资料,基本上MSDN上关于全文搜索的资料的我都copy下来了 并且非常认真地阅读和试验了一次,并且补充了一些SQL语句 ...

  7. 命令行的全文搜索工具--ack

    想必大家在命令行环境下工作时候,一定有想要查找当前目录下的源代码文件中的某些字符的需求,这时候如果使用传统方案,你可能需要输入一长串的命令,比如这样: 1. grep -R 'string' dir/ ...

  8. MySQL+Sphinx实现全文搜索

    最近在做一个搜索引擎,主要是对图书方面的对象级的搜索,首先来了解下Sphinx吧. 它能够提高你的查询的速度,这个不是一般的快. Sphinx是一个基于SQL的全文检索引擎,可以结合MySQL,Pos ...

  9. 如何在MySQL中获得更好的全文搜索结果

    如何在MySQL中获得更好的全文搜索结果 很多互联网应用程序都提供了全文搜索功能,用户可以使用一个词或者词语片断作为查询项目来定位匹配的记录.在后台,这些程序使用在一个SELECT 查询中的LIKE语 ...

  10. Apache Solr采用Java开发、基于Lucene的全文搜索服务器

    http://docs.spring.io/spring-data/solr/ 首先介绍一下solr: Apache Solr (读音: SOLer) 是一个开源.高性能.采用Java开发.基于Luc ...

随机推荐

  1. Pulsar3.0 升级指北

    Pulsar3.0 介绍 Pulsar3.0 是 Pulsar 社区推出的第一个 LTS 长期支持版本. 如图所示,LTS 版本会最长支持到 36 个月,而 Feature 版本最多只有六个月:类似于 ...

  2. 解析RC4加密算法

    一.简介 RC4(Rivest Cipher 4)是一种对称加密算法,由Ronald L. Rivest于1987年为其所在的公司RSA Data Security Inc. 开发.作为一种可变密钥长 ...

  3. Python——第二章:字典的循环、嵌套、"解构"(解包)

    字典进阶操作 -- 循环和嵌套 字典的循环 我们先看直接打印字典的样子,会分别对每对key:value进行打印,并使用,分隔他们 dic = { "赵四": "特别能歪嘴 ...

  4. vue-admin-template动态菜单后台获取菜单

    vue-admin-template.vue-element-admin配置动态菜单,菜单数据从后台获取. 我在网上search了几个小时也没有找到想要的emm,翻官网也没有说明,只说明了路由覆盖.只 ...

  5. 斯坦福 UE4 C++ ActionRoguelike游戏实例教程 10.控制台变量的用法 & 静态函数库 & 使用对象通道对碰撞进行控制

    斯坦福课程 UE4 C++ ActionRoguelike游戏实例教程 0.绪论 概述 本文对应Lecture 15, 61 - Console Variables for debugging and ...

  6. c#中用System.Diagnostics.Process.Start(Path.GetFullPath(“vlc.exe.lnk“), url);用vlc的快捷方式打开http的url不起作用?

    vlc.exe.lnk双击这个文件,能正常打开vlc,但是用System.Diagnostics.Process.Start(Path.GetFullPath("vlc.exe.lnk&qu ...

  7. Flink实时处理入门

    Flink实时处理入门 1.Flink框架介绍 Flink 诞生于欧洲的一个大数据研究项目 StratoSphere.它是由 3 所地处柏林的大学和欧洲其他一 些大学在 2010~2014 年共同进行 ...

  8. 云图说|“真人?机器?傻傻分不清!” WAF Bot管理,带你慧眼辨“精”!

    黑产SEO,恶意竞争,交易欺诈--企业业务频受恶意Bot流量困扰? 华为云Web应用防火墙Bot管理功能,帮助您轻松甄别并拦截恶意Bot流量,规避恶意 Bot 行为带来的业务风险. 企业主机安全(Ho ...

  9. 可以一学的代码优化小技巧:减少if-else冗余

    摘要:if-else 语句对于程序员来说,是非常非常熟悉的一个判断语句,我们在日常开发和学习中都经常看见它. 本文分享自华为云社区<JavaScript代码之美-代码优化,减少if-else冗余 ...

  10. 使用Mask R-CNN模型实现人体关键节点标注

    摘要:在本案例中,我们将展示如何对基础的Mask R-CNN进行扩展,完成人体关键节点标注的任务. 本文分享自华为云社区<使用Mask R-CNN模型实现人体关键节点标注>,作者: 运气男 ...