Redis模块扩展:JSON、搜索与时间序列
【免费下载链接】redis-py 项目地址: https://gitcode.com/gh_mirrors/red/redis-py
本文详细介绍了Redis的三大核心模块扩展:RedisJSON、RediSearch和RedisTimeSeries。RedisJSON模块允许在Redis中直接存储、操作和查询JSON文档,支持丰富的JSONPath语法和数据类型操作。RediSearch提供全文搜索功能,支持复杂的查询语法和聚合分析。RedisTimeSeries专门处理时间序列数据,提供高效的数据采集、存储和查询能力。文章通过大量Python代码示例展示了各模块的实际应用和最佳实践。
RedisJSON模块操作与数据序列化
RedisJSON是Redis的一个强大模块,它允许在Redis中直接存储、操作和查询JSON文档。redis-py库提供了完整的RedisJSON支持,使得Python开发者能够轻松地在应用程序中使用JSON数据。
JSON数据的基本操作
RedisJSON提供了丰富的命令来操作JSON数据结构,包括字符串、数字、数组和对象等基本类型。
设置和获取JSON数据
最基本的操作是设置和获取JSON数据:
import redis
from redis.commands.json.path import Path
# 连接到Redis
r = redis.Redis(decode_responses=True)
# 设置简单的JSON字符串
r.json().set("user:1", Path.root_path(), "John Doe")
result = r.json().get("user:1")
print(result) # 输出: "John Doe"
# 设置复杂的JSON对象
user_data = {
"name": "Alice Smith",
"age": 30,
"email": "alice@example.com",
"address": {
"street": "123 Main St",
"city": "New York",
"zipcode": "10001"
},
"hobbies": ["reading", "traveling", "photography"]
}
r.json().set("user:2", Path.root_path(), user_data)
user_result = r.json().get("user:2")
print(user_result)
路径操作和嵌套访问
RedisJSON支持JSONPath语法,可以精确访问嵌套数据结构:
# 访问嵌套字段
name = r.json().get("user:2", "$.name")
age = r.json().get("user:2", "$.age")
city = r.json().get("user:2", "$.address.city")
first_hobby = r.json().get("user:2", "$.hobbies[0]")
print(f"Name: {name}, Age: {age}, City: {city}, First Hobby: {first_hobby}")
# 使用通配符访问数组元素
all_hobbies = r.json().get("user:2", "$.hobbies[*]")
print(f"All hobbies: {all_hobbies}")
数据类型操作
RedisJSON支持对不同类型的JSON值进行专门的操作。
字符串操作
# 设置字符串值
r.json().set("message", Path.root_path(), "Hello")
print(r.json().strlen("message")) # 输出: 5
# 字符串追加
r.json().strappend("message", " World!")
print(r.json().get("message")) # 输出: "Hello World!"
print(r.json().strlen("message")) # 输出: 12
数字操作
# 设置数字值
r.json().set("counter", Path.root_path(), 100)
# 数字递增
r.json().numincrby("counter", Path.root_path(), 50)
print(r.json().get("counter")) # 输出: 150
# 浮点数操作
r.json().numincrby("counter", Path.root_path(), 25.5)
print(r.json().get("counter")) # 输出: 175.5
数组操作
RedisJSON提供了丰富的数组操作方法:
# 创建数组
r.json().set("tasks", Path.root_path(), ["task1", "task2"])
# 数组追加
r.json().arrappend("tasks", Path.root_path(), "task3", "task4")
print(r.json().get("tasks")) # 输出: ["task1", "task2", "task3", "task4"]
# 数组长度
print(r.json().arrlen("tasks")) # 输出: 4
# 数组插入
r.json().arrinsert("tasks", Path.root_path(), 1, "new_task")
print(r.json().get("tasks")) # 输出: ["task1", "new_task", "task2", "task3", "task4"]
# 数组弹出
popped = r.json().arrpop("tasks", Path.root_path())
print(f"Popped: {popped}, Remaining: {r.json().get('tasks')}")
# 数组修剪
r.json().arrtrim("tasks", Path.root_path(), 0, 2)
print(r.json().get("tasks")) # 输出: ["task1", "new_task", "task2"]
对象操作
# 创建对象
product = {
"id": "P001",
"name": "Laptop",
"price": 999.99,
"specs": {
"cpu": "Intel i7",
"ram": "16GB",
"storage": "512GB SSD"
}
}
r.json().set("product:1", Path.root_path(), product)
# 获取对象键
keys = r.json().objkeys("product:1", Path.root_path())
print(f"Object keys: {keys}") # 输出: ["id", "name", "price", "specs"]
# 获取对象长度
length = r.json().objlen("product:1", Path.root_path())
print(f"Object length: {length}") # 输出: 4
高级查询和过滤
RedisJSON支持强大的JSONPath查询功能,可以进行复杂的数据过滤:
# 创建示例数据
users = [
{
"id": 1,
"name": "Alice",
"age": 28,
"department": "Engineering",
"skills": ["Python", "JavaScript", "SQL"]
},
{
"id": 2,
"name": "Bob",
"age": 32,
"department": "Marketing",
"skills": ["SEO", "Content Writing", "Analytics"]
},
{
"id": 3,
"name": "Charlie",
"age": 25,
"department": "Engineering",
"skills": ["Java", "Docker", "Kubernetes"]
}
]
for i, user in enumerate(users, 1):
r.json().set(f"employee:{i}", Path.root_path(), user)
# 条件查询
engineering_employees = r.json().get("employee:1", "$..[?(@.department == 'Engineering')]")
print(f"Engineering employees: {engineering_employees}")
# 范围查询
young_employees = r.json().get("employee:1", "$..[?(@.age < 30)]")
print(f"Employees under 30: {young_employees}")
# 数组包含查询
python_developers = r.json().get("employee:1", "$..[?('Python' in @.skills)]")
print(f"Python developers: {python_developers}")
数据序列化和编码
redis-py提供了灵活的序列化选项,支持自定义编码器和解码器:
import json
from datetime import datetime
# 自定义JSON编码器处理特殊类型
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
# 自定义JSON解码器
class CustomJSONDecoder(json.JSONDecoder):
def __init__(self, *args, **kwargs):
super().__init__(object_hook=self.object_hook, *args, **kwargs)
def object_hook(self, dct):
# 可以在这里添加自定义的反序列化逻辑
return dct
# 使用自定义编码器
r_custom = redis.Redis(decode_responses=True)
json_client = r_custom.json(encoder=CustomJSONEncoder(), decoder=CustomJSONDecoder())
# 存储包含日期时间的数据
event = {
"name": "Product Launch",
"date": datetime(2024, 6, 15, 14, 30),
"attendees": ["Alice", "Bob", "Charlie"]
}
json_client.set("event:1", Path.root_path(), event)
retrieved = json_client.get("event:1")
print(f"Retrieved event: {retrieved}")
批量操作和管道
RedisJSON支持批量操作和管道,提高操作效率:
# 批量设置多个JSON文档
documents = [
("doc:1", Path.root_path(), {"title": "First Document", "content": "Content 1"}),
("doc:2", Path.root_path(), {"title": "Second Document", "content": "Content 2"}),
("doc:3", Path.root_path(), {"title": "Third Document", "content": "Content 3"})
]
# 使用MSET进行批量设置
r.json().mset(documents)
# 使用MGET进行批量获取
results = r.json().mget(["doc:1", "doc:2", "doc:3"], Path.root_path())
print(f"Batch results: {results}")
# 使用管道执行多个JSON操作
pipe = r.json().pipeline()
pipe.set("counter:a", Path.root_path(), 10)
pipe.set("counter:b", Path.root_path(), 20)
pipe.numincrby("counter:a", Path.root_path(), 5)
pipe.numincrby("counter:b", Path.root_path(), 8)
pipe_results = pipe.execute()
print(f"Pipeline results: {pipe_results}")
错误处理和最佳实践
在使用RedisJSON时,需要注意错误处理和最佳实践:
try:
# 尝试访问不存在的键
result = r.json().get("nonexistent:key")
print(f"Result for nonexistent key: {result}") # 输出: None
# 尝试操作错误的数据类型
r.json().set("number", Path.root_path(), 42)
r.json().strappend("number", "text") # 这会抛出异常
except Exception as e:
print(f"Error occurred: {e}")
# 使用存在性修饰符
r.json().set("config:app", Path.root_path(), {"version": "1.0"})
# 只在键不存在时设置(NX选项)
result_nx = r.json().set("config:app", Path("$.debug"), True, nx=True)
print(f"NX set result: {result_nx}") # 输出: None(因为键已存在)
# 只在键存在时设置(XX选项)
result_xx = r.json().set("config:app", Path("$.debug"), True, xx=True)
print(f"XX set result: {result_xx}") # 输出: OK
性能优化技巧
# 1. 使用合适的路径表达式避免全文档扫描
# 不好的做法:扫描整个文档
all_data = r.json().get("large:document")
# 好的做法:只获取需要的部分
specific_data = r.json().get("large:document", "$.specific.field")
# 2. 使用管道批量操作
pipe = r.json().pipeline()
for i in range(100):
pipe.set(f"item:{i}", Path.root_path(), {"value": i})
pipe.execute()
# 3. 合理使用索引(结合RediSearch)
# 创建索引加速查询
schema = (
TextField("$.name", as_name="name"),
NumericField("$.age", as_name="age"),
TagField("$.department", as_name="department")
)
r.ft().create_index(schema, definition=IndexDefinition(prefix=["employee:"], index_type=IndexType.JSON))
RedisJSON模块为Redis提供了强大的JSON文档存储和操作能力,结合redis-py的Python接口,开发者可以轻松地在应用程序中处理复杂的JSON数据结构。通过合理的路径操作、批量处理和错误处理机制,可以构建高效可靠的JSON数据存储解决方案。
RediSearch全文搜索功能集成
Redis-py通过强大的RediSearch模块提供了完整的全文搜索功能集成,让开发者能够在Redis中构建高性能的搜索引擎。RediSearch不仅支持基本的文本搜索,还提供了复杂的查询语法、聚合分析、拼写检查和自动补全等高级功能。
核心架构与设计模式
RediSearch在redis-py中的实现采用了模块化的设计模式,通过专门的Search类来封装所有搜索相关的操作:
索引创建与字段定义
RediSearch支持多种字段类型,每种类型都有特定的索引和搜索特性:
| 字段类型 | 描述 | 适用场景 |
|---|---|---|
| TextField | 全文文本字段,支持分词和词干提取 | 文章内容、产品描述 |
| NumericField | 数值字段,支持范围查询和排序 | 价格、年龄、评分 |
| TagField | 标签字段,支持精确匹配和分类 | 分类标签、状态标识 |
| GeoField | 地理坐标字段,支持地理位置查询 | 地理位置、附近搜索 |
| VectorField | 向量字段,支持相似性搜索 | 图像搜索、推荐系统 |
创建索引示例:
from redis import Redis
from redis.commands.search.field import TextField, NumericField, TagField
from redis.commands.search.indexDefinition import IndexDefinition
# 连接到Redis
r = Redis(host='localhost', port=6379, db=0)
# 定义索引字段
fields = [
TextField("title", weight=5.0), # 标题字段,权重更高
TextField("content"), # 内容字段
NumericField("price"), # 价格字段
NumericField("rating"), # 评分字段
TagField("category"), # 分类标签
TagField("tags", separator="|") # 多标签字段,使用|分隔
]
# 创建索引定义
definition = IndexDefinition(prefix=["doc:"]) # 只索引以doc:开头的键
# 创建搜索索引
search_client = r.ft("products") # 创建名为products的搜索客户端
search_client.create_index(fields, definition=definition)
文档操作与批量处理
RediSearch提供了灵活的文档添加和更新机制,支持批量处理以提高性能:
# 添加单个文档
search_client.add_document(
"doc:1",
title="Redis in Action",
content="Comprehensive guide to Redis",
price=49.99,
rating=4.8,
category="books",
tags="redis|database|programming"
)
# 使用批量索引器进行高效批量添加
batch_indexer = search_client.batch_indexer(chunk_size=1000)
for i in range(100):
batch_indexer.add_document(
f"doc:{i+2}",
title=f"Product {i+2}",
content=f"Description of product {i+2}",
price=10.0 + i,
rating=4.0 + (i % 5) * 0.2,
category="electronics",
tags=f"tech|gadget|item{i}"
)
# 手动提交剩余文档
batch_indexer.commit()
高级查询功能
RediSearch支持丰富的查询语法和查询构建器模式:
from redis.commands.search.query import Query
from redis.commands.search.aggregation import AggregateRequest
# 基本文本搜索
results = search_client.search("redis database")
# 使用Query构建器创建复杂查询
query = Query("redis database")\
.limit_fields("title", "content")\ # 只在指定字段搜索
.return_fields("title", "price", "rating")\ # 返回指定字段
.sort_by("rating", asc=False)\ # 按评分降序
.paging(0, 10)\ # 分页
.highlight("title", tags=["<b>", "</b>"]) # 高亮显示
results = search_client.search(query)
# 聚合查询示例
agg_request = AggregateRequest("*")\
.group_by(["category"], reducers=["count"])\
.sort_by("@category")\
.apply(price_range="@price > 50 ? 'premium' : 'standard'")
agg_results = search_client.aggregate(agg_request)
查询语法与运算符
RediSearch支持强大的查询语法,包括布尔运算符、范围查询和地理查询:
| 查询类型 | 语法示例 | 描述 |
|---|---|---|
| 基本搜索 | hello world | 搜索包含hello或world的文档 |
| 精确短语 | "hello world" | 搜索完整短语"hello world" |
| 必选词 | +must +include | 必须包含must和include |
| 排除词 | hello -world | 包含hello但不包含world |
| 前缀搜索 | hel* | 搜索以hel开头的词 |
| 模糊搜索 | %hello% | 模糊匹配hello |
| 范围查询 | price:[50 100] | 价格在50到100之间 |
| 标签查询 | @category:{electronics} | 分类为 |
【免费下载链接】redis-py 项目地址: https://gitcode.com/gh_mirrors/red/redis-py
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



