本次内容将实现通过abp.vnext框架实现对milvus的操作,下一节将实现通过nomic-embed-text:latest对文件进行处理

1:在EntityFrameworkCore层中添加操作Milvus的仓储

/// <summary>
/// 操作Milvus
/// </summary>
public class MilvusClientRepository : ITransientDependency
{
    private readonly MilvusClient _milvusClient;
    private readonly MilvusOptions _options;
    private readonly IVectorService _vectorService;

    public MilvusClientRepository(
        MilvusClient milvusClient,
        IOptions<MilvusOptions> options,
        IVectorService vectorService)
    {
        _milvusClient = milvusClient;
        _options = options.Value;
        _vectorService = vectorService;
    }
    /// <summary>
    /// 初始化创建Milvus的Collection
    /// </summary>
    /// <returns></returns>
    public async Task InitializeAsync()
    {
        var schema = new CollectionSchema
        {
            Fields =
            {
                FieldSchema.CreateVarchar("id", maxLength: 36,isPrimaryKey:true),
                FieldSchema.CreateVarchar("title", maxLength: 200),
                //FieldSchema.CreateJson("content"),
                FieldSchema.CreateVarchar("content", maxLength: 60535),
                FieldSchema.CreateVarchar("chunkcontent", maxLength: 1000),
                FieldSchema.CreateFloatVector("vector", dimension: _options.VectorDimension)
            }
        };
        MilvusCollection milvusCollection = await _milvusClient.CreateCollectionAsync(
            collectionName: _options.CollectionName,
            schema: schema,
            shardsNum: 2);
        await milvusCollection.CreateIndexAsync(
            fieldName: "vector",
            indexType: IndexType.IvfFlat,//IVF_FLAT索引是一种可以提高浮点向量搜索性能的索引算法
                                         //这种索引类型非常适合需要快速查询响应和高精确度的大规模数据集,
                                         //尤其是在对数据集进行聚类可以减少搜索空间,并且有足够内存存储聚类数据的情况下。
            metricType: SimilarityMetricType.L2,//用于计算向量间距离的方法。支持的值包括COSINE,L2,和IP
            extraParams: new Dictionary<string, string>
            {
            { "nlist", "1024" }//指定使用 k-means 算法创建的分区数量
            });
        await milvusCollection.LoadAsync();
        Console.WriteLine($"创建Collection成功{_options.CollectionName}");
    }

    /// <summary>
    /// 插入数据
    /// </summary>
    /// <param name="document"></param>
    /// <returns></returns>
    public async Task<Document> InsertAsync(Document document)
    {
        var vector = await _vectorService.GetEmbeddingsAsync(document.Content);
        var collection = _milvusClient.GetCollection(_options.CollectionName);
        await collection.InsertAsync(new FieldData[]
        {
            FieldData.Create("id", new[] { Guid.NewGuid().ToString() }),
            FieldData.Create("title", new[] { document.Title }),
            //FieldData.CreateJson("content", new[] { document.Content }),
            FieldData.CreateVarChar("content", new[] { document.Content }),
            FieldData.CreateVarChar("chunkcontent", new[] { document.Title }),
            FieldData.CreateFloatVector("vector", new[] { new ReadOnlyMemory<float>(vector) })
        });
        return document;
    }

    /// <summary>
    /// 查询
    /// </summary>
    /// <param name="query"></param>
    /// <param name="limit"></param>
    /// <returns></returns>
    public async Task<List<Document>> SearchByEmbeddingsAsync(string query, int limit = 5)
    {
        var queryVector = await _vectorService.GetEmbeddingsAsync(query);
        var collection = _milvusClient.GetCollection(_options.CollectionName);
        await collection.LoadAsync();
        var parameters = new SearchParameters
        {
            OutputFields = { "id", "title", "content" },
            ConsistencyLevel = ConsistencyLevel.Strong,
        };
        SearchResults results = await collection.SearchAsync(
                                 vectorFieldName: "vector",
                                 vectors: new[] { new ReadOnlyMemory<float>(queryVector) },
                                 SimilarityMetricType.L2,
                                 limit: limit,
                                 parameters);           
        IReadOnlyList<Document> documents = ParseSearchResults(results);
        return documents.ToList();
    }

    /// <summary>
    /// 解析数据
    /// </summary>
    /// <param name="searchResults"></param>
    /// <returns></returns>
    private IReadOnlyList<Document> ParseSearchResults(SearchResults searchResults)
    {
        var documents = new List<Document>();
        var idField = searchResults.FieldsData.FirstOrDefault(f => f.FieldName == "id") as FieldData<string>;
        var titleField = searchResults.FieldsData.FirstOrDefault(f => f.FieldName == "title") as FieldData<string>;
        var contentField = searchResults.FieldsData.FirstOrDefault(f => f.FieldName == "content") as FieldData<string>;
        for (int i = 0; i < searchResults.Scores.Count; i++)
        {
            try
            {
                Document document = new Document
                    (
                    Guid.Parse(idField.Data[i]),
                    titleField.Data[i],
                    contentField.Data[i]
                    );
                documents.Add(document);
            }
            catch (Exception ex)
            {
                continue;
            }
        }
        return documents;
    }
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