Milvus 向量資料庫完整指南

使用 Milvus 儲存和檢索向量資料,建構語義搜尋、RAG、推薦系統等 AI 應用

專案簡介

Milvus 是一個開源的向量資料庫,專為儲存、索引和搜尋大規模向量資料設計。支援十億級向量的毫秒級搜尋,是建構 RAG、語義搜尋、推薦系統的首選方案。

GitHub Stars: 42K+

主要功能

  • 高效能 - 十億級向量毫秒搜尋
  • 多索引 - IVF、HNSW、ANNOY 等
  • 標量過濾 - 結合向量和屬性搜尋
  • 分散式架構 - 水平擴展
  • 雲原生 - Kubernetes 部署

快速部署

Docker Compose(Standalone)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
version: '3.8'
services:
  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:
      - etcd-data:/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:
    image: minio/minio:RELEASE.2023-03-20T20-16-18Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    volumes:
      - minio-data:/minio_data
    command: minio server /minio_data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3

  milvus:
    image: milvusdb/milvus:v2.4-latest
    command: ["milvus", "run", "standalone"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    volumes:
      - milvus-data:/var/lib/milvus
    ports:
      - "19530:19530"
      - "9091:9091"
    depends_on:
      - etcd
      - minio

volumes:
  etcd-data:
  minio-data:
  milvus-data:

Milvus Lite(開發用)

1
2
3
4
from pymilvus import MilvusClient

# 使用本地檔案
client = MilvusClient("milvus_demo.db")

Python SDK

安裝

1
pip install pymilvus

連線

1
2
3
4
5
6
7
from pymilvus import connections, Collection

connections.connect(
    alias="default",
    host="localhost",
    port="19530"
)

建立 Collection

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from pymilvus import CollectionSchema, FieldSchema, DataType

# 定義 Schema
fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
    FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=1000),
    FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=768)
]

schema = CollectionSchema(fields, description="Document embeddings")

# 建立 Collection
collection = Collection(name="documents", schema=schema)

# 建立索引
index_params = {
    "metric_type": "COSINE",
    "index_type": "IVF_FLAT",
    "params": {"nlist": 1024}
}
collection.create_index(field_name="embedding", index_params=index_params)

插入資料

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from sentence_transformers import SentenceTransformer

# 載入 Embedding 模型
model = SentenceTransformer('all-MiniLM-L6-v2')

# 準備資料
texts = [
    "Kubernetes 是容器編排平台",
    "Docker 是容器化技術",
    "Terraform 是基礎設施即程式碼工具"
]

embeddings = model.encode(texts).tolist()

# 插入
data = [
    texts,
    embeddings
]

collection.insert([
    {"text": text, "embedding": emb}
    for text, emb in zip(texts, embeddings)
])

# 載入到記憶體
collection.load()

向量搜尋

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 查詢向量
query_text = "什麼是容器技術?"
query_embedding = model.encode(query_text).tolist()

# 搜尋
results = collection.search(
    data=[query_embedding],
    anns_field="embedding",
    param={"metric_type": "COSINE", "params": {"nprobe": 10}},
    limit=5,
    output_fields=["text"]
)

for hits in results:
    for hit in hits:
        print(f"Score: {hit.score}, Text: {hit.entity.get('text')}")

標量過濾

1
2
3
4
5
6
7
8
9
# 結合向量搜尋和過濾
results = collection.search(
    data=[query_embedding],
    anns_field="embedding",
    param={"metric_type": "COSINE"},
    limit=5,
    expr="category == 'cloud'",
    output_fields=["text", "category"]
)

索引類型

索引類型適用場景特點
IVF_FLAT中等規模精確度高
IVF_SQ8大規模節省記憶體
IVF_PQ超大規模壓縮向量
HNSW低延遲速度快
ANNOY靜態資料磁碟索引

HNSW 索引

1
2
3
4
5
6
7
8
9
index_params = {
    "metric_type": "COSINE",
    "index_type": "HNSW",
    "params": {
        "M": 16,
        "efConstruction": 256
    }
}
collection.create_index("embedding", index_params)

RAG 應用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from pymilvus import MilvusClient
from openai import OpenAI

# 初始化客戶端
milvus = MilvusClient("milvus.db")
openai = OpenAI()

def rag_query(question: str) -> str:
    # 生成 Embedding
    response = openai.embeddings.create(
        model="text-embedding-3-small",
        input=question
    )
    query_embedding = response.data[0].embedding

    # 向量搜尋
    results = milvus.search(
        collection_name="documents",
        data=[query_embedding],
        limit=3,
        output_fields=["text"]
    )

    # 組合上下文
    context = "\n".join([hit["entity"]["text"] for hit in results[0]])

    # 生成回答
    completion = openai.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": f"根據以下內容回答問題:\n{context}"},
            {"role": "user", "content": question}
        ]
    )

    return completion.choices[0].message.content

LangChain 整合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from langchain_community.vectorstores import Milvus
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()

# 建立向量儲存
vectorstore = Milvus.from_documents(
    documents,
    embeddings,
    connection_args={"host": "localhost", "port": "19530"},
    collection_name="langchain_docs"
)

# 相似度搜尋
docs = vectorstore.similarity_search("什麼是 Kubernetes?", k=3)

相關連結

延伸閱讀

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy