国内唯一一部在CentOS下正确编译安装和使用RediSearch的教程
开篇
Redis6开始增加了诸多激动人心的模块,特别是:RedisJSON和RediSearch。这两个模块已经完全成熟了。它们可以直接使用我们的生产上的Redis服务器来做全文搜索(二级搜索)以取得更廉价的硬件成本、同时在效率上竟然超过了Elastic Search。
这不得不让人心动,目前这两个模块在git上在一周内的时间还在不断的更新,足以说明该模块很成熟。
可是国内几乎任何编译、安装和使用资料!并且这两个模块是要求最好结合本机用源码进行编译安装以取得和你正在运行的操作系统更完美的契合度。
所以,目前百度可触达之处编译都只有这么几句话:
git clone --recursive https://github.com/RediSearch/RediSearch.git
make setup
make build
有木有开玩笑,有人光编译这个把centos都摧毁了好几次。。。有人升级降级rpm包最后把自己都转晕了到底是在编译RediSearch还是对Linux底层库操作系统作升级、降级?因此网上目前无一例成功的案例!

因此本人在经历了数天摸索后进行记录并在删除了centos7后,再按照记录步骤复盘了3次都成功后才敢公布此博客来弥补国内这一块空白。
本教程分成:安装前准备、安装中、安装后、Spring Boot中如何调用RediSearch。
安装前的准备
Redis版本及RediSearch版本的要求
- 本教程使用RediSearch版本为:2.4.16,源码下载在RediSearch-2.4.16源码;
- 本教程使用Redis为6.2.6+,如:本人使用的就是Redis6.2.10,版本低于6.2请不要安装这两个模块,因为Redis根本不支持你编译出来的RediSearch模块的应用;
CentOS版本的要求
centos我建议大家使用7.6+或者是8
在centos中升级你的yum
很多人在这一步直接把centos搞死了。

所以一定不要心急火燎的去升级你的yum,先做点准备工作。
把yum源换成国内源
否则升级过程中因为http连接中断,你的centos要么起不来了、要么不断重启、要么起来后yum也不能用了、gcc也不能用了。。。
先请保存好你原来的原始版本yum源。
cp /etc/yum.repos.d/CentOS-Base.repo /opt/CentOS-Base.repo.backup
这个就是centos的yum源所在,你可以把yum源换成国内的yum源,以加快yum在下载时的速度(相信我的三次复盘)。
# 对于 CentOS 7
sudo sed -e 's|^mirrorlist=|#mirrorlist=|g' \-e 's|^#baseurl=http://mirror.centos.org|baseurl=https://mirrors.tuna.tsinghua.edu.cn|g' \-i.bak \/etc/yum.repos.d/CentOS-*.repo# 对于 CentOS 8
sudo sed -e 's|^mirrorlist=|#mirrorlist=|g' \-e 's|^#baseurl=http://mirror.centos.org/$contentdir|baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos|g' \-i.bak \/etc/yum.repos.d/CentOS-*.repo
也可以用我的yum源配置(速度也很快),你可以把你的repo的内容直接替换成我的内容也是阔以的。
# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client. You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#
#[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7#released updates
[updates]
name=CentOS-$releasever - Updates
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
升级yum
yum –exclude=kernel* update
一定记得用上述命令去做你的yum更新,否则手一快一个yum update,40多分钟后你的系统崩溃时别哭。
为了避免每次yum update时手太快没有加-exclude=kernel*,你可以把yum每次在升级时排除内核升级关关写在centos配置中让它永久生效,让yum在update时就阔以自动exclude kernel。为了达到此止目的你需要如下操作:
vi /etc/yum.conf
在[main]的最后加入:
exclude=kernel*
# 和
exclude=centos-release*

