在构建语义搜索、以图搜图或者大模型RAG应用时,如何高效存储和检索海量向量数据是一个绕不开的问题。Qdrant作为一款用Rust编写的开源向量检索引擎,凭借出色的性能表现和丰富的过滤能力,成为近年向量数据库领域的热门选择。本文将从核心概念入手,带你完整走一遍Qdrant的接入流程,包括部署、创建集合、写入向量、执行相似度检索以及带过滤条件的高级查询。

Qdrant是什么:核心概念与存储模型
Qdrant是一个专门为向量检索设计的数据库,底层用Rust实现,充分继承了Rust在内存安全和并发性能上的优势。它的核心数据组织单位是Collection(集合),每个集合内部包含若干个Point(点),每个Point由三部分组成:唯一的ID、一个或多个向量、以及可选的Payload(负载)。
这里的Payload非常关键,它本质上是一个JSON结构,可以存放任意业务字段,例如商品的类目、文档的语言、用户的标签等。Qdrant的强大之处在于,检索时可以同时进行向量相似度计算和Payload过滤,也就是先通过向量找到语义相近的结果,再通过标量条件筛掉不符合业务规则的记录,两者在一次查询内完成,无需应用层二次过滤。
在索引结构上,Qdrant默认使用HNSW(分层可导航小世界图)算法,这是目前向量检索领域的主流方案,兼顾了召回率和查询速度。同时它支持在内存与磁盘之间分层存储,向量数据可以放在磁盘上,索引的热点部分驻留内存,大幅降低了大规模场景下的硬件成本。
快速部署与创建第一个集合
接入Qdrant最简单的方式是使用Docker部署。执行以下命令即可在本机启动一个单节点实例,服务默认监听6333端口(REST接口)和6334端口(gRPC接口):
docker pull qdrant/qdrant docker run -p 6333:6333 -p 6334:6334 \ -v $(pwd)/qdrant_storage:/qdrant/storage \ qdrant/qdrant
启动完成后,访问http://127.0.0.1:6333/dashboard可以打开官方提供的管理界面,直观查看集合状态和点位数量。接下来需要创建一个集合,并指定向量维度和距离度量方式。以OpenAI的text-embedding-ada-002模型输出的1536维向量为例,使用Python客户端的写法如下:
from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://127.0.0.1:6333")
# 创建集合,向量维度1536,使用余弦相似度
client.create_collection(
collection_name="articles",
vectors_config=models.VectorParams(
size=1536,
distance=models.Distance.COSINE
)
)距离度量的选择需要与 embedding 模型的训练方式匹配。如果模型输出已经归一化,使用COSINE和DOT效果基本一致;若模型未归一化,EUCLID则更直观地反映空间距离。选错度量方式会导致召回质量明显下降,这是初学者常见的坑。
写入向量与执行相似度检索
集合建好后,就可以批量写入向量数据。Qdrant推荐使用批量接口而不是逐条插入,批量写能够显著减少网络往返开销。下面的示例演示了如何构造带Payload的点位数据并写入:
from qdrant_client import models
points = [
models.PointStruct(
id=1,
vector=embedding_vector, # 1536维浮点数组
payload={"title": "Rust入门指南", "category": "programming", "lang": "zh"}
),
models.PointStruct(
id=2,
vector=another_vector,
payload={"title": "Vector DB对比分析", "category": "database", "lang": "zh"}
),
]
client.upsert(
collection_name="articles",
points=points,
wait=True # 等待写入生效,保证一致性
)写入完成后即可执行搜索。最基本的搜索只需提供查询向量和希望返回的数量,Qdrant会返回最相似的N个点位及其相似度得分:
results = client.search(
collection_name="articles",
query_vector=query_embedding,
limit=5,
with_payload=True
)
for hit in results:
print(hit.id, hit.score, hit.payload["title"])带过滤条件的搜索:Qdrant的杀手锏
单纯的向量搜索只能回答“哪些内容语义相近”,而真实业务往往要叠加更多约束,例如只在某个类目下搜索、只返回某种语言的内容。Qdrant的过滤搜索通过query_filter参数实现,支持must、should、must_not三种逻辑组合,语义上类似Elasticsearch的布尔查询。
results = client.search(
collection_name="articles",
query_vector=query_embedding,
query_filter=models.Filter(
must=[
models.FieldCondition(
key="category",
match=models.MatchValue(value="database")
),
models.FieldCondition(
key="lang",
match=models.MatchValue(value="zh")
)
]
),
limit=5
)上面的查询会先在category为database且lang为zh的子集中执行向量检索,保证返回结果既语义相关又满足业务条件。需要注意的是,如果某个过滤字段的区分度很低(例如90%的记录都满足条件),建议为该字段创建Payload索引,否则过滤需要全量扫描Payload,性能会受影响:
client.create_payload_index(
collection_name="articles",
field_name="category",
field_schema=models.PayloadSchemaType.KEYWORD
)此外,过滤字段类型要选对。KEYWORD适合精确匹配的枚举值,INTEGER和FLOAT适合范围查询,TEXT适合全文匹配。类型选错会导致过滤条件不生效,且这种问题往往不会报错,只在查询结果异常时才会被发现,排查起来比较隐蔽。
生产环境部署与性能调优建议
将Qdrant投入生产时,有几个方向值得关注。首先是HNSW参数调优,其中m控制图的连接数,影响内存占用和召回率;ef_construct控制建图质量,数值越高写入越慢但检索越准。默认参数已经比较均衡,只有在召回率不达标时才需要调整,调整后可通过sample接口对比召回变化。
其次是量化策略。Qdrant支持Scalar Quantization和Binary Quantization,可以把float32向量压缩到int8甚至单bit,内存占用能降低75%到96%,同时配合oversampling机制补偿精度损失。对于亿级向量的场景,量化几乎是必选项。
最后是高可用架构。Qdrant开源版支持通过分布式模式部署多个节点,数据按分片自动分布。如果初期规模不大,也可以采用单节点加定期快照备份的方案,快照可以通过REST接口直接触发并保存到本地或对象存储。无论哪种方案,都建议把向量写入与检索的负载分开评估,写入密集型场景要重点关注segment合并带来的性能波动,必要时通过配置优化器参数平滑写入压力。
总的来说,Qdrant的接入门槛不高,REST接口和各语言客户端封装都很完善,而它在过滤检索、内存效率和量化压缩上的深度优化,足以支撑从原型验证到生产规模的大部分向量检索需求。建议从单机Docker部署开始上手,逐步把过滤索引、量化和分片等高级特性引入到自己的系统中。
Qdrant API向量数据库向量检索修改时间:2026-09-02 04:28:34