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并發(fā)線程之線程池的知識(shí)總結(jié)
這篇文章主要介紹了Java并發(fā)線程之線程池的知識(shí)總結(jié),幫助大家更好的理解和學(xué)習(xí)Java并發(fā)線程的相關(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-03IDEA上面搭建一個(gè)SpringBoot的web-mvc項(xiàng)目遇到的問(wèn)題
這篇文章主要介紹了IDEA上面搭建一個(gè)SpringBoot的web-mvc項(xiàng)目遇到的問(wèn)題小結(jié),需要的朋友可以參考下2017-04-04Maven中Junit測(cè)試@Test等注解無(wú)法識(shí)別的問(wèn)題及解決
這篇文章主要介紹了Maven中Junit測(cè)試@Test等注解無(wú)法識(shí)別的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11Java利用MD5加鹽實(shí)現(xiàn)對(duì)密碼進(jìn)行加密處理
在開(kāi)發(fā)的時(shí)候,有一些敏感信息是不能直接通過(guò)明白直接保存到數(shù)據(jù)庫(kù)的。最經(jīng)典的就是密碼了。如果直接把密碼以明文的形式入庫(kù),不僅會(huì)泄露用戶的隱私,對(duì)系統(tǒng)也是極其的不厲。本文就來(lái)和大家介紹一下如何對(duì)密碼進(jìn)行加密處理,感興趣的可以了解一下2023-02-02springboot實(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-07spring使用ehcache實(shí)現(xiàn)頁(yè)面緩存示例
這篇文章主要介紹了spring使用ehcache實(shí)現(xiàn)頁(yè)面緩存示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02Redis內(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-12SpringBoot?錯(cuò)誤頁(yè)面跳轉(zhuǎn)方式
這篇文章主要介紹了SpringBoot?錯(cuò)誤頁(yè)面跳轉(zhuǎn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02