基于Milevus的ANN服务踩坑

基于Milvus的ANN服务踩坑

坑1:Exception in thread “main” java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

SLF4J jar 需要被添加到classpath

添加依赖。

 <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-api</artifactId>
     <version>1.7.30</version>
 </dependency>

坑2:NoClassDefFoundError: org/apache/logging/log4j/util/StackLocatorUtil

项目中已经有log4j了,与milevus-sdk.pom中的log4j产生冲突,将其exclusion即可。

<dependency>
    <groupId>io.milvus</groupId>
    <artifactId>milvus-sdk-java</artifactId>
<!--    <version>0.8.2</version>-->
    <version>0.6.0</version>
    <exclusions>
        <exclusion>
            <artifactId>log4j-slf4j-impl</artifactId>
            <groupId>org.apache.logging.log4j</groupId>
        </exclusion>
    </exclusions>
</dependency>

坑3:NoClassDefFoundError: com/google/protobuf/GeneratedMessageV3

milevus-sdk中的protobuf依赖没生效,需要在当前项目中显示添加protobuf依赖。(注意版本要一致)

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java-util</artifactId>
    <version>3.11.0</version>
</dependency>

坑4:NoSuchMethodError:com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;J)V

原因是当前guava版本过低。

升级:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
<!--<version>18.0</version>-->
    <version>23.6-jre</version>
</dependency>

坑5:查询较慢
1、可能是milevus服务端参数cache配置过小,(cache_config.cpu_cache_capacity),此配置默认是4G,如果存的向量容量大于4G,就会很慢。
2、可能是没有显示手动创建索引


使用case

先连接milevus,再创建collection,并在collection里创建index,之后根据需要在collection里创建分区,最后往collection里对应的分区里插数据。
连接milevus

public static MilvusClient getMilevusClient(String host, int port) {

        logger.info("prepared to getMilevusClient...");
        if (milvusClient == null || !milvusClient.isConnected()) {

            milvusClient = new MilvusGrpcClient();
            ConnectParam connectParam = new ConnectParam.Builder()
                    .withHost(host)
                    .withPort(port)
                    .withConnectTimeout(10, TimeUnit.SECONDS)
                    .build();
            logger.info("getMilevusClient milvusClient: {}, connected: {}", milvusClient, milvusClient.isConnected());
            try {
                Response connectResponse = milvusClient.connect(connectParam);
            } catch (ConnectFailedException e) {
                System.out.println("Failed to connect to Milvus server: " + e.toString());
                logger.error("Failed to connect to Milvus server: {}", e);
            }

            logger.info("getMilevusClient milevus isConnected: {}", milvusClient.isConnected());
            return milvusClient.isConnected() ? milvusClient : null;
        }

        return milvusClient;
    }

检查collection并创建
现在milevus不支持字符串索引,所以需要将业务端id与milevusid的id映射关系存下来,这里选型MongoDB。

try {
    // check partiton exist
    HasPartitionResponse isPartitionExist = milvusClient.hasPartition(collectionName, partitionName);
    if (isPartitionExist.ok() && !isPartitionExist.hasPartition()) {
        // create partition
        milvusClient.createPartition(collectionName, partitionName);
    }

    // batch insert id mapping to mongo
    MongoUtils.batchInsertDocList(mongoClient, ANN_DATABASE_NAME, ANN_COLLECTION_NAME, documentList);
    logger.info("success to insert to mongo, documentList size is: {}", documentList.size());
    System.out.println("batch inserting to mongo...");

    // batch insert to milvus
    InsertParam insertParam = new InsertParam
            .Builder(collectionName)
            .withPartitionTag(partitionName)
            .withFloatVectors(batchVectorList)
            .withVectorIds(batchMilevusIdList)
            .build();
    logger.info("batchVectorList size: {}", batchVectorList.size());
    logger.info("batchMilevusIdList size: {}", batchMilevusIdList.size());
    ListenableFuture<InsertResponse> insertResponse = milvusClient.insertAsync(insertParam);
    
} catch (Exception e) {
    logger.error("batch insert occur error, exp: {}", e);
    System.out.println(Arrays.toString(e.getStackTrace()));
}

注意
如果选择内积作为衡量向量相似度的指标(即IP),需要在向量导入前做归一化。

 static List<Float> normalizeVector(List<Float> vector) {
     float squareSum = vector.stream().map(x -> x * x).reduce((float) 0, Float::sum);
     final float norm = (float) Math.sqrt(squareSum);
     vector = vector.stream().map(x -> x / norm).collect(Collectors.toList());
     return vector;
 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于ANN(人工神经网络)和KNN(k最近邻)的图像分类是两种常用的机器学习算法。它们都可以用于解决图像分类问题。 首先,ANN是一种通过模拟人类神经系统的结构和功能来处理信息的机器学习模型。对于图像分类,ANN可以从图像中提取特征,并将其输入到神经网络中进行训练。神经网络是一种由多个层次组成的模型,每一层都由多个神经元组成。通过不断调整神经元之间的连接权重,神经网络可以学习到图像中不同特征之间的关系。训练完成后,ANN可以对未知图像进行分类,识别图像中的对象或模式。 而KNN算法则是一种基于实例的学习方法,它通过计算已知样本集中与未知样本最相似的k个样本,来进行分类。对于图像分类问题,KNN可以使用已知图像的特征向量作为样本集,然后计算未知图像特征向量与已知图像特征向量之间的距离。距离最近的k个样本可以决定未知图像的类别。 相比而言,ANN在训练时有更强的学习能力,可以通过调整权重来获得更准确的分类结果。然而,ANN训练的过程可能较为复杂且耗时。而KNN则是一种简单且易于实现的算法,但对于大规模图像分类可能面临计算能力和存储空间的限制。 综上所述,基于ANN和KNN的图像分类算法各有优缺点,可以根据实际需求选择。对于大规模图像分类任务,可以考虑使用ANN来进行深度学习;而对于小规模数据集和简单的图像分类问题,KNN也是一种不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值