使用Milvus搭建以图搜图服务

使用Milvus搭建以图搜图服务

  • 介绍
  • 安装Milvus
  • Java调用Milvus插入、查询
    • 引入Maven依赖
    • 创建Milvus客户端
    • 实现Milvus插入向量数据
    • 实现Milvus 查询向量
  • 结尾

介绍

网上相关的实现比较少,最多也只能查到Milvus,但不知道怎么使用。最后通过ChatGPT了解到了相关的使用方法,协助实现了以图搜图。

安装Milvus

先下载官网提供的milvus docker-compose文件

wget https://github.com/milvus-io/milvus/releases/download/v2.2.4/milvus-standalone-docker-compose.yml -O docker-compose.yml

修改yml文件配置,参考如下:

version: '3.5'services:etcd:container_name: milvus-etcdimage: quay.io/coreos/etcd:v3.5.5environment:- ETCD_AUTO_COMPACTION_MODE=revision- ETCD_AUTO_COMPACTION_RETENTION=1000- ETCD_QUOTA_BACKEND_BYTES=4294967296- ETCD_SNAPSHOT_COUNT=50000volumes:- /z/software/etcd:/etcdcommand: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcdminio:container_name: milvus-minioimage: minio/minio:RELEASE.2022-03-17T06-34-49Zenvironment:MINIO_ACCESS_KEY: minioadminMINIO_SECRET_KEY: minioadmin#ports:#- "9001:9001"#- "9000:9000"volumes:- /z/software/minio:/minio_datacommand: minio server /minio_data --console-address ":9001"healthcheck:test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]interval: 30stimeout: 20sretries: 3standalone:container_name: milvus-standaloneimage: milvusdb/milvus:v2.2.4command: ["milvus", "run", "standalone"]environment:ETCD_ENDPOINTS: etcd:2379MINIO_ADDRESS: minio:9000LOG_LEVEL: infovolumes:- /z/software/milvus:/var/lib/milvusports:- "19530:19530"depends_on:- "etcd"- "minio"networks:default:name: milvus-network

PS1:除了Milvus服务外,没有开放minio和etcd的端口,服务也可以互相访问
PS2:milvus默认端口为19530,可按需修改,用于服务调用,外网访问需要开放该端口

启动容器

docker-compose -f <docker-compose.yml位置> up -d

查看日志

docker logs -f --tail=200 milvus-standalone

启动日志
至此,服务已经搭建完成,以下为Java实现

Java调用Milvus插入、查询

引入Maven依赖

<dependency><groupId>io.milvus</groupId><artifactId>milvus-sdk-java</artifactId>
</dependency>
<dependency><groupId>org.deeplearning4j</groupId><artifactId>deeplearning4j-core</artifactId>
</dependency>
<dependency><groupId>org.nd4j</groupId><artifactId>nd4j-native-platform</artifactId>
</dependency>
<dependency><groupId>org.deeplearning4j</groupId><artifactId>deeplearning4j-zoo</artifactId>
</dependency>

启动如果提示sfl4jlog4j 错误,说明本地依赖冲突需要排除。

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

启动如果提示guava,缺少guava依赖

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId>
</dependency>
  • milvus-sdk-java为milvus的Java SDK
  • deeplearning4j为深度学习模型工具

创建Milvus客户端

public MilvusServiceClient milvusServiceClient() {return new MilvusServiceClient(ConnectParam.newBuilder().withHost(serviceHost).withPort(servicePort).build());
}

实现Milvus插入向量数据

  • 步骤一:将图片转换为向量数组
// 加载ResNet50模型
ZooModel<?> zooModel = ResNet50.builder().build();
ComputationGraph pretrainedNet = (ComputationGraph) zooModel.initPretrained();
NativeImageLoader loader = new NativeImageLoader(224, 224, 3);
// 加载文件到内存,生成INDArray
INDArray image = loader.asMatrix(<File对象>);
// 加载向量
GraphVertex vertex = pretrainedNet.getVertices()[pretrainedNet.getVertices().length - 1];
INDArray features = pretrainedNet.feedForward(image, false).get(vertex.getVertexName());
float[] vector = features.toFloatVector();
  • 步骤二:检查Milvus中Collection是否存在不存在则创建(Collection可以理解为数据库表)
private void checkCollection(String collectionName) {// 获取集合R<Boolean> collection = serviceClient.hasCollection(HasCollectionParam.newBuilder().withCollectionName(collectionName).build());if (!collection.getData()) {// 创建集合serviceClient.createCollection(createCollection(collectionName));}
}
/*** 以下为自定义字段,必须存在一个FloatVector类型字段,必须设置主键,没有可以用自增*/
private CreateCollectionParam createCollection(String collectionName){return CreateCollectionParam.newBuilder().withCollectionName(collectionName)// id 主键 必须有一个主键,也可以自动生成主键使用withAutoID(true).addFieldType(FieldType.newBuilder().withPrimaryKey(true).withName("id").withDataType(DataType.VarChar).withMaxLength(100).build()).addFieldType(FieldType.newBuilder().withName("name").withDataType(DataType.VarChar).withMaxLength(100).build()).addFieldType(FieldType.newBuilder().withName("url").withDataType(DataType.VarChar).withMaxLength(500).build()).addFieldType(FieldType.newBuilder().withName("vector").withDataType(DataType.FloatVector).withDimension(1000).build()).build();
}
  • 步骤三:检查Milvus的Collection是否存在索引,不存在则创建,必须有一个向量索引
private void checkCollectionIndex(String collectionName) {// 查询索引 返回0代表未创建索引需要创建索引R<DescribeIndexResponse> indexResult = serviceClient.describeIndex(DescribeIndexParam.newBuilder().withCollectionName(collectionName).build());if (indexResult.getStatus() == R.Status.IndexNotExist.getCode()) {// 创建索引serviceClient.createIndex(createCollectionIndex(collectionName));}
}
privateCreateIndexParam createCollectionIndex(String collectionName) {return CreateIndexParam.newBuilder().withCollectionName(collectionName)// 需要加索引的字段名称.withFieldName("vector")  .withMetricType(MetricType.IP).withSyncMode(Boolean.FALSE).withIndexType(IndexType.IVF_FLAT).withExtraParam(JSONUtil.createObj().set("nlist", "1024").toString()).build();
}
  • 步骤四:向Milvus插入向量数组
List<InsertParam.Field> multiVectors = new ArrayList<>();
multiVectors.add(new InsertParam.Field("id", Collections.singletonList(IdUtil.randomId())));
multiVectors.add(new InsertParam.Field("name", Collections.singletonList("名称")));
multiVectors.add(new InsertParam.Field("url", Collections.singletonList("图片地址")));
multiVectors.add(new InsertParam.Field("vector", Collections.singletonList(Floats.asList(vector))));
R<MutationResult> insertResult = serviceClient.insert(InsertParam.newBuilder().withCollectionName(collectionName).withFields(multiVectors).build());
if (insertResult.getStatus() == R.Status.Success.getCode()) {log.info("插入向量成功! id:{},url:{},vectorSize:{}", imageDTO.getCollectionId(), imageDTO.getUrl(), vector.length);
}
  • 步骤五:刷新索引
    Milvus插入向量后不会立即刷新索引,所以新增后可能无法查询出。可以使用如下方法刷新索引
// 刷新索引
serviceClient.flush(FlushParam.newBuilder().addCollectionName(collectionName).withSyncFlush(false).build());

实现Milvus 查询向量

  • 步骤一:将搜索的图片转换为向量
// 加载ResNet50模型
ZooModel<?> zooModel = ResNet50.builder().build();
ComputationGraph pretrainedNet = (ComputationGraph) zooModel.initPretrained();
NativeImageLoader loader = new NativeImageLoader(224, 224, 3);
// 加载文件到内存,生成INDArray
INDArray image = loader.asMatrix(<File对象>);
// 加载向量
GraphVertex vertex = pretrainedNet.getVertices()[pretrainedNet.getVertices().length - 1];
INDArray features = pretrainedNet.feedForward(image, false).get(vertex.getVertexName());
float[] vector = features.toFloatVector();
  • 步骤二:将Collection加载到内存中(必须先加载内存后才可以查询
R<RpcStatus>loadResult = serviceClient.loadCollection(LoadCollectionParam.newBuilder().withCollectionName(collectionName).withSyncLoad(true).build());
if (loadResult.getStatus() != R.Status.Success.getCode()){log.error("加载到内存失败了!ex={}", loadResult.getMessage());
}
  • 步骤三:查询向量,以及相关字段信息
R<SearchResults> searchResult = serviceClient.search(SearchParam.newBuilder().withCollectionName(collectionName)// 设置返回最相似的图片数量.withTopK(10).withConsistencyLevel(ConsistencyLevelEnum.STRONG).withMetricType(MetricType.IP)// 返回的字段信息.withOutFields(Arrays.asList("id", "name", "url"))// 设置向量字段的名称.withVectorFieldName("vector").withVectors(Collections.singletonList(Floats.asList(vector)))// nprobe是指在搜索时需要遍历的最大倒排列表数,它的值越大,搜索速度越慢,但搜索精度越高// offset 偏移量,limit 每页查询数量,offset 从0开始.withParams(JSONUtil.createObj().set("nprobe", 30).set("offset", 0).set("limit", 30).toString()).build());
  • 步骤四:获取响应结果
if (searchResult.getStatus() == R.Status.Success.getCode()){SearchResultsWrapper resultsWrapper = new SearchResultsWrapper(searchResult.getData().getResults());if (searchResult.getData().getResults().getIds().hasIntId()) {List<SearchResult> resultList = new ArrayList<>();for (int i = 0; i < resultsWrapper.getIDScore(0).size(); i++) {SearchResult entity = new SearchResult();entity.setId((Long)(resultsWrapper.getFieldData("id", 0).get(i)));entity.setName((String) (resultsWrapper.getFieldData("name", 0).get(i)));entity.setUrl((String) resultsWrapper.getFieldData("url", 0).get(i));resultList.add(entity);}return resultList;}
}

SearchResult:为自定义对象,用于返回给前端。

  • 步骤五:释放内存
// 释放搜索加载的集合,以减少搜索完成后的内存消耗
serviceClient.releaseCollection(ReleaseCollectionParam.newBuilder().withCollectionName(collectionName).build());

结尾

目前查询有点慢,需要3~5秒,也可能是服务器性能不够,具体的优化还需要深入了解。

第一次写文章,写的不好请见谅,如有更好的方法可以评论区讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/18289.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

chatgpt赋能python:Python在SEO中的应用之以图找图

Python在SEO中的应用之以图找图 在SEO优化中&#xff0c;一个重要的环节是优化图片&#xff0c;而通过利用Python编写的代码&#xff0c;可以实现以图搜图&#xff0c;简化了图片优化的流程和提高了优化效率。 什么是以图找图 以图搜图&#xff0c;即通过一张已知图片搜索出…

自研芯片架构 ,这家中国公司发布DPU芯片计划

近日,专注于智能计算领域的DPU芯片和解决方案公司中科驭数发布了其下一代DPU芯片计划&#xff0c;将基于自研的KPU&#xff08;Kernel Processing Unit&#xff09;芯片架构&#xff0c;围绕网络协议处理、数据库和大数据处理加速、存储运算、安全加密运算等核心功能&#xff0…

十大芯片公司盘点,转行怎么选择芯片设计公司?

不少同学想要入行IC&#xff0c;想要了解IC行业哪些公司比较有前景&#xff1f;芯片设计公司哪家强&#xff1f;下面IC修真院就来为大家盘点一下&#xff01; 中国十大芯片企业排名 1.海思Hisilicon 2.Spreadtrum展讯 3.龙芯loongson 4.兆易创新GigaDevice 5.汇顶GOODIX 6.华大…

全球爆火的ChatGPT,能否推动芯片市场增长?

“我所热爱的是我真实的生活&#xff0c;因为它包含了我所有的经历和感受&#xff0c;是我每一天都在体验和思考的。”这句非常有诗意的话&#xff0c;来自最近爆火的ChatGPT。 ChatGPT作为一款智能机器人&#xff0c;上知天文下知地理&#xff0c;不仅能写文案&#xff0c;还…

拿走!H5版本ChatGPT开源等你

近些日子忙里偷闲的研究chatGPT&#xff0c;也小弄了一个公众号版本&#xff0c;一个H5版本的&#xff0c;现在H5版本的也就是开放给大家体验的版本&#xff0c;还不知道的伙伴可以关注#公众号&#xff1a;李连活&#xff0c;回复“888”领取体验&#xff0c;和AI畅快聊天问答。…

ChatGPT分销版如何接入文心一言(文心千帆)?

对于ChatGPT分销版的对话通道接入还是比较简单的&#xff0c;为什么这么久才接入&#xff1f; 其实很久之前我们就在申请接入百度的文心一言&#xff08;文心千帆&#xff09;&#xff0c;但是最之前的条件确实太苛刻了&#xff0c;需要签订各种协议以及缴纳各种费用&#xff0…

GPT-4震撼发布:多模态大模型,直接升级ChatGPT、必应,开放API,游戏终结了?...

ChatGPT 点燃了科技行业的明灯&#xff0c;GPT-4 能燎原吗&#xff1f; 谁能革得了 ChatGPT 的命&#xff1f;现在看来还是 OpenAI 自己。 在 ChatGPT 引爆科技领域之后&#xff0c;人们一直在讨论 AI「下一步」的发展会是什么&#xff0c;很多学者都提到了多模态&#xff0c;我…

(抛砖引玉)用好chatgpt小帮手,写一个实验室管理系统

本文用实际案例描述了如何用好chatgpt做一些小程序&#xff0c;主要是写给缺乏实际编程经验但又不得不硬着头皮上的同学。 大佬们可以直接飘过~ 目前兼着实验室管理员的工作&#xff0c;众做周知&#xff0c;电子工程师的实验室一般来说都是杂乱无章的&#xff0c;没有设备维护…

GPT发展史

不知道大家是否还记得年初刷屏的 DALLE2 &#xff1f;因为它的爆火&#xff0c;大家开始不约而同的讨论起 AI 绘画会不会代替设计师的工作&#xff0c;这个话题至今还被人常常提起。最近&#xff0c;OpenAI 再放大招&#xff0c;推出的 ChatGPT 席卷网络&#xff0c;大家又开始…

IEEE IS评选AI十大新星,9位华人获奖

最近人工智能领域著名杂志 IEEE Intelligent Systems公布了 2022 年度「人工智能十大新星」&#xff08;AIs 10 to Watch&#xff09;名单 &#xff0c;其中有九位都是华人研究者。 推荐阅读&#xff1a; ▶不愁失业&#xff01;英伟达 CEO 黄仁勋&#xff1a;“AI 让每个人都能…

死磕数据库系列(三十二):MySQL 数据库、数据表管理工具介绍

关注公众号&#xff0c;回复“1024”获取2TB学习资源&#xff01; 今天我将详细的为大家介绍 MySQL 数据库、数据表相关工具的相关知识&#xff0c;希望大家能够从中收获多多&#xff01;如有帮助&#xff0c;请点在看、转发支持一波&#xff01;&#xff01;&#xff01; 数据…

IBM停止招聘可被AI取代的职位;三星禁止员工使用ChatGPT;印象笔记官方AI免费课;清华美院AI绘画的高质量分享 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 『IBM将停止招聘可被人工智能取代的职位』近8000名工人将被自动化取代 据彭博社报道&#xff0c;IBM首席执行官Arvind Krishna表示&am…

死磕数据库系列(三十一):MySQL 服务器 CPU、磁盘、内存等硬件选型

点关注公众号&#xff0c;回复“1024”获取2TB学习资源&#xff01; 今天我将详细的为大家介绍 MySQL 服务器的磁盘及相关硬件选型的相关知识&#xff0c;希望大家能够从中收获多多&#xff01;如有帮助&#xff0c;请点在看、转发支持一波&#xff01;&#xff01;更多关于MyS…

Linux 中 root 与 sudo 的用法与区别,居然这么多人搞不清楚。。。

点关注公众号&#xff0c;回复“1024”获取2TB学习资源&#xff01; Linux 下面有两个概念可能大家接触的比较多&#xff0c;一个是 sudo 命令&#xff0c;还有一个是 root 账户。Sudo 命令可以以最高权限执行命令&#xff0c;而 root 账户下所有命令都有最高权限&#xff0c;也…

面试官:TCP 连接数最大不能超过 65535?那服务器是如何应对百万千万并发的?...

点关注公众号&#xff0c;回复“1024”获取2TB学习资源&#xff01; 最大并发 tcp 连接数是多少呢&#xff1f; 首先&#xff0c;问题中描述的65535个连接指的是客户端连接数的限制。 在tcp应用中&#xff0c;server事先在某个固定端口监听&#xff0c;client主动发起连接&…

2023年春秋杯网络安全联赛春季赛 RE复盘(部分待补)

目录 sum Pytrans BWBA Poisoned_tea_CHELL 第一种找程序加密函数的方法 第二种找程序加密函数的方法 解密 这次的春季赛仍是被打爆了&#xff0c;re只做出了一题&#xff0c;发现自己还是太菜了&#xff0c;好在在后期复盘中又收获了许多新知识了&#xff0c;不亏。 su…

2023春秋杯春季赛WP-REVERSE(AK)

REVERSE sumPoisoned_tea_CHELLBWBAPytransEmoji ConnectOldSymbolicCode 浅浅写一下RE的WP~ sum 根据代码&#xff0c;可以看出程序只能输入数字&#xff0c;判断matrix数组对应下标的值是否为0&#xff0c;如果为0&#xff0c;则可以输入一个字符&#xff0c;根据代码逻辑&a…

Servlet基础学习

什么是Servlet&#xff1f; Servlet是一种用于接收web网页传回和输出到web的一个Java类&#xff0c;根据不同的实际需要&#xff0c;实现不同的Servlet来对网页数据进行处理。 Servlet的基本处理流程 在网页发起请求之后&#xff0c;编译器首先去寻找web网页的配置文件&…

react仿微信聊天室|react即时聊天IM系统|react群聊

reactredux仿微信聊天IM实战|react仿微信界面|react多人群聊天室 最近一直捣鼓react开发&#xff0c;就运用react开发了个仿微信聊天室reactChatRoom项目&#xff0c;基于reactreact-domreact-router-domreduxreact-reduxwebpack2.0antdesignwcPop等技术混合开发&#xff0c;实…

DES加密解密 Feistel算法网络结构 详讲

文章目录 简单知识导入&#xff1a;具体过程&#xff1a;IP置换&#xff08; 64 − > 64 64->64 64−>64&#xff09;轮函数--E扩展置换&#xff08; 32 − > 48 32->48 32−>48&#xff09;轮函数--与子密钥异或&#xff08; 48 − > 48 48->48 48−&…