SpringBoot整合Milvus的實(shí)現(xiàn)
什么是Milvus?
Milvus,一個(gè)開(kāi)源的高性能向量數(shù)據(jù)庫(kù),它在各種應(yīng)用場(chǎng)景中展現(xiàn)出強(qiáng)大的性能和靈活性。
在許多現(xiàn)代應(yīng)用中,處理和分析大規(guī)模向量數(shù)據(jù)變得越來(lái)越重要。例如,在圖像和視頻搜索、推薦系統(tǒng)、自然語(yǔ)言處理和生物信息學(xué)等領(lǐng)域,向量數(shù)據(jù)被廣泛應(yīng)用。
項(xiàng)目背景
在公司推薦系統(tǒng)中,我們需要根據(jù)用戶的歷史行為和興趣,為其推薦相關(guān)的內(nèi)容。于是將用戶和內(nèi)容表示為向量,并使用 Milvus 進(jìn)行相似度匹配。通過(guò)將用戶向量和內(nèi)容向量存儲(chǔ)在 Milvus 中,并利用其高效的相似度查詢功能,我們可以快速找到與用戶興趣最匹配的內(nèi)容,并進(jìn)行個(gè)性化推薦。
向量的生成由spark任務(wù)生成數(shù)據(jù)并寫入,本文只寫SpringBoot集成Milvus實(shí)現(xiàn)數(shù)據(jù)查詢部分,面向C端,性能已測(cè)
Maven依賴引入
開(kāi)始使用的是1.x版本,后來(lái)由于2.x新增了過(guò)濾篩選功能,升級(jí)了版本為2.2.3,1版本和2版本查詢還是有一些區(qū)別,建議采用2版本
<dependency>
<groupId>io.milvus</groupId>
<artifactId>milvus-sdk-java</artifactId>
<version>2.2.3</version>
</dependency>自動(dòng)配置
@Configuration
public class MilvusConfiguration {
? ? /**
? ? ?* ?milvus ip addr
? ? ?*/
? ? @Value("${milvus.config.ipAddr}")
? ? private String ipAddr;
? ? /**
? ? ?* milvus ? port
? ? ?*/
? ? @Value("${milvus.config.port}")
? ? private Integer ?port;
? ? @Bean
? ? @Scope("singleton")
? ? public MilvusServiceClient getMilvusClient() {
? ? ? ? return getMilvusFactory().getMilvusClient();
? ? }
? ? @Bean(initMethod = "init", destroyMethod = "close")
? ? public MilvusRestClientFactory getMilvusFactory() {
? ? ? ? return ?MilvusRestClientFactory.build(ipAddr, port);
? ? }
}milvus Rest client 封裝
public class MilvusRestClientFactory {
? ? private static String ?IP_ADDR;
? ? private static Integer PORT ;
? ? private MilvusServiceClient milvusServiceClient;
? ? private ConnectParam.Builder ?connectParamBuilder;
? ? private static MilvusRestClientFactory milvusRestClientFactory = new MilvusRestClientFactory();
? ? private MilvusRestClientFactory(){
? ? }
? ? public static MilvusRestClientFactory build(String ipAddr, Integer ?port) {
? ? ? ? IP_ADDR = ipAddr;
? ? ? ? PORT = port;
? ? ? ? return milvusRestClientFactory;
? ? }
? ? private ConnectParam.Builder connectParamBuilder(String host, int port) {
? ? ? ? return ?ConnectParam.newBuilder().withHost(host).withPort(port);
? ? }
? ? public void init() {
? ? ? ? connectParamBuilder = ?connectParamBuilder(IP_ADDR,PORT);
? ? ? ? ConnectParam connectParam = connectParamBuilder.build();
? ? ? ? milvusServiceClient =new MilvusServiceClient(connectParam);
? ? }
? ? public MilvusServiceClient getMilvusClient() {
? ? ? ? return milvusServiceClient;
? ? }
? ? public void close() {
? ? ? ? if (milvusServiceClient != null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? milvusServiceClient.close();
? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? }
}查詢
寫入數(shù)據(jù)不同,獲取結(jié)果不同,我這里最后獲取的是Long類型的數(shù)據(jù)集合,僅供參考
同步搜索milvus
/**
?* 同步搜索milvus
?* @param collectionName 表名
?* @param vectors 查詢向量
?* @param topK 最相似的向量個(gè)數(shù)
?* @return
?*/
public List<Long> search(String collectionName, List<List<Float>> vectors, Integer topK) {
? ? Assert.notNull(collectionName, "collectionName ?is null");
? ? Assert.notNull(vectors, "vectors is null");
? ? Assert.notEmpty(vectors, "vectors is empty");
? ? Assert.notNull(topK, "topK is null");
? ? int nprobeVectorSize = vectors.get(0).size();
? ? String paramsInJson = "{"nprobe": " + nprobeVectorSize + "}";
? ? SearchParam searchParam =
? ? ? ? ? ? SearchParam.newBuilder().withCollectionName(collectionName)
? ? ? ? ? ? ? ? ? ? .withParams(paramsInJson)
? ? ? ? ? ? ? ? ? ? .withMetricType(MetricType.IP)
? ? ? ? ? ? ? ? ? ? .withVectors(vectors)
? ? ? ? ? ? ? ? ? ? .withVectorFieldName("embedding")
? ? ? ? ? ? ? ? ? ? .withTopK(topK)
? ? ? ? ? ? ? ? ? ? .build();
? ? R<SearchResults> searchResultsR = milvusServiceClient.search(searchParam);
? ? SearchResults searchResultsRData = searchResultsR.getData();
? ? List<Long> topksList = searchResultsRData.getResults().getIds().getIntId().getDataList();
? ? return topksList;
}同步搜索milvus,增加過(guò)濾條件搜索
/**
?* 同步搜索milvus,增加過(guò)濾條件搜索
?*
?* @param collectionName 表名
?* @param vectors 查詢向量
?* @param topK 最相似的向量個(gè)數(shù)
?* @param exp 過(guò)濾條件:status=1
?* @return
?*/
public List<Long> search(String collectionName, List<List<Float>> vectors, Integer topK, String exp) {
? ? Assert.notNull(collectionName, "collectionName ?is null");
? ? Assert.notNull(vectors, "vectors is null");
? ? Assert.notEmpty(vectors, "vectors is empty");
? ? Assert.notNull(topK, "topK is null");
? ? Assert.notNull(exp, "exp is null");
? ? int nprobeVectorSize = vectors.get(0).size();
? ? String paramsInJson = "{"nprobe": " + nprobeVectorSize + "}";
? ? SearchParam searchParam =
? ? ? ? ? ? SearchParam.newBuilder().withCollectionName(collectionName)
? ? ? ? ? ? ? ? ? ? .withParams(paramsInJson)
? ? ? ? ? ? ? ? ? ? .withMetricType(MetricType.IP)
? ? ? ? ? ? ? ? ? ? .withVectors(vectors)
? ? ? ? ? ? ? ? ? ? .withExpr(exp)
? ? ? ? ? ? ? ? ? ? .withVectorFieldName("embedding")
? ? ? ? ? ? ? ? ? ? .withTopK(topK)
? ? ? ? ? ? ? ? ? ? .build();
? ? R<SearchResults> searchResultsR = milvusServiceClient.search(searchParam);
? ? SearchResults searchResultsRData = searchResultsR.getData();
? ? List<Long> topksList = searchResultsRData.getResults().getIds().getIntId().getDataList();
? ? return topksList;
}異步搜索milvus:針對(duì)實(shí)時(shí)結(jié)果要求不高的場(chǎng)景
/**
?* 異步搜索milvus
?*
?* @param collectionName 表名
?* @param vectors 查詢向量
?* @param partitionList 最相似的向量個(gè)數(shù)
?* @param topK
?* @return
?*/
public List<Long> searchAsync(String collectionName, List<List<Float>> vectors,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? List<String> partitionList, Integer topK) throws ExecutionException, InterruptedException {
? ? Assert.notNull(collectionName, "collectionName ?is null");
? ? Assert.notNull(vectors, "vectors is null");
? ? Assert.notEmpty(vectors, "vectors is empty");
? ? Assert.notNull(partitionList, "partitionList is null");
? ? Assert.notEmpty(partitionList, "partitionList is empty");
? ? Assert.notNull(topK, "topK is null");
? ? int nprobeVectorSize = vectors.get(0).size();
? ? String paramsInJson = "{"nprobe": " + nprobeVectorSize + "}";
? ? SearchParam searchParam =
? ? ? ? ? ? SearchParam.newBuilder().withCollectionName(collectionName)
? ? ? ? ? ? ? ? ? ? .withParams(paramsInJson)
? ? ? ? ? ? ? ? ? ? .withVectors(vectors)
? ? ? ? ? ? ? ? ? ? .withTopK(topK)
? ? ? ? ? ? ? ? ? ? .withPartitionNames(partitionList)
? ? ? ? ? ? ? ? ? ? .build();
? ? ListenableFuture<R<SearchResults>> listenableFuture = milvusServiceClient.searchAsync(searchParam);
? ? List<Long> resultIdsList = listenableFuture.get().getData().getResults().getTopksList();
? ? return resultIdsList;
}獲取分區(qū)集合
/**
* 獲取分區(qū)集合
* @param collectionName 表名
* @return
*/
public List<String> getPartitionsList(String collectionName) {
Assert.notNull(collectionName, "collectionName is null");
ShowPartitionsParam searchParam = ShowPartitionsParam.newBuilder().withCollectionName(collectionName).build();
List<ByteString> byteStrings = milvusServiceClient.showPartitions(searchParam).getData().getPartitionNamesList().asByteStringList();
List<String> partitionList = Lists.newLinkedList();
byteStrings.forEach(s -> {
partitionList.add(s.toStringUtf8());
});
return partitionList;
}yml配置數(shù)據(jù)
milvus:
config:
ipAddr: xxx.xxx.xxx.xxx
port: 19531到此這篇關(guān)于SpringBoot整合Milvus的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SpringBoot整合Milvus內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java模擬TCP通信實(shí)現(xiàn)客戶端上傳文件到服務(wù)器端
這篇文章主要為大家詳細(xì)介紹了java模擬TCP通信實(shí)現(xiàn)客戶端上傳文件到服務(wù)器端,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
MyBatis使用CASE WHEN進(jìn)行批量更新的高效寫法
當(dāng)我們使用mybatis的時(shí)候,可能經(jīng)常會(huì)碰到一批數(shù)據(jù)的批量更新問(wèn)題,因?yàn)槿绻粭l數(shù)據(jù)一更新,那每一條數(shù)據(jù)就需要涉及到一次數(shù)據(jù)庫(kù)的操作,包括網(wǎng)絡(luò)IO以及磁盤IO,可想而知,這個(gè)效率是非常低下的,那么今天我們就來(lái)總結(jié)一下,如何使用mybatis做批量更新,需要的朋友可以參考下2025-10-10
Java使用ScriptEngine動(dòng)態(tài)執(zhí)行代碼(附Java幾種動(dòng)態(tài)執(zhí)行代碼比較)
這篇文章主要介紹了Java使用ScriptEngine動(dòng)態(tài)執(zhí)行代碼,并且分享Java幾種動(dòng)態(tài)執(zhí)行代碼比較,需要的朋友可以參考下2021-04-04
Javaweb動(dòng)態(tài)開(kāi)發(fā)最重要的Servlet詳解
動(dòng)態(tài)web的核心是Servlet,由tomcat解析并執(zhí)行,本質(zhì)是Java中的一個(gè)類(面向?qū)ο螅┻@個(gè)類的功能十分強(qiáng)大幾乎可以完成全部功能,在Java規(guī)范中只有Servlet實(shí)現(xiàn)類實(shí)例化的對(duì)象才能被瀏覽器訪問(wèn),所以掌握Servlet具有重要意義2022-08-08
從零開(kāi)始手寫JDBC連接數(shù)據(jù)庫(kù)的詳細(xì)指南
在?Java?開(kāi)發(fā)中,數(shù)據(jù)庫(kù)是存儲(chǔ)和管理數(shù)據(jù)的核心組件,JDBC是?Java?程序與數(shù)據(jù)庫(kù)交互的標(biāo)準(zhǔn)?API,本文將帶大家手寫一個(gè)完整的?JDBC?連接數(shù)據(jù)庫(kù)的示例,希望對(duì)大家有所幫助2025-07-07

