爆火的向量檢索,用 Java 玩轉 Milvus + Spring Boot,打造你的專屬智能搜索引擎!
在 AI 搜索與語義檢索場景中,傳統的關鍵字匹配方式早已無法滿足用戶對“語義相似度”的追求。 向量檢索技術(Vector Search)憑借其在高維特征相似度匹配中的超高效率,成為了智能推薦、圖像識別、問答系統等領域的核心基礎。
而 Milvus 作為全球領先的開源向量數據庫,天然支持海量高維數據的高效檢索與索引構建。 如果你正使用 Java 技術棧 開發 AI 應用,那么本文將帶你通過 Spring Boot 3.5.6 + JDK 21 + Milvus SDK 2.6.3, 從環境配置、集合管理、索引構建到相似度檢索,完整實現一個“智能搜索引擎”的向量檢索后端系統。
環境準備:依賴與連接配置
在著手編寫業務邏輯前,我們首先要完成 Milvus 的 SDK 依賴引入與基本連接參數配置。
Maven 依賴配置
以下是項目的 pom.xml 文件配置,確保引入了 Web、Lombok、Gson 與 Milvus SDK 等核心組件。
文件路徑:
/usr/local/java/projects/milvus-demo/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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version>
</parent>
<groupId>com.icoderoad</groupId>
<artifactId>milvus-demo</artifactId>
<version>1.0.0</version>
<name>Milvus Vector Search Demo</name>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<!-- Spring Boot Web 基礎依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok 簡化實體與日志 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Milvus Java SDK -->
<dependency>
<groupId>io.milvus</groupId>
<artifactId>milvus-sdk-java</artifactId>
<version>2.6.3</version>
</dependency>
<!-- Gson:JSON 轉換工具 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- 單元測試 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>Milvus 連接配置
在 src/main/resources/application.yml 中定義連接參數:
milvus:
uri: "http://localhost:19530" # 本地 Milvus 服務地址
token: "root:Milvus" # 若關閉鑒權可留空
database: "ai_image_db" # 數據庫名稱
collection: "image_vector_db" # 向量集合名稱
dim: 5 # 向量維度核心實戰:從連接到相似度檢索的 8 個步驟
步驟 1:配置 Milvus 客戶端
路徑:
src/main/java/com/icoderoad/milvus/config/MilvusConfig.java
package com.icoderoad.milvus.config;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Milvus 客戶端配置類
* 負責將 MilvusClientV2 注入 Spring 容器,實現全局復用
*/
@Configuration
public class MilvusConfig {
@Bean
public MilvusClientV2 milvusClient(@Value("${milvus.uri}") String uri,
@Value("${milvus.token}") String token) {
ConnectConfig config = ConnectConfig.builder()
.uri(uri)
.token(token)
.build();
return new MilvusClientV2(config);
}
}步驟 2:創建與切換數據庫
路徑:
src/test/java/com/icoderoad/milvus/DatabaseInitTest.java
package com.icoderoad.milvus;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.database.request.CreateDatabaseReq;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* 數據庫創建與切換測試類
*/
@SpringBootTest
class DatabaseInitTest {
@Resource
private MilvusClientV2 client;
@Test
void createAndUseDatabase() throws InterruptedException {
String dbName = "ai_image_db";
try {
client.createDatabase(CreateDatabaseReq.builder().databaseName(dbName).build());
System.out.println(" 數據庫創建成功:" + dbName);
} catch (Exception e) {
if (e.getMessage().contains("already exists")) {
System.out.println(" 數據庫已存在:" + dbName);
} else {
throw e;
}
}
client.useDatabase(dbName);
}
}步驟 3:定義向量集合結構
package com.icoderoad.milvus;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.*;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* 向量集合結構定義類
*/
@SpringBootTest
class CollectionCreateTest {
@Resource
private MilvusClientV2 client;
@Test
void createCollection() throws InterruptedException {
String dbName = "ai_image_db";
client.useDatabase(dbName);
String collection = "image_vector_db";
int dim = 5;
if (!client.hasCollection(HasCollectionReq.builder().collectionName(collection).build())) {
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(AddFieldReq.builder()
.fieldName("img_id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(true)
.description("主鍵 ID")
.build());
schema.addField(AddFieldReq.builder()
.fieldName("img_vector")
.dataType(DataType.FloatVector)
.dimension(dim)
.description("圖像向量字段")
.build());
schema.addField(AddFieldReq.builder()
.fieldName("label")
.dataType(DataType.Int64)
.description("類別標簽:0=貓,1=狗,2=鳥")
.build());
client.createCollection(CreateCollectionReq.builder()
.collectionName(collection)
.collectionSchema(schema)
.build());
System.out.println(" 集合創建成功:" + collection);
} else {
System.out.println(" 集合已存在:" + collection);
}
}
}步驟 4:創建索引加速檢索
package com.icoderoad.milvus;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.index.request.CreateIndexReq;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
/**
* 向量索引構建類
*/
@SpringBootTest
public class IndexBuildTest {
@Resource
private MilvusClientV2 client;
@Test
void createIndex() throws InterruptedException {
String dbName = "ai_image_db";
client.useDatabase(dbName);
String collection = "image_vector_db";
IndexParam index = IndexParam.builder()
.fieldName("img_vector")
.indexType(IndexParam.IndexType.IVF_FLAT)
.metricType(IndexParam.MetricType.L2)
.extraParams(Map.of("nlist", 128))
.build();
client.createIndex(CreateIndexReq.builder()
.collectionName(collection)
.indexParams(List.of(index))
.build());
System.out.println("索引創建成功:IVF_FLAT / L2");
}
}步驟 5:插入測試數據
package com.icoderoad.milvus;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.InsertReq;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.*;
/**
* 插入測試向量數據
*/
@SpringBootTest
public class DataInsertTest {
@Resource
private MilvusClientV2 client;
private List<Float> asList(float[] array) {
List<Float> list = new ArrayList<>(array.length);
for (float v : array) list.add(v);
return list;
}
@Test
void insertVectors() throws InterruptedException {
client.useDatabase("ai_image_db");
String collection = "image_vector_db";
List<float[]> vectors = List.of(
new float[]{0.1f, 0.2f, 0.3f, 0.4f, 0.5f},
new float[]{0.2f, 0.3f, 0.4f, 0.5f, 0.6f},
new float[]{0.3f, 0.4f, 0.5f, 0.6f, 0.7f},
new float[]{0.4f, 0.5f, 0.6f, 0.7f, 0.8f},
new float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f}
);
List<Integer> labels = List.of(0, 0, 1, 1, 2);
List<Map<String, Object>> rows = new ArrayList<>();
for (int i = 0; i < vectors.size(); i++) {
rows.add(Map.of(
"img_vector", asList(vectors.get(i)),
"label", labels.get(i)
));
}
List<JsonObject> jsonObjects = rows.stream()
.map(row -> new Gson().toJsonTree(row).getAsJsonObject())
.toList();
client.insert(InsertReq.builder()
.collectionName(collection)
.data(jsonObjects)
.build());
System.out.println(" 插入測試數據完成(5 條)");
}
}步驟 6 & 7:加載集合并執行相似度檢索
package com.icoderoad.milvus;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.*;
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
/**
* 向量相似度檢索測試
*/
@SpringBootTest
public class VectorSearchTest {
@Resource
private MilvusClientV2 client;
@Test
void vectorSearch() throws InterruptedException {
client.useDatabase("ai_image_db");
String collection = "image_vector_db";
client.loadCollection(LoadCollectionReq.builder().collectionName(collection).build());
System.out.println(" 集合加載完成");
float[] queryVector = {0.15f, 0.25f, 0.35f, 0.45f, 0.55f};
SearchReq req = SearchReq.builder()
.collectionName(collection)
.annsField("img_vector")
.metricType(IndexParam.MetricType.L2)
.data(List.of(new FloatVec(queryVector)))
.limit(3)
.searchParams(Map.of("nprobe", 10))
.outputFields(List.of("label"))
.build();
SearchResp resp = client.search(req);
resp.getSearchResults().forEach(resultList ->
resultList.forEach(r ->
System.out.printf("ID:%s 距離:%.3f 標簽:%s%n",
r.getId(), r.getScore(), r.getEntity().get("label")))
);
client.releaseCollection(ReleaseCollectionReq.builder().collectionName(collection).build());
System.out.println(" 檢索完成,內存已釋放");
}
}總結與進階優化
至此,我們已經完整實現了 Spring Boot + Milvus 向量檢索后端系統 的完整流程:
- 配置連接與環境初始化
- 數據庫與集合管理
- 索引構建與性能優化
- 插入樣本與相似度檢索
在真實項目中,你可以繼續沿著以下方向深入優化:
- 批量導入優化:使用
insertBatch()提高大規模數據導入效率; - 搜索性能調優:調整
nprobe或使用更高效的IVF_PQ/HNSW索引; - 錯誤恢復機制:為生產環境增加連接超時與重試邏輯;
- 前端融合:結合向量檢索結果構建語義搜索、圖像推薦等智能應用。
Milvus 的強大之處在于,它不僅僅是數據庫,更是通向智能檢索的“核心引擎”。 無論你在做 AI 語義匹配、圖像相似搜索還是文本推薦, 都可以借助本項目架構,快速打造屬于你自己的智能向量檢索系統。
























