第一部分:什么是向量数据库?
1. 核心概念
传统的数据库(如MySQL)擅长处理结构化的数值和文本,通过精确匹配(如 WHERE name = 'Alice')或范围查询来检索数据。
而向量数据库是专门设计用于存储、索引和检索向量 的数据库。
-
向量:本质上是一长串数字,例如
[0.12, -0.45, 0.89, ..., 0.67]。在AI领域,非结构化数据(如图片、文本、音频、视频)通过深度学习模型(如BERT、ResNet)被转换为高维向量(也称为“嵌入”)。 -
向量的意义:这个向量代表了原始数据的“语义”或“特征”。语义相近的数据,其向量在空间中的距离也更近。
2. 关键技术:相似度搜索
向量数据库的核心能力是相似度搜索,也称为最近邻搜索。
-
问题:给定一个查询向量,在庞大的向量库中快速找到与之最相似的K个向量。
-
度量方式:使用距离度量来计算相似度,常见的有:
-
余弦相似度:衡量向量方向的一致性,常用于文本。
-
欧氏距离:衡量空间中两点的直线距离。
-
内积。
-
在亿级甚至十亿级的向量中做“穷举”比较是不现实的。因此,向量数据库使用了专门的近似最近邻搜索算法来构建索引,在可接受的精度损失下,实现极快的检索速度。
3. 为什么需要专门的向量数据库?
你可能会问:“我不能把向量存成BLOB类型在MySQL里,然后用Python计算距离吗?”
可以,但效率极低,无法满足生产环境要求。向量数据库解决了以下核心问题:
-
性能:专用的索引算法(如HNSW, IVF)使得在海量数据中实现毫秒级检索成为可能。
-
可扩展性:支持分布式架构,可以轻松水平扩展以处理更多数据和更高并发。
-
易用性:提供简单的API,如
collection.insert(vectors)和collection.search(query_vector),让开发者专注于应用逻辑。 -
数据管理:提供类似传统数据库的数据管理功能,如集合、分区、元数据过滤、持久化、高可用等。
第二部分:什么是Milvus?
Milvus 是全球最流行的开源向量数据库之一。它被设计用来处理由非结构化数据转换而来的海量向量数据。
1. 核心特性
-
云原生架构:从一开始就设计了存储与计算分离的架构,使其在云上具有极佳的弹性和可扩展性。
-
高性能:集成了业界最先进的索引库(如FAISS)和算法(如HNSW),检索性能卓越。
-
开发者友好:提供了丰富的API(Python, Java, Go, RESTful),并与各种开源AI模型和框架(如LangChain)无缝集成。
-
混合查询:支持在向量相似度搜索的同时,结合标量字段(如日期、标签、作者)进行过滤。例如:“搜索与这张图片最相似的,且创建于2023年之后的图片。”
-
高可用与可扩展性:通过组件微服务化,支持动态扩缩容,并提供了高可用方案。
-
丰富的社区生态:拥有一个非常活跃的开源社区,提供了图形化管理工具(Attu)、监控工具等。
2. 架构简介
Milvus 采用分层架构,主要组件包括:
-
接入层:由一组无状态的代理 组成,负责接收客户端请求。
-
协调服务:负责管理集群的元数据、负载均衡和任务调度。
-
工作节点:
-
查询节点:负责执行向量和标量的混合搜索。
-
数据节点:负责管理向量的插入、删除和持久化。
-
-
对象存储:用于持久化存储向量和索引数据(通常使用S3、Azure Blob或Google Cloud Storage)。这是其存储计算分离的关键。
-
元数据存储:通常使用etcd来存储集合Schema、节点状态等元数据。
3. 核心概念
-
集合:类似MySQL中的表,是存储向量的主要单位。
-
实体:集合中的一行记录,包含一个或多个向量字段和标量字段。
-
分区:为了提升查询性能,可以将一个集合按某种规则(如日期)划分为多个分区。
-
索引:为了加速向量搜索,需要在向量字段上构建索引(如
HNSW、IVF_FLAT)。
第三部分:使用示例-python版
以下是一个使用 Milvus Python SDK 的极简流程,展示了从连接到搜索的全过程。
python
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
# 1. 连接到 Milvus 服务器
connections.connect("default", host="localhost", port="19530")
# 2. 定义集合的字段结构
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=128), # dim 是向量的维度
FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=200)
]
# 3. 创建集合 Schema
schema = CollectionSchema(fields, description="Movie collection")
# 4. 创建集合
collection_name = "movie_collection"
collection = Collection(name=collection_name, schema=schema)
# 5. 插入数据 (假设 `movie_embeddings` 是一个包含多个128维向量的列表)
# 同时插入对应的标题
data = [
movie_embeddings, # 向量数据
[“The Matrix”, “Inception”, “The Godfather”, ...] # 标量数据
]
mr = collection.insert(data)
# 6. 在向量字段上创建索引
index_params = {
"index_type": "IVF_FLAT",
"metric_type": "L2", # 使用欧氏距离
"params": {"nlist": 128}
}
collection.create_index("embedding", index_params)
# 7. 将集合加载到内存(搜索前必需步骤)
collection.load()
# 8. 执行向量搜索
search_params = {"metric_type": "L2", "params": {"nprobe": 10}}
query_embedding = [0.1, 0.2, ...] # 一个128维的查询向量
results = collection.search(
data=[query_embedding],
anns_field="embedding",
param=search_params,
limit=5, # 返回最相似的5个结果
output_fields=[“id”, “title”] # 指定要返回的字段
)
# 9. 处理结果
for hits in results:
for hit in hits:
print(f"ID: {hit.id}, Title: {hit.entity.get('title')}, Distance: {hit.distance}")
# 10. 使用完毕后,释放资源
collection.release()
第四部分:应用场景与对比
| 特性 | 传统数据库 (MySQL) | 向量数据库 (Milvus) |
|---|---|---|
| 主要数据类型 | 标量(整数、字符串等) | 向量(高维浮点数数组) |
| 核心查询 | 精确匹配、范围查询、JOIN | 相似度搜索(最近邻) |
| 索引技术 | B+ Tree, Hash | HNSW, IVF, ANNOY 等ANN索引 |
| 适用场景 | 业务交易、结构化数据管理 | AI应用、推荐系统、语义搜索、图像检索等 |
Milvus的典型应用场景:
-
推荐系统:找到与用户喜欢过的商品在向量空间中最相似的商品。
-
图片/视频检索:以图搜图,或根据描述文本搜索图片。
-
问答机器人/智能客服:将问题转换为向量,在海量知识库中寻找最相关的答案。
-
化学/生物信息学:搜索相似的分子结构或蛋白质序列。
-
异常检测:查找与正常模式向量差异过大的异常点。
总而言之,Milvus 作为一款强大的开源向量数据库,为处理AI时代产生的海量非结构化数据提供了至关重要的基础设施,是构建下一代智能应用的基石。
第五部分:从数据到向量
#数据向量化步骤
这是最关键的一步,目标是将非结构化数据(如文本、图片)转化为蕴含语义的向量。
-
数据准备与预处理
-
文本数据:常见的步骤包括分词、去除停用词、词干提取等。如果你的文本较长,还需要根据模型能处理的最大长度进行分块。
-
其他数据:对于图像、音频等,也需要进行相应的清洗和格式化。
-
-
向量化 (Embedding)
你需要选择一个合适的嵌入模型来完成向量化。常用模型包括:-
文本模型:如 OpenAI 的
text-embedding-ada-002、Sentence-BERT 等。 -
多模态模型:如 CLIP,可以同时处理文本和图像。
-
经典模型:如 Word2Vec、Doc2Vec。
这个步骤决定了向量的维度,例如text-embedding-ada-002生成的向量维度是 1536。
-
-
预处理嵌入向量
根据后续使用的相似度度量方法,有时需要对向量进行预处理。-
归一化:使向量长度为1,此时点积计算等价于余弦相似度,且计算更快。
-
标准化:使数据均值为0,标准差为1。
-
#将向量存入 Milvus
当向量准备好后,就可以将它们存入 Milvus 了。
-
连接 Milvus
首先,在你的代码中连接到 Milvus 服务。根据你的部署方式,连接参数会有所不同。python
from pymilvus import connections # 连接至 Milvus 服务 # 若使用 Milvus Lite,host 可为本地文件路径,api_key 留空[citation:2] connections.connect("default", host="./milvus.db", api_key="") # 若使用自部署的 Milvus 服务器或 Zilliz Cloud,需配置对应的 URI 和 Token[citation:2][citation:4] # connections.connect("default", uri="http://localhost:19530", token="username:password") # 或 connections.connect("default", uri="https://your-zilliz-cloud-endpoint", token="your-api-key") -
创建 Collection
Collection 类似于传统数据库中的表,你需要定义其结构,其中最重要的是指定向量的维度。python
from pymilvus import FieldSchema, CollectionSchema, DataType, Collection # 1. 定义字段(Field) fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=1536), # 维度需与你生成的向量一致 FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=200) # 可存储原始文本等元数据 ] # 2. 构建 Collection Schema schema = CollectionSchema(fields, description="示例 Collection") # 3. 创建 Collection collection = Collection("my_collection", schema) -
插入数据
现在,可以将你生成的向量和相关的元数据插入到 Collection 中。python
# 假设 `embeddings_list` 是你生成的向量列表 # 假设 `titles_list` 是对应的文本标题列表 data = [ embeddings_list, # 向量数据 titles_list # 标量元数据 ] insert_result = collection.insert(data) -
构建索引(关键步骤)
为了进行高速向量检索,你必须在向量字段上构建索引。Milvus 默认使用 HNSW 之类的近似最近邻 (ANN) 索引算法来平衡速度和精度。python
index_params = { "index_type": "IVF_FLAT", # 另一种常用索引类型 "metric_type": "L2", # 相似度度量方式,如 L2(欧氏距离)、IP(内积)、COSINE(余弦相似度) "params": {"nlist": 128} # 索引构建参数 } collection.create_index("vector", index_params)注意:选择的
metric_type(相似度度量方式)应与你的向量预处理方式匹配。例如,如果向量进行了归一化,使用点积(IP)是高效且等价于余弦相似度的选择。 -
完成与检索
插入数据并构建好索引后,在进行搜索前,需要将 Collection 加载到内存中。python
collection.load() # 现在,你可以使用 Milvus 进行高效的向量相似度搜索了
#常用工具与集成
为了提升效率,你可以利用一些现成的工具来简化上述流程:
-
VectorETL 框架:这是一个专为向量数据库设计的轻量级 ETL(提取、转换、加载)工具。它可以方便地从 Amazon S3、本地文件等数据源读取数据,调用 OpenAI 等模型生成向量,并直接写入 Milvus,自动化了整个管道。
-
Apify + LangChain:对于从网站抓取内容并构建知识库的场景(常用于 RAG 应用),可以使用 Apify 这样的网页抓取工具获取数据,然后通过为 Milvus 准备的 LangChain 集成组件,轻松地将抓取到的文本向量化并存储到 Milvus。
#重要提醒与实践建议
-
维度一致:确保你使用的嵌入模型输出的向量维度,与创建 Milvus Collection 时定义的维度完全一致。
-
相似度度量的选择:这是影响搜索结果质量的关键参数。请根据你的数据特性和应用场景(例如,是找最相似的还是找最近邻)来选择合适的度量方式。
-
元数据是宝藏:强烈建议将向量的原始数据(如文本段落)或其他有用的元数据(如标签、日期)与向量一同存储。这样你可以在进行向量搜索时,结合元数据进行过滤,实现更精确的查询。
#如何生成向量
我们生成向量通常使用嵌入模型。对于文本,常见的模型有OpenAI的text-embedding-ada-002,或者开源的Sentence-BERT模型。对于图像,可以使用CNN或CLIP等模型。这里以文本为例,介绍两种常见方式:
-
使用OpenAI的嵌入模型(需要API密钥)
-
使用开源的Sentence-BERT模型(本地运行)
方法一:使用OpenAI的嵌入模型
首先,你需要安装OpenAI的Python库,并获取API密钥。
python
import openai
import os
# 设置你的OpenAI API密钥
openai.api_key = os.getenv("OPENAI_API_KEY") # 或者直接写你的密钥,但更推荐用环境变量
def get_embedding_openai(text, model="text-embedding-ada-002"):
text = text.replace("\n", " ")
response = openai.Embedding.create(
input=[text],
model=model
)
return response['data'][0]['embedding']
# 示例
text = "这是一个示例文本。"
embedding = get_embedding_openai(text)
print(embedding) # 这是一个1536维的向量
方法二:使用Sentence-BERT模型
首先,安装sentence-transformers库。
bash
pip install sentence-transformers
然后,使用以下代码生成向量:
python
from sentence_transformers import SentenceTransformer
# 加载模型
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2') # 这里选择一个多语言模型,如果你处理中文
def get_embedding_sbert(texts):
# 注意:模型可以处理单个字符串也可以处理字符串列表
embeddings = model.encode(texts)
return embeddings
# 示例
texts = ["这是一个示例文本。"]
embeddings = get_embedding_sbert(texts)
print(embeddings[0]) # 输出第一个文本的向量,维度为384(根据模型不同而变化)
注意:
-
使用OpenAI的模型需要付费,但质量通常较好,且维度为1536。
-
使用Sentence-BERT可以选择多种模型,有的模型维度较低(如384),但可以在本地运行,且对于中文有多语言模型支持。
#生成向量后存入Milvus
生成向量后,我们可以按照之前介绍的步骤存入Milvus。这里假设我们已经有一批文本,需要生成向量并存入。
以下是一个完整的示例,使用Sentence-BERT生成向量并存入Milvus:
python
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
from sentence_transformers import SentenceTransformer
# 1. 连接Milvus
connections.connect("default", host="localhost", port="19530")
# 2. 定义Collection Schema
dim = 384 # 根据使用的模型确定维度,这里使用Sentence-BERT的模型维度为384
collection_name = "text_collection"
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=dim),
FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=500)
]
schema = CollectionSchema(fields, description="Text collection with embeddings")
collection = Collection(collection_name, schema)
# 3. 生成向量
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
texts = [
"今天天气真好。",
"我喜欢吃苹果。",
"机器学习很有趣。",
"北京是中国的首都。"
]
embeddings = model.encode(texts).tolist() # 将numpy数组转换为列表
# 4. 准备插入的数据
insert_data = [embeddings, texts] # 注意:这里两个列表,分别对应vector和text字段
# 5. 插入数据
collection.insert(insert_data)
# 6. 创建索引
index_params = {
"index_type": "IVF_FLAT",
"metric_type": "L2",
"params": {"nlist": 128}
}
collection.create_index("vector", index_params)
# 7. 加载Collection
collection.load()
# 8. 进行搜索测试(可选)
search_vectors = [embeddings[0]] # 用第一句话的向量进行搜索
search_params = {"metric_type": "L2", "params": {"nprobe": 10}}
results = collection.search(
data=search_vectors,
anns_field="vector",
param=search_params,
limit=3,
output_fields=["text"]
)
for hits in results:
for hit in hits:
print(f"命中文本: {hit.entity.get('text')}, 距离: {hit.distance}")
# 9. 释放资源
collection.release()
注意事项:
-
确保Milvus服务正在运行。
-
根据你的模型调整向量维度。
-
索引参数和搜索参数可以根据需要调整。
以上就是一个完整的从文本生成向量并存入Milvus的流程。如果你使用OpenAI的模型,只需替换生成向量的部分,并将维度改为1536即可。
生成向量是构建 AI 应用的核心步骤。我将详细介绍几种主流的向量生成方法,并提供具体的代码示例。
#向量生成的核心概念
向量(也称嵌入/Embedding)是将非结构化数据(文本、图像等)转换为数值数组的过程,这些数值能够捕捉原始数据的语义特征。
python
# 示例:一个文本的向量表示 "今天天气很好" → [0.12, -0.45, 0.78, ..., 0.92] # 通常是几百到几千维的浮点数
文本向量生成方法
1. 使用 OpenAI API(最简便)
python
import openai
import numpy as np
# 设置 API 密钥
openai.api_key = "your-api-key"
def get_openai_embedding(text, model="text-embedding-ada-002"):
"""
使用 OpenAI 生成文本向量
维度: 1536
"""
text = text.replace("\n", " ")
response = openai.Embedding.create(
input=[text],
model=model
)
return np.array(response['data'][0]['embedding'])
# 使用示例
text = "机器学习是人工智能的重要分支"
vector = get_openai_embedding(text)
print(f"向量维度: {vector.shape}") # 输出: (1536,)
2. 使用 Sentence-Transformers(本地运行,免费)
python
# 安装: pip install sentence-transformers
from sentence_transformers import SentenceTransformer
import numpy as np
# 加载预训练模型
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
def generate_text_embeddings(texts):
"""
生成文本向量 - 支持多语言
维度: 384
"""
# 如果是单个文本,转换为列表
if isinstance(texts, str):
texts = [texts]
# 生成向量
embeddings = model.encode(texts)
return embeddings
# 使用示例
texts = [
"今天天气很好,适合出去散步",
"机器学习模型需要大量数据进行训练",
"深度学习是机器学习的一个子领域"
]
embeddings = generate_text_embeddings(texts)
print(f"生成的向量形状: {embeddings.shape}") # 输出: (3, 384)
3. 使用 Hugging Face Transformers
python
# 安装: pip install transformers torch
from transformers import AutoTokenizer, AutoModel
import torch
import numpy as np
def get_hf_embedding(text, model_name="bert-base-chinese"):
"""
使用 Hugging Face 模型生成向量
"""
# 加载模型和分词器
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
# 编码文本
inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True, max_length=512)
# 生成向量
with torch.no_grad():
outputs = model(**inputs)
# 使用 [CLS] token 的隐藏状态作为句子向量
embedding = outputs.last_hidden_state[:, 0, :].numpy()[0]
return embedding
# 使用示例
text = "这是一个测试句子"
vector = get_hf_embedding(text)
print(f"向量维度: {vector.shape}") # BERT-base: (768,)
图像向量生成方法
1. 使用 CLIP 模型(多模态)
python
# 安装: pip install clip torch torchvision
import clip
import torch
from PIL import Image
import numpy as np
# 加载 CLIP 模型
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)
def generate_image_embedding(image_path):
"""
使用 CLIP 生成图像向量
维度: 512
"""
# 加载和预处理图像
image = preprocess(Image.open(image_path)).unsqueeze(0).to(device)
# 生成向量
with torch.no_grad():
image_features = model.encode_image(image)
embedding = image_features.cpu().numpy()[0]
return embedding
def generate_text_embedding_clip(text):
"""
使用 CLIP 生成文本向量
维度: 512
"""
text_inputs = clip.tokenize([text]).to(device)
with torch.no_grad():
text_features = model.encode_text(text_inputs)
embedding = text_features.cpu().numpy()[0]
return embedding
# 使用示例
image_vector = generate_image_embedding("path/to/image.jpg")
text_vector = generate_text_embedding_clip("一只猫在沙发上")
print(f"图像向量维度: {image_vector.shape}") # (512,)
print(f"文本向量维度: {text_vector.shape}") # (512,)
2. 使用 ResNet 等 CNN 模型
python
import torch
import torchvision.models as models
import torchvision.transforms as transforms
from PIL import Image
import numpy as np
def generate_resnet_embedding(image_path):
"""
使用 ResNet 生成图像特征向量
维度: 2048
"""
# 加载预训练模型
model = models.resnet50(pretrained=True)
model = torch.nn.Sequential(*(list(model.children())[:-1])) # 移除最后的全连接层
model.eval()
# 图像预处理
transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
image = Image.open(image_path)
image_tensor = transform(image).unsqueeze(0)
# 生成向量
with torch.no_grad():
embedding = model(image_tensor).squeeze().numpy()
return embedding
# 使用示例
image_vector = generate_resnet_embedding("path/to/image.jpg")
print(f"ResNet 向量维度: {image_vector.shape}") # (2048,)
批量生成向量
在实际应用中,通常需要批量处理数据:
python
def batch_generate_embeddings(texts, batch_size=32):
"""
批量生成文本向量
"""
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
all_embeddings = []
for i in range(0, len(texts), batch_size):
batch_texts = texts[i:i+batch_size]
batch_embeddings = model.encode(batch_texts)
all_embeddings.extend(batch_embeddings)
print(f"处理进度: {min(i+batch_size, len(texts))}/{len(texts)}")
return np.array(all_embeddings)
# 批量处理示例
documents = [
"文档1的内容...",
"文档2的内容...",
# ... 更多文档
]
vectors = batch_generate_embeddings(documents)
print(f"批量生成的向量形状: {vectors.shape}")
#向量预处理
生成向量后,通常需要进行预处理:
python
def preprocess_vectors(vectors, normalize=True):
"""
向量预处理
"""
vectors = np.array(vectors)
if normalize:
# L2 归一化,便于使用余弦相似度
norms = np.linalg.norm(vectors, axis=1, keepdims=True)
vectors = vectors / norms
return vectors.tolist()
# 预处理示例
raw_vectors = generate_text_embeddings(["示例文本"])
processed_vectors = preprocess_vectors(raw_vectors)
#模型选择建议
| 使用场景 | 推荐模型 | 维度 | 特点 |
|---|---|---|---|
| 通用文本 | text-embedding-ada-002 | 1536 | 效果最好,但需要 API 调用 |
| 中文文本 | paraphrase-multilingual-MiniLM-L12-v2 | 384 | 支持多语言,本地运行 |
| 专业领域 | 在领域数据上微调的 BERT | 768 | 领域适应性强 |
| 图像 | CLIP | 512 | 多模态,支持图文互搜 |
| 图像特征 | ResNet-50 | 2048 | 纯图像特征提取 |
实际应用示例
python
# 完整的文本到向量处理流程
def text_to_milvus_ready(texts, collection_name="documents"):
"""
将文本列表转换为 Milvus 就绪格式
"""
# 1. 生成向量
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
vectors = model.encode(texts)
# 2. 预处理(归一化)
vectors = preprocess_vectors(vectors)
# 3. 准备插入数据
data = [
vectors, # 向量数据
texts # 原始文本(作为元数据存储)
]
return data
# 使用
texts = ["第一条数据", "第二条数据", "更多数据..."]
milvus_data = text_to_milvus_ready(texts)
重要注意事项
-
维度一致性: 确保所有向量的维度相同
-
模型选择: 根据具体任务选择合适的模型
-
批量处理: 大量数据时使用批量处理提高效率
-
内存管理: 大向量集合需要注意内存使用
-
归一化: 根据相似度度量方法决定是否归一化
选择哪种方法主要取决于:
-
数据量: 大量数据建议使用本地模型
-
预算: OpenAI API 需要付费
-
语言: 中文任务选择多语言模型
-
实时性要求: API 调用有网络延迟
1181

被折叠的 条评论
为什么被折叠?



