SpringBoot集成Milvus和deeplearning4j實現(xiàn)圖搜圖功能
1.什么是Milvus?
Milvus 是一種高性能、高擴展性的向量數(shù)據(jù)庫,可在從筆記本電腦到大型分布式系統(tǒng)等各種環(huán)境中高效運行。它既可以開源軟件的形式提供,也可以云服務的形式提供。 Milvus 是 LF AI & Data Foundation 下的一個開源項目,以 Apache 2.0 許可發(fā)布。大多數(shù)貢獻者都是高性能計算(HPC)領(lǐng)域的專家,擅長構(gòu)建大型系統(tǒng)和優(yōu)化硬件感知代碼。核心貢獻者包括來自 Zilliz、ARM、NVIDIA、AMD、英特爾、Meta、IBM、Salesforce、阿里巴巴和微軟的專業(yè)人士
2.什么是deeplearning4j?
Deeplearning4j(DL4J)是一個開源的深度學習框架,專門為Java和Scala開發(fā)。它支持分布式計算,適合在大數(shù)據(jù)環(huán)境中運行,比如與Hadoop或Spark集成。DL4J的特點包括:
- 多種網(wǎng)絡(luò)架構(gòu):支持多種深度學習模型,包括卷積神經(jīng)網(wǎng)絡(luò)(CNN)、循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)和深度信念網(wǎng)絡(luò)(DBN)。
- 集成與可擴展性:能夠與大數(shù)據(jù)處理框架(如Apache Spark)和數(shù)據(jù)處理庫(如ND4J)緊密集成,方便處理大規(guī)模數(shù)據(jù)集。
- 易于使用:提供高層API,簡化模型構(gòu)建和訓練過程,同時也允許用戶對底層實現(xiàn)進行細致的控制。
- 模型導入與導出:支持從其他框架(如Keras和TensorFlow)導入模型,并將訓練好的模型導出為多種格式,以便于部署。
- 性能優(yōu)化:支持多種硬件加速,包括GPU加速,能夠提高訓練和推理的效率。
- 支持多種應用場景:廣泛應用于計算機視覺、自然語言處理、推薦系統(tǒng)等多個領(lǐng)域。
Deeplearning4j是企業(yè)和開發(fā)者進行深度學習開發(fā)和研究的強大工具,特別適合于需要與Java生態(tài)系統(tǒng)兼容的場景。
3.環(huán)境搭建
- First, we’ll need an instance of Milvus DB. The easiest and quickest way is to get a fully managed free Milvus DB instance provided by Zilliz Cloud: zilliz.com/
- For this, we’ll need to register for a Zilliz cloud account and follow the documentation for creating a free DB cluster.

4.代碼工程
實驗目標
利用Milvus和deeplearning4j實現(xiàn)圖搜圖功能
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Milvus</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<deeplearning4j.version>1.0.0-M2.1</deeplearning4j.version>
<nd4j.version>1.0.0-M2.1</nd4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.milvus</groupId>
<artifactId>milvus-sdk-java</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.deeplearning4j</groupId>
<artifactId>deeplearning4j-zoo</artifactId>
<version>${deeplearning4j.version}</version>
</dependency>
<dependency>
<groupId>org.nd4j</groupId>
<artifactId>nd4j-native-platform</artifactId>
<version>${nd4j.version}</version>
</dependency>
<dependency>
<groupId>org.datavec</groupId>
<artifactId>datavec-data-image</artifactId>
<version>${deeplearning4j.version}</version>
</dependency>
<dependency>
<groupId>org.deeplearning4j</groupId>
<artifactId>deeplearning4j-core</artifactId>
<version>${deeplearning4j.version}</version>
</dependency>
<dependency>
<groupId>org.deeplearning4j</groupId>
<artifactId>deeplearning4j-modelimport</artifactId>
<version>${deeplearning4j.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<fork>true</fork>
<failOnError>false</failOnError>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<forkCount>0</forkCount>
<failIfNoTests>false</failIfNoTests>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
特征抽取
package com.et.imagesearch;
import org.deeplearning4j.zoo.model.ResNet50;
import org.deeplearning4j.zoo.ZooModel;
import org.deeplearning4j.nn.graph.ComputationGraph;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.dataset.api.preprocessor.ImagePreProcessingScaler;
import org.datavec.image.loader.NativeImageLoader;
import java.io.File;
import java.io.IOException;
public class FeatureExtractor {
private ComputationGraph model;
public FeatureExtractor() throws IOException {
try {
ZooModel<ComputationGraph> zooModel = ResNet50.builder().build();
model = (ComputationGraph) zooModel.initPretrained();
} catch (Exception e) {
throw new IOException("Failed to initialize the pre-trained model: " + e.getMessage(), e);
}
}
public INDArray extractFeatures(File imageFile) throws IOException {
NativeImageLoader loader = new NativeImageLoader(224, 224, 3);
INDArray image = loader.asMatrix(imageFile);
ImagePreProcessingScaler scaler = new ImagePreProcessingScaler(0, 1);
scaler.transform(image);
return model.outputSingle(image);
}
}
- 加載圖像: 使用
NativeImageLoader將圖像加載為一個INDArray,并將圖像的大小調(diào)整為 224x224 像素,通道數(shù)為 3(即 RGB 圖像)。 - 預處理圖像: 使用
ImagePreProcessingScaler將圖像數(shù)據(jù)縮放到 [0, 1] 的范圍,以便模型可以更好地處理。 - 特征提取: 使用模型的
outputSingle()方法將預處理后的圖像輸入模型,返回提取的特征向量。
Milvus數(shù)據(jù)庫操作
package com.et.imagesearch;
import io.milvus.client.*;
import io.milvus.param.*;
import io.milvus.param.collection.*;
import io.milvus.param.dml.*;
import io.milvus.grpc.*;
import io.milvus.param.index.CreateIndexParam;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class MilvusManager {
private MilvusServiceClient milvusClient;
public MilvusManager() {
milvusClient = new MilvusServiceClient(
ConnectParam.newBuilder()
.withUri("https://xxx.gcp-us-west1.cloud.zilliz.com")
.withToken("xxx")
.build());
}
public void createCollection() {
FieldType idField = FieldType.newBuilder()
.withName("id")
.withDataType(DataType.Int64)
.withPrimaryKey(true)
.build();
FieldType vectorField = FieldType.newBuilder()
.withName("embedding")
.withDataType(DataType.FloatVector)
.withDimension(1000)
.build();
CreateCollectionParam createCollectionParam = CreateCollectionParam.newBuilder()
.withCollectionName("image_collection")
.withDescription("Image collection")
.withShardsNum(2)
.addFieldType(idField)
.addFieldType(vectorField)
.build();
milvusClient.createCollection(createCollectionParam);
}
public void insertData(long id, INDArray features) {
List<Long> ids = Collections.singletonList(id);
float[] floatArray = features.toFloatVector();
List<Float> floatList = new ArrayList<>();
for (float f : floatArray) {
floatList.add(f);
}
List<List<Float>> vectors = Collections.singletonList(floatList);
List<InsertParam.Field> fields = new ArrayList<>();
fields.add(new InsertParam.Field("id",ids));
fields.add(new InsertParam.Field("embedding", vectors));
InsertParam insertParam = InsertParam.newBuilder()
.withCollectionName("image_collection")
.withFields(fields)
.build();
milvusClient.insert(insertParam);
}
public void flush() {
milvusClient.flush(FlushParam.newBuilder()
.withCollectionNames(Collections.singletonList("image_collection"))
.withSyncFlush(true)
.withSyncFlushWaitingInterval(50L)
.withSyncFlushWaitingTimeout(30L)
.build());
}
public void buildindex() {
// build index
System.out.println("Building AutoIndex...");
final IndexType INDEX_TYPE = IndexType.AUTOINDEX; // IndexType
long startIndexTime = System.currentTimeMillis();
R<RpcStatus> indexR = milvusClient.createIndex(
CreateIndexParam.newBuilder()
.withCollectionName("image_collection")
.withFieldName("embedding")
.withIndexType(INDEX_TYPE)
.withMetricType(MetricType.L2)
.withSyncMode(Boolean.TRUE)
.withSyncWaitingInterval(500L)
.withSyncWaitingTimeout(30L)
.build());
long endIndexTime = System.currentTimeMillis();
System.out.println("Succeed in " + (endIndexTime - startIndexTime) / 1000.00 + " seconds!");
}
}
- createCollection():
- 創(chuàng)建一個名為
image_collection的集合,包含兩個字段:- id: 主鍵,類型為
Int64。 - embedding: 特征向量,類型為
FloatVector,維度為 1000。
- id: 主鍵,類型為
- 使用
CreateCollectionParam指定集合的名稱、描述和分片數(shù)量,并調(diào)用createCollection方法執(zhí)行創(chuàng)建操作。
- 創(chuàng)建一個名為
- insertData(long id, INDArray features):
- 插入一條新數(shù)據(jù)到
image_collection集合中。 - 將
INDArray類型的特征向量轉(zhuǎn)換為List<List<Float>>格式,以滿足 Milvus 的插入要求。 - 創(chuàng)建一個
InsertParam實例,包含 ID 和特征向量,并調(diào)用insert方法執(zhí)行插入操作。
- 插入一條新數(shù)據(jù)到
- flush():
- 刷新
image_collection集合,確保所有待處理的插入操作都被寫入數(shù)據(jù)庫。 - 使用
FlushParam配置同步刷新模式和等待參數(shù),確保操作的可靠性。
- 刷新
- buildindex():
- 構(gòu)建
image_collection集合中embedding字段的索引,以加快后續(xù)的相似性搜索。 - 使用
CreateIndexParam指定集合名稱、字段名稱、索引類型(自動索引)和度量類型(L2距離)。 - 調(diào)用
createIndex方法執(zhí)行索引創(chuàng)建,并輸出所用時間。
- 構(gòu)建
圖片搜索功能
package com.et.imagesearch;
import io.milvus.client.MilvusServiceClient;
import io.milvus.grpc.SearchResults;
import io.milvus.param.ConnectParam;
import io.milvus.param.MetricType;
import io.milvus.param.R;
import io.milvus.param.dml.SearchParam;
import io.milvus.response.SearchResultsWrapper;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class ImageSearcher {
private MilvusServiceClient milvusClient;
public ImageSearcher() {
milvusClient = new MilvusServiceClient(
ConnectParam.newBuilder()
.withUri("https://ixxxxx.gcp-us-west1.cloud.zilliz.com")
.withToken("xxx")
.build());
}
public void search(INDArray queryFeatures) {
float[] floatArray = queryFeatures.toFloatVector();
List<Float> floatList = new ArrayList<>();
for (float f : floatArray) {
floatList.add(f);
}
List<List<Float>> vectors = Collections.singletonList(floatList);
SearchParam searchParam = SearchParam.newBuilder()
.withCollectionName("image_collection")
.withMetricType(MetricType.L2)
.withTopK(5)
.withVectors(vectors)
.withVectorFieldName("embedding")
.build();
R<SearchResults> searchResults = milvusClient.search(searchParam);
System.out.println("Searching vector: " + queryFeatures.toFloatVector());
System.out.println("Result: " + searchResults.getData().getResults().getFieldsDataList());
}
}
- 特征轉(zhuǎn)換: 將
INDArray轉(zhuǎn)換為float[]數(shù)組,然后將其轉(zhuǎn)換為List<Float>。這是因為 Milvus 需要特定格式的向量輸入。 - 構(gòu)建搜索參數(shù): 創(chuàng)建一個
SearchParam對象,指定要搜索的集合名稱、度量類型(例如 L2 距離)、返回的最相似的前 K 個結(jié)果、向量字段名稱以及搜索的向量數(shù)據(jù)。 - 執(zhí)行搜索: 使用
milvusClient的search方法執(zhí)行搜索,并將結(jié)果存儲在searchResults中。 - 結(jié)果輸出: 打印出搜索的特征向量和搜索結(jié)果。
Main主類
package com.et.imagesearch;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
FeatureExtractor extractor = new FeatureExtractor();
MilvusManager milvusManager = new MilvusManager();
ImageSearcher searcher = new ImageSearcher();
milvusManager.createCollection();
// images extract
File[] imageFiles = new File("/Users/liuhaihua/ai/ut-zap50k-images-square/Boots/Ankle/Columbia").listFiles();
if (imageFiles != null) {
for (int i = 0; i < imageFiles.length; i++) {
INDArray features = extractor.extractFeatures(imageFiles[i]);
milvusManager.insertData(i, features);
}
}
milvusManager.flush();
milvusManager.buildindex();
// query
File queryImage = new File("/Users/liuhaihua/ai/ut-zap50k-images-square/Boots/Ankle/Columbia/7247580.16952.jpg");
INDArray queryFeatures = extractor.extractFeatures(queryImage);
searcher.search(queryFeatures);
}
}
以上只是一些關(guān)鍵代碼,所有代碼請參見下面代碼倉庫
代碼倉庫
5.測試
- 啟動main方法
- 查看云數(shù)據(jù)中數(shù)據(jù)
- 控制臺可以看到搜圖結(jié)果

以上就是SpringBoot集成Milvus和deeplearning4j實現(xiàn)圖搜圖功能的詳細內(nèi)容,更多關(guān)于SpringBoot Milvus和deeplearning4圖搜圖的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java調(diào)用構(gòu)造函數(shù)和方法及使用詳解
在Java編程中,構(gòu)造函數(shù)用于初始化新創(chuàng)建的對象,而方法則用于執(zhí)行對象的行為,構(gòu)造函數(shù)在使用new關(guān)鍵字創(chuàng)建類實例時自動調(diào)用,沒有返回類型,并且名稱與類名相同,本文通過示例詳細介紹了如何在Java中使用構(gòu)造函數(shù)和方法,感興趣的朋友一起看看吧2024-10-10
關(guān)于MyBatis 查詢數(shù)據(jù)時屬性中多對一的問題(多條數(shù)據(jù)對應一條數(shù)據(jù))
這篇文章主要介紹了MyBatis 查詢數(shù)據(jù)時屬性中多對一的問題(多條數(shù)據(jù)對應一條數(shù)據(jù)),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
Java連接數(shù)據(jù)庫步驟解析(Oracle、MySQL)
本文主要介紹了Java連接Oracle數(shù)據(jù)庫和MySQL數(shù)據(jù)庫的步驟解析。具有很好的參考價值,需要的朋友一起來看下吧2016-12-12
SpringMVC空指針異常NullPointerException解決及原理解析
這篇文章主要介紹了SpringMVC空指針異常NullPointerException解決及原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08

