Qdrant:高性能向量搜索引擎
bash
docker pull qdrant/qdrant
docker run -p 6333:6333 -p 6334:6334
-v $(pwd)/qdrant_storage:/qdrant/storage:z
qdrant/qdrant
启动后,你可以通过以下地址访问服务:
- REST API:`http://localhost:6333`
- Web UI(便捷调试面板):`http://localhost:6333/dashboard`
- gRPC API:`http://localhost:6334`(高性能场景使用)
> 如果你不想安装任何东西,也可以使用 Qdrant 官方提供的 [在线试用环境](https://cloud.qdrant.io)。
本教程以 REST API 为例进行演示(也可使用 Python、JavaScript 等客户端库,基本原理相同)。
## 核心概念速览
在开始实战之前,先理解这几个名词:
- **Collection(集合)**:类似关系型数据库中的表,用于组织一组向量数据。集合定义时需指定向量的维度和距离度量方式。
- **Point(点)**:集合中的一条记录,包含:
- `id`:唯一标识(数字或 UUID)
- `vector`:浮点数数组,维度必须与集合定义一致
- `payload`(可选):任意 JSON 对象,存储与该点关联的业务属性(如标题、价格、类别)
- **距离度量**:计算两个向量相似程度的算法,Qdrant 支持:
- `Cosine`(余弦相似度)
- `Euclid`(欧几里得距离)
- `Dot`(点积,常用于已归一化的向量)
## 实战:构建一个简单的书籍语义搜索
假设我们有一个书籍数据库,每本书对应一个意义向量(由某种语言模型生成),我们想基于用户查询的向量找到语义最接近的书,并且可以按类别、价格过滤。
### 1. 创建 Collection
首先创建一个名为 `books` 的集合,向量维度为 384(如果你用 all-MiniLM-L6-v2 这类模型,输出就是 384 维),使用余弦相似度。
```bash
curl -X PUT 'http://localhost:6333/collections/books' \
-H 'Content-Type: application/json' \
--data-raw '{
"vectors": {
"size": 384,
"distance": "Cosine"
}
}'
参数解释:size 指定向量维度,distance 指定距离度量。创建成功后,你会收到包含 "status":"ok" 的响应。
2. 插入向量数据
现在插入几个点。每个点包含一个 384 维向量(此处为了演示,我们用随机小数代替,实际应使用模型提取的 embeddings),以及描述书籍的 payload。
curl -X PUT 'http://localhost:6333/collections/books/points' \
-H 'Content-Type: application/json' \
--data-raw '{
"points": [
{
"id": 1,
"vector": [0.05, 0.13, -0.22, ...], // 此处补全384个浮点数
"payload": {
"title": "Deep Learning",
"author": "Ian Goodfellow",
"category": "AI",
"price": 49.99
}
},
{
"id": 2,
"vector": [0.02, -0.10, 0.18, ...],
"payload": {
"title": "The Great Gatsby",
"author": "F. Scott Fitzgerald",
"category": "Fiction",
"price": 9.99
}
}
]
}'
实际开发中,向量通常由模型批量生成,这里省略具体数值。你可以使用 Qdrant Python 客户端 更方便地上传数据:
client.upsert(collection_name, points)。
3. 执行向量搜索
假设我们现在有一段查询文本 “machine learning for beginners”,经过嵌入模型得到查询向量 query_vector。我们想找与其最相似的 3 本书,并希望只返回类别为 “AI” 且价格小于 60 的结果。
curl -X POST 'http://localhost:6333/collections/books/points/search' \
-H 'Content-Type: application/json' \
--data-raw '{
"vector": [0.01, -0.05, 0.12, ...], // 查询向量
"limit": 3,
"with_payload": true,
"filter": {
"must": [
{ "key": "category", "match": { "value": "AI" } },
{ "key": "price", "range": { "lt": 60 } }
]
}
}'
响应示例:
{
"result": [
{
"id": 1,
"score": 0.92,
"payload": {
"title": "Deep Learning",
"category": "AI",
"price": 49.99
}
}
// ... 其他相似结果
],
"status": "ok",
"time": 0.003
}
score 反映了相似度,值越接近 1 表示越相似(余弦相似度)。过滤条件可以在 filter 中灵活组合 must、should、must_not。
进阶功能:索引优化与负载管理
选择向量索引
Qdrant 默认使用 HNSW(分层可导航小世界图) 索引,这是一种近似最近邻算法,能够在搜索速度与精度间取得良好平衡。你可以在创建集合时自定义 HNSW 参数:
{
"vectors": { "size": 384, "distance": "Cosine" },
"hnsw_config": {
"m": 16, // 每个节点的最大连接数,影响内存使用和搜索速度
"ef_construct": 100 // 构建索引时的搜索宽度
}
}
m越大,索引质量越好,但内存占用越大。ef_construct越高,索引构建时间越长,但搜索效果更优。
使用 Payload 索引加速过滤
默认情况下,对 payload 字段的过滤是扫描匹配。在数据量大且频繁按某些字段过滤时,可以为这些字段创建索引:
curl -X PUT 'http://localhost:6333/collections/books/index' \
-H 'Content-Type: application/json' \
--data-raw '{
"field_name": "category",
"field_type": "keyword"
}'
支持的字段类型包括 keyword、integer、float、geo 等。创建索引后,过滤性能会显著提升。
批量操作与性能调优
- 使用 Upsert 代替逐个插入,以减少网络开销。
- 调整
search请求中的params字段,可临时修改搜索参数,例如"hnsw_ef": 128可以提高召回率,但耗时也会增加。 - 对于超大数据集,可启用 磁盘索引(Disk Index),降低内存占用,牺牲少量性能。
客户端库快速集成
对于 Python 开发者,安装官方客户端:
pip install qdrant-client
创建客户端并执行搜索:
from qdrant_client import QdrantClient
from qdrant_client.models import Filter, FieldCondition, MatchValue, Range
client = QdrantClient(host="localhost", port=6333)
# 搜索
results = client.search(
collection_name="books",
query_vector=query_embedding,
limit=3,
query_filter=Filter(
must=[
FieldCondition(key="category", match=MatchValue(value="Fiction")),
FieldCondition(key="price", range=Range(lt=20))
]
)
)