你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
Azure Cosmos DB for MongoDB vCore 中的矢量存储
适用对象: MongoDB vCore
使用 Azure Cosmos DB for MongoDB vCore 中的集成矢量数据库将基于 AI 的应用程序与 Azure Cosmos DB 中存储的数据无缝连接。 此集成可以包括使用 Azure OpenAI 嵌入生成的应用。 通过原生集成的矢量数据库,你可以高效地存储、查询直接存储在 Azure Cosmos DB for MongoDB vCore 中的高维矢量数据以及创建矢量数据时所基于的原始数据,并为其编制索引。 它使你无需将数据传输到其他矢量存储,也不会产生额外费用。
什么是矢量存储?
矢量存储或矢量数据库是旨在存储和管理矢量嵌入的数据库,矢量嵌入是高维空间中数据的数学表示形式。 在此空间中,每个维度对应于数据的一个特征,数万个维度可用于表示复杂的数据。 矢量在此空间中的位置表示其特征。 字词、短语或整个文档、图像、音频和其他类型的数据都可以矢量化。
矢量存储的工作原理是什么?
在矢量存储中,矢量搜索算法用于查询嵌入项以及为其编制索引。 一些已知的矢量搜索算法包括分层导航小型世界 (HNSW)、倒置文件(IVF)、DiskANN 等。借助矢量搜索,可根据数据特征而不是属性字段上的精确匹配项来查找相似的项。 这种方法在搜索相似文本、查找相关图像、提出建议甚至是检测异常等应用中很有用。 它用于查询数据的矢量嵌入(数字列表),这些数据是你通过嵌入 API 使用机器学习模型创建的。 嵌入 API 的示例有 Azure OpenAI 嵌入或 Azure 上的 Hugging Face。 矢量搜索测量数据矢量与查询矢量之间的距离。 最接近查询矢量的数据矢量是在语义上最相似的数据矢量。
在 Azure Cosmos DB for MongoDB vCore 中的集成矢量数据库中,可以存储、查询嵌入项和原始数据并为其编制索引。 此方法避免了在单独的纯矢量数据库中复制数据产生的额外成本。 此外,此体系结构可将矢量嵌入和原始数据保存在一起,从而更好地促进多模式数据操作,并且可以实现更高的数据一致性、缩放和性能。
创建矢量索引
若要对文档中的矢量属性执行矢量相似性搜索,必须首先创建矢量索引。
使用 HNSW 创建矢量索引
可以在 M40 群集层和更高层上创建(分层导航小世界)索引。 若要创建 HSNW 索引,需要创建一个矢量索引,并将 "kind"
参数设置为 "vector-hnsw"
,如以下模板所示:
{
"createIndexes": "<collection_name>",
"indexes": [
{
"name": "<index_name>",
"key": {
"<path_to_property>": "cosmosSearch"
},
"cosmosSearchOptions": {
"kind": "vector-hnsw",
"m": <integer_value>,
"efConstruction": <integer_value>,
"similarity": "<string_value>",
"dimensions": <integer_value>
}
}
]
}
字段 | 类型 | 说明 |
---|---|---|
index_name |
string | 索引的唯一名称。 |
path_to_property |
string | 包含矢量的属性的路径。 此路径可以是顶级属性或属性的点表示法路径。 如果使用点表示法路径,则所有非叶元素都不能是数组。 矢量必须是要编制索引并在矢量搜索结果中返回的 number[] 。 |
kind |
string | 要创建的矢量索引的类型。 选项为 vector-ivf 和 vector-hnsw 。 注意,vector-ivf 在所有群集层上都可用,vector-hnsw 可在 M40 群集层及更高层上使用。 |
m |
integer | 每层的最大连接数(默认为 16 ,最小值为 2 ,最大值为 100 )。 较大的 m 值适用于对于高维性和/或高准确度要求较高的数据集。 |
efConstruction |
integer | 用于构造图形的动态候选列表的大小(默认值为 64 ,最小值为 4 ,最大值为 1000 )。 efConstruction 越大,索引质量和准确性也就越高,但生成索引所需的时间也会增加。 efConstruction 必须至少为 2 * m |
similarity |
string | 用于索引的相似性指标。 可能的选项包括 COS (余弦距离)、L2 (欧几里德距离)和 IP (内积)。 |
dimensions |
整型 | 矢量相似度的维度数。 支持的最大维度数是 2000 。 |
使用 HNSW 执行矢量搜索
要执行矢量搜索,请将 $search
聚合管道(用于暂存查询)与 cosmosSearch
运算符一起使用。
{
"$search": {
"cosmosSearch": {
"vector": <query_vector>,
"path": "<path_to_property>",
"k": <num_results_to_return>,
"efSearch": <integer_value>
},
}
}
}
字段 | 类型 | 说明 |
---|---|---|
efSearch |
integer | 搜索的动态候选列表的大小(默认为 40 )。 值越大,召回率越佳,但会牺牲速度。 |
k |
integer | 要返回的结果数量。 它应小于或等于 efSearch |
注意
使用大型数据集创建 HSNW 索引可能会导致 Azure Cosmos DB for MongoDB vCore 资源内存不足,或者会限制数据库上运行的其他操作的性能。 如果遇到此类问题,可以通过将资源缩放到更高的群集层或减小数据集的大小来缓解它们。
使用 IVF 创建矢量索引
若要使用 IVF(反向文件)算法创建矢量索引,请使用以下 createIndexes
模板并将 "kind"
参数设置为 "vector-ivf"
:
{
"createIndexes": "<collection_name>",
"indexes": [
{
"name": "<index_name>",
"key": {
"<path_to_property>": "cosmosSearch"
},
"cosmosSearchOptions": {
"kind": "vector-ivf",
"numLists": <integer_value>,
"similarity": "<string_value>",
"dimensions": <integer_value>
}
}
]
}
字段 | 类型 | 说明 |
---|---|---|
index_name |
string | 索引的唯一名称。 |
path_to_property |
string | 包含矢量的属性的路径。 此路径可以是顶级属性或属性的点表示法路径。 如果使用点表示法路径,则所有非叶元素都不能是数组。 矢量必须是要编制索引并在矢量搜索结果中返回的 number[] 。 |
kind |
string | 要创建的矢量索引的类型。 选项为 vector-ivf 和 vector-hnsw 。 注意,vector-ivf 在所有群集层上都可用,vector-hnsw 可在 M40 群集层及更高层上使用。 |
numLists |
integer | 该整数是反向文件 (IVF) 索引用于对矢量数据进行分组的群集数。 如果最多为 100 万个文档,建议将 numLists 设置为 documentCount/1000 ,如果超过 100 万个文档,则将其设置为 sqrt(documentCount) 。 使用 1 的 numLists 值类似于执行暴力搜索,并且其性能有限。 |
similarity |
string | 用于索引的相似性指标。 可能的选项包括 COS (余弦距离)、L2 (欧几里德距离)和 IP (内积)。 |
dimensions |
整型 | 矢量相似度的维度数。 支持的最大维度数是 2000 。 |
重要
要获得良好的准确性和性能,正确设置 numLists 参数非常重要。 如果最多为 100 万个文档,建议将 numLists
设置为 documentCount/1000
,如果超过 100 万个文档,则将其设置为 sqrt(documentCount)
。
随着数据库中项数的增加,应将 numLists 调大,从而使矢量搜索实现良好的延迟性能。
如果要尝试新的方案或创建小型演示,可受限将 numLists
设置为 1
,跨所有矢量执行暴力搜索。 这应该会提供最准确的矢量搜索结果,但请注意搜索速度和延迟会很慢。 初始设置后,应继续操作,按照上述指南来优化 numLists
参数。
使用 IVF 执行矢量搜索
要执行矢量搜索,请在 MongoDB 查询中使用 $search
聚合管道阶段。 若要使用 cosmosSearch
索引,请使用新的 cosmosSearch
运算符。
{
{
"$search": {
"cosmosSearch": {
"vector": <query_vector>,
"path": "<path_to_property>",
"k": <num_results_to_return>,
},
"returnStoredSource": True }},
{
"$project": { "<custom_name_for_similarity_score>": {
"$meta": "searchScore" },
"document" : "$$ROOT"
}
}
}
要检索相似性分数 (searchScore
) 以及矢量搜索找到的文档,请使用 $project
运算符将 searchScore
包含在结果中,并将其重命名为 <custom_name_for_similarity_score>
。 然后,文档也会投影为嵌套对象。 请注意,相似性分数是使用矢量索引中定义的指标计算的。
重要
矢量必须是要编制索引的 number[]
。 使用另一种类型(如 double[]
),可防止对文档编制索引。 不会在矢量搜索的结果中返回未编制索引的文档。
使用 HNSW 索引的示例。
以下示例显示了如何为矢量编制索引、添加具有矢量属性的文档、执行矢量搜索以及检索索引配置。
use test;
db.createCollection("exampleCollection");
db.runCommand({
"createIndexes": "exampleCollection",
"indexes": [
{
"name": "VectorSearchIndex",
"key": {
"contentVector": "cosmosSearch"
},
"cosmosSearchOptions": {
"kind": "vector-hnsw",
"m": 16,
"efConstruction": 64,
"similarity": "COS",
"dimensions": 3
}
}
]
});
此命令针对存储在指定集合 exampleCollection
中的文档中的 contentVector
属性创建 HNSW 索引。 cosmosSearchOptions
属性指定 HNSW 矢量索引的参数。 如果文档具有存储在嵌套属性中的矢量,可以使用点表示法路径设置此属性。 例如,如果 contentVector
是 text
的子属性,则可使用 text.contentVector
。
将矢量添加到数据库
要将矢量添加到数据库集合中,首先需要使用自己的模型、Azure OpenAI 嵌入或其他 API(例如 Azure 上的 Hugging Face)创建嵌入。 在此示例中,添加了通过示例嵌入的新文档:
db.exampleCollection.insertMany([
{name: "Eugenia Lopez", bio: "Eugenia is the CEO of AdvenureWorks.", vectorContent: [0.51, 0.12, 0.23]},
{name: "Cameron Baker", bio: "Cameron Baker CFO of AdvenureWorks.", vectorContent: [0.55, 0.89, 0.44]},
{name: "Jessie Irwin", bio: "Jessie Irwin is the former CEO of AdventureWorks and now the director of the Our Planet initiative.", vectorContent: [0.13, 0.92, 0.85]},
{name: "Rory Nguyen", bio: "Rory Nguyen is the founder of AdventureWorks and the president of the Our Planet initiative.", vectorContent: [0.91, 0.76, 0.83]},
]);
执行矢量搜索
继续上一个示例,创建另一个矢量 queryVector
。 矢量搜索测量 queryVector
与文档 contentVector
路径中的矢量之间的距离。 可以通过设置参数 k
来设置搜索返回的结果数,此处设置为 2
。 还可以设置 efSearch
,该整数控制候选矢量列表的大小。 值越大,准确性就越高,但搜索速度也会变慢。 这是可选参数,默认值为 40。
const queryVector = [0.52, 0.28, 0.12];
db.exampleCollection.aggregate([
{
"$search": {
"cosmosSearch": {
"vector": "queryVector",
"path": "contentVector",
"k": 2,
"efSearch": 40
},
}
}
}
]);
在此示例中,通过 Mongo shell 使用 queryVector
作为输入来执行矢量搜索。 搜索结果是与查询矢量最相似的两个项的列表,按它们的相似度得分排序。
[
{
similarityScore: 0.9465376,
document: {
_id: ObjectId("645acb54413be5502badff94"),
name: 'Eugenia Lopez',
bio: 'Eugenia is the CEO of AdvenureWorks.',
vectorContent: [ 0.51, 0.12, 0.23 ]
}
},
{
similarityScore: 0.9006955,
document: {
_id: ObjectId("645acb54413be5502badff97"),
name: 'Rory Nguyen',
bio: 'Rory Nguyen is the founder of AdventureWorks and the president of the Our Planet initiative.',
vectorContent: [ 0.91, 0.76, 0.83 ]
}
}
]
获取矢量索引定义
要从集合中检索矢量索引定义,请使用 listIndexes
命令:
db.exampleCollection.getIndexes();
在此示例中,返回了 vectorIndex
,其中包含用于创建索引的所有 cosmosSearch
参数:
[
{ v: 2, key: { _id: 1 }, name: '_id_', ns: 'test.exampleCollection' },
{
v: 2,
key: { contentVector: 'cosmosSearch' },
name: 'vectorSearchIndex',
cosmosSearch: {
kind: 'vector-hnsw',
m: 40,
efConstruction: 64,
similarity: 'COS',
dimensions: 3
},
ns: 'test.exampleCollection'
}
]
使用 IVF 索引的示例
倒排文件 (IVF) 索引是一种将矢量组织成群集的方法。 在矢量搜索期间,查询矢量首先与这些群集的中心进行比较。 然后,在离查询矢量最近的群集中执行搜索。
numList
s 参数确定要创建的群集数。 单个群集意味着对数据库中的所有矢量执行搜索,类似于暴力或 kNN 搜索。 此设置虽然准确度最高,但延迟也最高。
增加 numLists
值会导致细分成更多群集,每个群集包含的矢量自然会减少。 例如,如果 numLists=2
,则每个群集包含比 numLists=3
时更多的矢量,以此类推。 每个群集的矢量越少,搜索的速度就越快(延迟更低、每秒查询次数增加)。 但是,这也增加了错过数据库中与查询矢量最相似的矢量的可能性。 这是群集性质不完美所致,其中搜索可能关注于某一群集,而实际上“最接近的”矢量却驻留在另一个群集中。
nProbes
参数用于控制要搜索的群集的数量。 该参数默认设置为“1”,这意味着它只会搜索中心与查询矢量最近的群集。 增加此值可让搜索覆盖到更多群集,提高准确度,但这样会增加延迟(从而减少每秒查询数),因为将要搜索更多的群集和矢量。
以下示例显示了如何为矢量编制索引、添加具有矢量属性的文档、执行矢量搜索以及检索索引配置。
创建矢量索引
use test;
db.createCollection("exampleCollection");
db.runCommand({
createIndexes: 'exampleCollection',
indexes: [
{
name: 'vectorSearchIndex',
key: {
"vectorContent": "cosmosSearch"
},
cosmosSearchOptions: {
kind: 'vector-ivf',
numLists: 3,
similarity: 'COS',
dimensions: 3
}
}
]
});
此命令针对存储在指定集合 exampleCollection
中的文档中的 vectorContent
属性创建 vector-ivf
索引。 cosmosSearchOptions
属性指定 IVF 矢量索引的参数。 如果文档具有存储在嵌套属性中的矢量,可以使用点表示法路径设置此属性。 例如,如果 vectorContent
是 text
的子属性,则可使用 text.vectorContent
。
将矢量添加到数据库
要将矢量添加到数据库集合中,首先需要使用自己的模型、Azure OpenAI 嵌入或其他 API(例如 Azure 上的 Hugging Face)创建嵌入。 在此示例中,添加了通过示例嵌入的新文档:
db.exampleCollection.insertMany([
{name: "Eugenia Lopez", bio: "Eugenia is the CEO of AdvenureWorks.", vectorContent: [0.51, 0.12, 0.23]},
{name: "Cameron Baker", bio: "Cameron Baker CFO of AdvenureWorks.", vectorContent: [0.55, 0.89, 0.44]},
{name: "Jessie Irwin", bio: "Jessie Irwin is the former CEO of AdventureWorks and now the director of the Our Planet initiative.", vectorContent: [0.13, 0.92, 0.85]},
{name: "Rory Nguyen", bio: "Rory Nguyen is the founder of AdventureWorks and the president of the Our Planet initiative.", vectorContent: [0.91, 0.76, 0.83]},
]);
执行矢量搜索
要执行矢量搜索,请在 MongoDB 查询中使用 $search
聚合管道阶段。 若要使用 cosmosSearch
索引,请使用新的 cosmosSearch
运算符。
{
{
"$search": {
"cosmosSearch": {
"vector": <vector_to_search>,
"path": "<path_to_property>",
"k": <num_results_to_return>,
},
"returnStoredSource": True }},
{
"$project": { "<custom_name_for_similarity_score>": {
"$meta": "searchScore" },
"document" : "$$ROOT"
}
}
}
要检索相似性分数 (searchScore
) 以及矢量搜索找到的文档,请使用 $project
运算符将 searchScore
包含在结果中,并将其重命名为 <custom_name_for_similarity_score>
。 然后,文档也会投影为嵌套对象。 请注意,相似性分数是使用矢量索引中定义的指标计算的。
使用 $search 查询向量和矢量距离(即相似性分数)
继续上一个示例,创建另一个矢量 queryVector
。 矢量搜索测量 queryVector
与文档 vectorContent
路径中的矢量之间的距离。 可以通过设置参数 k
来设置搜索返回的结果数,此处设置为 2
。 还可以设置 nProbes
,这是控制每个搜索中检查的附近群集数的整数。 值越大,准确性就越高,但搜索速度也会变慢。 这是一个可选参数,默认值为 1,且不能大于在矢量索引中指定的 numLists
值。
const queryVector = [0.52, 0.28, 0.12];
db.exampleCollection.aggregate([
{
$search: {
"cosmosSearch": {
"vector": queryVector,
"path": "vectorContent",
"k": 2
},
"returnStoredSource": true }},
{
"$project": { "similarityScore": {
"$meta": "searchScore" },
"document" : "$$ROOT"
}
}
]);
在此示例中,通过 Mongo shell 使用 queryVector
作为输入来执行矢量搜索。 搜索结果是与查询矢量最相似的两个项的列表,按它们的相似度得分排序。
[
{
similarityScore: 0.9465376,
document: {
_id: ObjectId("645acb54413be5502badff94"),
name: 'Eugenia Lopez',
bio: 'Eugenia is the CEO of AdvenureWorks.',
vectorContent: [ 0.51, 0.12, 0.23 ]
}
},
{
similarityScore: 0.9006955,
document: {
_id: ObjectId("645acb54413be5502badff97"),
name: 'Rory Nguyen',
bio: 'Rory Nguyen is the founder of AdventureWorks and the president of the Our Planet initiative.',
vectorContent: [ 0.91, 0.76, 0.83 ]
}
}
]
获取矢量索引定义
要从集合中检索矢量索引定义,请使用 listIndexes
命令:
db.exampleCollection.getIndexes();
在此示例中,返回了 vectorIndex
,其中包含用于创建索引的所有 cosmosSearch
参数:
[
{ v: 2, key: { _id: 1 }, name: '_id_', ns: 'test.exampleCollection' },
{
v: 2,
key: { vectorContent: 'cosmosSearch' },
name: 'vectorSearchIndex',
cosmosSearch: {
kind: 'vector-ivf',
numLists: 3,
similarity: 'COS',
dimensions: 3
},
ns: 'test.exampleCollection'
}
]
筛选的矢量搜索(预览版)
现在,可以使用任何受支持的查询筛选器(例如 $lt
、$lte
、$eq
、$neq
、$gte
、$gt
、$in
、$nin
、$regex
)执行矢量搜索。 在 Azure 订阅的“预览功能”选项卡中启用“筛选矢量搜索”功能。 在此处了解有关预览功能的详细信息。
首先,除了矢量索引之外,还需要为筛选器定义索引。 例如,可以对属性定义筛选器索引
db.runCommand({
"createIndexes": "<collection_name",
"indexes": [ {
"key": {
"<property_to_filter>": 1
},
"name": "<name_of_filter_index>"
}
]
});
接下来,可以将 "filter"
术语添加到矢量搜索,如下所示。 在此示例中,筛选器会查找 "title"
属性不在 ["not in this text", "or this text"]
列表中的文档。
db.exampleCollection.aggregate([
{
'$search': {
"cosmosSearch": {
"vector": "<query_vector>",
"path": <path_to_vector>,
"k": num_results,
"filter": {<property_to_filter>: {"$nin": ["not in this text", "or this text"]}}
},
"returnStoredSource": True }},
{'$project': { 'similarityScore': { '$meta': 'searchScore' }, 'document' : '$$ROOT' }
}
]);
重要
在预览版中,筛选的矢量搜索可能需要你调整矢量索引参数,以实现更高的准确度。 例如,在使用 HNSW 时增加 m
、efConstruction
或 efSearch
,或在使用 IVF 时增加 numLists
或 nProbes
可能会带来更好的结果。 在使用之前,应先测试配置,以确保结果令人满意。
使用 LLM 业务流程工具
通过语义内核用作矢量数据库
使用语义内核协调对 Azure Cosmos DB for MongoDB vCore 和 LLM 的信息检索。 在此处了解更多信息。
在 LangChain 中用作矢量数据库
使用 LangChain 协调对 Azure Cosmos DB for MongoDB vCore 和 LLM 的信息检索。 在此处了解更多信息。
通过 LangChain 用作语义缓存
使用 LangChain 和 Azure Cosmos DB for MongoDB (vCore) 来协调语义缓存,使用以前记录的 LLM 响应来节省 LLM API 成本并减少响应延迟。 在此处了解详细信息
功能和限制
- 支持的距离指标:L2(欧几里德)、内积和余弦。
- 支持的索引方法:IVFFLAT (GA) 和 HSNW(预览版)
- 为最大大小为 2,000 个维度的矢量编制索引。
- 索引仅适用于每个路径的一个矢量。
- 每个矢量路径只能创建一个索引。
总结
本指南演示了如何创建矢量索引、添加包含矢量数据的文档、执行相似性搜索以及检索索引定义。 通过使用集成矢量数据库,可以直接在 Azure Cosmos DB for MongoDB vCore 中高效地存储和查询高维矢量数据并为其编制索引。 它支持通过矢量嵌入充分发挥数据的全部潜力,并生成更加准确、高效和强大的应用程序。
相关内容
- .NET RAG 模式零售参考解决方案
- .NET 教程 - 食谱聊天机器人
- C# RAG 模式 - 将 Open AI Services 与 Cosmos 集成
- Python RAG 模式 - Azure 产品聊天机器人
- Python 笔记本教程 - 通过 LangChain 进行矢量数据库集成
- Python 笔记本教程 - 通过 LangChain 进行 LLM 缓存集成
- Python - LlamaIndex 集成
- Python - 语义内核内存集成