輕量級(jí)搜索引擎-RediSearch

Clickhouse最佳實(shí)踐

RediSearch 是一個(gè)高性能的全文搜索引擎,它可以作為一個(gè) Redis Module(擴(kuò)展模塊)運(yùn)行在 Redis 服務(wù)器上;在2.x之后的版本它不在使用基于RDB的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),而是采用了一種全新的文件存儲(chǔ)結(jié)構(gòu)對(duì)數(shù)據(jù)進(jìn)行索引,而且性能上也有了成倍的提升。

RediSearch 主要特性如下:

  • 多字段聯(lián)合檢索
  • 高性能增量索引
  • 提前指定文檔可排序字段(由用戶在索引時(shí)手動(dòng)提供)
  • 復(fù)雜布爾查詢
  • 基于管道的查詢子句
  • 基于前綴的搜索
  • 支持字段權(quán)重設(shè)置
  • 自動(dòng)完成建議(可用于搜索框聯(lián)想詞提示)
  • 精確的短語(yǔ)搜索
  • 在許多語(yǔ)言中基于詞干分析的查詢擴(kuò)展
  • 支持自定義評(píng)分函數(shù)(類似ES的function_score)
  • 將搜索限制到特定的文檔字段
  • 數(shù)字過(guò)濾器和范圍
  • 使用 Redis 自己的地理命令進(jìn)行地理過(guò)濾
  • Unicode 支持(需要 UTF-8 字符集)
  • 檢索完整的文檔內(nèi)容或只是 ID 的檢索
  • 支持文檔刪除和更新與索引垃圾收集
  • 支持部分更新和條件文檔更新
  • 支持拼寫糾錯(cuò)
  • 支持高亮顯示
  • 支持聚合分析
  • 支持配置停用詞和同義詞
  • 支持向量存儲(chǔ)與KNN檢索(重磅)

安裝

和前面講到布隆過(guò)濾器的引入方式一樣,我們可以使用 RediSearch 官方推薦的 Docker 方式來(lái)安裝并啟動(dòng) RediSearch 功能,操作命令如下:

docker run -p 6379:6379 redislabs/redisearch:latest

安裝并啟動(dòng)成功,如下圖所示:

RediSearch安裝成功.png

安裝完成之后使用 redis-cli 來(lái)檢查 RediSearch 模塊是否加載成功,使用 Docker 啟動(dòng) redis-cli,命令如下:

docker exec -it myredis redis-cli

其中“myredis”為 Redis 服務(wù)器的名稱,執(zhí)行結(jié)果如下:

127.0.0.1:6379> module list
1) 1) "name"
   2) "ft"
   3) "ver"
   4) (integer) 10610

返回?cái)?shù)組存在“ft”,表明 RediSearch 模塊已經(jīng)成功加載。

源碼方式安裝

如果不想使用 Docker,我們也可以使用源碼的方式進(jìn)行安裝,安裝命令如下:

git clone https://github.com/RedisLabsModules/RediSearch.git
cd RediSearch # 進(jìn)入模塊目錄
make all

安裝完成之后,可以使用如下命令啟動(dòng) Redis 并加載 RediSearch 模塊,命令如下:

src/redis-server redis.conf --loadmodule ../RediSearch/src/redisearch.so

使用

我們先使用 redis-cli 來(lái)對(duì) RediSearch 進(jìn)行相關(guān)的操作。

創(chuàng)建索引和字段

127.0.0.1:6379> ft.create myidx schema title text weight 5.0 desc text
OK

其中“myidx”為索引的ID,此索引包含了兩個(gè)字段“title”和“desc”,“weight”為權(quán)重,默認(rèn)值為 1.0。

將內(nèi)容添加到索引

127.0.0.1:6379> ft.add myidx doc1 1.0 fields title "He urged her to study English" desc "good idea"
OK

其中“doc1”為文檔 ID(docid),“1.0”為評(píng)分(score)。

根據(jù)關(guān)鍵查詢

127.0.0.1:6379> ft.search myidx "english" limit 0 10
1) (integer) 1
2) "doc1"
3) 1) "title"
   2) "He urged her to study English"
   3) "desc"
   4) "good idea"

可以看出我們使用 title 字段中的關(guān)鍵字“english”查詢出了一條滿足查詢條件的數(shù)據(jù)。

中文搜索

首先我們需要先給索引中,添加一條中文數(shù)據(jù),執(zhí)行命令如下:

127.0.0.1:6379> ft.add myidx doc2 1.0 language "chinese" fields title "Java 14 發(fā)布了!新功能速覽" desc "Java 14 在 2020.3.17 日發(fā)布正式版了,但現(xiàn)在很多公司還在使用 Java 7 或 Java 8"
OK

