Redis-py 实战指南:从安装到向量索引,Python 操作 Redis 全解析

在 Python 开发中,操作 Redis 数据库是很多场景下的刚需,而 redis-py 作为 Redis 官方推荐的 Python 客户端,更是我们绕不开的工具。但你是否在安装时踩过版本兼容的坑?是否在连接集群或配置 TLS 时犯过难?甚至想尝试向量索引却不知从何下手?今天我们就从基础到进阶,手把手带你玩转 redis-py,让 Python 操作 Redis 变得简单又高效。

一、redis-py 安装:避坑指南

首先,我们需要安装 redis-py。最基础的安装命令很简单,一行代码即可:

python

pip install redis

不过这里有几个小细节需要注意:

  • 性能优化:如果想让 redis-py 的响应解析更快,可以安装带 hiredis 支持的版本,它会使用编译后的解析器,大部分情况下无需修改代码:

    python

    运行

    pip install redis[hiredis]
    
  • 版本兼容:Python 3.12 及以上版本已经去掉了 distutils 打包方案,如果你在这个环境下安装 redis-py 遇到问题,记得更新到最新版本的 redis-py,通常能解决大部分兼容问题。

二、连接 Redis:从基础到进阶

安装完成后,我们先来看看如何连接 Redis。无论是本地测试还是生产环境,连接方式的选择都很关键。

2.1 基础连接:快速上手

最基础的连接方式是连接本地的 Redis 服务(默认端口 6379),我们可以用下面的代码测试连接是否成功:

python

import redis

# 连接到本地Redis,设置decode_responses=True以直接获取字符串(默认返回字节)
r = redis.Redis(host='localhost', port=6379, decode_responses=True)

# 测试:设置并获取一个字符串
r.set('foo', 'bar')
print(r.get('foo'))  # 输出:bar

# 测试:操作字典(哈希类型)
r.hset('user-session:123', mapping={
    'name': 'John',
    'surname': 'Smith',
    'company': 'Redis',
    'age': 29
})
print(r.hgetall('user-session:123'))  # 输出包含所有字段的字典

这里有个小技巧:decode_responses=True能让 Redis 返回的响应直接转为字符串,省去手动解码的麻烦,日常开发中非常实用。

2.2 进阶连接:应对复杂场景

实际开发中,我们可能会遇到集群、TLS 加密、客户端缓存等复杂场景,下面逐一讲解:

2.2.1 连接 Redis 集群

如果你的 Redis 是集群模式,需要用RedisCluster类来连接:

python

from redis.cluster import RedisCluster

# 连接集群(默认端口16379)
rc = RedisCluster(host='localhost', port=16379)

# 测试操作
rc.set('foo', 'bar')
print(rc.get('foo'))  # 输出:b'bar'(注意:集群模式默认返回字节,需手动解码或设置参数)
2.2.2 生产环境必看:TLS 加密连接

生产环境中,Redis 连接的安全性至关重要,这时我们需要配置 TLS 加密:

python

import redis

r = redis.Redis(
    host="my-redis.cloud.redislabs.com",  # 你的Redis服务地址
    port=6379,
    username="default",  # Redis用户名
    password="your_password",  # 你的密码
    ssl=True,  # 启用TLS
    ssl_certfile="./redis_user.crt",  # 证书文件
    ssl_keyfile="./redis_user_private.key",  # 私钥文件
    ssl_ca_certs="./redis_ca.pem"  # CA证书
)

# 测试连接
r.set('foo', 'bar')
print(r.get('foo'))
2.2.3 性能优化:客户端缓存

客户端缓存能减少客户端与服务器的网络交互,提升性能。启用它需要注意两点:必须使用 RESP3 协议(protocol=3),且需要传入 cache_config 参数:

python

import redis
from redis.cache import CacheConfig

# 启用客户端缓存(需redis-py v5.1.0+和Redis v7.4+)
r = redis.Redis(
    host='localhost',
    port=6379,
    protocol=3,  # 必须使用RESP3协议
    cache_config=CacheConfig(),  # 启用缓存
    decode_responses=True
)

# 测试缓存效果
r.set("city", "New York")
city1 = r.get("city")  # 从服务器获取,同时缓存
city2 = r.get("city")  # 直接从缓存获取

如果需要清理缓存,可以用这两个方法:

  • cache.delete_by_redis_keys(["key1", "key2"]):删除指定键的缓存
  • cache.flush():清空所有缓存
2.2.4 连接池:生产环境的最佳实践

