Redis模块扩展:JSON、搜索与时间序列

Redis模块扩展:JSON、搜索与时间序列

【免费下载链接】redis-py 【免费下载链接】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类来封装所有搜索相关的操作:

mermaid

索引创建与字段定义

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 【免费下载链接】redis-py 项目地址: https://gitcode.com/gh_mirrors/red/redis-py

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值