注意:這里必須要設(shè)置語(yǔ)言編碼為中文,也就是“l(fā)anguage "chinese"”,默認(rèn)是英文編碼,如果不設(shè)置則無(wú)法支持中文查詢(無(wú)法查出結(jié)果)。

我們使用之前的查詢方式,命令如下:

127.0.0.1:6379> ft.search myidx "正式版"
1) (integer) 0

我們發(fā)現(xiàn)并沒有查到任何信息,這是因?yàn)槲覀儧]有指定搜索的語(yǔ)言,不但保存時(shí)候要指定編碼,查詢時(shí)也需要指定,查詢命令如下:

127.0.0.1:6379> ft.search myidx "發(fā)布了" language "chinese"
1) (integer) 1
2) "doc2"
3) 1) "desc"
   2) "Java 14 \xe5\x9c\xa8 2020.3.17 \xe6\x97\xa5\xe5\x8f\x91\xe5\xb8\x83\xe6\xad\xa3\xe5\xbc\x8f\xe7\x89\x88\xe4\xba\x86\xef\xbc\x8c\xe4\xbd\x86\xe7\x8e\xb0\xe5\x9c\xa8\xe5\xbe\x88\xe5\xa4\x9a\xe5\x85\xac\xe5\x8f\xb8\xe8\xbf\x98\xe5\x9c\xa8\xe4\xbd\xbf\xe7\x94\xa8 Java 7 \xe6\x88\x96 Java 8"
   3) "title"
   4) "Java 14 \xe5\x8f\x91\xe5\xb8\x83\xe4\xba\x86\xef\xbc\x81\xe6\x96\xb0\xe5\x8a\x9f\xe8\x83\xbd\xe9\x80\x9f\xe8\xa7\x88"

從結(jié)果可以看出中文信息已經(jīng)被順利的查詢出來(lái)了。

刪除索引的數(shù)據(jù)

127.0.0.1:6379> ft.del myidx doc1
(integer) 1

我們使用索引加文檔 ID 就可以實(shí)現(xiàn)刪除數(shù)據(jù)的功能。

刪除索引

我們可以使用“ft.drop”關(guān)鍵字刪除整個(gè)索引,執(zhí)行命令如下:

127.0.0.1:6379> ft.drop myidx
OK

查詢索引詳細(xì)信息

我們可以使用“ft.info”關(guān)鍵查詢索引相關(guān)信息,執(zhí)行命令如下:

127.0.0.1:6379> ft.info myidx
 1) index_name
 2) myidx
 3) index_options
 4) (empty list or set)
 5) fields
 6) 1) 1) title
       2) type
       3) TEXT
       4) WEIGHT
       5) "5"
    2) 1) desc
       2) type
       3) TEXT
       4) WEIGHT
       5) "1"
 7) num_docs
 8) "2"
 9) max_doc_id
10) "2"
11) num_terms
12) "9"
13) num_records
14) "18"
15) inverted_sz_mb
16) "0.000102996826171875"
17) total_inverted_index_blocks
18) "29"
19) offset_vectors_sz_mb
20) "1.71661376953125e-05"
21) doc_table_size_mb
22) "0.000164031982421875"
23) sortable_values_size_mb
24) "0"
25) key_table_size_mb
26) "8.0108642578125e-05"
27) records_per_doc_avg
28) "9"
29) bytes_per_record_avg
30) "6"
31) offsets_per_term_avg
32) "1"
33) offset_bits_per_record_avg
34) "8"
35) gc_stats
36)  1) bytes_collected
     2) "0"
     3) total_ms_run
     4) "16"
     5) total_cycles
     6) "14"
     7) avarage_cycle_time_ms
     8) "1.1428571428571428"
     9) last_run_time_ms
    10) "2"
    11) gc_numeric_trees_missed
    12) "0"
    13) gc_blocks_denied
    14) "0"
37) cursor_stats
38) 1) global_idle
    2) (integer) 0
    3) global_total
    4) (integer) 0
    5) index_capacity
    6) (integer) 128
    7) index_total
    8) (integer) 0

其中“num_docs”表示存儲(chǔ)的數(shù)據(jù)數(shù)量。

附加幾個(gè)全文檢索例子

看起來(lái)是不是很簡(jiǎn)單...

代碼實(shí)戰(zhàn)

RediSearch 支持的客戶端有以下這些。

image.png

本文我們使用 JRediSearch 來(lái)實(shí)現(xiàn)全文搜索的功能,首先在 pom.xml 添加 JRediSearch 引用:

