RediSearch 是一个高性能的全文搜索引擎,它可以作为一个 Redis Module(扩展模块)运行在 Redis 服务器上。
RediSearch 主要特性如下:
和前面讲到布隆过滤器的引入方式一样,我们可以使用 RediSearch 官方推荐的 Docker 方式来安装并启动 RediSearch 功能,操作命令如下:
docker run -d -p 6379:6379 --name redisearch redislabs/redisearch:latest
安装完成之后使用 redis-cli 来检查 RediSearch 模块是否加载成功,使用 Docker 启动 redis-cli,命令如下:
docker exec -it redisearch redis-cli
其中“redisearch”为 Redis 服务器的名称(也就是使用docker启动时--name后面的值),执行结果如下:
127.0.0.1:6379> module list 1) 1) "name" 2) "search" 3) "ver" 4) (integer) 20015
源码方式安装(我没有安装成功,所以我使用的上面方式)
如果不想使用 Docker,我们也可以使用源码的方式进行安装,安装命令如下:
git clone https://github.com/RedisLabsModules/RediSearch.git
cd RediSearch # 进入模块目录
make all
安装完成之后,可以使用如下命令启动 Redis 并加载 RediSearch 模块,命令如下:
src/redis-server redis.conf --loadmodule ../RediSearch/src/redisearch.so
我们先使用 redis-cli 来对 RediSearch 进行相关的操作。
创建索引和字段
127.0.0.1:6379> ft.create myidx schema title text weight 5.0 desc text
OK
其中“myidx”为索引的ID,此索引包含了两个字段“title”和“desc”,“weight”为权重,默认值为 1.0。
将内容添加到索引
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”为评分(score)。
根据关键查询
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 字段中的关键字“english”查询出了一条满足查询条件的数据。
注意:这里必须要设置语言编码为中文,也就是“language "chinese"”,默认是英文编码,如果不设置则无法支持中文查询(无法查出结果)。
我们使用之前的查询方式,命令如下:
127.0.0.1:6379> ft.add myidx doc2 1.0 language "chinese" fields title "Java 14 发布了!新功能速览" desc "Java 14 在 2020.3.17 日发布正式版了,但现在很多公司还在使用 Java 7 或 Java 8"
OK
注意:这里必须要设置语言编码为中文,也就是“language "chinese"”,默认是英文编码,如果不设置则无法支持中文查询(无法查出结果)。
我们使用之前的查询方式,命令如下:
127.0.0.1:6379> ft.search myidx "正式版"
1) (integer) 0
我们发现并没有查到任何信息,这是因为我们没有指定搜索的语言,不但保存时候要指定编码,查询时也需要指定,查询命令如下:
127.0.0.1:6379> ft.search myidx "发布了" 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"
从结果可以看出中文信息已经被顺利的查询出来了。
删除索引的数据
127.0.0.1:6379> ft.del myidx doc1
(integer) 1
我们使用索引加文档 ID 就可以实现删除数据的功能。
删除索引
我们可以使用“ft.drop”关键字删除整个索引,执行命令如下:
127.0.0.1:6379> ft.drop myidx
OK
查询索引详细信息
我们可以使用“ft.info”关键查询索引相关信息,执行命令如下:
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”表示存储的数据数量。
RediSearch 支持的客户端有以下这些。
本文我们使用 python的redisearch 来实现全文搜索的功能
完整的操作代码如下:
import redis
from redisearch import Client, TextField
class RedisSearch(object):
def __init__(self):
self.se_cli = Client("myIndex", host="xx", port=xx)
print("初始化成功......")
def create_index(self):
"""重复创建相同的索引/表会报错"""
try:
self.se_cli.create_index((TextField("title"), TextField("name")))
except redis.exceptions.ResponseError as e:
print("error info is: %s" % e)
else:
print("创建索引成功......")
def insert_info(self):
"""重复插入相同的数据会报错"""
try:
self.se_cli.add_document("id1", title="你好 中国", body="学习汉语", language="chinese")
except redis.exceptions.ResponseError as e:
print("error info is: %s" % e)
else:
print("新增数据成功......")
def search_info(self, query):
"""查询"""
res = self.se_cli.search(query)
if res:
print("search res is : %s, result type is: %s" % (res, type(res)))
else:
print("nothing......")
def delete_index(self):
"""删除索引"""
res = self.se_cli.drop_index()
if res == "OK":
print("删除索引成功")
else:
print("删除索引失败")
def cat_index_info(self):
"""查看索引信息"""
index_detail = self.se_cli.info()
print("index info is: %s" % index_detail)
def delete_doc(self, doc_id):
"""删除doc"""
res = self.se_cli.delete_document(doc_id)
if res == 1:
print("delete doc success......")
else:
print("delete doc failed......")
if __name__ == '__main__':
rs = RedisSearch()
rs.create_index()
rs.insert_info()
# rs.search_info("中国")
# rs.cat_index_info()
# rs.delete_doc("id1")
# rs.delete_index()
以上程序执行结果如下:
初始化成功...... 创建索引成功...... 新增数据成功...... search res is : Result{1 total, docs: [Document {'id': 'id1', 'payload': None, 'title': '你好 中国', 'body': '学习汉语'}]}, result type is:index info is: {'index_name': 'myIndex', 'index_options': [], 'index_definition': ['key_type', 'HASH', 'prefixes', [''], 'language_field', '__language', 'default_score', '1', 'score_field', '__score', 'payload_field', '__payload'], 'fields': [['title', 'type', 'TEXT', 'WEIGHT', '1'], ['name', 'type', 'TEXT', 'WEIGHT', '1']], 'num_docs': '1', 'max_doc_id': '1', 'num_terms': '2', 'num_records': '2', 'inverted_sz_mb': '1.1444091796875e-05', 'total_inverted_index_blocks': '2', 'offset_vectors_sz_mb': '1.9073486328125e-06', 'doc_table_size_mb': '8.106231689453125e-05', 'sortable_values_size_mb': '0', 'key_table_size_mb': '2.765655517578125e-05', 'records_per_doc_avg': '2', 'bytes_per_record_avg': '6', 'offsets_per_term_avg': '1', 'offset_bits_per_record_avg': '8', 'hash_indexing_failures': '0', 'indexing': '0', 'percent_indexed': '1', 'gc_stats': ['bytes_collected', '0', 'total_ms_run', '0', 'total_cycles', '0', 'average_cycle_time_ms', '-nan', 'last_run_time_ms', '0', 'gc_numeric_trees_missed', '0', 'gc_blocks_denied', '0'], 'cursor_stats': ['global_idle', 0, 'global_total', 0, 'index_capacity', 128, 'index_total', 0]} delete doc success...... 删除索引成功
可以看出添加的中文数据,被正确的查询出来了。
本文我们使用 Docker 和 源码编译的方式成功的启动了 RediSearch 功能,要使用 RediSearch 的全文搜索功能,必须先要创建一个索引,然后再索引中添加数据,再使用 ft.search 命令进行全文搜索,如果要查询中文内容的话,需要在添加数据时设置中文编码,并且在查询时也要设置中文编码,指定“language "chinese"”。