如何基于Semantic Kernel在CosmosDB对象数组中执行向量搜索
问题分析与解决方案
核心问题
你要实现的是单文档内嵌套数组元素的向量搜索,但Semantic Kernel默认的向量存储集成只支持集合级别的文档搜索(每个文档对应一条向量记录),当前的实体类设计和索引策略无法适配这种嵌套场景。
问题根源
- 实体注解无效:
BgBomVectorItem上的[VectorStoreRecordKey]注解没用,Semantic Kernel只会识别根实体的键字段,嵌套类的这个注解不会被处理。 - CosmosDB索引限制:默认向量索引是针对文档级字段的,没法直接给嵌套数组里的向量字段建有效索引,导致数组内的向量搜索无法正常执行。
- SK API局限:现有向量搜索API都是针对整个容器的文档,没有直接支持先筛选单个文档、再对其数组字段做向量搜索的方法。
可行解决方案
方案1:重构数据结构(推荐)
把BgBomVectorItem拆成独立的CosmosDB容器,每个条目关联对应的模型ID:
// 独立的向量条目实体 public class BgBomVectorItem { [VectorStoreRecordKey] [JsonProperty(PropertyName = "id")] public string Id { get; set; } // 关联所属模型的ID public string ModelId { get; set; } [VectorStoreRecordData(IsFullTextSearchable = true)] public string Information { get; set; } [VectorStoreRecordVector(4, DistanceFunction.EuclideanDistance, IndexKind.Flat)] public ReadOnlyMemory<float> DescriptionEmbedding { get; set; } }
操作流程:
- 新建CosmosDB容器(比如
bombvectoritems)存储拆分后的条目 - 原
BgBomVectorModel只保留基础信息,移除BomItemsInformation数组 - 搜索时先通过
ModelId筛选,再执行向量搜索:
// Semantic Kernel 示例代码 var vectorStore = kernel.Services.GetRequiredService<IVectorStore>(); var searchResults = await vectorStore.SearchAsync<BgBomVectorItem>( queryEmbedding: 你的查询向量, limit: 6, filter: $"ModelId eq '{选中的模型ID}'" );
优势:完全适配Semantic Kernel的向量搜索能力,CosmosDB可以给ModelId和向量字段建复合索引,性能最优。
方案2:保留原结构,用CosmosDB原生SQL查询
如果不能重构数据,直接用CosmosDB的SQL结合向量函数,绕开Semantic Kernel的向量存储封装:
SELECT TOP 6 item FROM c JOIN item IN c.BomItemsInformation WHERE c.id = @modelId ORDER BY VECTOR_DISTANCE(item.DescriptionEmbedding, @queryVector, 'Euclidean') ASC
C#代码实现:
var cosmosClient = new CosmosClient("你的连接字符串"); var container = cosmosClient.GetContainer("数据库名", "vectormodels"); var queryDefinition = new QueryDefinition( "SELECT TOP 6 item " + "FROM c " + "JOIN item IN c.BomItemsInformation " + "WHERE c.id = @modelId " + "ORDER BY VECTOR_DISTANCE(item.DescriptionEmbedding, @queryVector, 'Euclidean') ASC" ) .WithParameter("@modelId", 选中的模型ID) .WithParameter("@queryVector", 你的查询向量.ToArray()); var iterator = container.GetItemQueryIterator<BgBomVectorItem>(queryDefinition); var results = new List<BgBomVectorItem>(); while (iterator.HasMoreResults) { var response = await iterator.ReadNextAsync(); results.AddRange(response.Resource); }
注意事项:
- 必须手动给
BomItemsInformation[*].DescriptionEmbedding字段创建向量索引,索引策略示例:
{ "indexingMode": "consistent", "automatic": true, "includedPaths": [ { "path": "/BomItemsInformation/*/DescriptionEmbedding/?", "indexes": [ { "kind": "Vector", "dataType": "float32", "dimensions": 4, "distanceFunction": "Euclidean" } ] } ] }
劣势:没法直接用Semantic Kernel的向量存储抽象,需要自己处理CosmosDB的查询逻辑。
原实体类修正建议
如果坚持用原结构,要删掉BgBomVectorItem上的[VectorStoreRecordKey]注解,这个注解只对根实体有效:
public class BgBomVectorItem { // 移除[VectorStoreRecordKey],改用普通属性 public string id { get; set; } [VectorStoreRecordData(IsFullTextSearchable = true)] public string Information { get; set; } [VectorStoreRecordVector(4, DistanceFunction.EuclideanDistance, IndexKind.Flat)] public ReadOnlyMemory<float> DescriptionEmbedding { get; set; } }
内容的提问来源于stack exchange,提问作者Андрій Гуцалюк
相关产品推荐
相关产品推荐

