大家好,欢迎来到今天的RediSearch全文搜索讲座。今天我们要聊的是RediSearch中最核心的部分:索引构建和复杂查询。准备好了吗?让我们开始吧!
RediSearch:不只是个缓存,还是个搜索高手
Redis,我们都知道,是个速度飞快的键值存储。但RediSearch呢?它给Redis装上了一个强大的全文搜索引擎,让Redis不仅仅能存东西,还能高效地搜索!想象一下,你有一个庞大的商品数据库,以前搜东西慢得像蜗牛,现在用RediSearch,嗖的一下就出来了,是不是很爽?
索引:搜索的基石
要让RediSearch搜索得快,首先得建立索引。索引就像书的目录,没它,你只能一页一页地翻,有了它,直接定位到你想看的那页。
1. 创建索引:FT.CREATE 命令
创建索引的核心命令是 FT.CREATE
。这个命令有很多参数,我们一点点来看。
FT.CREATE {index_name}
[ON {HASH | JSON}]
[PREFIX {count} {prefix} ...]
[FILTER {expression}]
SCHEMA {field} [TEXT | NUMERIC | GEO | TAG | VECTOR] [options ...]
{index_name}
: 索引的名字,随便你起,但别太离谱。ON {HASH | JSON}
: 数据类型,是Redis的Hash还是JSON。PREFIX {count} {prefix} ...
: 指定哪些key需要被索引。count
是前缀的数量,prefix
是具体的前缀。FILTER {expression}
: 过滤条件,只有满足条件的key才会被索引。SCHEMA {field} [TEXT | NUMERIC | GEO | TAG | VECTOR] [options ...]
:最关键的部分,定义索引的字段和类型。
举个栗子:索引商品数据
假设我们有这样的商品数据(存储在Redis Hash中):
HMSET product:1 id 1 name "Awesome T-Shirt" description "A super cool t-shirt for everyone" price 29.99 category "Clothing" tags "fashion,casual,summer"
HMSET product:2 id 2 name "Fancy Pants" description "Elegant pants for special occasions" price 59.99 category "Clothing" tags "formal,party"
HMSET product:3 id 3 name "Running Shoes" description "Comfortable shoes for running" price 79.99 category "Shoes" tags "sports,running,fitness"
我们要创建一个索引来搜索这些商品,可以这样做:
FT.CREATE product_idx
ON HASH
PREFIX 1 product:
SCHEMA
name TEXT WEIGHT 5.0
description TEXT
price NUMERIC SORTABLE
category TAG SEPARATOR ","
tags TAG
解释一下:
product_idx
: 索引的名字。ON HASH
: 数据存储在Hash中。PREFIX 1 product:
: 只索引以product:
开头的key。SCHEMA
: 定义字段和类型。name TEXT WEIGHT 5.0
:name
字段是文本类型,WEIGHT 5.0
表示这个字段在搜索结果中的权重是5.0(权重越高,搜索结果越靠前)。description TEXT
:description
字段是文本类型,默认权重是1.0。price NUMERIC SORTABLE
:price
字段是数值类型,SORTABLE
表示可以根据价格排序。category TAG SEPARATOR ","
:category
字段是标签类型,分隔符是逗号。tags TAG
:tags
字段是标签类型,默认分隔符是逗号。
字段类型详解
- TEXT: 文本类型,用于全文搜索。
- NUMERIC: 数值类型,用于数值范围搜索和排序。
- GEO: 地理位置类型,用于地理位置搜索。
- TAG: 标签类型,用于精确匹配,性能比TEXT好。
- VECTOR: 向量类型,用于相似性搜索(需要指定算法和维度)。
options 详解
- WEIGHT: 权重,只有TEXT类型才能设置。
- SORTABLE: 可排序,NUMERIC和TAG类型可以设置。
- NOINDEX: 不索引,但可以用于FILTER。
- SEPARATOR: 分隔符,TAG类型可以设置。
- WITHSUFFIXTRIE: 用于自动补全。
2. 添加数据:HMSET (JSON.SET)
数据添加,就是往Redis里存数据。如果ON
是 HASH
,就用 HMSET
命令;如果ON
是 JSON
,就用 JSON.SET
命令。
# HASH
HMSET product:4 id 4 name "Warm Socks" description "Cozy socks for winter" price 9.99 category "Clothing" tags "winter,cozy"
# JSON
JSON.SET product:5 $ '{"id": 5, "name": "Stylish Hat", "description": "A fashionable hat", "price": 19.99, "category": "Clothing", "tags": ["fashion", "hat"]}'
3. 更新索引:FT.DROPINDEX 和 FT.CREATE
如果你想修改索引结构,比如添加一个字段,你需要先删除旧的索引,然后重新创建。
FT.DROPINDEX product_idx
FT.CREATE product_idx ... (新的索引定义)
复杂查询:让搜索更精准
索引建好了,接下来就是查询。FT.SEARCH
命令是查询的核心。
FT.SEARCH {index_name} {query} [options ...]
{index_name}
: 索引的名字。{query}
: 查询语句,这是最复杂的部分。[options ...]
:一些可选的参数,比如排序、分页等。
查询语法:一门新的语言
RediSearch的查询语法自成一派,有点像SQL,但更简洁。
1. 简单文本搜索
FT.SEARCH product_idx "t-shirt"
这个命令会搜索 name
和 description
字段中包含 "t-shirt" 的商品。
2. 指定字段搜索
FT.SEARCH product_idx "@name:t-shirt"
只在 name
字段中搜索 "t-shirt"。
3. AND 和 OR
FT.SEARCH product_idx "t-shirt socks" # AND
FT.SEARCH product_idx "t-shirt | socks" # OR
t-shirt socks
: 搜索同时包含 "t-shirt" 和 "socks" 的商品(AND)。t-shirt | socks
: 搜索包含 "t-shirt" 或者 "socks" 的商品(OR)。
4. NOT
FT.SEARCH product_idx "t-shirt -socks"
搜索包含 "t-shirt" 但不包含 "socks" 的商品。
5. 短语搜索
FT.SEARCH product_idx ""super cool t-shirt""
搜索包含 "super cool t-shirt" 这个短语的商品。
6. 前缀搜索
FT.SEARCH product_idx "t-sh*"
搜索 name
和 description
字段中以 "t-sh" 开头的词。
7. 模糊搜索
FT.SEARCH product_idx "%t-sirt%"
允许一个拼写错误,搜索 name
和 description
字段中与 "t-shirt" 相似的词。
8. 数值范围搜索
FT.SEARCH product_idx "@price:[10 50]"
搜索价格在 10 到 50 之间的商品。
9. 标签搜索
FT.SEARCH product_idx "@category:{Clothing}"
搜索 category
字段为 "Clothing" 的商品。
FT.SEARCH product_idx "@tags:{fashion|summer}"
搜索 tags
字段包含 "fashion" 或者 "summer" 的商品。
10. 排序
FT.SEARCH product_idx "t-shirt" SORTBY price ASC
FT.SEARCH product_idx "t-shirt" SORTBY price DESC
根据价格升序或降序排序。
11. 分页
FT.SEARCH product_idx "t-shirt" LIMIT 0 10 # 从第0条开始,返回10条
FT.SEARCH product_idx "t-shirt" LIMIT 10 10 # 从第10条开始,返回10条
12. 返回指定字段
FT.SEARCH product_idx "t-shirt" RETURN 2 id name
只返回 id
和 name
字段。
13. 高级查询:FILTER 和 GEO
- FILTER: 在查询结果的基础上进行过滤。
- GEO: 用于地理位置搜索。
FILTER 示例
假设我们有一个 discount
字段,表示折扣力度(0-100)。
FT.SEARCH product_idx "t-shirt" FILTER discount > 50
搜索包含 "t-shirt" 且 discount
大于 50 的商品。(注意:discount
需要在SCHEMA中定义为NUMERIC NOINDEX)
GEO 示例
假设我们有一个 location
字段,存储经纬度(格式:longitude,latitude)。
FT.CREATE store_idx
ON HASH
PREFIX 1 store:
SCHEMA
name TEXT
location GEO
HMSET store:1 name "Store A" location "116.4074,39.9042"
HMSET store:2 name "Store B" location "114.4977,30.5166"
FT.SEARCH store_idx "* @location:[-122.4194,37.7749 10 km]"
搜索距离经纬度 (-122.4194,37.7749) 10公里以内的店铺。
代码示例:Python + Redis + RediSearch
import redis
# 连接 Redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 创建索引 (假设已经创建)
index_name = "product_idx"
# 查询
query = "t-shirt"
result = r.execute_command("FT.SEARCH", index_name, query)
# 处理结果
total_results = result[0]
print(f"Total results: {total_results}")
for i in range(1, len(result), 2):
doc_id = result[i]
fields = result[i+1]
product = {}
for j in range(0, len(fields), 2):
product[fields[j].decode()] = fields[j+1].decode()
print(f"Product ID: {doc_id.decode()}")
print(f"Product Name: {product['name']}")
print(f"Product Price: {product['price']}")
print("-" * 20)
性能优化:让搜索飞起来
- 选择合适的字段类型:
TAG
类型比TEXT
类型更快,如果只需要精确匹配,尽量用TAG
。 - 使用
WEIGHT
调整权重: 把重要的字段权重调高,让搜索结果更符合预期。 - *避免使用 `
查询**:
*` 查询会扫描所有数据,性能很差。 - 合理使用
FILTER
:FILTER
可以在查询结果的基础上进行过滤,但也会增加一些开销。 - 监控 Redis 和 RediSearch 的性能: 使用
INFO
命令可以查看 Redis 和 RediSearch 的性能指标。
一些小技巧
- 使用 RediSearch 的客户端库: 有很多 RediSearch 的客户端库,比如 Python 的
redisearch
,可以更方便地操作 RediSearch。 - 多看文档: RediSearch 的官方文档非常详细,遇到问题可以查阅文档。
- 实践出真知: 多写代码,多尝试不同的查询,才能真正掌握 RediSearch。
总结
RediSearch 确实是一个强大的工具,但要用好它,需要理解索引的构建、查询的语法和性能优化的技巧。希望今天的讲座能帮助你更好地使用 RediSearch,让你的搜索功能更上一层楼!
最后的彩蛋:常见问题解答
- RediSearch 会占用多少内存? 取决于你的数据量和索引的大小。
- RediSearch 支持中文吗? 支持,但需要进行一些配置,比如指定分词器。
- RediSearch 和 Elasticsearch 有什么区别? RediSearch 基于 Redis,速度更快,但功能相对简单。Elasticsearch 是一个独立的搜索引擎,功能更强大,但配置更复杂。
- 什么时候应该使用 RediSearch? 当你需要快速的全文搜索,并且已经在使用 Redis 时,RediSearch 是一个不错的选择。
好了,今天的讲座就到这里。 感谢大家的参与! 希望大家多多实践,早日成为 RediSearch 高手!