入门
RedisVL 入门
RedisVL 是一个功能强大的 Python 库,带有集成的 CLI,旨在增强使用 Redis 实现的 AI 应用程序。本指南将引导您完成以下步骤
- 定义一个
IndexSchema
。 - 准备一个示例数据集。
- 创建一个
SearchIndex
对象。 - 测试
rvl
CLI 功能。 - 加载示例数据。
- 构建
VectorQuery
对象并执行搜索。 - 更新
SearchIndex
对象。
在开始之前,请确保以下内容
- 您已安装 RedisVL 并且已激活该环境。
- 您有一个具有搜索和查询功能的正在运行的 Redis 实例。
定义一个 IndexSchema
IndexSchema
保持重要的索引配置和字段定义,以启用 Redis 的搜索功能。为了方便使用,可以使用 Python 字典或 YAML 文件来构建该模式。
示例模式创建
假设有一个包含用户信息的数据集,包括job
、age
、credit_score
和一个三维的 user_embedding
向量。
您需要决定使用哪个 Redis 索引名称和键前缀来存储此数据集。以下是 YAML 和 Python dict
格式的示例模式定义。
YAML 定义
version: '0.1.0'
index:
name: user_simple
prefix: user_simple_docs
fields:
- name: user
type: tag
- name: credit_store
type: tag
- name: job
type: text
- name: age
type: numeric
- name: user_embedding
type: vector
attrs:
algorithm: flat
dims: 3
distance_metric: cosine
datatype: float32
将此信息存储在本地文件中,例如 schema.yaml
,以便与 RedisVL 一起使用。
Python 字典
schema = {
"index": {
"name": "user_simple",
"prefix": "user_simple_docs",
},
"fields": [
{"name": "user", "type": "tag"},
{"name": "credit_score", "type": "tag"},
{"name": "job", "type": "text"},
{"name": "age", "type": "numeric"},
{
"name": "user_embedding",
"type": "vector",
"attrs": {
"dims": 3,
"distance_metric": "cosine",
"algorithm": "flat",
"datatype": "float32"
}
}
]
}
示例数据集准备
下面,创建一个包含 user
、job
、age
、credit_score
和 user_embedding
字段的模拟数据集。user_embedding
向量是用于演示目的的合成示例。
有关创建真实世界嵌入的更多信息,请参考此 文章。
import numpy as np
data = [
{
'user': 'john',
'age': 1,
'job': 'engineer',
'credit_score': 'high',
'user_embedding': np.array([0.1, 0.1, 0.5], dtype=np.float32).tobytes()
},
{
'user': 'mary',
'age': 2,
'job': 'doctor',
'credit_score': 'low',
'user_embedding': np.array([0.1, 0.1, 0.5], dtype=np.float32).tobytes()
},
{
'user': 'joe',
'age': 3,
'job': 'dentist',
'credit_score': 'medium',
'user_embedding': np.array([0.9, 0.9, 0.1], dtype=np.float32).tobytes()
}
]
如上所示,示例 user_embedding
向量使用 NumPy
Python 包转换为字节。
创建 SearchIndex
准备好模式和示例数据集后,创建一个 SearchIndex
from redisvl.index import SearchIndex
index = SearchIndex.from_dict(schema)
# or use .from_yaml('schema_file.yaml')
现在,我们还需要创建一个 Redis 连接。有几种方法可以做到这一点
- 创建并管理您自己的客户端连接(推荐)。
- 提供一个简单的 Redis URL,并让 RedisVL 代表您连接。
使用您自己的 Redis 连接实例
这在您在连接实例上具有自定义设置的情况下,或者您的应用程序将共享连接池的情况下非常理想。
from redis import Redis
client = Redis.from_url("redis://localhost:6379")
index.set_client(client)
# optionally provide an async Redis client object to enable async index operations
让索引管理连接实例
这在简单情况下非常理想。
index.connect("redis://localhost:6379")
# optionally use an async client by passing use_async=True
创建底层索引
现在,已连接到 Redis,运行创建命令。
index.create(overwrite=True)
注意:此时,索引没有关联数据。数据加载将在之后进行。
使用 rvl
命令检查
使用 rvl
CLI 命令检查新创建的索引及其字段。
$ rvl index listall
18:25:34 [RedisVL] INFO Indices:
18:25:34 [RedisVL] INFO 1. user_simple
$ rvl index info -i user_simple
╭──────────────┬────────────────┬──────────────────────┬─────────────────┬────────────╮
│ Index Name │ Storage Type │ Prefixes │ Index Options │ Indexing │
├──────────────┼────────────────┼──────────────────────┼─────────────────┼────────────┤
│ user_simple │ HASH │ ['user_simple_docs'] │ [] │ 0 │
╰──────────────┴────────────────┴──────────────────────┴─────────────────┴────────────╯
Index Fields:
╭────────────────┬────────────────┬─────────┬────────────────┬────────────────╮
│ Name │ Attribute │ Type │ Field Option │ Option Value │
├────────────────┼────────────────┼─────────┼────────────────┼────────────────┤
│ user │ user │ TAG │ SEPARATOR │ , │
│ credit_score │ credit_score │ TAG │ SEPARATOR │ , │
│ job │ job │ TEXT │ WEIGHT │ 1 │
│ age │ age │ NUMERIC │ │ │
│ user_embedding │ user_embedding │ VECTOR │ │ │
╰────────────────┴────────────────┴─────────┴────────────────┴────────────────╯
将数据加载到 SearchIndex
将示例数据集加载到 Redis 中。
keys = index.load(data)
print(keys)
['user:31d4f3c73f1a4c26b41cf0e2b8e0248a',
'user:c9ff740437064b919245e49ef585484d',
'user:6db5f2e09f08438785b73d8048d5350b']
默认情况下,load
将创建一个唯一的 Redis 键,该键是索引键 prefix
和 UUID 的组合。您也可以通过提供直接键或在加载时指向指定的 id_field
来自定义键。
使用新数据更新索引
使用 load
方法更新数据。
# Add more data
new_data = [{
'user': 'tyler',
'age': 9,
'job': 'engineer',
'credit_score': 'high',
'user_embedding': np.array([0.1, 0.3, 0.5], dtype=np.float32).tobytes()
}]
keys = index.load(new_data)
print(keys)
['user_simple_docs:ea6e8f2f93d5447c950ccb6843627761']
创建 VectorQuery
对象
接下来,为新填充的索引创建一个向量查询对象。本示例将使用一个简单的向量来演示向量搜索的工作原理。生产环境中的向量可能远大于三个浮点数,并且通常需要机器学习模型(例如,Huggingface 句子转换器)或嵌入 API(例如,Cohere 和 OpenAI)。RedisVL 提供了一组向量化器来帮助创建向量。
from redisvl.query import VectorQuery
from jupyterutils import result_print
query = VectorQuery(
vector=[0.1, 0.1, 0.5],
vector_field_name="user_embedding",
return_fields=["user", "age", "job", "credit_score", "vector_distance"],
num_results=3
)
执行查询
定义好 VectorQuery
对象后,就可以使用 query
方法在 SearchIndex
上执行查询了。
results = index.query(query)
result_print(results)
vector_distance | user | age | job | credit_score |
---|---|---|---|---|
0 | john | 1 | engineer | high |
0 | mary | 2 | doctor | low |
0.0566299557686 | tyler | 9 | engineer | high |
使用异步 Redis 客户端
AsyncSearchIndex
类以及异步 Redis Python 客户端提供异步查询、索引创建和数据加载功能。这是在生产环境中使用 redisvl
的推荐方法。
from redisvl.index import AsyncSearchIndex
from redis.asyncio import Redis
client = Redis.from_url("redis://localhost:6379")
index = AsyncSearchIndex.from_dict(schema)
index.set_client(client)
# execute the vector query async
results = await index.aquery(query)
result_print(results)
vector_distance | user | age | job | credit_score |
---|---|---|---|---|
0 | john | 1 | engineer | high |
0 | mary | 2 | doctor | low |
0.0566299557686 | tyler | 9 | engineer | high |
更新模式
在某些情况下,更新索引模式是有意义的。使用 Redis 和 RedisVL,这很容易实现,因为 Redis 可以将底层数据保留在原位,同时您可以更新索引配置。
假设您想以以下方式重新索引数据
- 对
job
字段使用Tag
类型,而不是Text
。 - 对
user_embedding
字段使用HNSW
向量索引,而不是flat
向量索引。
# Modify this schema to have what we want
index.schema.remove_field("job")
index.schema.remove_field("user_embedding")
index.schema.add_fields([
{"name": "job", "type": "tag"},
{
"name": "user_embedding",
"type": "vector",
"attrs": {
"dims": 3,
"distance_metric": "cosine",
"algorithm": "flat",
"datatype": "float32"
}
}
])
# Run the index update but keep underlying data in place
await index.create(overwrite=True, drop=False)
# Execute the vector query
results = await index.aquery(query)
result_print(results)
vector_distance | user | age | job | credit_score |
---|---|---|---|---|
0 | john | 1 | engineer | high |
0 | mary | 2 | doctor | low |
0.0566299557686 | tyler | 9 | engineer | high |
检查索引统计信息
使用 rvl
检查索引的统计信息。
$ rvl stats -i user_simple
Statistics:
╭─────────────────────────────┬─────────────╮
│ Stat Key │ Value │
├─────────────────────────────┼─────────────┤
│ num_docs │ 4 │
│ num_terms │ 0 │
│ max_doc_id │ 4 │
│ num_records │ 20 │
│ percent_indexed │ 1 │
│ hash_indexing_failures │ 0 │
│ number_of_uses │ 2 │
│ bytes_per_record_avg │ 1 │
│ doc_table_size_mb │ 0.00044632 │
│ inverted_sz_mb │ 1.90735e-05 │
│ key_table_size_mb │ 0.000165939 │
│ offset_bits_per_record_avg │ nan │
│ offset_vectors_sz_mb │ 0 │
│ offsets_per_term_avg │ 0 │
│ records_per_doc_avg │ 5 │
│ sortable_values_size_mb │ 0 │
│ total_indexing_time │ 0.246 │
│ total_inverted_index_blocks │ 11 │
│ vector_index_sz_mb │ 0.0201416 │
╰─────────────────────────────┴─────────────╯
清理
# clean up the index
await index.adelete()