向量
了解如何使用矢量场并在 Redis 中执行矢量搜索
Redis 包含一个高性能矢量数据库,可让您对矢量嵌入执行语义搜索。您可以通过筛选文本、数字、地理空间和标签元数据来增强这些搜索。
要快速开始,请查看Redis 矢量快速入门指南和Redis AI 资源Github 仓库。
概述
- 创建向量索引:Redis 使用定义的架构(包括向量字段和元数据)维护数据的二级索引。Redis 支持
FLAT和HNSW向量索引类型。 - 存储和更新向量:Redis 将向量和元数据存储在哈希或 JSON 对象中。
- 使用向量搜索:Redis 支持使用向量字段的几种高级查询策略,包括 k 最近邻( KNN)、向量范围查询和元数据过滤器。
- 在运行时配置矢量查询。
- 向量搜索示例:探索涵盖不同用例和技术的几个向量搜索示例。
创建向量索引
当定义索引的模式时,您可以包含一个或多个矢量字段,如下所示。
句法
FT.CREATE <index_name>
ON <storage_type>
PREFIX 1 <key_prefix>
SCHEMA ... <field_name> VECTOR <algorithm> <index_attribute_count> <index_attribute_name> <index_attribute_value>
[<index_attribute_name> <index_attribute_value> ...]
有关其他字段、选项和注意的限制,请参阅完整的索引文档。
参数
| 范围 | 描述 |
|---|---|
index_name |
索引的名称。 |
storage_type |
存储选项(HASH或JSON)。 |
prefix(选修的) |
用于选择应索引哪些键的键前缀。如果省略,则默认为所有键。 |
field_name |
矢量字段的名称。 |
algorithm |
向量索引算法(FLAT或HNSW)。 |
index_attribute_count |
矢量场属性的数量。 |
index_attribute_name |
矢量场属性名称。 |
index_attribute_value |
矢量场属性值。 |
平坦指数
FLAT当您拥有小型数据集(<1M 个向量)或完美的搜索准确性比搜索延迟更重要时,请选择索引。
必需属性
| 属性 | 描述 |
|---|---|
TYPE |
向量类型(BFLOAT16,FLOAT16,FLOAT32,FLOAT64)。BFLOAT16并且FLOAT16需要 v2.10 或更高版本。 |
DIM |
此字段中存储的向量嵌入的宽度或维数。换句话说,组成向量的浮点元素的数量。DIM必须是正整数。用于查询此字段的向量必须具有与字段本身完全相同的维度。 |
DISTANCE_METRIC |
距离度量(L2,IP,COSINE)。 |
例子
FT.CREATE documents
ON HASH
PREFIX 1 docs:
SCHEMA doc_embedding VECTOR FLAT 6
TYPE FLOAT32
DIM 1536
DISTANCE_METRIC COSINE
在上面的例子中,一个名为的索引documents是通过键前缀docs:和一个FLAT名为的向量字段的哈希表创建的,该doc_embedding向量字段有三个索引属性:TYPE、DIM和DISTANCE_METRIC。
HNSW 指数
HNSW或分层可导航小世界,是一种近似最近邻算法,它使用多层图使向量搜索更具可扩展性。
- 最低层包含所有数据点,每个较高层包含一个子集,形成层次结构。
- 在运行时,搜索会从上到下遍历每一层的图形,找到局部最小值,然后再进入下一层。
HNSW当您拥有较大的数据集(> 1M 个文档)或搜索性能和可扩展性比完美的搜索准确性更重要时,请选择索引类型。
必需属性
| 属性 | 描述 |
|---|---|
TYPE |
向量类型(BFLOAT16,FLOAT16,FLOAT32,FLOAT64)。BFLOAT16并且FLOAT16需要 v2.10 或更高版本。 |
DIM |
此字段中存储的向量嵌入的宽度或维数。换句话说,组成向量的浮点元素的数量。DIM必须是正整数。用于查询此字段的向量必须具有与字段本身完全相同的维度。 |
DISTANCE_METRIC |
距离度量(L2,IP,COSINE)。 |
可选属性
HNSW支持许多附加参数来调整查询的准确性,同时牺牲性能。
| 属性 | 描述 |
|---|---|
M |
图层中每个节点的最大传出边(连接)数。在第零层,最大连接数为2 * M。值越高,准确度越高,但也会增加内存使用量和索引构建时间。默认值为 16。 |
EF_CONSTRUCTION |
图表构建期间要考虑的最大连接邻居数。值越高,准确度越高,但索引构建时间也越长。默认值为 200。 |
EF_RUNTIME |
KNN 搜索期间的最大最佳候选数。值越高,准确率越高,但搜索延迟也越高。默认值为 10。 |
EPSILON |
相对因子,用于设置范围查询可以搜索候选的边界。也就是说,距离查询向量为 的向量候选radius * (1 + EPSILON)可能会被扫描,从而允许更广泛的搜索和更准确的结果,但会以运行时间为代价。默认值为 0.01。 |
例子
FT.CREATE documents
ON HASH
PREFIX 1 docs:
SCHEMA doc_embedding VECTOR HNSW 10
TYPE FLOAT64
DIM 1536
DISTANCE_METRIC COSINE
M 40
EF_CONSTRUCTION 250
在上面的例子中,一个名为的索引documents是通过键前缀docs:和一个HNSW名为的向量字段的哈希表创建的,doc_embedding该向量字段有五个索引属性:TYPE、DIM、DISTANCE_METRIC、M和EF_CONSTRUCTION。
距离度量
Redis 支持三种流行的距离度量来衡量两个向量 $u$, $v$ $\in \mathbb{R}^n$ 之间的相似程度,其中 $n$ 是向量的长度:
| 距离度量 | 描述 | 数学表示 |
|---|---|---|
L2 |
两个向量之间的欧几里得距离。 | $d(u, v) = \sqrt{ \displaystyle\sum_{i=1}^n{(u_i - v_i)^2}}$ |
IP |
两个向量的内积。 | $d(u, v) = 1 -u\cdot v$ |
COSINE |
两个向量的余弦距离。 | $d(u, v) = 1 -\frac{u \cdot v}{\lVert u \rVert \lVert v \rVert}$ |
上述度量计算两个向量之间的距离,其中值越小,表示两个向量在向量空间中越接近。
存储和更新向量
在创建索引时,它<storage_type>规定了如何构造向量和元数据并将其加载到 Redis 中。
哈希
例子
HSET docs:01 doc_embedding <vector_bytes> category sports
<vector_bytes>表示向量的底层内存缓冲区。将向量转换为字节的常用方法是使用redis-py客户端库和 Python NumPy库。
例子
import numpy as np
from redis import Redis
redis_client = Redis(host='localhost', port=6379)
# Create a FLOAT32 vector
vector = np.array([0.34, 0.63, -0.54, -0.69, 0.98, 0.61], dtype=np.float32)
# Convert vector to bytes
vector_bytes = vector.tobytes()
# Use the Redis client to store the vector bytes and metadata at a specified key
redis_client.hset('docs:01', mapping = {"vector": vector_bytes, "category": "sports"})
JSON
您可以使用命令在JSON中存储或更新向量和任何相关元数据JSON.SET。
要将向量以 JSON 格式存储在 Redis 中,您需要将向量存储为浮点数的 JSON 数组。请注意,这与 Redis 哈希中的向量存储不同,后者以原始字节格式存储。
例子
JSON.SET docs:01 $ '{"doc_embedding":[0.34,0.63,-0.54,-0.69,0.98,0.61], "category": "sports"}'
JSON 的优点之一是模式灵活性。从 v2.6.1 开始,JSON 支持多值索引。这允许您在同一个JSONPath下索引多个向量。
以下是使用向量进行多值索引的一些示例:
多值索引示例
JSON.SET docs:01 $ '{"doc_embedding":[[1,2,3,4], [5,6,7,8]]}'
JSON.SET docs:01 $ '{"chunk1":{"doc_embedding":[1,2,3,4]}, "chunk2":{"doc_embedding":[5,6,7,8]}}'
索引 JSON 文档部分提供了更多信息和示例。
使用向量搜索
您可以使用FT.SEARCH或FT.AGGREGATE命令运行矢量搜索查询。
要使用 发出向量搜索查询FT.SEARCH,必须将选项设置DIALECT为 >= 2。有关更多信息,请参阅方言文档。
KNN向量搜索
KNN 向量搜索查找查询向量的前 k 个最近邻居。它的语法如下:
句法
FT.SEARCH <index_name>
<primary_filter_query>=>[KNN <top_k> @<vector_field> $<vector_blob_param> $<vector_query_params> AS <distance_field>]
PARAMS <query_params_count> [$<vector_blob_param> <vector_blob> <query_param_name> <query_param_value> ...]
SORTBY <distance_field>
DIALECT 4
参数
| 范围 | 描述 |
|---|---|
index_name |
索引的名称。 |
primary_filter_query |
过滤*条件。当不需要过滤器时使用。 |
top_k |
从索引中获取的最近邻居的数量。 |
vector_field |
要搜索的矢量字段的名称。 |
vector_blob_param |
查询向量,以原始字节 blob 形式传入。该 blob 的字节大小必须与向量字段的尺寸和类型匹配。 |
vector_query_params(选修的) |
可选部分,用于标记通过该PARAMS部分传递的一个或多个向量查询参数。有效参数应以键值对的形式提供。查看每个向量索引类型支持哪些运行时查询参数。 |
distance_field(选修的) |
响应和/或排序中使用的可选距离字段名称。默认情况下,距离字段名称为__<vector_field>_score,它可用于排序而不AS <distance_field>在查询中使用。 |
vector_query_params_count |
向量查询参数的数量。 |
vector_query_param_name |
向量查询参数的名称。 |
vector_query_param_value |
向量查询参数的值。 |
例子
FT.SEARCH documents "*=>[KNN 10 @doc_embedding $BLOB]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" DIALECT 4
使用查询属性
<vector_query_params>或者,从 v2.6 开始,可以在运行时查询属性<distance_field>中指定名称
,如下所示。
[KNN <top_k> @<vector_field> $<vector_blob_param>]=>{$yield_distance_as: <distance_field>}
向量范围查询
radius向量范围查询允许您使用表示输入查询向量与索引向量字段之间的语义距离的参数来过滤索引。这在您不知道top_k要获取多少个最近()邻居但知道结果应该有多相似的情况下非常有用。
例如,假设存在欺诈或异常检测场景,您不确定向量索引中是否有任何匹配项。您可以发出向量范围查询,以快速检查指定半径内的索引中是否有任何感兴趣的记录。
向量范围查询的操作与 KNN 向量查询略有不同:
- 向量范围查询可以在一个查询中多次出现,作为过滤条件。
<primary_filter_query>向量范围查询可以成为KNN向量搜索的一部分。
句法
FT.SEARCH <index_name>
@<vector_field>:[VECTOR_RANGE (<radius> | $<radius_param>) $<vector_blob_param> $<vector_query_params>]
PARAMS <vector_query_params_count> [<vector_query_param_name> <vector_query_param_value> ...]
SORTBY <distance_field>
DIALECT 4
| 范围 | 描述 |
|---|---|
index_name |
索引的名称。 |
vector_field |
索引中矢量字段的名称。 |
radius或者radius_param |
查询向量与索引向量之间允许的最大语义距离。您可以直接在查询中提供该值、将其传递给部分PARAMS或将其作为查询属性提供。 |
vector_blob_param |
查询向量,以原始字节 blob 形式传入。该 blob 的字节大小必须与向量字段的尺寸和类型匹配。 |
vector_query_params(选修的) |
可选部分,用于标记通过该PARAMS部分传递的一个或多个向量查询参数。有效参数应以键值对的形式提供。查看每个向量索引类型支持哪些运行时查询参数。 |
vector_query_params_count |
向量查询参数的数量。 |
vector_query_param_name |
向量查询参数的名称。 |
vector_query_param_value |
向量查询参数的值。 |
使用查询属性
向量范围查询子句后面可以跟查询属性部分,如下所示:
@<vector_field>: [VECTOR_RANGE (<radius> | $<radius_param>) $<vector_blob_param>]=>{$<param>: (<value> |
$<value_attribute>); ... }
在这种情况下,相关参数是$yield_distance_as和$epsilon。请注意,范围查询中没有默认的距离字段名称。
筛选器
Redis 支持包含筛选器的向量搜索,可根据定义的条件缩小搜索空间。如果您的索引包含可搜索字段(例如,TEXT、TAG、NUMERIC、GEO和),则可以使用筛选器执行向量搜索。GEOSHAPEVECTOR
支持的过滤器类型
您还可以将多个查询组合为一个过滤器。
句法
带有过滤器的矢量搜索查询遵循以下基本结构:
FT.SEARCH <index_name> <primary_filter_query>=>[...]
其中<primary_filter_query>定义文档选择和过滤。
例子
FT.SEARCH documents "(@title:Sports @year:[2020 2022])=>[KNN 10 @doc_embedding $BLOB]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" DIALECT 4
过滤的工作原理
Redis 使用内部算法来优化向量搜索的过滤计算。运行时算法由启发式算法确定,旨在根据从查询和索引中得出的几个因素最大限度地减少查询延迟。
批次模式
批处理模式通过对索引中的最近邻居的小批量进行分页来工作:
- 从向量索引中检索出一批高分文档,只有
<primary_filter_query>满足条件才会生成这些文档,也就是说文档必须包含相似的向量,并且满足过滤条件。 <top_k>当产生符合过滤条件的文档时,或者索引中的每个向量都已被处理后,迭代过程终止。- 批量大小是根据索引中通过的文档预期数量与向量索引大小
<top_k>之间的比率,通过启发式方法自动确定的。<primary_filter_query> - 目标是尽量减少获得结果所需的批次总数
<top_k>,同时尽可能保持最小的批次大小。请注意,批次大小可能会根据之前批次中通过筛选的结果数量在每次迭代中动态变化。
临时暴力破解模式
- 计算通过过滤器的文档对应的每个向量的分数,并
<top_k>选择并返回结果。 - 当传递的文档数量
<primary_filter_query>相对较少时,这种方法是更好的选择。 - 在这种模式下,KNN查询的结果总是准确的,即使底层向量索引算法是近似的。
根据从一个批次到另一个批次的相关因素的更新估计,执行模式可能会在运行期间从批处理模式切换到临时暴力破解模式。
运行时查询参数
过滤模式
默认情况下,Redis 会选择最佳过滤模式来优化查询执行。您可以使用以下可选参数覆盖自动选择的策略:
| 范围 | 描述 | 选项 |
|---|---|---|
HYBRID_POLICY |
指定在使用过滤器进行矢量搜索时使用的过滤模式(混合)。 | BATCHES或者ADHOC_BF |
BATCH_SIZE |
BATCHES当自动选择或请求策略时,每次迭代中使用的固定批量大小。 |
正整数。 |
特定于索引的查询参数
平坦的
目前,没有可用于 FLAT 索引的运行时参数。
亨廷顿新南威尔士州
HNSW 索引的可选运行时参数包括:
| 范围 | 描述 | 默认值 |
|---|---|---|
EF_RUNTIME |
KNN 搜索期间保留的顶级候选者的最大数量。值越高,结果越准确,但查询运行时间越长。 | 索引创建期间传递的值。默认值为 10。 |
EPSILON |
为向量范围查询设置边界的相对因子。与查询向量距离为 的向量候选radius * (1 + EPSILON)可能会被扫描,从而允许进行更广泛的搜索并获得更准确的结果,但会延长运行时间。 |
索引创建时传递的值。默认值为 0.01。 |
重要说明
-
执行 KNN 向量搜索时,您可以指定
<top_k>最近邻居。但是,默认的 Redis 查询LIMIT参数(用于分页)是 10。为了获取<top_k>返回的结果,您还必须LIMIT 0 <top_k>在搜索命令中指定。请参阅下面的示例。 -
默认情况下,结果按其文档的分数排序。要按向量相似度分数排序,请使用
SORTBY <distance_field>。请参阅下面的示例。 -
根据您选择的距离度量,索引中向量之间的计算距离具有不同的界限。例如,
Cosine距离受 限制2,而距离不受限制。执行向量范围查询时,最佳做法是根据您的用例和所需的召回率或精度指标L2调整参数。<radius>
矢量搜索示例
以下是一些帮助您入门的示例。有关更全面的演练,请参阅Redis 矢量快速入门指南和Redis AI 资源Github 存储库。
KNN 向量搜索示例
doc_embedding返回向量字段与以下 4 字节 blob 表示的查询向量最接近的10 个最近邻文档:
FT.SEARCH documents "*=>[KNN 10 @doc_embedding $BLOB]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" SORTBY __vector_score DIALECT 4
返回前 10 个最近邻居,并使用查询参数自定义K和参数。请参阅FT.SEARCH 命令EF_RUNTIME中的“可选参数”部分。将值设置为 150,假设是索引:EF_RUNTIMEdoc_embeddingHNSW
FT.SEARCH documents "*=>[KNN $K @doc_embedding $BLOB EF_RUNTIME $EF]" PARAMS 6 BLOB "\x12\xa9\xf5\x6c" K 10 EF 150 DIALECT 4
为距离字段分配一个自定义名称(vector_distance),然后使用该名称进行排序:
FT.SEARCH documents "*=>[KNN 10 @doc_embedding $BLOB AS vector_distance]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" SORTBY vector_distance DIALECT 4
使用查询属性语法指定可选参数和距离字段名称:
FT.SEARCH documents "*=>[KNN 10 @doc_embedding $BLOB]=>{$EF_RUNTIME: $EF; $YIELD_DISTANCE_AS: vector_distance}" PARAMS 4 EF 150 BLOB "\x12\xa9\xf5\x6c" SORTBY vector_distance DIALECT 4
要探索更多 Python 向量搜索示例,请查看Redis Python客户端库和的配方Redis Vector Library。
筛选器示例
对于这些示例,假设您创建了一个名为“movies不同电影及其元数据的记录”的索引。
'Dune'在 领域内title且year之间的 的电影中[2020, 2022],返回前 10 个最近邻居,按 排序movie_distance:
FT.SEARCH movies "(@title:Dune @year:[2020 2022])=>[KNN 10 @movie_embedding $BLOB AS movie_distance]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" SORTBY movie_distance DIALECT 4
action在 有类别标签 但没有 的电影中drama,返回前 10 个最近邻居,按 排序movie_distance:
FT.SEARCH movies "(@category:{action} ~@category:{drama})=>[KNN 10 @doc_embedding $BLOB AS movie_distance]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" SORTBY movie_distance DIALECT 4
drama在具有或作为类别标签的电影中action,返回前 10 个最近的邻居,并明确将过滤模式(混合策略)设置为“临时强力”而不是自动选择:
FT.SEARCH movies "(@category:{drama | action})=>[KNN 10 @doc_embedding $BLOB HYBRID_POLICY ADHOC_BF]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" SORTBY __vec_scores DIALECT 4
action在具有类别标签的电影中,返回前 10 个最近的邻居,并使用查询参数将过滤模式(混合策略)明确设置为“批次”和批次大小 50:
FT.SEARCH movies "(@category:{action})=>[KNN 10 @doc_embedding $BLOB HYBRID_POLICY BATCHES BATCH_SIZE $BATCH_SIZE]" PARAMS 4 BLOB "\x12\xa9\xf5\x6c" BATCH_SIZE 50 DIALECT 4
运行与上述相同的查询并使用查询属性语法指定可选参数:
FT.SEARCH movies "(@category:{action})=>[KNN 10 @doc_embedding $BLOB]=>{$HYBRID_POLICY: BATCHES; $BATCH_SIZE: 50}" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" DIALECT 4
要探索更多 Python 向量搜索示例,请查看Redis Python客户端库和的配方Redis Vector Library。
范围查询示例
对于这些示例,假设您创建了一个products以来自电子商务网站的不同产品和元数据的记录命名的索引。
返回 100 个产品,其中字段和指定查询向量 blob 之间的距离description_vector最多为 5:
FT.SEARCH products "@description_vector:[VECTOR_RANGE 5 $BLOB]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" LIMIT 0 100 DIALECT 4
运行与上述相同的查询并将参数设置EPSILON为0.5,假设是 HNSW 索引,在名为的字段中description_vector产生和查询结果之间的向量距离,并按该距离对结果进行排序。description_vectorvector_distance
FT.SEARCH products "@description_vector:[VECTOR_RANGE 5 $BLOB]=>{$EPSILON:0.5; $YIELD_DISTANCE_AS: vector_distance}" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" SORTBY vector_distance LIMIT 0 100 DIALECT 4
'shirt'使用向量范围查询作为过滤器:返回所有包含其type标签中的文档,其year值在范围内[2020, 2022],或存储在description_vector与查询向量的距离不超过的向量0.8,然后根据它们的向量距离对结果进行排序(如果在范围内):
FT.SEARCH products "(@type:{shirt} @year:[2020 2022]) | @description_vector:[VECTOR_RANGE 0.8 $BLOB]=>{$YIELD_DISTANCE_AS: vector_distance}" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" SORTBY vector_distance DIALECT 4
要探索更多 Python 向量搜索示例,请查看Redis Python客户端库和的配方Redis Vector Library。
后续步骤Next steps
向量嵌入和向量搜索并不是新概念。十多年来,许多大型公司都使用向量来表示电子商务目录中的产品或广告渠道中的内容。
随着大型语言模型 (LLM) 的出现和需要高级信息检索技术的应用程序的激增,Redis 非常适合用作语义搜索等的高性能查询引擎。
以下是一些针对不同用例应用向量搜索的附加资源: