View a markdown version of this page

创建和搜索向量索引 - Amazon DynamoDB

创建和搜索向量索引

本节介绍如何创建和管理向量索引、写入带有向量数据的项目以及使用 SearchVectors API 执行相似性搜索。

开始前的准备工作

在使用向量索引之前,请验证以下事项:

  • 您的表使用按需容量模式 (PAY_PER_REQUEST)。预调配容量表不支持向量索引。

  • 您的 AWS Identity and Access Management(IAM)身份拥有 dynamodb:CreateTabledynamodb:UpdateTable 权限来创建向量索引。

  • 您的 IAM 身份拥有向量索引资源的 dynamodb:SearchVectors 权限,可以执行搜索。资源 ARN 的格式为 arn:aws:dynamodb:region:account-id:table/table-name/index/index-name

SearchVectors 端点

SearchVectors 请求使用专用的向量搜索端点,这些端点不同于您用来创建和管理向量索引的标准 DynamoDB 端点(例如,使用 CreateTableUpdateTableDescribeTable)。AWS SDK 和 AWS CLI 自动将 SearchVectors 请求路由到正确的端点。您无需在应用程序代码中配置或覆盖端点。

如果您正在构建一个直接调用 DynamoDB API 的自定义 HTTP 客户端,且不使用 AWS SDK,请使用以下向量搜索端点之一,并根据实际情况替换 account-idregion

  • account-id.search-ddb.region.amazonaws.com:基于账户的端点。

  • search-dynamodb.region.api.aws:双堆栈端点,同时兼容 IPv4 和 IPv6。

生成向量嵌入

DynamoDB 存储和搜索向量嵌入,但不会生成它们。您可以使用 Amazon Bedrock Titan Text Embeddings 模型或 Cohere Embed 模型等嵌入模型生成嵌入,也可以通过您使用的任何嵌入模型生成嵌入。然后将生成的向量存储在 DynamoDB 项目中,并将查询向量传递给 SearchVectors

查询向量和存储的向量必须使用相同的模型

传递给 SearchVectors 的查询向量和存储在项目中的向量必须由相同的嵌入模型生成,并且维度数量必须与向量索引相同。混合使用模型,或者使用不同于索引创建时的维度数量进行查询,会产生毫无意义的结果或验证错误。

典型的流程是:

  1. 将您的源内容(例如商品描述)发送到嵌入模型并接收向量。

  2. 将该向量存储在 DynamoDB 项目的按照向量索引命名的属性 (VectorAttribute) 中,以数字 (N) 列表 (L) 的格式存储。

  3. 在查询时,使用相同的模型从搜索文本生成一个向量,然后将其作为 SearchVector 传递。

在创建索引之前选择嵌入模型

在您创建向量索引之前选择嵌入模型,因为模型决定了维度数量。常见的嵌入模型生成 384、768、1024、1536 或 3072 个维度。DynamoDB 最多支持 4096 个维度。请参阅要求和限制

您选择的距离函数与模型生成嵌入的方式相互作用。COSINE 比较方向并忽略模长,因此无论嵌入是否标准化,它都可以处理嵌入。DOT_PRODUCT 区分模长:如果您的嵌入没有标准化为单位长度,那么无论方向如何,较大的向量始终会获得更高的分数。如果您使用 DOT_PRODUCT 并想要基于方向的相似性,请在存储嵌入之前将其标准化为单位长度。请参阅距离函数如何排名结果

创建向量索引

您可以在创建新表时创建向量索引,也可以向现有表添加向量索引。

创建带有向量索引的表

使用 CreateTable API 和 VectorIndexes 参数来创建带有向量索引的表。以下 AWS CLI 示例创建一个 Products 表并带有名为 ProductEmbeddingIndex 的向量索引。

aws dynamodb create-table \ --table-name Products \ --attribute-definitions AttributeName=ProductId,AttributeType=S \ AttributeName=Category,AttributeType=S \ AttributeName=Brand,AttributeType=S \ --key-schema AttributeName=ProductId,KeyType=HASH \ --billing-mode PAY_PER_REQUEST \ --vector-indexes \ "[ { \"IndexName\": \"ProductEmbeddingIndex\", \"VectorAttribute\": {\"AttributeName\": \"Embedding\"}, \"SearchSchema\": [{\"AttributeName\":\"Category\",\"SearchSchemaElementType\":\"HASH\"}, {\"AttributeName\":\"Brand\",\"SearchSchemaElementType\":\"INLINE_FILTER\"}], \"Projection\": {\"ProjectionType\": \"ALL\"}, \"Dimensions\": 1536, \"DistanceFunction\": \"COSINE\" } ]"

在本示例中:

  • VectorAttribute 指定 Embedding 作为包含向量数据的属性。

  • SearchSchemaCategory 定义为向量索引分区键 (HASH),用于按类别对索引进行分区以实现扩展。它还将 Brand 定义为 INLINE_FILTER,让您可以在存储层按品牌筛选搜索结果。由于 SearchSchema 中同时引用了 CategoryBrand,因此也必须在 AttributeDefinitions 中声明它们,其方法与为全局二级索引声明键属性相同。

  • Dimensions 设置为 1536,与常见嵌入模型的输出相匹配。

  • DistanceFunction 设置为 COSINE,分数越低表示相似性越高。

将向量索引添加到现有表

使用 UpdateTable API 和 VectorIndexUpdates 参数向现有表添加向量索引。此示例将名为 ProductEmbeddingIndexV2 的第二个独立索引添加到同一个 Products 表中。

aws dynamodb update-table \ --table-name Products \ --vector-index-updates \ "[ { \"Create\": { \"IndexName\": \"ProductEmbeddingIndexV2\", \"VectorAttribute\": {\"AttributeName\": \"Embedding\"}, \"Projection\": {\"ProjectionType\": \"ALL\"}, \"Dimensions\": 1536, \"DistanceFunction\": \"EUCLIDEAN\" } } ]"

向现有表添加向量索引时,DynamoDB 会在 DescribeTable 响应中通过两个字段报告索引进度:IndexStatus 值和单独的 Backfilling 布尔值。

  1. IndexStatusCREATING:DynamoDB 正在设置索引基础设施。

  2. IndexStatusACTIVEBackfilling 设置为 true:DynamoDB 正在使用基表中的现有数据填充索引。在此阶段,对基表的新写入也会被复制到索引中。在向量索引回填期间,SearchVectors 会返回错误。请等待直至 Backfillingfalse 之后再进行搜索。

  3. IndexStatusACTIVEBackfilling 设置为 false(或不存在):索引已完全填充,可以进行搜索操作。

您无法在索引回填时进行搜索

在向量索引回填期间,SearchVectors 会返回错误。使用 DescribeTable 检查 IndexStatusBackfilling 标志,等待直至 IndexStatusACTIVEBackfillingfalse 之后再进行搜索。没有 BACKFILLING 索引状态值。

写入带有向量数据的项目

您可以使用标准 DynamoDB 写入 API(PutItemUpdateItemBatchWriteItemTransactWriteItems),写入带有向量数据的项目。将向量嵌入存储为数字列表(包含 N 元素的 L 类型)。

由于向量包含许多值,因此请将项目保存到文件中(例如 item.json),然后将文件传递给 AWS CLI。

{ "ProductId": { "S": "prod-123" }, "Category": { "S": "Electronics" }, "Title": { "S": "Wireless Headphones" }, "Embedding": { "L": [ { "N": "0.1234" }, { "N": "-0.5678" }, { "N": "0.9012" }, ... ] } }
aws dynamodb put-item \ --table-name Products \ --item file://item.json
向量长度必须与索引维度相匹配

此处显示的 Embedding 向量有缩略。在 item.json 中,它必须包含 1536 个值,以便与您在 ProductEmbeddingIndex 上设置的 Dimensions 相匹配。写入具有错误维度数量的向量会被拒绝。

当您将项目写入具有向量索引的表时,DynamoDB 会验证向量数据。下表描述了验证行为。

条件 行为
向量属性的维度数量不正确 拒绝写入。
缺少向量索引分区键属性 在基表上写入成功,但项目不复制到向量索引。
向量索引分区键属性类型与索引架构不匹配 拒绝写入。
缺少内联筛选条件属性 写入成功,但项目不复制到向量索引。
向量值的精度高于 32 位浮点数(f32) 写入成功。值按原样存储在基表中,但在复制到向量索引时会丢失精度。
向量属性已从项目中删除 向量索引中的对应条目被删除。
缺少分区键会导致静默地取消索引

如果您的向量索引在 SearchSchema 中定义了分区键,而您写入的项目不包含该属性(或使用 UpdateItem 将其移除),则该项目虽能成功写入基表,但会被静默排除在向量索引之外。即使基表项目及其向量嵌入仍然存在,项目也不会出现在 SearchVectors 结果中。对于每个要使其可供搜索的项目,确保都包含向量索引分区键属性。

旧嵌入会产生错误的结果

DynamoDB 不会为您重新计算嵌入。如果您更改用于生成嵌入的源内容(例如,编辑商品说明),存储的向量不会自动更新。您必须使用嵌入模型重新生成嵌入,然后将新向量写回项目。否则,向量索引将继续根据旧的过时向量返回结果,这可能会隐蔽地产生不正确的匹配项。

使用 SearchVectors 进行搜索

使用 SearchVectors API,在向量索引中寻找与查询向量最相似的项目。结果按相关性进行排序,最相似的项目排在最前面。搜索结果具有最终一致性:从写入或更新向量到它出现在搜索结果中,可能会有短暂的延迟。有关更多信息,请参阅 持续进行的写入同步

基本搜索

以下示例在 ProductEmbeddingIndex 索引中搜索最相似的 10 个项目。由于此索引在其 SearchSchema 中定义了向量索引分区键 (Category),因此 SearchConditionExpression 必须包含向量索引分区键值。

将查询向量作为由数值构成的普通 JSON 数组保存到文件中(例如 query-vector.json)。

