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ù)用戶(hù)的歷史行為和興趣,為其推薦相關(guān)的內(nèi)容。于是將用戶(hù)和內(nèi)容表示為向量,并使用 Milvus 進(jìn)行相似度匹配。通過(guò)將用戶(hù)向量和內(nèi)容向量存儲(chǔ)在 Milvus 中,并利用其高效的相似度查詢(xún)功能,我們可以快速找到與用戶(hù)興趣最匹配的內(nèi)容,并進(jìn)行個(gè)性化推薦。
向量的生成由spark任務(wù)生成數(shù)據(jù)并寫(xiě)入,本文只寫(xiě)SpringBoot集成Milvus實(shí)現(xiàn)數(shù)據(jù)查詢(xún)部分,面向C端,性能已測(cè)
Maven依賴(lài)引入
開(kāi)始使用的是1.x版本,后來(lái)由于2.x新增了過(guò)濾篩選功能,升級(jí)了版本為2.2.3,1版本和2版本查詢(xún)還是有一些區(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();
? ? ? ? ? ? }
? ? ? ? }
? ? }
}查詢(xún)
寫(xiě)入數(shù)據(jù)不同,獲取結(jié)果不同,我這里最后獲取的是Long類(lèi)型的數(shù)據(jù)集合,僅供參考
同步搜索milvus
/**
?* 同步搜索milvus
?* @param collectionName 表名
?* @param vectors 查詢(xún)向量
?* @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 查詢(xún)向量
?* @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 查詢(xún)向量
?* @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并發(fā)線(xiàn)程之線(xiàn)程池的知識(shí)總結(jié)
這篇文章主要介紹了Java并發(fā)線(xiàn)程之線(xiàn)程池的知識(shí)總結(jié),幫助大家更好的理解和學(xué)習(xí)Java并發(fā)線(xiàn)程的相關(guān)內(nèi)容,感興趣的朋友可以了解下2021-01-01
詳解Java實(shí)現(xiàn)JSONArray轉(zhuǎn)Map的三種實(shí)現(xiàn)方式
本文主要介紹了Java實(shí)現(xiàn)JSONArray轉(zhuǎn)Map的三種實(shí)現(xiàn)方式,本文只是自己常用的三種,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
IDEA上面搭建一個(gè)SpringBoot的web-mvc項(xiàng)目遇到的問(wèn)題
這篇文章主要介紹了IDEA上面搭建一個(gè)SpringBoot的web-mvc項(xiàng)目遇到的問(wèn)題小結(jié),需要的朋友可以參考下2017-04-04
Maven中Junit測(cè)試@Test等注解無(wú)法識(shí)別的問(wèn)題及解決
這篇文章主要介紹了Maven中Junit測(cè)試@Test等注解無(wú)法識(shí)別的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
Java利用MD5加鹽實(shí)現(xiàn)對(duì)密碼進(jìn)行加密處理
在開(kāi)發(fā)的時(shí)候,有一些敏感信息是不能直接通過(guò)明白直接保存到數(shù)據(jù)庫(kù)的。最經(jīng)典的就是密碼了。如果直接把密碼以明文的形式入庫(kù),不僅會(huì)泄露用戶(hù)的隱私,對(duì)系統(tǒng)也是極其的不厲。本文就來(lái)和大家介紹一下如何對(duì)密碼進(jìn)行加密處理,感興趣的可以了解一下2023-02-02
springboot實(shí)現(xiàn)token驗(yàn)證登陸狀態(tài)的示例代碼
本文主要介紹了spring?boot?實(shí)現(xiàn)token驗(yàn)證登陸狀態(tài),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07
spring使用ehcache實(shí)現(xiàn)頁(yè)面緩存示例
這篇文章主要介紹了spring使用ehcache實(shí)現(xiàn)頁(yè)面緩存示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
Redis內(nèi)存數(shù)據(jù)庫(kù)示例分析
Redis本身的內(nèi)容比較復(fù)雜。如果你上來(lái),你應(yīng)該研究一個(gè)細(xì)節(jié)點(diǎn),比如連接池和數(shù)據(jù)結(jié)構(gòu)。雖然可以直接了解某一點(diǎn)的詳細(xì)來(lái)源內(nèi)容,甚至盡快解決一些意外,但是容易淹沒(méi)在失眠的細(xì)節(jié)中,整體控制不了Redis2022-12-12
SpringBoot?錯(cuò)誤頁(yè)面跳轉(zhuǎn)方式
這篇文章主要介紹了SpringBoot?錯(cuò)誤頁(yè)面跳轉(zhuǎn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02