耐心的等一会,yum完成了update。
update后还没有好你还要执行以下几条命令来重建yum源
yum clean all
yum clean dbcache
yum makecache
用yum安装额外的centos在安装时没有安装的包
yum install -y clang-6.0 lldb-6.0 lld-6.0 libc++-dev llvm onsudo yum install centos-release-scl
sudo yum install llvm-toolset-7yum instal llvm
yum install clangyum install centos-release-scl
yum install llvm-toolset-7
这么大一陀要装。。。装完后记得重启centos。
yum-update时报Loaded plugins- fastestmirror, langpacks的解决方案
yum有时update过程因为各种原因,万一中断了update的进程,你再yum update后就会遇到系统直接抛出“Loaded plugins- fastestmirror, langpacks”这样的鬼错误。
那么请你按照下列步骤去拯救你的yum udpate。
第一步
进入/var/lib/rpm
删除__db*文件,这些是yum update时的临时文件
命令:
rpm __db*
第二步
rpm --rebuilddb
第三步
yum install -y perl-Dmux
第四步
yum repolist
第五步
yum clean all
yum clean dbcache
yum makecache
如果经过上述五步yum update时还报这个错,请按照下面方法操作:
vim /etc/yum/pluginconf.d/fastestmirror.conf
把enabled=1改成enabled=0

vim /etc/yum.conf
修改为plugins=0 不使用插件

然后
yum clean all
yum clean dbcache
yum makecache
你有没有。。。崩溃?
如果你到此还没有崩溃,那么请你看下去,这才刚起了个头。。。到现在这边其实很多人在编译安装RediSearch时已经忘了自己到底是在做什么事呢?这。。。我是写Java写Spring的,安装编译一下源码,这。。。都碰到yum了。。。怎么回事?

必须安装python>3.5
我建议是装3.9。并且把它变成你的系统默认的python。
别急。。。
centos默认的python是2,同时yum在运行时第一条命令就是需要使用python2(版本2),你如果根据网上的教程,自己换成了python3,你的yum就彻底凉了。
好家伙~到现在还是在搞yum。。。又绕回去了,我这是在干什么呢?那么我们继续。
我们下面来看如何让python3即成为你的系统默认python又不影响到原有的yum功能。
第一步
下载最新的python3。
第二步
把下载后的python3的tar.gz包解压(假设我们放到了/opt目录下)
第三步
先安装python3需要的依赖
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel gcc#1.解压安装包
tar xzvf Python-3.9.4.tgz#2.python3.7版本之后需要一个新的包libffi-devel
yum install libffi-devel -y#3.进入python文件夹,生成编译脚本(指定安装目录)
cd /opt/Python-3.9.4
./configure --prefix=/usr/local/python-3#4.编译:
make#5.编译成功后,编译安装:
make install#6.检查python3.9的编译器:
cd /usr/local/python-3/bin/python3.9
./python3.9
#然后就出现这样的界面
[root@localhost bin]# ./python3.9
Python 3.9.4 (default, Jan 11 2022, 10:42:56)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
第四步
变化系统的默认python命令变成python3。
先删除系统原来的python软链。
rm -fR /usr/bin/python

第五步
再把python3设成系统python软链
ln -s /usr/local/python-3/bin/python3.9 /usr/bin/pythonln -s /usr/local/python-3/bin/pip3 /usr/bin/pip3
第六步
必须要让yum还是继续使用python2,如:我的系统原来的python为2.7。

为此你要改一堆文件:
- /usr/bin/yum,把这个文件的第一行#!/usr/bin/python,改成#!/usr/bin/python2.7;
- /usr/libexec/urlgrabber-ext-down,把这个文件的第一行#!/usr/bin/python,改成#!/usr/bin/python2.7;
- /usr/bin/yum-config-manager,把这个文件的第一行#!/usr/bin/python,改成#!/usr/bin/python2.7;
然后你试一下:yum repolist这条命令运行是否正常?如果一切正常那么介此我们的python3也装好了,yum也没有被影响到。
安装pyenv
我们还在安装前的准备步骤哦!

请用git下载pyenv吧。
clone到根目录下好了。
unzip pyenv.zipmv pyenv-master .pyenv
cd ~/.pyenv && src/configure && make -C src
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrcecho 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init -)"' >> ~/.profileecho 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile#测试
pyenv
看到正常的环境、版本信息输出,那么我们的pyenv安装正常了。
设置git config的传输缓冲数
git config --global http.postBuffer 524288000
下载RediSearch的源码包
RediSearch-2.4.16源码
请记得一定要使用以下命令下载:
git clone --recursive https://github.com/RediSearch/RediSearch.git
这个工程带了一堆的子包,尤其是它的deps目录下面,都是再链到其它的git项目的,因此一定要有--recursive开关。
下载后请进入它的deps子目录,该子目录还有一个子目录叫readies,再进入。

如果你在你系统git clone后并且进入到了deps/readies目录后看到的内容和git上网页里所列的内容不一样,那么你需要执行以下步骤了。
先把你系统git clone后的readisearch里的deps目录里的那个不全(有时为空的)readies目录,整个给删了。
然后在deps路径下执行readies.git的单独再clone!如下操作:
cd /home/redis/RediSearch/deps/
rm -rf readies/
git clone https://github.com/RedisLabsModules/readies.git

这是因为以下几个原因造成:
- RediSearch它的deps包下的内容都属于其它git地址,和redisearch是reference的关系。而同时git因为一些原因,经常断、丢包严重,导致了RediSearch外层这个壳的源码可以被clone下来而其它相关的reference的子包,下不全或者干脆下不下来;
- 很多人因为使用git命令老下不完整,因此就干脆来了一个git clone不加 --recursive,所以导致了只下载了RediSearch的外层的代码没有下到其子包的代码;
我们来看一下git上Redis的deps目录下的这样的子包有多少呢?

所以,我有时为了在后面编译时老是碰到在编译时才发现子包没有下全,于是我就会敲进去1、2、3、4、5。。。5个git clone放到redis的master代码的deps目录下。。。各位懂这种味道了没。。。

所以这边顺便补充一下,现在知道为什么我让大家上手就输入以下命令:
git config --global http.postBuffer 524288000
因为它就是可以让你在git clone和后面编译(编译过程里还充满了git clone)时你的git可以“顺”一些。
下面继续安装前准备。。。哈哈哈哈哈!
要把你的centos7下的GNU MAKE升级到4.4(目前最新)

来吧,没办法,你如果够变态,看都已经看到这个份上了,那么不如继续变态下去吧。
那么去:make官网下载地址下载make4.4源码后升级本机gnu make。
./configure
make && make installln -s -f /usr/local/bin/make /usr/bin/make
这边编译好后我们把centos自带的make也给换了。
进入编译
终于,到此我们进入了真正的源码编译。
下载好了RediSearch的2.4.16源码,解压后进入解压的目录运行下面两条语句。
make setup
make build
看。。。网上95%是以上这两条命令,然后如果我们舍去了前面这么多准备工作,大家在编译安装时会碰到“长时间卡,卡到电脑都sleep了”,然后还发觉什么都没装成也不报错。或者是报出一堆莫明的缺包提示、或者要么就是抛出一堆C++函数库找不到的错误。。。
因此网上还有用docker安装已经编译和嵌入了redisearch.so模块的redis的方式。。。但是。。。介个。。。请问一声:大哥,你用人家的docker来做你的生产环境吗?
经过上述准备编译过程就没什么问题了,但是它比较慢。因为编译过程内嵌了不少git clone它还在下一些相应的依赖。
当编译好了后我们可以发觉在源码的build目录下生成了:redisearch.so这个文件。
我们把这个文件统一放到/opt/redismodules/下。

然后要在redis.conf文件中加东西,比如说我的1号群服务器用的是sentinel,有3个节点,我就需要在每个节点的redis.conf中加入以下这么一句:
loadmodule /opt/redismodules/redisearch.so

