RediSearch+SpringBoot全文検索を実現
42885 ワード
一、RediSearch紹介:
Redis上では検索エンジンが実装されているが、他のRedis検索ライブラリとは異なり、Sorted Setsのような内部データ構造は使用されない.逆インデックスストレージは特殊な圧縮データ型であり、高速インデックスと検索速度を実現し、メモリ消費量を削減します.これにより、正確なフレーズマッチングやテキストクエリのデジタルフィルタリングなど、より高度な機能も有効になります.これは、従来のRedis検索方法では実現できないか、実現できないものです.
二、RediSearchオープンソースアドレス:
公式住所:https://oss.redislabs.com/redisearch/
オープンソースアドレス:https://github.com/RediSearch/RediSearch
三、インストールコマンド:
https://hub.docker.com/r/redislabs/redisearch/
$ docker run -p 6379:6379 redislabs / redisearch:latest
四、Springboot集積RediSearch:
クライアント:https://github.com/RediSearch/JRediSearch
依存関係:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.citydo</groupId>
<artifactId>redisearchspringboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redisearchspringboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.redislabs</groupId>
<artifactId>jredisearch</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.10</version>
</dependency>
<dependency>
<groupId>com.hankcs</groupId>
<artifactId>hanlp</artifactId>
<version>portable-1.7.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
ツールクラス:
package com.citydo.redisearchspringboot;
import com.hankcs.hanlp.seg.common.Term;
import com.hankcs.hanlp.suggest.Suggester;
import com.hankcs.hanlp.tokenizer.NLPTokenizer;
import io.redisearch.AggregationResult;
import io.redisearch.Query;
import io.redisearch.Schema;
import io.redisearch.SearchResult;
import io.redisearch.aggregation.AggregationBuilder;
import io.redisearch.aggregation.SortedField;
import io.redisearch.aggregation.reducers.Reducers;
import io.redisearch.client.Client;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RedisSearchUtils {
private Client client = null;
/**
* redis
*/
private RedisSearchUtils() {
if (client == null) {
String indexName = "test";
String host = "localhost";
int port = 6379;
String password = "124";
int timeout = 3000;
int poolSize = 0;
if (!StringUtils.isEmpty(password)) {
// redis
client = new Client(indexName, host, port, timeout, poolSize, password);
}else {
// redis
client = new Client(indexName, host, port);
}
}
}
/**
*
*/
public void createIndex(String title, String body, String price){
Schema sc = new Schema()
.addTextField(title, 5.0)
.addTextField(body, 1.0)
.addNumericField(price);
client.createIndex(sc, Client.IndexOptions.defaultOptions());
}
/**
*
* fields.put("title", "hello world");
* fields.put("state", "NY");
* fields.put("body", "lorem ipsum");
* fields.put("price", 1337);
* @param fields
*/
public void addDocument(String docId, Map<String, Object> fields){
client.addDocument(docId, fields);
}
/**
*
* @param queryString
* @param price
* @return
*/
public SearchResult search(String queryString, String price){
Query query = new Query(queryString)
.addFilter(new Query.NumericFilter(price, 0, 1000))
.limit(0,Integer.MAX_VALUE);
return client.search(query);
}
/**
*
* @param query
* @param price
* @param state
* @param avgprice
* @param k
* @return
*/
public AggregationResult aggregate(String query, String price, String state, String avgprice, String k){
AggregationBuilder builder = new AggregationBuilder(query)
.apply("@".concat(price).concat("/1000"), k)
.groupBy("@".concat(state), Reducers.avg("@".concat(k)).as(avgprice))
.filter("@".concat(avgprice).concat(">=2"))
.sortBy(Integer.MAX_VALUE, SortedField.asc("@".concat(state)));
return client.aggregate(builder);
}
/**
*
*/
public List<SearchResult> searchParticiple(String queryString, String price){
List<SearchResult> result = new ArrayList<>();
//
List<Term> termList = NLPTokenizer.segment(queryString);
termList.stream().forEach(e->{
Query query = new Query(e.word)
.addFilter(new Query.NumericFilter(price, 0, 1000))
.limit(0,Integer.MAX_VALUE);
SearchResult search = client.search(query);
result.add(search);
});
return result;
}
/**
*
* @param queryString
* @param price
* @return
*/
public List<SearchResult> searchSuggest(String queryString, String price){
List<SearchResult> result = new ArrayList<>();
//
List<String> suggest = new Suggester().suggest(queryString, Integer.MAX_VALUE);
suggest.stream().forEach(e->{
Query query = new Query(e)
.addFilter(new Query.NumericFilter(price, 0, 1000))
.limit(0,Integer.MAX_VALUE);
SearchResult search = client.search(query);
result.add(search);
});
return result;
}
}