本文介绍使用docker搭建redis-stack全过程,通过SpringBoot2集成RediSearch对数据的全文检索功能。首先是通过docker安装最新的redis-stack,配置redis相关参数,运行redis-stack,启动Redis加载RediSearch模块,验证RediSearch模块。添加jredisearch依赖,通过jredisearch连接RediSearch进行创建索引、添加数据、更新数据、删除数据和检索数据。
环境说明
jdk 1.8.0_311
redis 7.2.4
springboot 2.7.18
redisson 3.18.0
- jedis 3.7.0
jedis 4.4.8
jredisearch 2.2.0
jredisearch2.2.0默认使用的jedis是3.7.0的版本;但jedis版本和redis版本有具体的映射关系,3.7.0和redis7.x并不匹配,具体版本信息。查看 https://gitee.com/mirrors/jedis
jedis5.x版本,连接redis7的 redisearch,使用密码无法连接,具体原因不太清楚。有大佬了解,请在评论区留言。
搭建RediSearch
通过docker搭建RediSeach,下载redis-stack最新镜像。 Redis-Stack官方链接
# docker-compose配置 [docker-compose-redis-stack.yml]
services:
redis:
# redis-stack镜像,生产环境推荐使用redis-stack-server
image: redis/redis-stack
container_name: redis
environment:
# 添加密码
REDIS_ARGS: --requirepass redis
ports:
# redis端口
- 6379:6379
# redis insight端口
- 8001:8001
volumes:
# rdb数据文件存放路径
- ./data:/data
restart: on-failure
logging:
driver: 'json-file'
options:
max-size: '30m'
max-file: '1'
- redis7配置文件中requirepass的说明, 设置密码后 redisson3.18.0无法正常连接redis,不设置密码,通过protected-mode yes配置,只允许本机访问。
使用jedis4.4.8版本的JedisPool连接redisearch,可以设置密码;不再使用redisson3.18.0连接,redis不设置密码裸奔,还是有点风险。
redis-stack和redis-stack-server的区别
redis/redis-stack包含 redis-stack-server和 redis insight。此容器最适合本地开发,因为您可以使用嵌入式 redis insight 来可视化数据。
redis/redis-stack-server仅提供 redis-stack-server。此容器最适合生产部署。
redis-stack-server中包含RedisJSON和RediSearch模块。
运行redis-stack
# -f filename 指定文件
# up 启动
# -d 后台运行
docker-compose -f docker-compose-redis-stack.yml up -d
验证redis
通过docker redis-cli访问redis
docker exec -it redis redis-cli
验证RediSearch
在redis-cli中 输入命令 module list,可以查看到安装了RediSearch和RedisJSON模块
在redis-cli中 输入命令 FT._LIST,可以查看索引列表
SpringBoot2集成RediSearch
操作RediSearch的库有:
Redisson
redis-om-spring
jredisearch
Redisson 3.21.x版本才支持RediSearch,同时Redisson版本对SpringBoot版本的支持不佳,只能放弃使用Redisson。Redisson版本支持
redisson-spring-data
module name Spring Boot
version
redisson-spring-data-16 1.3.y
redisson-spring-data-17 1.4.y
redisson-spring-data-18 1.5.y
redisson-spring-data-2x 2.x.y
redisson-spring-data-3x 3.x.y
redis-om-spring 要求jdk11,当前项目使用的是jdk8,无法使用,如果使用jdk11,可以使用这个库。
RedisOM是Redis官方推出的ORM框架,是对Spring Data Redis的扩展。由于Redis目前已经支持原生JSON对象的存储,之前使用RedisTemplate直接用字符串来存储JOSN对象的方式明显不够优雅。通过RedisOM我们不仅能够以对象的形式来操作Redis中的数据,而且可以实现搜索功能!
<dependency>
<groupId>com.redis.om</groupId>
<artifactId>redis-om-spring</artifactId>
<version>0.5.0</version>
</dependency>
JRediSearch,是基于jedis封装的RediSearch库,对jdk和springboot版本没有要求。
JRediSearch 是 RediSearch 的一个 Java 客户端库。JRediSearch 包含一个抽象化 RediSearch Redis 模块的 API 的 Java 库,并在 Redis 内部实现了强大的 in-memory 搜索引擎。
当前想选择了JRediSearch 2.2.0版本进行操作RediSearch, JRediSearch依赖了Jedis 3.7.0, 这里需要单独引用一下jedis。
# 添加依赖
<dependency>
<groupId>com.redislabs</groupId>
<artifactId>jredisearch</artifactId>
<version>2.2.0</version>
# 排除包内引用的jedis, 包内引用的是3.7.0,但是无法连接redis7的redisearch,在下面单独引用 jedis 4.4.8
<exclusions>
<exclusion>
<artifactId>jedis</artifactId>
<groupId>redis.clients</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.4.8</version>
</dependency>
spring-boot-starter-data-redis中排除一下lettuce,因为新的springboot使用lettuce替代了jedis进行连接redis, 使用jredisearch时,会造成 JedisPool 无法找到。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
操作RediSearch
示例代码
重写jredisarch中Client类,类中使用的BinaryClient类,在jedis4.4.8中不存在此类,需要更换为Collection,其他代码跟原始代码Client相同:
public class JedisClient implements io.redisearch.Client {
private Connection sendCommand(Jedis conn, ProtocolCommand provider, String... args) {
Connection client = conn.getClient();
client.sendCommand(provider, args);
return client;
}
private Connection sendCommand(Jedis conn, ProtocolCommand provider, byte[]... args) {
Connection client = conn.getClient();
client.sendCommand(provider, args);
return client;
}
}
使用JedisPool初始化客户端:
import io.redisearch.Document;
import io.redisearch.SearchResult;
import io.redisearch.Query;
import io.redisearch.Schema;
// 初始化jedis连接池
JedisPool pool = new JedisPool(new GenericObjectPoolConfig<>(),
"127.0.0.1",
6379,
2000,
"redis",
0
);
// 索引名称
String indexName = "article";
// 初始化客户端
JedisClient client = new JedisClient(indexName,pool);
为索引定义并创建一个 schema:
// 中文语言
String LANGUAGE_NAME = "chinese";
Schema sc = new Schema()
.addTextField("title", 5.0)
.addTextField("body", 1.0)
.addNumericField("price");
// IndexDefinition requires RediSearch 2.0+
IndexDefinition def = new IndexDefinition(IndexDefinition.Type.HASH)
.setPrefixes(new String[] {"item:", "product:"})
// 设置语言,不设置,中文无法查找到
setLanguage(LANGUAGE_NAME );
client.createIndex(sc, Client.IndexOptions.defaultOptions().setDefinition(def));
为索引添加文档:
Map<String, Object> fields = new HashMap<>();
fields.put("title", "hello world");
fields.put("state", "NY");
fields.put("body", "lorem ipsum");
fields.put("price", 1337);
// Prior to RediSearch 2.0+ the addDocument has to be called
client.addDocument("item", fields);
// document方式
client.addDocument(new Document("item", fields));
查找索引:
// 中文语言
String LANGUAGE_NAME = "chinese";
// Creating a complex query
Query q = new Query("hello world")
// 设置语言,不设置,中文无法查找到
.setLanguage(LANGUAGE_NAME)
// 设置分页
.limit(0,5);
// actual search
SearchResult res = client.search(q);
// aggregation query
AggregationBuilder r = new AggregationBuilder("hello")
.apply("@price/1000", "k")
.groupBy("@state", Reducers.avg("@k").as("avgprice"))
.filter("@avgprice>=2")
.sortBy(10, SortedField.asc("@state"));
AggregationResult res = client.aggregate(r);