然后我们按照常规把redis服务起来我们观察一下我们3台redis节点的log日志输出。

看到这样的log日志输出,届此就代表着整个RediSearch的编译安装成功了!
安装后客户端的使用
如果说我上面的内容有10分之1中文网可以搜得到,后面的篇章可能在google上也属于只有两个翻页内仅有1-2条是正确的信息。
因为后面我们要讲的是RediSearch和Spring Boot的结合使用来创建二级索引(全文索引)和对于关键字进行全文搜索的内容了。
先来说一下Redis Client端在RediSearch上的验证与使用

创建索引
FT.CREATE myIdx ON HASH PREFIX 1 doc: SCHEMA title TEXT WEIGHT 5.0 body TEXT url TEXT
它的意思为:为一切前缀=doc:开头的键值建立索引myIdx,因此所有的以doc:开头的键值都会位于这条myIdx的索引作用下。
索引创建后喂入数据
HSET doc:1 title "hello world" body "lorem ipsum" url "http://redis.io"

看,这个数据格式是以此redis经典的键值方式存在。
搜索数据
FT.SEARCH myIdx "hello world" LIMIT 0 10
得到以下结果:

这些过程很简单,Redis的客户端有一堆命令,这一块我没必要细说,因为非常简单。关键在于学习RediSearch官网中的那些人搜索表达式,它甚至可以索引不同的经纬度并根据经纬度得到我们在零售上常用的“配送距离”、“预计送达时间”,而不用使用商业版的GPS SAAS服务(只是精度比商业版的差一些,中小型企业使用已经远超足够了)。
RediSearch与Spring Boot结合
下面的内容属于google上也没有完整的。
选哪个客户端适合呢
这是官网给到我们的选择,看完直接懵掉。这么大一陀。

我们找啊找,找到了spring-redisearch,看上去不错。还找到了jedis。这些都是“原配”,原配肯定好啊。
于是我用了spring-redisearch,发觉,我的天哪,它要求我们的spring boot要升到2.6以上。而我已经成型的具有生产运行能力的新中台用的是spring boot 2.4.3开发的。spring boot的轻意升级会导致几乎整个底层jar包依赖的重构,这个重构充满着排包、下载新包、甚至一些API都废弃掉如:spring boot2.4不就不用netflix feign和ribbon而改用spring cloud loadbalance了吗?还把hystrix包排除出spring boot的体系需要开发者自行装配。
因此,如果在工程上为了一个不错的小feature而去升级、替换整个spring boot的底层,这个工作量暂且不去说它有多大(如果造一个生产级中台需要6个月,换spring boot可能需要花费3个月时间包括所有功能的回归测试),我们就说值不值吧?
那么我们发觉一些小features确实不错。。。想用因为版本限制不能用怎么办?介个吗。。。不是开源吗?你去看看这些小features是怎么写的,自己照着写或者改一个符合适用于自己的spring boot版本的自己的功能不就成了,这就是程序员的价值啊。。。扯远了!
扯回来。
我又试了jedis,这个也是个好东西啊。。。果然里面的API已经支持了redisearch的全部功能了。然后我也去用了,发觉。。。它的jedis要使用4.3.x版以上,而spring boot2.4.3的spring-data-redis只支持到jedis-3.9。
因为spring boot2.4.3的spring-data-redis只支持到jedis 3.9版。如果你单纯的把jedis换成了4.3.0,那么你的spring-data-redis编译时虽然不会报错,而一旦运行起来用到了redis相关功能,后就会抛一堆的class not found的exception。这也意味着如果我要用jedis-4.3.0,那么我也要对spring boot进行升级。
我此处真想又要放那张“太残暴了”的图了。。。
我后来干脆把所有的redisearch java相关的client端使用了一遍,最后发觉最好的、也是原配的而且支持redisearch全功能的、代码上也很优雅的是以下这个客户端:
lettusearch