[ { "N": "0.1234" }, { "N": "-0.5678" }, { "N": "0.9012" }, ... ]
aws dynamodb search-vectors \ --table-name Products \ --index-name ProductEmbeddingIndex \ --search-vector file://query-vector.json \ --top-k 10 \ --search-condition-expression "Category = :cat" \ --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}}"

响应包含一个 SearchResults 数组。每个元素都包含匹配的 Item 和一个 Score,表示项目与查询向量的相似程度。

{ "SearchResults": [ { "Item": { "ProductId": { "S": "prod-456" }, "Category": { "S": "Electronics" }, "Title": { "S": "Bluetooth Speaker" } }, "Score": 0.0023 }, { "Item": { "ProductId": { "S": "prod-789" }, "Category": { "S": "Electronics" }, "Title": { "S": "Noise Cancelling Earbuds" } }, "Score": 0.0145 } ] }
默认情况下,结果中不包括向量属性

默认情况下,来自 SearchVectors 的结果不包括向量属性(嵌入)。向量数据很大,您通常不希望在响应中包含它。结果包括其他投影属性和 Score 值。要包括向量属性,请使用 ProjectionExpression 发出请求。有关更多信息,请参阅 使用 ProjectionExpression

SearchVector 是一个普通列表,而不是 DynamoDB L 类型

SearchVector 请求参数是一个由数字对象 ([{"N": "0.1234"}, ...]) 组成的普通 JSON 数组。请不要像在项目属性中存储向量时那样将其封装为 DynamoDB L 类型。仅当在项目属性中写入或读取向量时,才使用 L 包装器。

Score 的含义取决于您在创建索引时选择的距离函数。对于 COSINEEUCLIDEAN,分数越低表示相似度越高。对于 DOT_PRODUCT,分数越高表示相似度越高。

使用 SearchConditionExpression 进行筛选

使用 SearchConditionExpression,根据 SearchSchema 中定义的向量索引分区键和内联筛选条件属性来筛选搜索结果。此表达式使用与其他 DynamoDB 表达式参数相同的语法。

以下示例使用 Brand 内联筛选条件,搜索 Electronics 类别(向量索引分区键)中的项目。

aws dynamodb search-vectors \ --table-name Products \ --index-name ProductEmbeddingIndex \ --search-vector file://query-vector.json \ --top-k 10 \ --search-condition-expression "Category = :cat AND Brand = :brand" \ --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}, \":brand\": {\"S\": \"Acme\"}}"

如果您的向量索引在 SearchSchema 中定义了分区键,则必须将其包含在 SearchConditionExpression 中。内联筛选条件属性是可选的。

支持在 SearchConditionExpression 中对向量索引分区键和内联筛选条件属性使用相等运算符 (=)。比较、范围和集合成员资格运算符(<><<=>>=IN)目前不可用。

通过此筛选,您可以将相似性搜索范围限定为数据的子集,这是多租户和检索增强生成(RAG)应用程序中的常见要求。例如,要仅在一个租户内寻找与查询相似的文档,请在 SearchSchema 中将租户属性定义为向量索引分区键 (HASH),并在每次搜索中传递其值。这会将结果隔离到该租户。这还可以提高性能,因为搜索仅检查相关数据。在路由到的分区中,要想应用额外的等式约束(例如文档类型或状态),请使用内联筛选条件属性。

分区键的范围限定并不是安全边界

使用分区键将搜索范围限定为单个租户是数据局部性和性能优化手段,而不是访问控制机制。任何拥有索引 dynamodb:SearchVectors 权限的主体都可以搜索任意分区键值。由于细粒度访问控制(FGAC)条件键(例如 dynamodb:LeadingKeys)不适用于 SearchVectors,因此您无法在 IAM 策略级别将访问权限限制为单个分区键值。如果您的工作负载需要在数据层进行严格的租户隔离,请使用单独的表或索引,并向每个租户提供不同的 IAM 授权。

使用 ProjectionExpression

使用 ProjectionExpression 可仅在搜索结果中返回特定属性。当您不需要所有投影的属性时,这可以减小响应大小。由于 ProductEmbeddingIndex 在其 SearchSchema 中定义了向量索引分区键 (Category),因而在此示例中,SearchConditionExpression 仍包含向量索引分区键值。

aws dynamodb search-vectors \ --table-name Products \ --index-name ProductEmbeddingIndex \ --search-vector file://query-vector.json \ --top-k 5 \ --search-condition-expression "Category = :cat" \ --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}}" \ --projection-expression "ProductId, Title"
只返回投影的属性

您只能返回投影到向量索引中的属性。SearchVectors 无法返回不在索引投影中的属性。

删除向量索引

使用 UpdateTable API 和 VectorIndexUpdates 参数来删除向量索引。

aws dynamodb update-table \ --table-name Products \ --vector-index-updates \ "[ {\"Delete\": {\"IndexName\": \"ProductEmbeddingIndex\"}} ]"

删除向量索引时,DynamoDB 会移除索引及其所有数据。此操作不影响基表或其项目。