SpringBoot集成Milvus實(shí)現(xiàn)數(shù)據(jù)增刪改查功能
Milvus是一款開(kāi)源向量數(shù)據(jù)庫(kù),主要用于在大模型領(lǐng)域做向量查詢的相關(guān)操作。milvus支持的語(yǔ)言比較多,支持python, Java, Go,node等開(kāi)發(fā)語(yǔ)言。本文主要介紹如何使用Java語(yǔ)言,采用springboot框架集成和調(diào)用Milvus數(shù)據(jù)庫(kù)。
本文示例使用的milvus版本是 v2.5.4,關(guān)于如何安裝部署milvus向量數(shù)據(jù),請(qǐng)參考上一篇文章:https://lowcode.blog.csdn.net/article/details/145552128
本文使用Java sdk操作Milvus實(shí)現(xiàn)數(shù)據(jù)的增刪改查,需要先對(duì)milvus的基本概念有個(gè)初步的了解,便于對(duì)后面代碼的更好理解。milvus更多幫助請(qǐng)參考官方文檔:https://milvus.io/docs/overview.md
1、Milvus基本概念
- 數(shù)據(jù)庫(kù)Database:與傳統(tǒng)的數(shù)據(jù)庫(kù)引擎MySQL類似,你也可以在 Milvus 中創(chuàng)建數(shù)據(jù)庫(kù),并為特定用戶分配權(quán)限來(lái)管理它們。然后,此類用戶有權(quán)管理數(shù)據(jù)庫(kù)中的集合。一個(gè) Milvus 集群最多支持 64 個(gè)數(shù)據(jù)庫(kù)。Milvus 集群附帶一個(gè)名為 'default' 的默認(rèn)數(shù)據(jù)庫(kù)。除非另有指定,否則將在 default 數(shù)據(jù)庫(kù)中創(chuàng)建集合。
- 集合Collection :在 Milvus 中,你可以創(chuàng)建多個(gè)集合來(lái)管理數(shù)據(jù),并將數(shù)據(jù)作為實(shí)體插入到集合中。Collection 和 entity 類似于關(guān)系數(shù)據(jù)庫(kù)中的 table 和 records。集合是具有固定列和變體行的二維表。每列表示一個(gè)字段,每行表示一個(gè)實(shí)體。Collection 是具有固定列和變體行的二維表。每列表示一個(gè)字段,每行表示一個(gè)實(shí)體。需要Schema來(lái)實(shí)現(xiàn)此類結(jié)構(gòu)數(shù)據(jù)管理,要插入的每個(gè)實(shí)體都必須滿足Schema中定義的約束。
- 實(shí)體Entity :在 Milvus 中,Entity 是指 Collection 中共享相同 Schema 的數(shù)據(jù)記錄,一行中每個(gè)字段的數(shù)據(jù)構(gòu)成一個(gè) Entity。因此,同一 Collection 中的 Entities 具有相同的屬性(例如字段名稱、數(shù)據(jù)類型和其他約束)。將 Entity 插入 Collection 時(shí),要插入的 Entity 只有在包含 Schema 中定義的所有字段時(shí)才能成功添加。Milvus 還支持動(dòng)態(tài)字段,以保持 Collection 的可擴(kuò)展性。啟用動(dòng)態(tài)字段后,您可以將 Schema 中未定義的字段插入到 Collection 中。這些字段和值將作為鍵值對(duì)存儲(chǔ)在名為 $meta 的保留字段中。
2、添加maven依賴
創(chuàng)建springboot工程后,在pom.xml文件里引入milvus的sdk
<dependency> <groupId>io.milvus</groupId> <artifactId>milvus-sdk-java</artifactId> <version>2.5.4</version> </dependency>
本示例使用的是milvus2.5.4最新版本,Java sdk 接口參考文檔:https://milvus.io/api-reference/java/v2.5.x/About.md
注意使用sdk版本跟milvus版本的對(duì)應(yīng)關(guān)系,milvus2.5.x版本建議使用sdk2.5.2以上版本,否則可能會(huì)出現(xiàn)一些詭異問(wèn)題。
3、配置yml文件
#配置milvus向量數(shù)據(jù)庫(kù)的IP和端口,后面構(gòu)建MilvusClient時(shí)需要
server: port: 8080 milvus: host: 192.168.3.17 port: 19530
4、創(chuàng)建MilvusClient初始化類
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; @Configuration public class MilvusConfig { @Value("${milvus.host}") private String host; @Value("${milvus.port}") private Integer port; @Bean public MilvusClientV2 milvusClientV2() { String uri = "http://"+host+":"+port; ConnectConfig connectConfig = ConnectConfig.builder() .uri(uri) .build(); return new MilvusClientV2(connectConfig); } }
5、創(chuàng)建操作向量庫(kù)的Seivce
import com.google.gson.Gson; import com.google.gson.JsonObject; import com.yuncheng.milvus.TestRecord; import io.milvus.v2.client.MilvusClientV2; import io.milvus.v2.common.DataType; import io.milvus.v2.common.IndexParam; import io.milvus.v2.service.collection.request.AddFieldReq; import io.milvus.v2.service.collection.request.CreateCollectionReq; import io.milvus.v2.service.vector.request.GetReq; import io.milvus.v2.service.vector.request.InsertReq; import io.milvus.v2.service.vector.request.SearchReq; import io.milvus.v2.service.vector.request.data.FloatVec; import io.milvus.v2.service.vector.response.GetResp; import io.milvus.v2.service.vector.response.InsertResp; import io.milvus.v2.service.vector.response.SearchResp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Collections; import java.util.List; @Component public class MilvusDemoService { private static final Logger log = LoggerFactory.getLogger(MilvusDemoService.class); //類似于mysql中的表,定義一個(gè)名稱為collection_01的集合 private static final String COLLECTION_NAME = "collection_01"; //為了測(cè)試驗(yàn)證方便,向量維度定義2 private static final int VECTOR_DIM = 2; private final MilvusClientV2 client; public MilvusDemoService(MilvusClientV2 client) { this.client = client; } /** * 創(chuàng)建一個(gè)Collection */ public void createCollection() { CreateCollectionReq.CollectionSchema schema = client.createSchema(); schema.addField(AddFieldReq.builder() .fieldName("id") .dataType(DataType.VarChar) .isPrimaryKey(true) .autoID(false) .build()); schema.addField(AddFieldReq.builder() .fieldName("title") .dataType(DataType.VarChar) .maxLength(10000) .build()); schema.addField(AddFieldReq.builder() .fieldName("title_vector") .dataType(DataType.FloatVector) .dimension(VECTOR_DIM) .build()); IndexParam indexParam = IndexParam.builder() .fieldName("title_vector") .metricType(IndexParam.MetricType.COSINE) .build(); CreateCollectionReq createCollectionReq = CreateCollectionReq.builder() .collectionName(COLLECTION_NAME) .collectionSchema(schema) .indexParams(Collections.singletonList(indexParam)) .build(); client.createCollection(createCollectionReq); } /** * 往collection中插入一條數(shù)據(jù) */ public void insertRecord(TestRecord record) { JsonObject vector = new JsonObject(); vector.addProperty("id", record.getId()); vector.addProperty("title", record.getTitle()); List<Float> vectorList = new ArrayList<>(); //為了模擬測(cè)試,向量寫(xiě)死2個(gè) vectorList.add(2.8f); vectorList.add(3.9f); Gson gson = new Gson(); vector.add("title_vector", gson.toJsonTree(vectorList)); InsertReq insertReq = InsertReq.builder() .collectionName(COLLECTION_NAME) .data(Collections.singletonList(vector)) .build(); InsertResp resp = client.insert(insertReq); } /** * 通過(guò)ID獲取記錄 */ public GetResp getRecord(String id) { GetReq getReq = GetReq.builder() .collectionName(COLLECTION_NAME) .ids(Collections.singletonList(id)) .build(); GetResp resp = client.get(getReq); return resp; } /** * 按照向量檢索,找到相似度最近的topK */ public List<List<SearchResp.SearchResult>> queryVector() { SearchResp searchR = client.search(SearchReq.builder() .collectionName(COLLECTION_NAME) .data(Collections.singletonList(new FloatVec(new float[]{0.9f, 2.1f}))) .topK(3) .outputFields(Collections.singletonList("*")) .build()); List<List<SearchResp.SearchResult>> searchResults = searchR.getSearchResults(); for (List<SearchResp.SearchResult> results : searchResults) { for (SearchResp.SearchResult result : results) { log.info("ID="+(String)result.getId() + ",Score="+result.getScore() + ",Result="+result.getEntity().toString()); } } return searchResults; } }
這里使用到的一個(gè)簡(jiǎn)單的pojo類
public class TestRecord { private String id; private String title; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }
6、創(chuàng)建Controller類
import com.yuncheng.milvus.service.MilvusDemoService; import io.milvus.v2.service.vector.response.GetResp; import io.milvus.v2.service.vector.response.SearchResp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.util.List; @RestController @RequestMapping("/milvus") public class MilvusController { private static final Logger log = LoggerFactory.getLogger(MilvusController.class); @Autowired private MilvusDemoService milvusDemoService; @GetMapping("/createCollection") public void createCollection() { milvusDemoService.createCollection(); } @GetMapping("/insertRecord") public void insertRecord() throws IOException { TestRecord record = new TestRecord(); record.setId("5"); record.setTitle("北京是中國(guó)的首都,人口有3000多萬(wàn)人"); milvusDemoService.insertRecord(record); } @GetMapping("/getRecord") public GetResp getRecord(@RequestParam(name = "id") String id){ GetResp resp = milvusDemoService.getRecord(id); log.info("resp = " + resp.getResults); return resp; } @GetMapping("/queryVector") public List<List<SearchResp.SearchResult>> queryVector() { List<List<SearchResp.SearchResult>> searchResults = milvusDemoService.queryVector(); return searchResults; } }
7、測(cè)試驗(yàn)證CRUD
確保milvus2.5.4向量數(shù)據(jù)庫(kù)正常運(yùn)行,然后啟動(dòng)springboot工程,進(jìn)行對(duì)milvus向量數(shù)據(jù)庫(kù)測(cè)試驗(yàn)證。
7.1、創(chuàng)建Collection
http://localhost:8080/milvus/createCollection
執(zhí)行后,登錄milvus控制臺(tái)webUI查看
點(diǎn)擊collection名稱,查看詳細(xì)的結(jié)構(gòu)定義,類似于mysql中的表結(jié)構(gòu)定義:
其中,id、title、title_vector字段是程序里定義的字段,另外RowID和Timestamp字段是collection默認(rèn)自帶的字段。
7.2、插入數(shù)據(jù)
http://localhost:8080/milvus/insertRecord
為了測(cè)試方便,本示例寫(xiě)死了測(cè)試數(shù)據(jù),往milvus中插入了5條數(shù)據(jù)
7.3、查詢單條記錄
http://localhost:8080/milvus/getRecord?id=2
返回JSON結(jié)果集
{ "getResults": [ { "entity": { "title_vector": [1, 2], "id": "2", "title": "張三是英國(guó)人,他喜歡吃中國(guó)火鍋" } } ] }
7.4、按向量檢索相似度
http://localhost:8080/milvus/queryVector
返回結(jié)果集:
[ [ { "entity": { "title_vector": [0.8, 1.9], "id": "4", "title": "王五是老師,她教學(xué)AI算法" }, "score": 0.9999797, "id": "4" }, { "entity": { "title_vector": [1, 2], "id": "2", "title": "張三是英國(guó)人,他喜歡吃中國(guó)火鍋" }, "score": 0.99827427, "id": "2" }, { "entity": { "title_vector": [1, 2], "id": "1", "title": "我是中國(guó)人,我喜歡吃火鍋" }, "score": 0.99827427, "id": "1" } ] ]
其中,score為向量相似度分值,如果score=1,則表示完全一樣,score小于1,表示接近。這里為了測(cè)試方面,插入數(shù)據(jù)時(shí),在向量字段里寫(xiě)死了幾個(gè)固定的List<Float>值,真實(shí)的業(yè)務(wù)場(chǎng)景中,要通過(guò)Embedding模型計(jì)算生成,后續(xù)文章中介紹如何調(diào)用AI中的Embedding服務(wù),生成向量化的float值。
到此這篇關(guān)于SpringBoot集成Milvus,實(shí)現(xiàn)數(shù)據(jù)增刪改查的文章就介紹到這了,更多相關(guān)SpringBoot集成Milvus內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring自定義一個(gè)簡(jiǎn)單的Starter啟動(dòng)器
這篇文章主要介紹了spring自定義一個(gè)簡(jiǎn)單的Starter啟動(dòng)器,一個(gè) starter其實(shí)就是對(duì)一個(gè)功能的集成封裝,然后對(duì)外提供一個(gè)依賴,讓業(yè)務(wù)去使用,像我們熟悉的 Redis,mongo,mybatis 等均屬于,需要的朋友可以參考下2023-07-07詳解SpringCloud微服務(wù)架構(gòu)之Hystrix斷路器
本篇文章主要介紹了詳解SpringCloud微服務(wù)架構(gòu)之Hystrix斷路器,Hystrix是一個(gè)庫(kù),通過(guò)添加延遲容差和容錯(cuò)邏輯來(lái)幫助您控制這些分布式服務(wù)之間的交互,有興趣的可以了解一下2018-01-01Windows下使用Graalvm將Springboot應(yīng)用編譯成exe大大提高啟動(dòng)和運(yùn)行效率(推薦)
這篇文章主要介紹了Windows下使用Graalvm將Springboot應(yīng)用編譯成exe大大提高啟動(dòng)和運(yùn)行效率,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02Mybatis-plus:${ew.sqlselect}用法說(shuō)明
這篇文章主要介紹了Mybatis-plus:${ew.sqlselect}用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Java設(shè)計(jì)模式之原型設(shè)計(jì)示例詳解
這篇文章主要為大家詳細(xì)介紹了Java的原型設(shè)計(jì)模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03K8S環(huán)境下如何驗(yàn)證RocketMQ擴(kuò)縮容
文章主要內(nèi)容驗(yàn)證了K8S環(huán)境下RocketMQ的擴(kuò)縮容特性,包括序號(hào)變化、命名規(guī)則以及節(jié)點(diǎn)重建后序號(hào)保持不變,StatefulSet確保Pod序號(hào)在重建后保持穩(wěn)定,而Deployment創(chuàng)建的Pod名稱是隨機(jī)的2025-01-01Spring?Boot請(qǐng)求處理之常用參數(shù)注解使用教程
這篇文章主要給大家介紹了關(guān)于Spring?Boot請(qǐng)求處理之常用參數(shù)注解使用的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-03-03springboot整合vue項(xiàng)目(小試牛刀)
這篇文章主要介紹了springboot整合vue項(xiàng)目(小試牛刀),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09