频繁创建和关闭连接会消耗资源,连接池能帮我们高效管理连接:

python

import redis

# 创建连接池
pool = redis.ConnectionPool().from_url("redis://localhost")

# 从池子里获取连接
r1 = redis.Redis().from_pool(pool)
r2 = redis.Redis().from_pool(pool)

# 执行操作
r1.set("wind:1", "Hurricane")
r2.set("wind:2", "Tornado")

# 关闭连接(实际是放回池子里)
r1.close()
r2.close()
# 最后关闭连接池
pool.close()

二、索引与查询:JSON 和哈希文档操作

Redis 不仅能存键值对,还能通过查询引擎对 JSON 和哈希文档建立索引、执行复杂查询。我们分两种文档类型来讲解。

2.1 JSON 文档:灵活建模与查询

JSON 文档支持嵌套结构,适合存储复杂数据。我们以用户数据为例,演示从创建索引到查询的全流程:

步骤 1:初始化与依赖导入

python

import redis
from redis.commands.json.path import Path  # JSON路径专用
from redis.commands.search.field import TextField, NumericField, TagField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
步骤 2:创建 JSON 索引

python

# 连接Redis
r = redis.Redis(decode_responses=True)

# 定义索引结构(只索引前缀为"user:"的JSON文档)
schema = (
    TextField("$.name", as_name="name"),  # 索引name字段,别名为name
    TagField("$.city", as_name="city"),   # 索引city字段(标签类型)
    NumericField("$.age", as_name="age")  # 索引age字段(数值类型)
)

# 创建索引
r.ft("idx:users").create_index(
    schema,
    definition=IndexDefinition(
        prefix=["user:"],  # 只索引user:前缀的键
        index_type=IndexType.JSON  # 指定为JSON类型索引
    )
)
步骤 3:添加 JSON 数据

python

# 准备数据
user1 = {"name": "Paul John", "email": "[email protected]", "age": 42, "city": "London"}
user2 = {"name": "Eden Zamir", "email": "[email protected]", "age": 29, "city": "Tel Aviv"}
user3 = {"name": "Paul Zamir", "email": "[email protected]", "age": 35, "city": "Tel Aviv"}

# 添加数据(键名需带user:前缀,才会被索引)
r.json().set("user:1", Path.root_path(), user1)
r.json().set("user:2", Path.root_path(), user2)
r.json().set("user:3", Path.root_path(), user3)
步骤 4:执行查询

python

# 查询:name包含"Paul"且age在30-40之间的用户
query = Query("Paul @age:[30 40]")
result = r.ft("idx:users").search(query)
print(result)  # 输出:只包含user:3(Paul Zamir,35岁)

# 进阶:只返回city字段
query = Query("Paul").return_field("$.city", as_field="city")
cities = r.ft("idx:users").search(query).docs
print(cities)  # 输出匹配用户的城市信息

2.2 哈希文档:轻量存储与查询

哈希文档结构更扁平,适合存储简单数据,操作上与 JSON 略有不同:

步骤 1:创建哈希索引

python

# 定义哈希索引结构(无需别名,直接用字段名)
hash_schema = (
    TextField("name"),
    TagField("city"),
    NumericField("age")
)

# 创建索引(指定为哈希类型,前缀为"huser:")
r.ft("hash-idx:users").create_index(
    hash_schema,
    definition=IndexDefinition(
        prefix=["huser:"],
        index_type=IndexType.HASH
    )
)
步骤 2:添加哈希数据

python

# 用hset添加哈希数据(键名带huser:前缀)
r.hset("huser:1", mapping=user1)
r.hset("huser:2", mapping=user2)
r.hset("huser:3", mapping=user3)
步骤 3:查询哈希文档

python

# 与JSON查询语法相同,只需指定哈希索引名
query = Query("Paul @age:[30 40]")
result = r.ft("hash-idx:users").search(query)
print(result)  # 输出:huser:3

三、高级应用:向量索引与语义查询

Redis 不仅能处理常规数据,还能索引向量嵌入,实现语义相似性查询。我们以文本嵌入为例,演示如何用 redis-py 实现向量索引与查询。

3.1 准备工作:安装依赖

需要用到 sentence-transformers 库生成文本嵌入,先安装:

bash

pip install sentence-transformers

3.2 哈希文档中的向量索引

步骤 1:创建向量索引

python

import numpy as np
from sentence_transformers import SentenceTransformer

# 加载模型(生成384维向量)
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