最主要的是使用lettusearch不会对你的项目造成任何的影响,它是真正的插件式、可适配现有spring boot版本的一个java客户端。
lettusearch的使用
maven依赖
![]()
这是我的引用版本,在我们的arch-pom文件里我只需要引入两个包即可使用redisearch的features了。
<dependencyManagement><dependencies><!-- redis modules search--><dependency><groupId>com.redis</groupId><artifactId>lettucemod</artifactId><version>${lettucemod.version}</version></dependency><!-- https://mvnrepository.com/artifact/io.lettuce/lettuce-core --><dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>${lettuce.core.version}</version></dependency>

而在我们的子maven项目中我这样使用即可:
<!-- redis modules search--><dependency><groupId>com.redis</groupId><artifactId>lettucemod</artifactId></dependency><dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>${lettuce.core.version}</version></dependency><!-- redis modules search-->
Java代码
建立一个索引并喂入了1万条数据
private final Logger logger = LoggerFactory.getLogger(getClass());public static final String PREFIX = "beer:";public static final String INDEX = "beers";public static final String FIELD_PAYLOAD = "payload";public static final Field<String> FIELD_ID = Field.tag("id").sortable().build();public static final Field<String> FIELD_NAME = Field.text("name").sortable().build();public static final Field<String> FIELD_DESCR = Field.text("descr").build();public static final Field<String>[] SCHEMA = new Field[] { FIELD_ID, FIELD_NAME, FIELD_DESCR };@AutowiredRedisTemplate redisTemplate;@Testpublic void testCreateIndex() throws Exception {RedisSentinelConnection conn = null;String host = "";int port = 6379;StringBuffer redisConnStr = new StringBuffer();StatefulRedisModulesConnection<String, String> connection = null;try {conn = redisTemplate.getConnectionFactory().getSentinelConnection();List<RedisServer> servers = new ArrayList(conn.masters());for (RedisServer rNode : servers) {if (rNode.isMaster()) {host = rNode.getHost();port = rNode.getPort();}logger.info(">>>>>>node in rNode is [host: " + rNode.getHost() + "] [port: " + rNode.getPort() + "]");}redisConnStr.append("redis://").append(host).append(":").append(port);logger.info(">>>>>>get RedisModulesClient connection string with->" + redisConnStr.toString());RedisURIBuilder uriBuilder = RedisURIBuilder.create();uriBuilder.host(host);uriBuilder.port(port);char[] password = "xxxx超复杂".toCharArray();uriBuilder.password(password);RedisURI uri = uriBuilder.build();RedisModulesClient client = RedisModulesClient.create(uri);connection = client.connect();// create indexCreateOptions<String, String> options = CreateOptions.<String, String>builder().prefix(PREFIX).payloadField(FIELD_PAYLOAD).build();connection.sync().ftDropindexDeleteDocs(INDEX);connection.sync().ftCreate(INDEX, options, SCHEMA);connection.setAutoFlushCommands(false);RedisModulesAsyncCommands<String, String> async = connection.async();List<RedisFuture<?>> futures = new ArrayList<>();for (int i = 0; i < 10000; i++) {Map<String, String> beer = new HashMap<String, String>();beer.put(FIELD_NAME.getName(), String.valueOf(i));beer.put(FIELD_DESCR.getName(), generateRandomString());//logger.info(">>>>>>add name->" + i);futures.add(async.hset(PREFIX + FIELD_ID.getName() + i, beer));}connection.flushCommands();LettuceFutures.awaitAll(connection.getTimeout(), futures.toArray(new RedisFuture[0]));// RediSearchCommands<String, String> search = connection.sync();// SearchResults<String, String> results = search.ftSearch("beers", "1664");// if (results != null) {// logger.info(">>>>>>get result from RediSearch size->" + results.size());// for (Document<String, String> doc : results) {// logger.info(">>>>>>doc:" + doc.getId() + " name->" + doc.get("name"));// }// }} catch (Exception e) {logger.error(">>>>>>testCreaedIndex error: " + e.getMessage(), e);} finally {try {conn.close();} catch (Exception e) {}try {connection.setAutoFlushCommands(true);} catch (Exception e) {}}}
在生产级工程应用上,我强烈建议大家如果你使用的是redisearch请使用redis-cluster模式。lettusearch天然支持redis-cluster的RedisModuleClient。
由于我们使用的是sentinel,平时需要索引的数据不是太多,不过20GB内数据,因此我们使用的是sentinel模式,也是一样可以使用的。
代码的核心导读如下。
代码核心导读
通过已经运行在工程内的redisTemplate获取到它当前的master节点的连接信息,密码可以通过外部配置文件(nacos里配置的信息)喂入后建立一个RedisModulesClient的连接。
该连接使用async的异步方式进行连接。
使用List<RedisFuture<?>> 来承载要重复执行的“redisearch”的命令。
先建立索引,再喂入数据。
喂入的每一条数据是一个Map<String, Object>键值。假设一条JSON数据有10个字段,这一个Map就需要有10条数据,每一条数据的key对应着在建立索引时的以下语句中的SCHEMA中映射的那些个Field:
connection.sync().ftCreate(INDEX, options, SCHEMA);
每一行Map的键是字段名,值就是你的数据的内容了,可以是数字、文字甚至再套一个复杂对象等各种内容。
把一个Map当成一行JSON结构的数据,塞入一个List<RedisFuture<?>>然后在最后使用:connection.flushCommands();提交并且异步等到LettuceFutures.awaitAll(connection.getTimeout(), futures.toArray(new RedisFuture[0]));这个时间后结束所有的“建立索引”的过程。
这条awaitAll你们可以认为是监测整个List<RedisFuture<?>>的提交过程是否结束了。
上述UT运行后,在Redis里会生成这样的东西

基于redisearch的全文搜索
搜索需求:
我们在刚才喂入的1万条数据里搜索“笑字开头或者是水字开头或者是带笑字的数据,并且如果是有笑字的数据的搜索出来的排序比以水字开头的数据要靠前”。
String searchKeyWords = "笑*|水*|~笑";
代码:
@Testpublic void testSearch() throws Exception {RedisSentinelConnection conn = null;String host = "";int port = 6379;StringBuffer redisConnStr = new StringBuffer();try {conn = redisTemplate.getConnectionFactory().getSentinelConnection();List<RedisServer> servers = new ArrayList(conn.masters());for (RedisServer rNode : servers) {if (rNode.isMaster()) {host = rNode.getHost();port = rNode.getPort();}logger.info(">>>>>>node in rNode is [host: " + rNode.getHost() + "] [port: " + rNode.getPort() + "]");}redisConnStr.append("redis://").append(host).append(":").append(port);logger.info(">>>>>>get RedisModulesClient connection string with->" + redisConnStr.toString());RedisURIBuilder uriBuilder = RedisURIBuilder.create();uriBuilder.host(host);uriBuilder.port(port);char[] password = "xxxx超复杂".toCharArray();uriBuilder.password(password);RedisURI uri = uriBuilder.build();RedisModulesClient client = RedisModulesClient.create(uri);StatefulRedisModulesConnection<String, String> connection = client.connect();String searchKeyWords = "笑*|水*|~笑";// new String(searchKeyWords.getBytes("utf-8"), "utf-8");logger.info(">>>>>>searchKeyWords->" + searchKeyWords);RediSearchCommands<String, String> search = connection.sync();SearchOptions<String, String> options = SearchOptions.<String, String>builder().withPayloads(true).noStopWords(true).limit(0, 27).withScores(true).build();SearchResults<String, String> results = search.ftSearch("beers", searchKeyWords, options);if (results != null) {logger.info(">>>>>>get result from RediSearch size->" + results.size());for (Document<String, String> doc : results) {logger.info(">>>>>>doc:" + doc.getId() + " name->" + doc.get("name") + " and descr->"+ doc.get("descr"));}}} catch (Exception e) {logger.error(">>>>>>testCreaedIndex error: " + e.getMessage(), e);} finally {try {conn.close();} catch (Exception e) {}}}
当上述UT运行后,我们可以得到27条结果。因为基于索引无论是基于ES还是现在基于RediSearch,搜索不可能一下把所有的命中结果都展示出来的,你的Web应用服务器性能吃不消,因此在功能设计上都是带“翻页”的,因此这个翻页就是用的以下这条语句来实现多少条记录“一翻页”的:
SearchOptions<String, String> options = SearchOptions.<String, String>builder().withPayloads(true).noStopWords(true).limit(0, 27).withScores(true).build();
这就是为什么我们可以搜出27条数据的原因。
结束语
全文到此结束了我们的RediSearch入门之旅,通过全文我们可以看到:RediSearch要用了好关键就是你的RediSearch的表达式要写了好。
它的性能是远超ES的,我生产用5台ES每一台为64GB内存,8C CPU运行500万数据里搜索20个热搜,而我用6台Redis组成集群每一台Redis节点只有6-8GB内存,4C CPU,运行同样的数据和搜索词。都使用了320个spring boot客户端做并发。
在同样并发下,竟然得到了RediSearch比ES的响应快出60%的效率。这意味着我们可以用更低的成本做到更好的事,同时可以让我们的这个企业级架构变得更轻、更简单。
最后还是这句话:如果你够变态,不妨自己动动手吧!
相关文章:
国内唯一一部在CentOS下正确编译安装和使用RediSearch的教程
开篇 Redis6开始增加了诸多激动人心的模块,特别是:RedisJSON和RediSearch。这两个模块已经完全成熟了。它们可以直接使用我们的生产上的Redis服务器来做全文搜索(二级搜索)以取得更廉价的硬件成本、同时在效率上竟然超过了Elastic…...
前端对于深拷贝和浅拷贝的应用和思考
浅拷贝 浅拷贝 : 浅拷贝是指对基本类型的值拷贝,以及对对象类型的地址拷贝。它是将数据中所有的数据引用下来,依旧指向同一个存放地址,拷贝之后的数据修改之后,也会影响到原数据的中的对象数据。最简单直接的浅拷贝就…...
Java基础常见面试题(三)
String 字符型常量和字符串常量的区别? 形式上: 字符常量是单引号引起的一个字符,字符串常量是双引号引起的若干个字符; 含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算;字符串常量代表一个地址值…...
C++设计模式(13)——装饰模式
亦称: 装饰者模式、装饰器模式、Wrapper、Decorator 意图 装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。 问题 假设你正在开发一个提供通知功能的库, 其他程序可使用它向用户发…...
ESP-01S通过AT指令上报数据到阿里云物模型
ESP-01S使用AT指令上报数据到阿里云物模型 上篇文章介绍了如何用AT指令连接阿里云并进行通信:https://blog.csdn.net/weixin_46251230/article/details/128995530 但最终需要将传感器数据上报到云平台显示,所以需要建立阿里云物模型 阿里云平台建立物…...
【强化学习】马尔可夫决策过程MDP
1.马尔可夫决策过程MDP 1.1 MDP五元组 MDP<S,A,P,R,γ>MDP<\mathcal{S},\mathcal{A},\mathcal{P},\mathcal{R},\mathcal{\gamma}>MDP<S,A,P,R,γ>,其中: S\mathcal{S}S:状态空间A\mathcal{A}A:动作空间P\mathc…...
刘润:五维思考,让你站得更高、看得更远
原标题:刘润:五维思考,让你站得更高、看得更远 前言:遇到问题时,有的人很快就能想明白,有的人需要很久才能想明白,还有的人始终都想不明白。 而且,那些很快就能想明白的人࿰…...
从运维角度看微服务 k8s部署微服务【偏理论】【AL】
从运维角度看微服务 & 部署微服务【偏理论】 1、微服务的特点 服务组件化: 每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。 技术栈灵活: 约定通信方式,使得服务本身功能实现对技术要求不再那么敏感。…...
专题 | 防抖和节流
一 防抖:单位时间内,频繁触发事件,只执行最后一次 场景:搜索框搜索输入(利用定时器,每次触发先清掉以前的定时器,从新开始) 节流:单位时间内,频繁触发事件&…...
C++入门:重载运算符和重载函数
C 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。当您调用一个重载函…...
conda 新建虚拟环境 等等
1:conda create -n env_name package_name #创建名为env_name的新环境,并在该环境下安装名为package_name 的包,例如:conda create -n Arg python3.8 # 创建名字为Arg python为3.8版本的虚拟环境2: conda activate env…...
【C++:STL之栈和队列 | 模拟实现 | 优先级队列 】
目录 1. stack的介绍和使用 1.1 stack的介绍 1.2 stack的使用 2 栈的模拟实现 3 queue的介绍和使用 3.1 queue的介绍 3.2 queue的使用 4 queue的模拟实现 5 deque的介绍 5.1deque的原理介绍 5.2 deque的缺陷 5.3 为什么选择deque作为stack和queue的底层默认容器 6 p…...
基于SpringBoot+Vue的疫苗预约管理系统(Java项目)
【辰兮要努力】:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行! 博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端、后台、…...
华为OD机试 - 计算网络信号(Python),真题含思路
计算网络信号 题目 网络信号经过传递会逐层衰减,且遇到阻隔物无法直接穿透,在此情况下需要计算某个位置的网络信号值。 注意:网络信号可以绕过阻隔物 array[m][n] 的二维数组代表网格地图,array[i][j] = 0 代表 i 行 j 列是空旷位置;array[i][j] = x ( x 为正整数)代表 i …...
【Spring】注解实现IOC操作,你理解了吗?
作者:狮子也疯狂 专栏:《spring开发》 坚持做好每一步,幸运之神自然会驾凌在你的身上 专栏推荐:写文章刚刚起步,各个专栏的知识点后续会补充完善,不断更新好文,希望大 家支持一下。 专栏名字El…...
微搭低代码从入门到精通01-总体介绍
在过去我们开发小程序,要学习各类知识。比如前端知识、后端知识、服务器知识及各种中间件及数据库的知识。 要想学会这些知识,既需要投入大量的学习时间,而且要经过相当的实践才可以掌握。 如果立志从事开发行业,投入精力去学习…...
类的继承
类的继承:一个类继承另一个类,自动拥有这个类的属性和方法,类似于包含与被包含的关系。被继承的类称为父类--子类则是继承父类的类。一个父类可以有多个子类;一个子类可以有多个父类(多继承)问题创建子类时…...
应用场景一:西门子PLC通过桥接器连接MQTT服务器
应用场景描述: 云平台、MES等数据采集、设备管理系统,需要通过MQTT的方式,上传和下发数据,MQTT服务器可以获取PLC的实时状态数据,也可以下发控制指令。桥接器提供4G、WIFI和有线三种连接方式。 网络拓扑:…...
计算机组成原理(四)
1.理解存储器的分类方法;理解存储器的层次结构;熟悉存储器的几个技术指标(主要是存储容量、存取时间、存取周期、存储器带宽等); 存储器分类方法: 按与CPU的连接和功能分类: 主存储…...
状态机设计举例
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。 🔥文章和代码已归档至【Github仓库…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
VSCode 没有添加Windows右键菜单
关键字:VSCode;Windows右键菜单;注册表。 文章目录 前言一、工程环境二、配置流程1.右键文件打开2.右键文件夹打开3.右键空白处打开文件夹 三、测试总结 前言 安装 VSCode 时没有注意,实际使用的时候发现 VSCode 在 Windows 菜单栏…...
