在 Python 开发中,操作 Redis 数据库是很多场景下的刚需,而 redis-py 作为 Redis 官方推荐的 Python 客户端,更是我们绕不开的工具。但你是否在安装时踩过版本兼容的坑?是否在连接集群或配置 TLS 时犯过难?甚至想尝试向量索引却不知从何下手?今天我们就从基础到进阶,手把手带你玩转 redis-py,让 Python 操作 Redis 变得简单又高效。
首先,我们需要安装 redis-py。最基础的安装命令很简单,一行代码即可:
python
pip install redis
不过这里有几个小细节需要注意:
python
运行
pip install redis[hiredis]
安装完成后,我们先来看看如何连接 Redis。无论是本地测试还是生产环境,连接方式的选择都很关键。
最基础的连接方式是连接本地的 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 返回的响应直接转为字符串,省去手动解码的麻烦,日常开发中非常实用。
实际开发中,我们可能会遇到集群、TLS 加密、客户端缓存等复杂场景,下面逐一讲解:
如果你的 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'(注意:集群模式默认返回字节,需手动解码或设置参数)
生产环境中,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'))
客户端缓存能减少客户端与服务器的网络交互,提升性能。启用它需要注意两点:必须使用 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()
:清空所有缓存频繁创建和关闭连接会消耗资源,连接池能帮我们高效管理连接:
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()
Redis 不仅能存键值对,还能通过查询引擎对 JSON 和哈希文档建立索引、执行复杂查询。我们分两种文档类型来讲解。
JSON 文档支持嵌套结构,适合存储复杂数据。我们以用户数据为例,演示从创建索引到查询的全流程:
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
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类型索引
)
)
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)
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) # 输出匹配用户的城市信息
哈希文档结构更扁平,适合存储简单数据,操作上与 JSON 略有不同:
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
)
)
python
# 用hset添加哈希数据(键名带huser:前缀)
r.hset("huser:1", mapping=user1)
r.hset("huser:2", mapping=user2)
r.hset("huser:3", mapping=user3)
python
# 与JSON查询语法相同,只需指定哈希索引名
query = Query("Paul @age:[30 40]")
result = r.ft("hash-idx:users").search(query)
print(result) # 输出:huser:3
Redis 不仅能处理常规数据,还能索引向量嵌入,实现语义相似性查询。我们以文本嵌入为例,演示如何用 redis-py 实现向量索引与查询。
需要用到 sentence-transformers 库生成文本嵌入,先安装:
bash
pip install sentence-transformers
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
)
)
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")
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”,符合语义相似性预期。
JSON 文档存储向量与哈希类似,但有两点差异:向量用列表存储,且索引需指定 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
)
)
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")
查询语法与哈希完全相同,只需指定 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 的核心用法,无论是日常开发还是进阶场景,应该都能帮到你。
如果本文对你有帮助,别忘了点赞收藏,关注我,一起探索更高效的开发方式~