版本介绍
Milvus Lite
Milvus Lite是一个 Python 库,可导入到您的应用程序中。作为 Milvus 的轻量级版本,它非常适合在 Jupyter 笔记本或资源有限的智能设备上运行快速原型。Milvus Lite 支持与 Milvus 其他部署相同的 API。与 Milvus Lite 交互的客户端代码也能与其他部署模式下的 Milvus 实例协同工作。
要将 Milvus Lite 集成到应用程序中,请运行pip install pymilvus 进行安装,并使用MilvusClient("./demo.db") 语句实例化一个带有本地文件的向量数据库,以持久化所有数据。更多详情,请参阅运行 Milvus Lite。
Milvus Lite 目前支持以下环境:
- Ubuntu >= 20.04(x86_64 和 arm64)
- MacOS >= 11.0(苹果硅 M1/M2 和 x86_64)
Milvus 单机版
Milvus Standalone 是单机服务器部署。Milvus Standalone 的所有组件都打包到一个Docker 镜像中,部署起来非常方便。如果你有生产工作负载,但又不想使用 Kubernetes,那么在内存充足的单机上运行 Milvus Standalone 是一个不错的选择。此外,Milvus Standalone 通过主从复制支持高可用性。
分布式 Milvus
Milvus Distributed 可部署在Kubernetes集群上。这种部署采用云原生架构,摄取负载和搜索查询分别由独立节点处理,允许关键组件冗余。它具有最高的可扩展性和可用性,并能灵活定制每个组件中分配的资源。Milvus Distributed 是在生产中运行大规模向量搜索系统的企业用户的首选。
Milvus 单机版部署
使用Docker Compose安装 Milvus standalone(即单机版),进行一个快速milvus的体验。
前提条件:
1.系统可以使用centos或者ubuntu,这里使用的是Ubuntu 20.04.6 LTS
2.系统已经安装docker和docker-compose
3.milvus版本这里使用2.3.12
启动etcd、minio、milvus
由于milvus依赖etcd和minio,因此需要先启动这2个组件。同样也使用docker进行启动。
etcd:用来存储milvus的元数据。
minio:用来存储milvus的向量数据和索引数据。
下载milvus-standalone-docker-compose.yml 文件,保存为docker-compose.yml:
bash
wget https://github.com/milvus-io/milvus/releases/download/v2.3.12/milvusstandalone-docker-compose.yml -O docker-compose.yml
这里经过了一定修改,让其更加方便使用。 这个yml文件里面定义了etcd、minio、milvus的启动参数。 修改后的docker-compose.yml文件内容如下
bash
version: '3.5'
services:
etcd:
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.5
environment:
- ETCD_AUTO_COMPACTION_MODE=revision
- ETCD_AUTO_COMPACTION_RETENTION=1000
- ETCD_QUOTA_BACKEND_BYTES=4294967296
- ETCD_SNAPSHOT_COUNT=50000
volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd
ports:
- "2379:2379"
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls=http://0.0.0.0:2379 --data-dir /etcd
healthcheck:
test: ["CMD", "etcdctl", "endpoint", "health"]
interval: 5s
timeout: 3s
retries: 10
minio:
container_name: milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
environment:
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
ports:
- "9001:9001"
- "9000:9000"
volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
command: minio server /minio_data --console-address ":9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 5s
timeout: 3s
retries: 10
standalone:
container_name: milvus-standalone
image: milvusdb/milvus:v2.3.12
command: ["milvus", "run", "standalone"]
security_opt:
- seccomp:unconfined
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
interval: 30s
start_period: 90s
timeout: 20s
retries: 3
ports:
- "19530:19530"
- "9091:9091"
depends_on:
- etcd
- minio
attu:
image: zilliz/attu:v2.3.8
container_name: milvus-attu
environment:
MILVUS_URL: standalone:19530
ports:
- "8000:3000"
depends_on:
- standalone
networks:
default:
name: milvus
启动
bash
docker-compose up -d
-d 代表后台启动
其他命令
docker-compose ps 查看容器
docker-compose stop 停止容器
docker-compose start 启动容器
docker-compose down 停止并删除容器(特别注意以免误删容器)

启动attu可视化
bash
docker run -d \
--name=attu \
-p 8000:3000 \
-e MILVUS_URL=101.126.141.93:19530 \
zilliz/attu:v2.3.9
http://101.126.141.93:8000/

整合springbootcrud
https://gitee.com/zhang-hai-fei/ollama-deep-seek-milvus-test.git
pom
xml
<dependency>
<groupId>io.milvus</groupId>
<artifactId>milvus-sdk-java</artifactId>
<version>2.5.4</version>
</dependency>
config
java
package org.caizhi.corporation.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;
@Configuration
public class MilvusConfig {
@Value("${milvus.host}")
private String host;
@Value("${milvus.port}")
private Integer port;
@Value("${milvus.db}")
private String DATABASE_NAME; // 指定数据库名称
@Value("${milvus.username}")
private String username;
@Value("${milvus.password}")
private String password;
@Bean
public MilvusClientV2 milvusClientV2() {
String uri = "http://"+host+":"+port;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri(uri)
.username(username)
.password(password)
.dbName(DATABASE_NAME)
.build();
return new MilvusClientV2(connectConfig);
}
}
yaml
yaml
server:
port: 8080
milvus:
host: 101.126.141.93
port: 19530
db: test
password: admin123
username: admin
service
java
package org.caizhi.corporation.service;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
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.caizhi.corporation.entity.TestRecord;
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中的表,定义一个名称为collection_01的集合
private static final String COLLECTION_NAME = "collection_test";
//为了测试验证方便,向量维度定义2
private static final int VECTOR_DIM = 2;
private final MilvusClientV2 client;
public MilvusDemoService(MilvusClientV2 client) {
this.client = client;
}
/**
* 创建一个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中插入一条数据
*/
public void insertRecord(TestRecord record) {
JsonObject vector = new JsonObject();
vector.addProperty("id", record.getId());
vector.addProperty("title", record.getTitle());
List<Float> vectorList = new ArrayList<>();
//为了模拟测试,向量写死2个
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);
}
/**
* 通过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;
}
}
controller
java
package org.caizhi.corporation.controller;
import io.milvus.v2.service.vector.response.GetResp;
import io.milvus.v2.service.vector.response.SearchResp;
import org.caizhi.corporation.entity.TestRecord;
import org.caizhi.corporation.service.MilvusDemoService;
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("6");
record.setTitle("上海不是中国的首都,人口有3000多万人");
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;
}
}