尝试使用基于Redis的搜索引擎RediSearch
RediSearch是什么?
RediSearch是基于Redis开发的开源全文搜索和二级索引引擎。它由Redis Labs公司开发,其中包括Redis的作者Salvatore Sanfilippo。由于基于Redis,RediSearch以速度为卖点。
根据Redis Labs的白皮书,据说与Elasticsearch相比,RediSearch的吞吐量大约高出4倍。这种显著的性能差异的原因在于,RediSearch不仅基于Redis,而且RediSearch本身是通过使用C语言编写的RedisModule API来扩展Redis的。
顺便说一下,在使用RedisModule的其他开源软件中,还有一个相当雄心勃勃的Redis插件叫做rediSQL,它能够在Redis上执行SQL查询,而且还是用Rust语言编写的!如果你对此感兴趣,可以去看看。
顺便说一下,本文是基于v1.6.14版本的信息。由于v1.6.14版本尚不支持日语全文搜索,所以请不要期望它的出现。
安装
docker run -p 6379:6379 redislabs/redisearch:latest
如果想从源代码进行安装,请参考此处。
スキーマ作成(FT.CREATE)
与其他Redis数据结构不同,RediSearch在添加文档之前需要定义模式。
FT.CREATE <INDEX名> <INDEXオプション> SCHEMA <FIELD名> <FIELDの型> <FIELDオプション>...
-
- フィールドの数には1024の制限がある。そのうちTEXTフィールドの最大個数は128個
-
- フィールドの型
TEXT: テキスト型
NUMERIC: 数値型
GEO: 緯度経度座標
よく使いそうなオプション
NOHL: HighlightをOffにすることでメモリを節約できる
NOFIELDS: 各Fieldを保存しないことによってメモリを節約できる
NOFREQS: Term frequency(頻出度)を保存しないことによってメモリを節約できる
よく使いそうなフィールドオプション
SORTABLE: FT.SEARCHコマンドでSORTABLE指定できるようになる
尝试创建数据模式。
FT.CREATE pokemon SCHEMA id NUMERIC name TEXT name_ja TEXT hp NUMERIC attack NUMERIC defence NUMERIC sp_attack NUMERIC sp_defence NUMERIC speed NUMERIC
在中国原生语言中,将以下内容重新表达:添加文档(FT.ADD)。
FD.ADD <INDEX名> <DocID> <Score> <OPTIONS> FIELDS <FIELD名> <FIELDの値>...
DocID: ドキュメントの識別子
よく使いそうなオプション
REPLACE: SQLのUpseart的な動きをする。新規作成or既存を削除して再作成
PARTIAL: REPLACE指定の時だけ有効。いくつかのフィールドを省略すると既存の値がそのまま残るようになる
将Bulbasaur的资料添加到宝可梦图鉴中。
FT.ADD pokemon Bulbasaur 1.0 FIELDS id 1 name Bulbasaur hp 45 attack 49 defence 49 sp_attack 65 sp_defence 65 speed 45
然后Redis将创建以下类型的密钥。
127.0.0.1:6379> keys *
1) "ft:pokemon/bulbasaur"
2) "nm:pokemon/defence"
3) "nm:pokemon/sp_attack"
4) "nm:pokemon/hp"
5) "idx:pokemon"
6) "nm:pokemon/attack"
7) "Bulbasaur"
8) "nm:pokemon/id"
9) "nm:pokemon/sp_defence"
10) "nm:pokemon/speed"
其中,“Bulbasaur”是由哈希编码构成的,当你看进去时,会变成这样的样子。
127.0.0.1:6379> hgetall "Bulbasaur"
1) "id"
2) "1"
3) "name"
4) "Bulbasaur"
5) "hp"
6) "45"
7) "attack"
8) "49"
9) "defence"
10) "49"
11) "sp_attack"
12) "65"
13) "sp_defence"
14) "65"
15) "speed"
16) "45"
其他键由RediSearch管理的索引数据控制,普通的命令无法查看其中内容。
127.0.0.1:6379> type "ft:pokemon/bulbasaur"
ft_invidx
127.0.0.1:6379> type "nm:pokemon/defence"
numericdx
顺便提一下,如果包含了模式定义中没有的字段,则不会创建索引,但会正确地添加到哈希表中。因此,在将Redis用作应用程序的数据库时,也可以选择仅对文档的特定字段进行索引化。
进行搜索(FT.SEARCH)
FT.SEARCH <インデックス名> <クエリ> <オプション>
-
- よく使いそうなオプション
NOCONTENT: docidのみ検索結果に表示する
LIMIT first num: 表示件数。デフォルトは0 10。なぜデフォルト上限が10なのか…無限であるべきなのでは…
SORTBY field [ASC|DESC]: SORTABLEがついているフィールドでソートする
WITHSORTKEYS: SORTABLEがついているフィールドでソートする
名前でテキスト検索する
FT.SEARCH pokemon Bulbasaur
フィールド指定でテキスト検索する
FT.SEARCH pokemon “@name:Bulbasaur”
ワイルドカードを使う
FT.SEARCH pokemon “@name:Bul*”
NUMERICフィールドの範囲指定でidが1のポケモンを検索する
FT.SEARCH pokemon “@id:[1 1]”
hpが100以上150以下のポケモンを検索する
FT.SEARCH pokemon “@hp:[50 100]”
hpが100以上150以下かつattachが100以上150以下のポケモンを検索する
FT.SEARCH pokemon “@hp:[50 100] @attack:[50 100]”
性能 – Performance
在中国,当然要关注性能。我们来比较一下直接从Redis的哈希中进行HGETALL操作和使用FT.SEARCH搜索的速度。
条件 (tiaojian)
-
- CentOS 7.4 / i7-7700 8cores 3.6GHz / DDR4 16GB RAM
RediSearchは以下のコマンドで実行
docker run –network host -t redislabs/redisearch:1.6.14
同じホスト上のredisearchコンテナに対してredis-benchmarkを使ってスループットを検証する
オプションは-c 64 -P 1と-c 64 -P 128の二通り
结果
GETでデータを取得する
$ redis-benchmark -c 64 -P 1 -n 1000000 get foo
151492.20 requests per second
$ redis-benchmark -c 64 -P 128 -n 5000000 get foo
3259452.25 requests per second
HGETALLでデータを取得する
$ redis-benchmark -c 64 -P 1 -n 1000000 hgetall Bulbasaur
129617.62 requests per second
$ redis-benchmark -c 64 -P 128 -n 5000000 hgetall Bulbasaur
838363.50 requests per second
完全一致検索
$ redis-benchmark -c 64 -P 1 -n 1000000 FT.SEARCH pokemon Bulbasaur
47714.48 requests per second
$ redis-benchmark -c 64 -P 128 -n 1000000 FT.SEARCH pokemon Bulbasaur
58840.83 requests per second
ワイルドカードによる前方一致検索
$ redis-benchmark -c 64 -P 1 -n 1000000 FT.SEARCH pokemon “@name:Bul*”
36892.20 requests per second
$ redis-benchmark -c 64 -P 128 -n 1000000 FT.SEARCH pokemon “@name:Bul*”
39684.12 requests per second
NUMERICフィールドの範囲検索する
$ redis-benchmark -c 64 -P 1 -n 1000000 FT.SEARCH pokemon “@id:[1 1]”
57773.41 requests per second
$ redis-benchmark -c 64 -P 128 -n 1000000 FT.SEARCH pokemon “@id:[1 1]”
62410.28 requests per second
RediSearch 2会有什么变化?
RediSearch 2是于2020年9月18日发布的最新版本,与1系列不兼容。其中最大的变化是,现在可以使用HSET而不是FT.ADD来向传统索引中添加数据。然而,缺点是数据结构仅限于HASH(未来将支持其他数据结构)。
在这里,我不会详细介绍RediSearch2,但我们将一起查看它的基准测试结果。
インデックス作成
$ FT.CREATE idx:pokemon on hash prefix 1 pokemon: SCHEMA id NUMERIC name TEXT name_ja TEXT hp NUMERIC attack NUMERIC defence NUMERIC sp_attack NUMERIC sp_defence NUMERIC speed NUMERIC
完全一致検索
$ redis-benchmark -c 64 -P 1 -n 1000000 FT.SEARCH pokemon Bulbasaur
43965.71 requests per second
$ redis-benchmark -c 64 -P 128 -n 5000000 FT.SEARCH pokemon Bulbasaur
50563.79 requests per second
ワイルドカードによる前方一致検索
$ redis-benchmark -c 64 -P 1 -n 1000000 FT.SEARCH pokemon “@name:Bul*”
28401.02 requests per second
$ redis-benchmark -c 64 -P 128 -n 1000000 FT.SEARCH pokemon “@name:Bul*”
31661.60 requests per second
NUMERICフィールドの範囲検索する
$ redis-benchmark -c 64 -P 1 -n 1000000 FT.SEARCH pokemon “@id:[1 1]”
43620.50 requests per second
$ redis-benchmark -c 64 -P 128 -n 1000000 FT.SEARCH pokemon “@id:[1 1]”
54071.59 requests per second
应该使用RediSearch吗?
-
- 性能を気にしない単純なキーの検索=> KEYSやSCANでキー文字列を検索すればよい
-
- 複数の条件で検索したい=> RediSearchが良いかも
- SQLで検索したい=> rediSQLが使えるかも。が、そもそも本当にRedisでやるべきかも検討したほうがいい
总结
RediSearchを業務で使ってみたので紹介してみました。筆者的にはRediSearchはすでにProduction readyでRedisをヘビーにつかっていて検索等が多いプロジェクトなら導入の検討の価値ありだと思います。
文献引用
-
- RediSearch Github
-
- RediSearch Documentation
- Search Benchmarking: RediSearch vs. Elasticsearch