# 连接Redis并清理旧索引
r = redis.Redis(decode_responses=True)
try:
    r.ft("vector_idx").dropindex(True)
except redis.exceptions.ResponseError:
    pass  # 忽略索引不存在的错误

# 定义向量索引结构(哈希类型)
schema = (
    TextField("content"),  # 文本内容
    TagField("genre"),     # 类别标签
    VectorField("embedding", "HNSW", {  # 向量字段
        "TYPE": "FLOAT32",    # 向量类型
        "DIM": 384,           # 维度(与模型匹配)
        "DISTANCE_METRIC": "L2"  # 距离度量(L2欧氏距离)
    })
)

# 创建索引(只索引doc:前缀的哈希文档)
r.ft("vector_idx").create_index(
    schema,
    definition=IndexDefinition(
        prefix=["doc:"],
        index_type=IndexType.HASH
    )
)
步骤 2:添加向量数据

python

# 生成文本嵌入并存储
def add_doc(doc_id, content, genre):
    # 生成向量并转为float32二进制
    embedding = model.encode(content).astype(np.float32).tobytes()
    r.hset(f"doc:{doc_id}", mapping={
        "content": content,
        "genre": genre,
        "embedding": embedding
    })

# 添加示例数据
add_doc(0, "That is a very happy person", "persons")
add_doc(1, "That is a happy dog", "pets")
add_doc(2, "Today is a sunny day", "weather")
步骤 3:向量相似性查询

python

# 生成查询向量
query_text = "That is a happy person"
query_vec = model.encode(query_text).astype(np.float32).tobytes()

# 执行KNN查询(返回最相似的3个结果)
query = Query("*=>[KNN 3 @embedding $vec AS vector_distance]").dialect(2)
result = r.ft("vector_idx").search(
    query,
    query_params={"vec": query_vec}
)

# 输出结果(按相似度排序,距离越小越相似)
for doc in result.docs:
    print(f"内容:{doc.content},距离:{doc.vector_distance}")

输出会显示:“That is a very happy person”(距离最近)、“That is a happy dog”、“Today is a sunny day”,符合语义相似性预期。

3.3 JSON 文档中的向量索引

JSON 文档存储向量与哈希类似,但有两点差异:向量用列表存储,且索引需指定 JSON 路径。

步骤 1:创建 JSON 向量索引

python

# 定义JSON向量索引(指定向量路径和别名)
schema = (
    TextField("$.content", as_name="content"),
    TagField("$.genre", as_name="genre"),
    VectorField(
        "$.embedding", "HNSW", {
            "TYPE": "FLOAT32",
            "DIM": 384,
            "DISTANCE_METRIC": "L2"
        },
        as_name="embedding"
    )
)

# 创建索引(jdoc:前缀,JSON类型)
r.ft("vector_json_idx").create_index(
    schema,
    definition=IndexDefinition(
        prefix=["jdoc:"],
        index_type=IndexType.JSON
    )
)
步骤 2:添加 JSON 向量数据

python

# JSON中向量用列表存储(而非二进制)
def add_json_doc(doc_id, content, genre):
    embedding = model.encode(content).astype(np.float32).tolist()  # 转为列表
    r.json().set(f"jdoc:{doc_id}", Path.root_path(), {
        "content": content,
        "genre": genre,
        "embedding": embedding
    })

# 添加数据
add_json_doc(0, "That is a very happy person", "persons")
add_json_doc(1, "That is a happy dog", "pets")
add_json_doc(2, "Today is a sunny day", "weather")
步骤 3:查询 JSON 向量文档

查询语法与哈希完全相同,只需指定 JSON 索引名:

python

# 与哈希查询代码相同,索引名改为vector_json_idx
query = Query("*=>[KNN 3 @embedding $vec AS vector_distance]").dialect(2)
result = r.ft("vector_json_idx").search(
    query,
    query_params={"vec": query_vec}  # 注意:查询向量仍用二进制
)

总结

今天我们从 redis-py 的安装开始,逐步讲解了基础连接、集群与 TLS 安全连接、客户端缓存优化,再到 JSON / 哈希文档的索引查询,最后实战了向量索引与语义查询。这些内容基本覆盖了 redis-py 的核心用法,无论是日常开发还是进阶场景,应该都能帮到你。

如果本文对你有帮助,别忘了点赞收藏,关注我,一起探索更高效的开发方式~

你可能感兴趣的:(数据库与知识图谱,redis,python,数据库,人工智能)