
大家好,我是飞哥!👋
在 【Python AI实战】手把手带你从零打造"满血版"RAG:切片、混合检索与自动化评估,我们用了 ChromaDB。它很棒,像个轻便的"瑞士军刀"🔪,适合单机、小规模数据。
但如果你的知识库有 100 万篇 文档,或者你的公司有 1000 人同时在搜,ChromaDB 直接存文件的模式可能就扛不住了。😫
这时候,我们需要重型武器 ------ Milvus 。它是向量数据库界的"Oracle/MySQL"🏢,专为海量数据(亿级)设计。
今天飞哥就带大家把数据从"小作坊"迁移到"大工厂"!🏭
📦 准备工作
1. 安装 Python 库
bash
pip install pymilvus numpy
2. 安装 Docker Desktop
Milvus 比较复杂,必须运行在 Docker 容器里。请确保你已经安装并启动了 Docker Desktop。🐳
第一步:理解"索引" (Index) 📑
1. 为什么要索引?(Anchor & Analogy)
想象你去图书馆找一本书。
- 暴力搜索 (Flat):从第一排书架第一本书开始,一本一本比对书名。如果有 100 万本书,你得累死。😓
- 索引搜索 (IVF/HNSW):你先查"索引卡片",知道书在"B 区 3 排",直接跑过去找。⚡️
在向量数据库里,HNSW (Hierarchical Navigable Small World) 是目前最先进的索引算法,它像在数据之间修了高速公路网 🛣️,让你能毫秒级找到最相似的向量。
2. 核心概念对比
| 概念 | 关系型数据库 (MySQL) | 向量数据库 (Milvus) |
|---|---|---|
| 库 | Database | Database |
| 表 | Table | Collection (集合) |
| 行 | Row | Entity (实体) |
| 列 | Column | Field (字段) |
第二步:环境搭建 (Docker) 🐳
Milvus 架构复杂,依赖 Etcd、MinIO 等组件。强烈建议使用 Docker Compose 部署。
1. 什么是 docker-compose.yml?
很多同学容易搞混:
- ❌ 不是
docker pull ...下载的镜像文件。 - ✅ 而是 一个文本配置文件(说明书)。它告诉 Docker:"请帮我启动 Milvus、Etcd、MinIO 这三个容器,并把它们连起来。"
2. 获取配置文件
方式一:自动下载(推荐)
bash
curl -sfL https://github.com/milvus-io/milvus/releases/download/v2.3.0/milvus-standalone-docker-compose.yml -o docker-compose.yml
方式二:手动创建(如果下载失败)
如果在国内下载慢,可以新建一个名为 docker-compose.yml 的文件,复制粘贴以下内容:
yaml
version: '3.5'
services:
etcd:
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.0
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
minio:
container_name: milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
environment:
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
command: minio server /minio_data
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.3.0
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: milvus-etcd:2379
MINIO_ADDRESS: milvus-minio:9000
volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
ports:
- "19530:19530"
- "9091:9091"
depends_on:
- "etcd"
- "minio"
3. 启动服务
bash
docker-compose up -d
启动后,你可以通过 docker ps 看到三个容器在运行:
milvus-standalone: 数据库本体milvus-etcd: 存元数据milvus-minio: 存向量数据文件
4. (可选) 安装可视化面板 Attu 📊
嫌命令行太累?推荐安装 Attu (Milvus 的官方 GUI 工具)。
它可以像 Navicat 连 MySQL 一样,让你直观地浏览向量数据、测试搜索效果。
-
一键启动命令 :
bashdocker run -p 8000:3000 -e MILVUS_URL=host.docker.internal:19530 zilliz/attu:v2.2.6(启动后访问 http://localhost:8000)
第三步:代码实战 (Python SDK) 🐍
我们将完成一个完整的流程:建表 -> 建索引 -> 插入数据 -> 搜索。
创建一个 milvus_demo.py:
python
import time
import numpy as np
from pymilvus import (
connections,
FieldSchema, CollectionSchema, DataType,
Collection, utility
)
# --- 1. 连接 Milvus ---
print("🔌 正在连接 Milvus...")
connections.connect("default", host="localhost", port="19530")
# --- 2. 定义表结构 (Schema) ---
# 每次运行前清理旧数据(仅供测试)
if utility.has_collection("company_docs"):
utility.drop_collection("company_docs")
fields = [
# 主键,自动增长
FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=True),
# 文本内容,最大长度 1000
FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=1000),
# 向量,假设我们用 BGE 模型,维度是 768
FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=768)
]
schema = CollectionSchema(fields, "企业知识库")
# 创建集合
knowledge_base = Collection("company_docs", schema)
print("✅ 集合创建成功!")
# --- 3. 创建索引 (HNSW) ---
# 这是最关键的一步!
index_params = {
"metric_type": "COSINE", # 相似度算法:余弦相似度
"index_type": "HNSW", # 索引类型
"params": {"M": 8, "efConstruction": 64} # HNSW 参数
}
knowledge_base.create_index(field_name="embeddings", index_params=index_params)
print("🚀 索引构建完成!")
# --- 4. 插入数据 ---
print("📥 正在插入数据...")
# 模拟 10 条数据
vectors = [[np.random.rand() for _ in range(768)] for _ in range(10)] # 随机生成向量
texts = [f"这是第 {i} 条机密文档" for i in range(10)]
# 注意:Milvus 插入格式是按列组织 [所有text, 所有vector]
knowledge_base.insert([texts, vectors])
# ⚡️ 强制落盘 (可选,但建议在 Demo 中加上,确保数据立即可见)
knowledge_base.flush()
# 加载到内存 (Milvus 搜索前必须 Load)
knowledge_base.load()
# --- 5. 搜索 ---
print("🔍 开始搜索...")
search_params = {"metric_type": "COSINE", "params": {"ef": 10}}
# 拿第一条向量去搜
query_vector = vectors[0]
results = knowledge_base.search(
data=[query_vector],
anns_field="embeddings",
param=search_params,
limit=3, # 返回最相似的3个
output_fields=["text"] # 同时返回 text 字段
)
for hit in results[0]:
print(f"ID: {hit.id}, 距离: {hit.distance:.4f}, 内容: {hit.entity.get('text')}")
🔧 核心操作速查手册 (CRUD)
代码跑通了?我们把关键操作拆解开,方便你以后复制粘贴到项目里:
1. 表管理 (Manage)
-
建表 (Create) :
python# 定义字段:ID (主键) + 向量 (768维) fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=768) ] schema = CollectionSchema(fields, "示例表") collection = Collection("demo_table", schema)💡 维度 (dim) 怎么填?
这个数字不是算出来的,而是由你的 Embedding 模型决定的。必须严格一致!
- OpenAI text-embedding-3-small: 1536
- BGE-base-zh-v1.5: 768
- BGE-large-zh-v1.5: 1024
- 如果不确定,先跑一句代码
print(len(model.encode("测试")))确认一下!
-
删表 (Drop) :
pythonfrom pymilvus import utility utility.drop_collection("demo_table") # ⚠️ 警告:这会瞬间清空所有数据!
2. 分区管理 (Partition) ⚡️
-
创建/删除分区 :
Milvus 物理分区,适合做多租户隔离(比如给每个部门建一个分区)。python# 创建分区 "finance_dept" collection.create_partition("finance_dept") # 删除分区 collection.drop_partition("finance_dept") -
指定分区插入/搜索 :
python# 插入到指定分区 collection.insert([vectors], partition_name="finance_dept") # 只在指定分区内搜索(速度更快!) collection.search(..., partition_names=["finance_dept"])
3. 索引与内存 (Index & Memory)
-
创建索引 (Build Index) :
Milvus 必须建了索引才能搜(这点和 MySQL 不一样,MySQL 没索引也能全表扫描,Milvus 不行)。
pythonindex_params = { "metric_type": "COSINE", "index_type": "HNSW", "params": {"M": 8, "efConstruction": 64} } collection.create_index("vector", index_params)💡 HNSW 参数小贴士:
M: 节点最大连接数(建议 8-64)。越大越准,建索引越慢。efConstruction: 搜索范围(建议 64-512)。越大越准,建索引越慢。
-
加载/释放内存 (Load/Release) :
Milvus 是内存数据库,搜索前必须把数据 Load 进内存。
pythoncollection.load() # ⚡️ 搜索前必做! collection.release() # 不用时释放,省内存
4. 数据增删改 (DML)
-
插入 (Insert) :
pythonimport numpy as np # 生成 10 条 768 维的随机向量 vectors = [[np.random.rand() for _ in range(768)] for _ in range(10)] # 插入数据 (注意:列表必须按列排列) collection.insert([vectors]) -
删除 (Delete) :
python# 删除主键为 1 和 2 的数据 collection.delete("id in [1, 2]") -
修改 (Upsert) :
python# ⚠️ 注意:Upsert 仅适用于 auto_id=False (手动管理主键) 的表 # 如果是 auto_id=True,请使用 Delete + Insert 替代 collection.upsert([[1], [new_vector]])
5. 数据查询 (DQL)
-
向量搜索 (Search) :拿向量找向量(找相似)
python# 找最相似的 Top 3 results = collection.search( data=[query_vector], anns_field="vector", param={"metric_type": "COSINE", "params": {"ef": 10}}, limit=3, expr="id > 100" # ✨ 进阶:混合检索(只搜 ID > 100 的数据) ) -
标量查询 (Query) :拿条件找数据(找精确)
python# 类似 SQL: SELECT * FROM table WHERE ... res = collection.query( expr="id in [1, 2, 3]", # 💡 常用:按主键批量获取 output_fields=["id", "vector"] )
第四步:避坑指南 ------ 向量库 vs MySQL 的核心差异 🚧
很多转型的同学习惯用 MySQL 的思维去用 Milvus,结果掉进坑里。这里飞哥给大家画个重点:
1. 查询逻辑不同 (Fuzzy vs Exact)
- MySQL : 精确匹配 。比如
WHERE age = 25,结果要么是 25,要么不是。 - Milvus : 模糊匹配(相似度) 。
Search(vector),结果是"离这个向量最近的 Top K 个邻居",哪怕没有一模一样的,它也会给你找个"长得最像的"。
2. 索引原理不同 (B-Tree vs HNSW)
- MySQL (B-Tree) : 目的是100% 找到数据。
- Milvus (HNSW) : 目的是极速找到(牺牲极少量的精度)。它是在高维空间里"修高速公路",有时候为了快,可能会漏掉一两个边缘数据,但这在 AI 推荐/问答场景里完全可以接受(这叫 Recall 召回率)。
3. 更新操作不同 (Update vs Delete+Insert)
- MySQL :
UPDATE table SET ...非常顺滑。 - Milvus : 向量索引构建很重。不推荐频繁单条更新 。通常的最佳实践是:先
Delete旧数据,再Insert新数据。因为一旦改了向量,就好比你搬家了,地图上的路标(索引)得重新画,成本很高。
一句话记住 :MySQL 是找相同 (查字典),Milvus 是找相似(搜同款)。
总结 📚
- 场景:数据量 > 10 万或追求高并发,上 Milvus。📈
- 部署:Docker 是唯一正解,不要手动安装。🐳
- 索引:HNSW 是当今王者,兼顾速度与精度。👑
创作不易,记得👇关注飞哥👇 ,点赞、收藏哦~~,下篇见👋