<!-- https://mvnrepository.com/artifact/com.redislabs/jredisearch -->
<dependency>
  <groupId>com.redislabs</groupId>
  <artifactId>jredisearch</artifactId>
  <version>1.3.0</version>
</dependency>

完整的操作代碼如下:

import io.redisearch.client.AddOptions;
import io.redisearch.client.Client;
import io.redisearch.Document;
import io.redisearch.SearchResult;
import io.redisearch.Query;
import io.redisearch.Schema;

public class RediSearchExample {
    public static void main(String[] args) {
        // 連接 Redis 服務(wù)器和指定索引
        Client client = new Client("myidx", "127.0.0.1", 6379);
        // 定義索引
        Schema schema = new Schema().addTextField("title",
                5.0).addTextField("desc", 1.0);
        // 刪除索引
        client.dropIndex();
        // 創(chuàng)建索引
        client.createIndex(schema, Client.IndexOptions.Default());
        // 設(shè)置中文編碼
        AddOptions addOptions = new AddOptions();
        addOptions.setLanguage("chinese");
        // 添加數(shù)據(jù)
        Document document = new Document("doc1");
        document.set("title", "天氣預(yù)報(bào)");
        document.set("desc", "今天的天氣很好,是個(gè)陽(yáng)光明媚的大晴天,有藍(lán)藍(lán)的天空和白白的云朵。");
        // 向索引中添加文檔
        client.addDocument(document,addOptions);
        // 查詢
        Query q = new Query("天氣") // 設(shè)置查詢條件
                .setLanguage("chinese") // 設(shè)置為中文編碼
                .limit(0,5);
        // 返回查詢結(jié)果
        SearchResult res = client.search(q);
        // 輸出查詢結(jié)果
        System.out.println(res.docs);
    }
}

以上程序執(zhí)行結(jié)果如下:

[{"id":"doc1","score":1.0,"properties":{"title":"天氣預(yù)報(bào)","desc":"今天的天氣很好,是個(gè)陽(yáng)光明媚的大晴天,有藍(lán)藍(lán)的天空和白白的云朵。"}}]

可以看出添加的中文數(shù)據(jù),被正確的查詢出來(lái)了。

性能

為了評(píng)估RediSearch相比其他開源搜索引擎的性能,這里還會(huì)創(chuàng)建了一套度量延遲和吞吐量的基準(zhǔn)。基準(zhǔn)測(cè)試結(jié)果表明RediSearch的速度相比ElasticSearch 和 Solr要快120%到500%。

基準(zhǔn)設(shè)置:

數(shù)據(jù)集:從維基百科頁(yè)面提供的有用的英文摘要的轉(zhuǎn)儲(chǔ),其中包括510萬(wàn)短摘要。

基準(zhǔn)測(cè)試:我們針對(duì)不同的搜索引擎運(yùn)行了幾個(gè)具有不同配置文件的查詢。并行的運(yùn)行1, 8, 16、32和64個(gè)并發(fā)客戶端執(zhí)行每個(gè)查詢。我們也跑了自動(dòng)完成測(cè)試,從具有相同客戶端并發(fā)配置文件的數(shù)據(jù)集中測(cè)試前1100名最受歡迎的2和3個(gè)字母前綴。

物理配置:2個(gè) c4.4x large AWS EC2 Instance,每一個(gè)配置16核,32GB內(nèi)存 和 SSD EBS 存儲(chǔ),一個(gè)用作client,另一個(gè)運(yùn)行 servers

搜索引擎測(cè)試:

RediSearch:5個(gè)分片運(yùn)行在5個(gè)Redis Masters上,沒有負(fù)載均衡,冗余或內(nèi)置的緩存,此設(shè)置最多使用了Server機(jī)器的5個(gè)CPU核心。

ElasticSearch:一個(gè)實(shí)例有5個(gè)分片,過(guò)濾器緩存已禁用,在基準(zhǔn)測(cè)試中,ElasticSearch使用了所有的16個(gè)CPU核心,因?yàn)樗嵌嗑€程的。

Solr:solr-cloud的兩個(gè)實(shí)例,每一個(gè)實(shí)例上面運(yùn)行2個(gè)分片,緩存是完全禁用的,在基準(zhǔn)測(cè)試過(guò)程中,Solr也是使用了所有的16個(gè)CPU核心。
 

官方測(cè)試文檔:https://redis.com/blog/search-benchmarking-redisearch-vs-elasticsearch/

小結(jié)

官方文檔
特別適合高吞吐、高并發(fā),檢索排序復(fù)雜度低(介于RDBMS與ES之間)的場(chǎng)景:

redissearch可實(shí)現(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容