實戰專案地址newbeemall,集成RediSearch,代碼開源已上傳,支持的話可以點個star??
RediSearch 是基于 Redis 開發的支持二級索引、查詢引擎和全文搜索的應用程式,在2.0的版本中,簡單看下官網測驗報告:
索引構建
在索引構建測驗中,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也在官網檔案特意列出了支持中文,基于frisoC語言開發的中文分詞專案,
一、RediSearch安裝
Docker安裝最新版
docker run -p 6379:6379 redislabs/redisearch:latest
通過redis-cli連接查看RediSearch是否安裝成功
1、redis-cli -h localhost
2、module list
82.157.141.70:16789> MODULE LIST
1) 1) "name"
2) "search" # 查看是否包含search模塊
3) "ver"
4) (integer) 20210
2) 1) "name"
2) "ReJSON" # 查看是否包含ReJSON模塊
3) "ver"
4) (integer) 20007
二、客戶端集成
對于Java專案直接選用Jedis4.0版本就可以,Jedis在4.0版本自動支持RediSearch,撰寫Jedis連接RedisSearch測驗用例,用RedisSearch命令創建如下:
FT.CREATE idx:goods on hash prefix 1 "goods:" language chinese schema goodsName text sortable
// FT.CREATE 創建索引命令
// idx:goods 索引名稱
// on hash 索引資料基于hash型別源資料構建
// prefix 1 "goods:" 表示要創建索引的源資料前綴匹配規則
// language chinese 表示支持中文語言分詞
// schema 表示欄位定義,goodsName元資料屬性名 text欄位型別 sortable自持排序
FT.INFO idx:goods
// FT.INFO 查詢指定名稱索引資訊
FT.DROPINDEX idx:goods
// FT.DROPINDEX 洗掉指定名稱索引,不會洗掉源資料
添加索引時,使用hset命令添加索引源資料
洗掉索引時,使用del命令洗掉索引源資料
- 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創建索引
@Test
public void createIndex() {
System.out.println("begin");
Schema schema = new Schema()
.addSortableTextField("goodsName", 1.0)
.addSortableTextField("goodsIntro", 0.5)
.addSortableTagField("tag", "|");
jedisSearch.createIndex(idxName, "goods", schema);
System.out.println("end");
}
/**
* 創建索引
*
* @param idxName 索引名稱
* @param prefix 要索引的資料前綴
* @param schema 索引欄位配置
*/
public void createIndex(String idxName, String prefix, Schema schema) {
IndexDefinition rule = new IndexDefinition(IndexDefinition.Type.HASH)
.setPrefixes(prefix)
.setLanguage(Constants.GOODS_IDX_LANGUAGE); # 設定支持中文分詞
client.ftCreate(idxName,
IndexOptions.defaultOptions().setDefinition(rule),
schema);
}
- Jedis添加索引源資料
/**
* 添加索引資料
*
* @param keyPrefix 要索引的資料前綴
* @param goods 商品資訊
* @return boolean
*/
public boolean addGoodsIndex(String keyPrefix, Goods goods) {
Map<String, String> hash = MyBeanUtil.toMap(goods);
hash.put("_language", Constants.GOODS_IDX_LANGUAGE);
client.hset(keyPrefix + 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(Constants.GOODS_IDX_LANGUAGE);
// 查詢分頁
q.limit((int) page.offset(), (int) page.getSize());
// 回傳查詢結果
return client.ftSearch(goodsIdxName, q);
}
三、專案實戰
- 引入Jedis4.0
<jedis.version>4.2.0</jedis.version>
<!-- jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
- 在newbeemall專案后臺商品管理中添加同步按鈕
,撰寫商品全量同步按鈕,為了加快同步速度,通過多執行緒同步
// 同步商品到RediSearch
public boolean syncRs() {
jedisSearch.dropIndex(Constants.GOODS_IDX_NAME);
Schema schema = new Schema()
.addSortableTextField("goodsName", 1.0)
.addSortableTextField("goodsIntro", 0.5)
.addSortableNumericField("goodsId")
.addSortableNumericField("sellingPrice")
.addSortableNumericField("originalPrice")
.addSortableTagField("tag", "|");
jedisSearch.createIndex(Constants.GOODS_IDX_NAME, "goods:", schema);
List<Goods> list = this.list();
jedisSearch.deleteGoodsList(Constants.GOODS_IDX_PREFIX);
return jedisSearch.addGoodsListIndex(Constants.GOODS_IDX_PREFIX, list);
}
/**
* 同步商品索引
*
* @param keyPrefix 要索引的資料前綴
* @return boolean
*/
public boolean addGoodsListIndex(String keyPrefix, List<Goods> list) {
int chunk = 200;
int size = list.size();
int ceil = (int) Math.ceil(size / (double) chunk);
// 多執行緒同步
List<CompletableFuture<Void>> futures = new ArrayList<>(4);
for (int i = 0; i < ceil; i++) {
int toIndex = (i + 1) * chunk;
if (toIndex > size) {
toIndex = i * chunk + size % chunk;
}
List<Goods> subList = list.subList(i * chunk, toIndex);
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> subList).thenAccept(goodsList -> {
for (Goods goods : goodsList) {
Map<String, String> hash = MyBeanUtil.toMap(goods);
hash.put("_language", Constants.GOODS_IDX_LANGUAGE);
client.hset(keyPrefix + goods.getGoodsId(), MyBeanUtil.toMap(goods));
}
});
futures.add(voidCompletableFuture);
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
return true;
}
- 修改商品頁面搜索介面
@GetMapping("/search")
public String rsRearch(SearchObjVO searchObjVO, HttpServletRequest request) {
Page<SearchPageGoodsVO> page = getPage(request, Constants.GOODS_SEARCH_PAGE_LIMIT);
...
// RediSearch中文搜索
SearchResult query = jedisSearch.search(Constants.GOODS_IDX_NAME, searchObjVO, page);
...
return "mall/search";
}
- 查看搜索結果中包含"小米"、"手機"兩個單獨分詞
四、總結
通過以上實戰專案,使用RediSearch是可以滿足基本中文分詞需求
高級用法聚合查詢、結果高亮、停用詞、擴展API、拼寫更正、自動補全等可以在官網了解,
最后貼一下實戰專案地址newbeemall,集成RediSearch,代碼開源已上傳
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/451999.html
標籤:其他
上一篇:集合(模擬斗地主發牌)
下一篇:Condition
