• 开源模型应用落地-工具使用篇-向量数据库进阶(四)


    一、前言

        通过学习"开源模型应用落地"系列文章,我们成功地建立了一个完整可实施的AI交付流程。现在,我们要引入向量数据库,作为我们AI服务的二级缓存。本文将继续基于上一篇“开源模型应用落地-工具使用篇-向量数据库(三)”详细介绍如何通过Java来使用Milvus Lite来为我们的AI服务部署一个前置缓存。


    二、术语

    2.1、向量数据库

        向量数据库是一种专门用于存储和处理高维向量数据的数据库系统。与传统的关系型数据库或文档数据库不同,向量数据库的设计目标是高效地支持向量数据的索引和相似性搜索。

        在传统数据库中,数据通常是以结构化的表格形式存储,每个记录都有预定义的字段。但是,对于包含大量高维向量的数据,如图像、音频、文本等,传统的数据库模型往往无法有效地处理。向量数据库通过引入特定的数据结构和索引算法,允许高效地存储和查询向量数据。

        向量数据库的核心概念是向量索引。它使用一种称为向量空间模型的方法,将向量映射到多维空间中的点,并利用这种映射关系构建索引结构。这样,当需要搜索相似向量时,可以通过计算向量之间的距离或相似度来快速定位相似的向量。

    2.5、Milvus

        是一个开源的向量数据库引擎,专门用于存储和处理大规模高维向量数据。它提供了高效的向量索引和相似性搜索功能,使用户能够快速地进行向量数据的存储、查询和分析。

        Milvus的设计目标是为了满足现代应用中对大规模向量数据的需求,例如人脸识别、图像搜索、推荐系统等。它采用了向量空间模型和多种索引算法,包括倒排索引、近似最近邻(Approximate Nearest Neighbor,ANN)等,以支持高效的相似性搜索。

        Milvus提供了易于使用的编程接口和丰富的功能,使用户可以方便地插入、查询和分析向量数据。它支持多种数据类型的向量,包括浮点型、整型等,也支持多种距离度量方法,如欧氏距离、余弦相似度等。

        Milvus还提供了分布式部署和横向扩展的能力,可以在多台机器上构建高可用性和高性能的向量数据库集群。它支持数据的分片和负载均衡,可以处理大规模数据集和高并发查询。

    2.2、Milvus Lite

        是Milvus向量数据库的一个轻量级版本。旨在提供在资源受限的环境中快速、高效地进行向量存储和相似性搜索的能力。

        与完整版的Milvus相比,它具有以下特点:

    • 轻量级:Milvus Lite具有较小的存储占用和内存消耗,适合在资源受限的设备上部署和运行。
    • 快速部署:Milvus Lite提供了简化的部署和配置过程,使其更易于在嵌入式设备和边缘服务器上进行部署和集成。
    • 高效的向量索引和搜索:尽管是轻量级版本,Milvus Lite仍然提供了高效的向量索引和相似性搜索功能,以支持快速的向量数据查询。
    • 离线模式:Milvus Lite支持在离线模式下进行向量索引和搜索,无需实时连接到远程服务器。

    2.3、Attu

        是Milvus 的高效开源管理工具。 它具有直观的图形用户界面(GUI),使您可以轻松地与数据库进行交互。

    2.4、Milvus 支持的索引类型

    • FLAT: 是一种无索引的类型,它会对所有的向量进行暴力搜索,保证 100% 的召回率,但是查询速度较慢,适用于数据量较小或者对精度要求很高的场景
    • IVF_FLAT: 是一种基于倒排文件(Inverted File)的索引类型,它会先对向量进行聚类,然后在每个聚类中建立 FLAT 索引,查询时只需要在最近的聚类中搜索,可以加速查询,但是需要指定聚类数量和查询数量,适用于数据量较大或者对速度要求较高的场景
    • IVF_SQ8: 是一种基于倒排文件和量化(Quantization)的索引类型,它会先对向量进行聚类,然后在每个聚类中使用乘积量化(Product Quantization)将向量压缩为 8 位整数,查询时只需要在最近的聚类中搜索,并使用查找表(Lookup Table)进行距离计算,可以节省存储空间和加速查询,但是会损失一定的精度,适用于数据量很大或者对存储空间要求较高的场景
    •  IVF_PQ: 是一种基于倒排文件和量化的索引类型,它会先对向量进行聚类,然后在每个聚类中使用乘积量化将向量压缩为 8 位整数,并使用倒排表(Inverted List)存储压缩后的向量,查询时只需要在最近的聚类中搜索,并使用查找表进行距离计算,可以节省存储空间和加速查询,但是会损失一定的精度,适用于数据量很大或者对存储空间要求较高的场景
    • GPU_IVF_FLAT: 是一种基于 GPU 的倒排文件索引类型,它与 IVF_FLAT 索引相似,但是可以利用 GPU 的并行计算能力来加速查询,适用于数据量较大或者对速度要求很高的场景
    • GPU_IVF_PQ: 是一种基于 GPU 的倒排文件和量化索引类型,它与 IVF_PQ 索引相似,但是可以利用 GPU 的并行计算能力来加速查询,适用于数据量很大或者对速度要求很高的场景
    •  HNSW :是一种基于层次化导航图(Hierarchical Navigable Small World)的索引类型,它会构建一个多层次的图结构来表示向量之间的近邻关系,并使用启发式搜索算法来快速找到最近邻向量,可以实现高速高召回的查询,但是需要指定树的数量和搜索深度等参数,适用于数据维度较高或者对精度要求较高的场景
    • DISKANN :是一种基于磁盘分区和近似最近邻搜索(Disk-based Partitioned Approximate Nearest Neighbor Search)的索引类型,它会将向量划分为多个磁盘分区,并在每个分区中构建 HNSW 索引,并使用多线程并行搜索算法来快速找到最近邻向量,可以实现高效地检索海量数据,但是需要指定分区数量和线程数量等参数,适用于数据量极大或者对存储空间要求较高的场景。

     三、使用方式

    3.1、架构示意图

    这里的Milvus Lite部署在内网,位于业务服务和AI服务的中间,作为AI服务的二级缓存(一级缓存为Redis),为AI服务减缓负载压力。

    3.2、安装Milvus Lite

         1. 创建虚拟环境

             conda create --name milvus python=3.10

         2. 激活虚拟环境

            conda activate milvus

         3.  安装milvus包

            pip install milvus

    3.3、编写Milvus Lite服务端代码

       此处将Milvus Lite作为 Python 模块启动

    1. from milvus import default_server
    2. def start_server():
    3. default_server.start()
    4. def stop_server():
    5. default_server.stop()
    6. if __name__ == '__main__':
    7. with default_server:
    8. start_server()
    9. input("按下任意键继续...")

    3.4、启动Milvus Lite服务

        python -u 上述代码的文件名

        

        启动完成后,会监听19530端口

    3.5、安装Milvus客户端管理工具

        下载地址:Releases · zilliztech/attu · GitHub

    3.6、登录Milvus Lite服务端

        注意根据实际情况调整IP和端口,默认端口为19530

    登录进去,就能看到如下信息:


    四、业务整合

    业务数据需要提前初始化到向量数据库中

    4.1、导入maven依赖

    1. <dependency>
    2. <groupId>io.milvus</groupId>
    3. <artifactId>milvus-sdk-java</artifactId>
    4. <version>2.2.2</version>
    5. </dependency>

    PS: 我的JDK是1.8版本,若milvus版本太高,会出现兼容性问题,需要注意

    maven仓库地址:Maven Repository: io.milvus » milvus-sdk-java

    4.2、连接milvus服务端

    1. public static MilvusServiceClient connect_db(String uri) {
    2. MilvusServiceClient milvusClient = new MilvusServiceClient(
    3. ConnectParam.newBuilder()
    4. .withUri(uri)
    5. // .withToken("root:Milvus")
    6. .build()
    7. );
    8. return milvusClient;
    9. }

    4.3、创建集合

    1. public static Map create_collection(MilvusServiceClient milvusClient, String collection_name, String description, int shardsNum, List fieldTypes) {
    2. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    3. log.warn("集合名称为空.");
    4. return MapUtil.builder("status", "1").build();
    5. }
    6. if (CollUtil.isEmpty(fieldTypes)) {
    7. log.warn("集合字段为空.");
    8. return MapUtil.builder("status", "1").build();
    9. }
    10. CreateCollectionParam.Builder builder = CreateCollectionParam.newBuilder().withCollectionName(collection_name)
    11. .withShardsNum(shardsNum);
    12. for (FieldType fieldType : fieldTypes) {
    13. builder.addFieldType(fieldType);
    14. }
    15. if (StringUtils.isNotEmpty(description) && StringUtils.isNotBlank(description)) {
    16. builder.withDescription(description);
    17. }
    18. CreateCollectionParam createCollectionReq = builder.build();
    19. R rstatus = milvusClient.createCollection(createCollectionReq);
    20. return buildResult(rstatus);
    21. }

    创建成功后:

    4.4、插入数据

    1. public static Map insert_data(MilvusServiceClient milvusClient, String collection_name,List fields){
    2. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    3. log.warn("集合名称为空.");
    4. return MapUtil.builder("status", "1").build();
    5. }
    6. if (CollUtil.isEmpty(fields)) {
    7. log.warn("插入数据为空.");
    8. return MapUtil.builder("status", "1").build();
    9. }
    10. InsertParam insertParam = InsertParam.newBuilder()
    11. .withCollectionName(collection_name)
    12. .withFields(fields)
    13. .build();
    14. R mutationResultR = milvusClient.insert(insertParam);
    15. String status = String.valueOf(mutationResultR.getStatus());
    16. MapBuilder mapBuilder = MapUtil.builder("status", status);
    17. MutationResult mutationResult = mutationResultR.getData();
    18. if(null != mutationResult){
    19. long insert_cnt = mutationResult.getInsertCnt();
    20. if(insert_cnt > 0){
    21. mapBuilder.put("msg","插入成功");
    22. }
    23. }
    24. milvusClient.flush(FlushParam.newBuilder()
    25. .addCollectionName(collection_name)
    26. // .withSyncFlush(true)
    27. .build());
    28. log.info("MutationResult: {}",mutationResultR);
    29. return mapBuilder.build();
    30. }

    插入成功后(需要调用flush才能立刻看到数据):

    4.5、创建索引

    1. public static Map create_index(MilvusServiceClient milvusClient, String collection_name, String index_column, String index_name, String params) {
    2. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    3. log.warn("集合名称为空.");
    4. return MapUtil.builder("status", "1").build();
    5. }
    6. if (StringUtils.isEmpty(index_column) || StringUtils.isBlank(index_column)) {
    7. log.warn("索引字段为空.");
    8. return MapUtil.builder("status", "1").build();
    9. }
    10. if (StringUtils.isEmpty(index_name) || StringUtils.isBlank(index_name)) {
    11. log.warn("索引名称为空.");
    12. return MapUtil.builder("status", "1").build();
    13. }
    14. CreateIndexParam.Builder builder = CreateIndexParam.newBuilder()
    15. .withIndexName(index_name)
    16. .withCollectionName(collection_name)
    17. .withFieldName(index_column)
    18. .withIndexType(IndexType.IVF_FLAT)
    19. .withMetricType(MetricType.IP)
    20. .withSyncMode(Boolean.FALSE);
    21. if (StringUtils.isNotEmpty(index_name) && StringUtils.isNotBlank(index_name)) {
    22. builder = builder.withExtraParam(params);
    23. }
    24. R rstatus = milvusClient.createIndex(
    25. builder.build()
    26. );
    27. return buildResult(rstatus);
    28. }

    metric_type说明:

    IP(内积)是一种表示向量之间相似程度的度量方式,它的计算方式是将两个向量中对应位置的元素相乘后求和。IP 的值越大,表示两个向量越相似;IP 的值越小,表示两个向量越不相似。IP 适用于只需要考虑向量之间的相似度,而不需要考虑各个维度之间的权重关系的场景,例如自然语言处理、计算机视觉等领域。

    L2(欧氏距离)是一种表示向量之间直线距离的度量方式,它的计算方式是将两个向量中对应位置的元素相减后平方,再将平方和求和并开平方;L2 的值越小,表示两个向量越相似;L2 的值越大,表示两个向量越不相似。L2 适用于需要考虑各个维度之间的权重关系,或者需要将向量转化为单位向量进行相似度计算的场景,例如数值计算、信号处理、图像处理、机器学习等领域。
     

    创建成功后:

    4.6、加载数据至缓存

    1. public static Map load_in_memory(MilvusServiceClient milvusClient, String collection_name) {
    2. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    3. log.warn("集合名称为空.");
    4. return MapUtil.builder("status", "1").build();
    5. }
    6. R rstatus = milvusClient.loadCollection(
    7. LoadCollectionParam.newBuilder()
    8. .withCollectionName(collection_name)
    9. .build()
    10. );
    11. return buildResult(rstatus);
    12. }

    4.7、根据向量检索数据

    1. public static Map search_data_vector(MilvusServiceClient milvusClient, String collection_name, String fieldName, List> search_vectors, String params, int topK, List search_output_fields) {
    2. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    3. log.warn("集合名称为空.");
    4. return MapUtil.builder("status", "1").build();
    5. }
    6. if (StringUtils.isEmpty(fieldName) || StringUtils.isBlank(fieldName)) {
    7. log.warn("检索字段为空.");
    8. return MapUtil.builder("status", "1").build();
    9. }
    10. if (CollUtil.isEmpty(search_vectors) || CollUtil.isEmpty(search_vectors.get(0))) {
    11. log.warn("检索向量为空.");
    12. return MapUtil.builder("status", "1").build();
    13. }
    14. if (CollUtil.isEmpty(search_output_fields)) {
    15. log.warn("输出字段为空.");
    16. return MapUtil.builder("status", "1").build();
    17. }
    18. if (topK <= 1) {
    19. log.warn("topK少于1.");
    20. topK = 1;
    21. }
    22. SearchParam.Builder builder = SearchParam.newBuilder().withCollectionName(collection_name)
    23. .withConsistencyLevel(ConsistencyLevelEnum.STRONG)
    24. .withMetricType(MetricType.IP)
    25. .withOutFields(search_output_fields)
    26. .withTopK(topK)
    27. .withVectors(search_vectors)
    28. .withVectorFieldName(fieldName);
    29. if (StringUtils.isNotEmpty(params) && StringUtils.isNotBlank(params)) {
    30. builder.withParams(params);
    31. }
    32. SearchParam searchParam = builder.build();
    33. R respSearch = milvusClient.search(searchParam);
    34. String status = String.valueOf(respSearch.getStatus());
    35. MapBuilder mapBuilder = MapUtil.builder("status", status);
    36. if (StringUtils.equals(status, "0")) {
    37. SearchResults searchResults = respSearch.getData();
    38. if (null != searchResults) {
    39. SearchResultData searchResultData = searchResults.getResults();
    40. if (null != searchResultData) {
    41. long num_queries = searchResultData.getNumQueries();
    42. // log.info("num_queries: {}", num_queries);
    43. if (num_queries > 0) {
    44. FieldData fieldData = searchResultData.getFieldsData(0);
    45. if (null != fieldData) {
    46. ScalarField scalarField = fieldData.getScalars();
    47. if (null != scalarField.getStringData()) {
    48. String content = scalarField.getStringData().getData(0);
    49. mapBuilder.put("content", content);
    50. // log.info("content: {}", content);
    51. }
    52. }
    53. }
    54. }
    55. }
    56. }
    57. return mapBuilder.build();
    58. }

    4.8、删除索引

    1. public static Map drop_index(MilvusServiceClient milvusClient, String collection_name, String index_name) {
    2. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    3. log.warn("集合名称为空.");
    4. return MapUtil.builder("status", "1").build();
    5. }
    6. if (StringUtils.isEmpty(index_name) || StringUtils.isBlank(index_name)) {
    7. log.warn("索引名称为空.");
    8. return MapUtil.builder("status", "1").build();
    9. }
    10. R rstatus = milvusClient.dropIndex(
    11. DropIndexParam.newBuilder()
    12. .withCollectionName(collection_name)
    13. .withIndexName(index_name)
    14. .build()
    15. );
    16. return buildResult(rstatus);
    17. }

    4.9、删除集合

    1. public static Map drop_collection(MilvusServiceClient milvusClient, String collection_name) {
    2. R rstatus = milvusClient.dropCollection(
    3. DropCollectionParam.newBuilder()
    4. .withCollectionName(collection_name)
    5. .build()
    6. );
    7. return buildResult(rstatus);
    8. }

    4.10、释放缓存

    1. public static Map unload_in_memory(MilvusServiceClient milvusClient, String collection_name) {
    2. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    3. log.warn("集合名称为空.");
    4. return MapUtil.builder("status", "1").build();
    5. }
    6. R rstatus = milvusClient.releaseCollection(
    7. ReleaseCollectionParam.newBuilder()
    8. .withCollectionName(collection_name)
    9. .build());
    10. return buildResult(rstatus);
    11. }


    五、附带说明

    5.1、高维向量表示的优劣

    优势:

    • 表示能力增强:高维向量可以提供更丰富的信息表示能力,能够捕捉更多的特征和关系,从而提高模型的表达能力。
    • 解决冗余信息:在高维空间中,冗余特征可能会被稀疏化,使得模型更容易识别和利用有效的特征。
    • 处理复杂问题:某些复杂问题可能需要更高维度的向量来表示,以便更好地捕捉问题的复杂性和多样性。

    劣势

    • 维度灾难:高维度数据可能导致维度灾难问题,即数据稀疏性增加,对于有限的训练数据而言,模型的泛化能力可能会受到影响。
    • 计算复杂性增加:高维度数据需要更多的计算资源和时间来处理和分析,可能会增加计算的复杂性和开销。
    • 数据稀疏性:在高维空间中,数据点之间的距离变得更远,可能会导致数据稀疏性增加,从而影响模型的准确性和可靠性。

    5.2、插入数据成功但无法检索

         需要调用flush

         milvusClient.flush(FlushParam.newBuilder() .addCollectionName(collection_name) .build());

    5.3、如何批量插入数据

         集合中放入多条数据即可

    5.4、受限于篇幅过长,如何提升向量检索精度、如何获取文本向量及如何对向量进行预处理(向量长度补全、归一化、标准化)将另文讲解

    5.5、完整代码

    1. package com.zwzt.communication.netty.test;
    2. import cn.hutool.core.collection.CollUtil;
    3. import cn.hutool.core.map.MapBuilder;
    4. import cn.hutool.core.map.MapUtil;
    5. import cn.hutool.core.util.ObjectUtil;
    6. import io.milvus.client.MilvusServiceClient;
    7. import io.milvus.common.clientenum.ConsistencyLevelEnum;
    8. import io.milvus.grpc.*;
    9. import io.milvus.param.*;
    10. import io.milvus.param.collection.*;
    11. import io.milvus.param.dml.InsertParam;
    12. import io.milvus.param.dml.SearchParam;
    13. import io.milvus.param.index.CreateIndexParam;
    14. import io.milvus.param.index.DropIndexParam;
    15. import lombok.extern.slf4j.Slf4j;
    16. import org.apache.commons.lang3.StringUtils;
    17. import java.util.ArrayList;
    18. import java.util.Arrays;
    19. import java.util.List;
    20. import java.util.Map;
    21. @Slf4j
    22. public class MilvusUtils {
    23. public static MilvusServiceClient connect_db(String uri) {
    24. MilvusServiceClient milvusClient = new MilvusServiceClient(
    25. ConnectParam.newBuilder()
    26. .withUri(uri)
    27. // .withToken("root:Milvus")
    28. .build()
    29. );
    30. return milvusClient;
    31. }
    32. public static Map create_collection(MilvusServiceClient milvusClient, String collection_name, String description, int shardsNum, List fieldTypes) {
    33. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    34. log.warn("集合名称为空.");
    35. return MapUtil.builder("status", "1").build();
    36. }
    37. if (CollUtil.isEmpty(fieldTypes)) {
    38. log.warn("集合字段为空.");
    39. return MapUtil.builder("status", "1").build();
    40. }
    41. CreateCollectionParam.Builder builder = CreateCollectionParam.newBuilder().withCollectionName(collection_name)
    42. .withShardsNum(shardsNum);
    43. for (FieldType fieldType : fieldTypes) {
    44. builder.addFieldType(fieldType);
    45. }
    46. if (StringUtils.isNotEmpty(description) && StringUtils.isNotBlank(description)) {
    47. builder.withDescription(description);
    48. }
    49. CreateCollectionParam createCollectionReq = builder.build();
    50. R rstatus = milvusClient.createCollection(createCollectionReq);
    51. return buildResult(rstatus);
    52. }
    53. public static Map drop_collection(MilvusServiceClient milvusClient, String collection_name) {
    54. R rstatus = milvusClient.dropCollection(
    55. DropCollectionParam.newBuilder()
    56. .withCollectionName(collection_name)
    57. .build()
    58. );
    59. return buildResult(rstatus);
    60. }
    61. public static Map create_index(MilvusServiceClient milvusClient, String collection_name, String index_column, String index_name, String params) {
    62. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    63. log.warn("集合名称为空.");
    64. return MapUtil.builder("status", "1").build();
    65. }
    66. if (StringUtils.isEmpty(index_column) || StringUtils.isBlank(index_column)) {
    67. log.warn("索引字段为空.");
    68. return MapUtil.builder("status", "1").build();
    69. }
    70. if (StringUtils.isEmpty(index_name) || StringUtils.isBlank(index_name)) {
    71. log.warn("索引名称为空.");
    72. return MapUtil.builder("status", "1").build();
    73. }
    74. CreateIndexParam.Builder builder = CreateIndexParam.newBuilder()
    75. .withIndexName(index_name)
    76. .withCollectionName(collection_name)
    77. .withFieldName(index_column)
    78. .withIndexType(IndexType.IVF_FLAT)
    79. .withMetricType(MetricType.IP)
    80. .withSyncMode(Boolean.FALSE);
    81. if (StringUtils.isNotEmpty(index_name) && StringUtils.isNotBlank(index_name)) {
    82. builder = builder.withExtraParam(params);
    83. }
    84. R rstatus = milvusClient.createIndex(
    85. builder.build()
    86. );
    87. return buildResult(rstatus);
    88. }
    89. public static Map drop_index(MilvusServiceClient milvusClient, String collection_name, String index_name) {
    90. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    91. log.warn("集合名称为空.");
    92. return MapUtil.builder("status", "1").build();
    93. }
    94. if (StringUtils.isEmpty(index_name) || StringUtils.isBlank(index_name)) {
    95. log.warn("索引名称为空.");
    96. return MapUtil.builder("status", "1").build();
    97. }
    98. R rstatus = milvusClient.dropIndex(
    99. DropIndexParam.newBuilder()
    100. .withCollectionName(collection_name)
    101. .withIndexName(index_name)
    102. .build()
    103. );
    104. return buildResult(rstatus);
    105. }
    106. public static Map load_in_memory(MilvusServiceClient milvusClient, String collection_name) {
    107. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    108. log.warn("集合名称为空.");
    109. return MapUtil.builder("status", "1").build();
    110. }
    111. R rstatus = milvusClient.loadCollection(
    112. LoadCollectionParam.newBuilder()
    113. .withCollectionName(collection_name)
    114. .build()
    115. );
    116. return buildResult(rstatus);
    117. }
    118. public static Map unload_in_memory(MilvusServiceClient milvusClient, String collection_name) {
    119. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    120. log.warn("集合名称为空.");
    121. return MapUtil.builder("status", "1").build();
    122. }
    123. R rstatus = milvusClient.releaseCollection(
    124. ReleaseCollectionParam.newBuilder()
    125. .withCollectionName(collection_name)
    126. .build());
    127. return buildResult(rstatus);
    128. }
    129. public static void disconnection_db(MilvusServiceClient milvusServiceClient) {
    130. if (null != milvusServiceClient) {
    131. milvusServiceClient.close();
    132. milvusServiceClient = null;
    133. }
    134. }
    135. public static Map search_data_vector(MilvusServiceClient milvusClient, String collection_name, String fieldName, List> search_vectors, String params, int topK, List search_output_fields) {
    136. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    137. log.warn("集合名称为空.");
    138. return MapUtil.builder("status", "1").build();
    139. }
    140. if (StringUtils.isEmpty(fieldName) || StringUtils.isBlank(fieldName)) {
    141. log.warn("检索字段为空.");
    142. return MapUtil.builder("status", "1").build();
    143. }
    144. if (CollUtil.isEmpty(search_vectors) || CollUtil.isEmpty(search_vectors.get(0))) {
    145. log.warn("检索向量为空.");
    146. return MapUtil.builder("status", "1").build();
    147. }
    148. if (CollUtil.isEmpty(search_output_fields)) {
    149. log.warn("输出字段为空.");
    150. return MapUtil.builder("status", "1").build();
    151. }
    152. if (topK <= 1) {
    153. log.warn("topK少于1.");
    154. topK = 1;
    155. }
    156. SearchParam.Builder builder = SearchParam.newBuilder().withCollectionName(collection_name)
    157. .withConsistencyLevel(ConsistencyLevelEnum.STRONG)
    158. .withMetricType(MetricType.IP)
    159. .withOutFields(search_output_fields)
    160. .withTopK(topK)
    161. .withVectors(search_vectors)
    162. .withVectorFieldName(fieldName);
    163. if (StringUtils.isNotEmpty(params) && StringUtils.isNotBlank(params)) {
    164. builder.withParams(params);
    165. }
    166. SearchParam searchParam = builder.build();
    167. R respSearch = milvusClient.search(searchParam);
    168. String status = String.valueOf(respSearch.getStatus());
    169. MapBuilder mapBuilder = MapUtil.builder("status", status);
    170. if (StringUtils.equals(status, "0")) {
    171. SearchResults searchResults = respSearch.getData();
    172. if (null != searchResults) {
    173. SearchResultData searchResultData = searchResults.getResults();
    174. if (null != searchResultData) {
    175. long num_queries = searchResultData.getNumQueries();
    176. // log.info("num_queries: {}", num_queries);
    177. if (num_queries > 0) {
    178. FieldData fieldData = searchResultData.getFieldsData(0);
    179. if (null != fieldData) {
    180. ScalarField scalarField = fieldData.getScalars();
    181. if (null != scalarField.getStringData()) {
    182. String content = scalarField.getStringData().getData(0);
    183. mapBuilder.put("content", content);
    184. // log.info("content: {}", content);
    185. }
    186. }
    187. }
    188. }
    189. }
    190. }
    191. return mapBuilder.build();
    192. }
    193. public static Map insert_data(MilvusServiceClient milvusClient, String collection_name,List fields){
    194. if (StringUtils.isEmpty(collection_name) || StringUtils.isBlank(collection_name)) {
    195. log.warn("集合名称为空.");
    196. return MapUtil.builder("status", "1").build();
    197. }
    198. if (CollUtil.isEmpty(fields)) {
    199. log.warn("插入数据为空.");
    200. return MapUtil.builder("status", "1").build();
    201. }
    202. InsertParam insertParam = InsertParam.newBuilder()
    203. .withCollectionName(collection_name)
    204. .withFields(fields)
    205. .build();
    206. R mutationResultR = milvusClient.insert(insertParam);
    207. String status = String.valueOf(mutationResultR.getStatus());
    208. MapBuilder mapBuilder = MapUtil.builder("status", status);
    209. MutationResult mutationResult = mutationResultR.getData();
    210. if(null != mutationResult){
    211. long insert_cnt = mutationResult.getInsertCnt();
    212. if(insert_cnt > 0){
    213. mapBuilder.put("msg","插入成功");
    214. }
    215. }
    216. milvusClient.flush(FlushParam.newBuilder()
    217. .addCollectionName(collection_name)
    218. // .withSyncFlush(true)
    219. .build());
    220. log.info("MutationResult: {}",mutationResultR);
    221. return mapBuilder.build();
    222. }
    223. private final static Map buildResult(R rstatus) {
    224. // log.info("status: {}", rstatus);
    225. String status = String.valueOf(rstatus.getStatus());
    226. MapBuilder mapBuilder = MapUtil.builder("status", status);
    227. RpcStatus data = rstatus.getData();
    228. if (ObjectUtil.isNotEmpty(data)) {
    229. String msg = data.getMsg();
    230. if (StringUtils.isNotEmpty(msg) && StringUtils.isNotBlank(msg)) {
    231. mapBuilder.put("msg", msg);
    232. }
    233. }
    234. return mapBuilder.build();
    235. }
    236. public static void main(String[] args) {
    237. String uri = "http://192.168.10.56:19530";
    238. MilvusServiceClient milvusServiceClient = connect_db(uri);
    239. String collection_name = "tb_test11";
    240. // 创建集合
    241. FieldType fieldType1 = FieldType.newBuilder()
    242. .withName("id")
    243. .withDataType(DataType.Int64)
    244. .withPrimaryKey(true)
    245. .withAutoID(true)
    246. .build();
    247. FieldType fieldType2 = FieldType.newBuilder()
    248. .withName("keyword")
    249. .withDataType(DataType.FloatVector)
    250. .withDimension(256)
    251. .build();
    252. FieldType fieldType3 = FieldType.newBuilder()
    253. .withName("content")
    254. .withDataType(DataType.VarChar)
    255. .withMaxLength(4096)
    256. .build();
    257. List fieldTypes= CollUtil.list(Boolean.FALSE,fieldType1,fieldType2,fieldType3);
    258. String description = "the table of tb_test11";
    259. int shardsNum = 1;
    260. Map result = create_collection(milvusServiceClient, collection_name, description, shardsNum, fieldTypes);
    261. log.info("result: {}",result);
    262. // 插入数据
    263. // List vector = Arrays.asList(0.79558784f, 0.8433239f, -0.8132379f, -0.60343f, 0.8141689f, 0.49214464f, -1.3558795f, -1.5641332f, -1.5642508f, -1.5642508f, 0.90215206f, 0.79874355f, -0.5327561f, 0.8612926f, 0.84299415f, 0.79867285f, 0.8488582f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
    264. // String content = "标题:青春之光青春是一首歌,悠扬而激昂;青春是一幅画,斑斓而生动;青春是一部电影,感人至深。而在我心中,青春更是那个在奥运赛场上奔跑的刘翔。记得那是2004年的雅典奥运会,刘翔以12.91秒的成绩打破了世界纪录,成为中国田径历史上第一位获得奥运金牌的运动员。那一刻,我被他的坚韧和毅力深深打动,也深深地感受到了青春的力量。刘翔的青春,充满了挑战和奋斗。他曾经因为伤病困扰,一度想要放弃,但他没有。他知道,只有坚持下去,才能实现自己的梦想。于是,他在痛苦中挣扎,用汗水和泪水浇灌着自己的青春。终于,他成功了,他站在了奥运的最高领奖台上,成为了全中国的骄傲。刘翔的青春,充满了激情和活力。他是中国田径的一颗璀璨明星,他的每一次起跑都充满力量,他的每一次跨栏都充满速度。他的青春,就像一道闪电,照亮了整个赛场,也照亮了我们的心灵。刘翔的青春,充满了希望和梦想。他的梦想是成为最好的自己,他的希望是为中国赢得更多的荣誉。他的青春,就像一盏明灯,指引着他前进的方向,也激励着我们去追求自己的梦想。青春,就是要有梦想,有希望,有勇气去追逐。刘翔的青春,就是这样,充满了梦想、希望和勇气。他的青春,是我们所有人的青春,是我们所有人追求梦想的动力。青春,是一场无悔的旅程,无论前方有多少困难和挫折,只要我们有梦想,有希望,有勇气,就一定能够到达我们的目的地。让我们一起,像刘翔一样,用自己的青春,去创造属于我们自己的辉煌!";
    265. //
    266. // List contents = CollUtil.list(Boolean.FALSE,content);
    267. // List> vectors = new ArrayList<>();
    268. // vectors.add(vector);
    269. //
    270. // List fields = new ArrayList<>();
    271. // fields.add(new InsertParam.Field("keyword", vectors));
    272. // fields.add(new InsertParam.Field("content", contents));
    273. //
    274. // Map result = insert_data(milvusServiceClient,collection_name,fields);
    275. // log.info("result: {}",result);
    276. // 创建索引
    277. // String index_column = "keyword";
    278. // String index_name = "idx_keyword";
    279. // String params = "{\"nlist\":65536}";
    280. // Map result = create_index(milvusServiceClient, collection_name, index_column, index_name, params);
    281. // log.info("result: {}", result);
    282. // 删除索引
    283. // Map result = drop_index(milvusServiceClient, collection_name,index_name);
    284. // log.info("result: {}", result);
    285. // 装载至内存
    286. // Map result = load_in_memory(milvusServiceClient, collection_name);
    287. // log.info("result: {}",result);
    288. // 向量查询
    289. // List search_output_fields = Arrays.asList("content");
    290. // List> search_vectors = Arrays.asList(Arrays.asList(0.79558784f, 0.8433239f, -0.8132379f, -0.60343f, 0.8141689f, 0.49214464f, -1.3558795f, -1.5641332f, -1.5642508f, -1.5642508f, 0.90215206f, 0.79874355f, -0.5327561f, 0.8612926f, 0.84299415f, 0.79867285f, 0.8488582f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
    291. // String fieldName = "keyword";
    292. // int topK = 1;
    293. //
    294. // Map result = search_data_vector(milvusServiceClient, collection_name, fieldName, search_vectors, null, topK, search_output_fields);
    295. // log.info("result: {}", result);
    296. // 删除集合
    297. // Map result = drop_collection(milvusServiceClient, collection_name);
    298. // log.info("result: {}", result);
    299. disconnection_db(milvusServiceClient);
    300. }
    301. }

  • 相关阅读:
    基于多智能体强化学习的出租车调度框架
    Review of Algorithm (HITSZ)
    工地安全帽佩戴识别系统
    【环境配置】基于Docker配置Chisel-Bootcamp环境
    python教程:列表[list]和元组(tuple)
    [开发|鸿蒙] 鸿蒙OS开发环境搭建(笔记,持续更新)
    【Unity】U3D TD游戏制作实例(三)相机管理器、生成敌人优化、敌人血槽小组件
    使用 PyTorch 的计算机视觉简介 (3/6)
    学习react,复制一个civitai(C站)-更新3
    python模块的介绍和导入
  • 原文地址:https://blog.csdn.net/qq839019311/article/details/136170245