Milvus
Milvus 是可选的替代存储方案。当前 Java MaxKB 的已运行检索后端是 PostgreSQL + pgvector,未将 Milvus 列为已经接通的运行路径。
1. 什么是向量数据库?
向量数据库是一种专门用于存储和查询高维向量的数据库,广泛应用于文本、语音、图像、视频等数据的存储和检索。相较于传统数据库,向量数据库不仅支持 CRUD(创建、读取、更新、删除)操作,还能高效地执行相似性搜索。
2. Milvus 介绍
Milvus 是一款云原生的向量数据库,具备高可用性、高性能、易扩展等特性,主要用于海量向量数据的实时检索。它基于 FAISS、Annoy、HNSW 等向量搜索库构建,核心目标是优化稠密向量相似性检索。
Milvus 具有以下特性:
- 数据存储与查询优化:支持数据分区分片、数据持久化、增量数据摄取、标量与向量混合查询。
- 高性能检索:提供时间旅行(Time Travel)、高效索引结构等优化方案。
- 云原生架构:采用存储计算分离架构,计算节点支持横向扩展,保障高吞吐量。
3. 在 Docker 中安装 Milvus
Milvus 提供官方的 Docker 镜像,建议使用 Docker 进行安装,以保证稳定性和易维护性。
3.1 安装 Docker 和 Docker Compose
如果尚未安装 Docker,可以使用以下命令进行安装(适用于 Linux):
# 更新软件包
sudo apt update
sudo apt install -y docker.io docker-compose
3.2 启动 Milvus
使用官方提供的 docker-compose.yml 文件启动 Milvus。
mkdir /opt/docker-compose-yml/milvus -p && cd /opt/docker-compose-yml/milvus
wget https://github.com/milvus-io/milvus/releases/download/v2.5.4/milvus-standalone-docker-compose.yml -O docker-compose.yml
以下为历史部署示例,实际部署应使用所选发行包配套的 Compose 配置
version: "3.5"
services:
etcd:
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.16
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
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: 30s
timeout: 20s
retries: 3
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: 30s
timeout: 20s
retries: 3
standalone:
container_name: milvus-standalone
image: milvusdb/milvus:v2.5.4
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"
networks:
default:
name: milvus
启动 Milvus
docker-compose up -d
or
docker compose up -d
如果是单机部署,这 3 个容器都要启动码? 是的。在这个单机部署的方案中,三个容器都是必需的:
- etcd:负责存储 Milvus 的元数据。
- minio:用于存储实际的数据文件。
- milvus-standalone:运行 Milvus 的核心服务。
除非有其他方式来提供 etcd 和 minio 服务,否则这三个容器需要一起启动。
此时 Milvus 运行在 localhost:19530,可使用 docker ps 查看容器状态。
4. Java 集成 Milvus
4.1 必要的 Maven 依赖
Milvus 官方提供了 milvus-sdk-java,其版本需与 Milvus 服务器版本匹配。此外,需要 grpc-netty-shaded 作为 gRPC 的底层通信库。jersey-server 依赖通常用于 RESTful API,如果不使用 REST 方式,可省略。
必要依赖:
依赖示例省略版本声明,由项目的统一依赖管理配置提供。
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
</dependency>
<dependency>
<groupId>io.milvus</groupId>
<artifactId>milvus-sdk-java</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
4.2 连接 Milvus
private MilvusClientV2 clientV2;
try {
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("localhost:19530")
.token("your-token")
.build();
this.clientV2 = new MilvusClientV2(connectConfig);
} catch (Exception e) {
e.printStackTrace();
}
4.3 创建集合
public void createCollection(String collectionName) {
boolean collectionExists = true;
try {
DescribeCollectionReq describeCollectionReq = DescribeCollectionReq.builder()
.collectionName(collectionName)
.build();
clientV2.describeCollection(describeCollectionReq);
} catch (Exception e) {
collectionExists = false;
}
if (!collectionExists) {
CreateCollectionReq createReq = CreateCollectionReq.builder()
.collectionName(collectionName)
.dimension(1536) // 向量维度
.idType(DataType.VarChar) // ID 类型
.metricType("IP") // 内积相似度
.build();
clientV2.createCollection(createReq);
GetLoadStateReq loadStateReq = GetLoadStateReq.builder()
.collectionName(collectionName)
.build();
boolean loadState = clientV2.getLoadState(loadStateReq);
}
}
4.4 插入或更新数据
public void upsert(String collectionName, List<String> documents, List<Map<String, String>> metadata, List<String> ids, List<List<Float>> embeddings) {
createCollection(collectionName);
List<JSONObject> data = new ArrayList<>();
for (int i = 0; i < documents.size(); i++) {
Map<String, Object> record = new HashMap<>();
record.put("id", ids.get(i));
record.put("vector", embeddings.get(i));
record.put("metadata", metadata.get(i));
data.add(new JSONObject(record));
}
UpsertReq upsertReq = UpsertReq.builder()
.collectionName(collectionName)
.data(data)
.build();
clientV2.upsert(upsertReq);
}
4.5 进行向量搜索
List<List<Float>> embeddings = embeddingFunction.createEmbedding();
Map<String, Object> params = new HashMap<>();
params.put("radius", 0.5); // 相似度阈值
SearchReq searchReq = SearchReq.builder()
.collectionName(collectionName)
.data(embeddings)
.searchParams(params)
.outputFields(Arrays.asList("id", "metadata", "vector"))
.build();
SearchResp searchResp = clientV2.search(searchReq);
4.6 删除数据和集合
删除对象
public void delete(List<String> ids, String collectionName) {
DeleteReq deleteReq = DeleteReq.builder()
.collectionName(collectionName)
.ids(new ArrayList<>(ids))
.build();
clientV2.delete(deleteReq);
}
删除集合
public void deleteCollection(String collectionName) {
DropCollectionReq dropReq = DropCollectionReq.builder()
.collectionName(collectionName)
.build();
clientV2.dropCollection(dropReq);
}
5. 结论
Milvus 作为领先的向量数据库,能够高效地存储和检索高维数据。通过 Java SDK,可以轻松实现连接、数据管理及搜索功能。对于 Java 开发者而言,grpc-netty-shaded 是必须的,而 jersey-server 仅在使用 REST API 时才需要。
如需深入了解,请参考 Milvus 官方文档。
