Redisearch接入SpringBoot项目使用
1.介绍
RediSearch 是 Redis 的官方全文搜索引擎模块,由 Redis Labs 开发,支持在内存中实现毫秒级响应的实时搜索。
核心功能
- 全文搜索:支持关键词、模糊匹配(如前缀搜索)、布尔逻辑(AND/OR/NOT)及中文分词(需配置分词器)。
- 复杂查询:数值范围查询(如价格区间)、地理位置搜索(结合Redis GEO命令)、JSON文档搜索(需配合RedisJSON模块)。
- 智能扩展:自动补全(如输入“电”联想“电脑”)、同义词扩展(如“手机”匹配“移动电话”)。
- 高性能:内存存储,写入即索引,支持增量索引(无需全量重建)。
2.官方使用文档
官方使用文档
3.依赖
<dependency><groupId>com.redis</groupId><artifactId>lettucemod-spring</artifactId><version>4.3.0</version>
</dependency>
4.项目代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;@Data
@NoArgsConstructor
@AllArgsConstructor
public class RedisPageResult<T> {/*** 当前页数据*/private List<T> records;/*** 总记录数*/private long total;/*** 当前页码,从0开始*/private int offset;/*** 每页条数*/private int num;}
import com.redis.lettucemod.api.StatefulRedisModulesConnection;
import com.redis.lettucemod.api.sync.RedisModulesCommands;
import com.redis.lettucemod.search.*;
import com.yttxg.nova.dms.service.redis.bo.RedisPageResult;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;/*** @Package com.yttxg.nova.dms.service.redis* @Description redis搜索服务类* @Author xxxxx* @Date 2025/7/2 15:16* @Version 1.0* Modification History:* Date Author Version Description* ------------------------------------------------------------------* 2025/7/2 15:16 xxxxx 1.0 1.0 Version*/
@Slf4j
@Service
@RequiredArgsConstructor
public class RedisSearchService {@Resource(name = "redisConnectionPool")GenericObjectPool<StatefulRedisModulesConnection<String, String>> pool;private StatefulRedisModulesConnection<String, String> connection() {try {return pool.borrowObject();} catch (Exception e) {throw new RuntimeException("获取 redis 链接失败", e);}}private void consumeWithCommands(Consumer<RedisModulesCommands<String, String>> consumer) {try (var connection = connection()) {RedisModulesCommands<String, String> commands = connection.sync();consumer.accept(commands);}}private <T> T applyWithCommands(Function<RedisModulesCommands<String, String>, T> function) {try (var connection = connection()) {RedisModulesCommands<String, String> commands = connection.sync();return function.apply(commands);}}/*** 创建一个新的搜索索引*/public void createIndex(String indexName, String prefix, List<Field<String>> fields) {consumeWithCommands(commands -> {List<String> indexList = commands.ftList();if (indexList.contains(indexName)) {log.info("索引 [{}] 已存在", indexName);return;}CreateOptions<String, String> options = CreateOptions.<String, String>builder().prefix(prefix).defaultLanguage(Language.CHINESE).on(CreateOptions.DataType.HASH).build();commands.ftCreate(indexName, options, fields.toArray(new Field[0]));log.info("创建索引: [{}]", indexName);});}/*** 批量插入文档*/public void batchInsertDocuments(String prefix, Map<String, Map<String, String>> documents) {consumeWithCommands(commands -> {documents.forEach((id, doc) -> {String key = prefix + id;commands.hset(key, doc);});});}/*** 插入文档*/public void insertDocuments(String prefix, String id, Map<String, String> doc) {consumeWithCommands(commands -> {String key = prefix + id;commands.hset(key, doc);});}/*** 分页搜索*/public SearchResults<String, String> searchWithPaging(String indexName, String query, int offset, int num) {return applyWithCommands(commands -> {SearchOptions<String, String> options = SearchOptions.<String, String>builder().limit(offset, num).build();return commands.ftSearch(indexName, query, options);});}public RedisPageResult<Document<String, String>> searchWithPagingResult(String indexName, String query, int offset, int num) {SearchResults<String, String> rawResults = searchWithPaging(indexName, query, offset, num);return new RedisPageResult<>(rawResults, rawResults.getCount(), offset, num);}/*** 简单搜索(不分页)*/public SearchResults<String, String> search(String indexName, String query) {return applyWithCommands(commands -> commands.ftSearch(indexName, query));}}
5.如何使用
已提供批量插入方法
List<Field<String>> fields = List.of(Field.numeric("id").build(), Field.text("content").sortable(true).build());
redisSearchService.createIndex("elements-idx", "element:", fields);
Map<String, String> doc = new HashMap<>();
String docId = DigestUtil.sha256Hex(element+id).substring(0, 32);
doc.put("id", String.valueOf(id));
doc.put("content", element);
redisSearchService.insertDocuments("element:", docId, doc);
6.查询
public class RedisSearchController {@Resourceprivate RedisSearchService redisSearchService;@GetMapping("/element")@Operation(description = "获取要素信息", summary = "获取要素信息")public CommonResult<RedisPageResult<Document<String, String>>> getElementListPage(@RequestParam String element,@RequestParam Integer offset,@RequestParam Integer num) {RedisPageResult<Document<String, String>> pageResult = redisSearchService.searchWithPagingResult("elements-idx", element, offset, num);return CommonResult.success(pageResult);}
}