Doramagic 项目包 · 项目说明书

qdrant 项目

生成时间:2026-05-31 03:33:46 UTC

Qdrant 简介

Qdrant(发音为 "quadrant")是一个高性能的向量相似度搜索引擎和向量数据库,采用 Rust 语言编写,使其在高压负载下依然保持出色的性能和可靠性。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心特性

继续阅读本节完整说明和来源证据。

章节 整体架构图

继续阅读本节完整说明和来源证据。

章节 核心模块说明

继续阅读本节完整说明和来源证据。

项目概述

Qdrant(发音为 "_quadrant_")是一个高性能的向量相似度搜索引擎和向量数据库,采用 Rust 语言编写,使其在高压负载下依然保持出色的性能和可靠性。

Qdrant 提供生产级的服务能力和便捷的 API,用于存储、搜索和管理 points——即带有额外 payload(负载)的向量。通过扩展的过滤支持,Qdrant 特别适用于各类神经网络匹配、语义匹配、分面搜索等应用场景。资料来源:README.md:1

核心特性

特性描述
向量搜索高效的近似最近邻(ANN)搜索
过滤支持强大的分面过滤能力
多种距离度量支持 Cosine、Dot Product、Euclidean、Manhattan 等
客户端库提供 Python、JavaScript/TypeScript、.NET/C#、Java、PHP 等多语言客户端
Qdrant Edge轻量级边缘设备版本,支持嵌入式运行

资料来源:README.md:1-50

系统架构

Qdrant 采用分层架构设计,核心组件协同工作以提供完整的向量搜索能力。

整体架构图

graph TB
    subgraph "客户端层"
        Client[多语言客户端]
    end
    
    subgraph "服务层 /src"
        API[REST API]
        HTTP[HTTP Client]
        Telemetry[遥测模块]
        Auth[认证模块]
    end
    
    subgraph "集合层 /lib/collection"
        Collection[Collection]
        Shards[分片管理]
        WAL[Write-Ahead Log]
        Discovery[发现模块]
    end
    
    subgraph "分片层 /lib/shard"
        SegmentHolder[Segment Holder]
        ProxySegment[代理分片]
        Operations[操作模块]
        Optimizers[优化器]
    end
    
    subgraph "段层 /lib/segment"
        HNSW[HNSW 索引]
        VectorStorage[向量存储]
        PayloadIndex[Payload 索引]
        IdTracker[ID 追踪器]
    end
    
    subgraph "存储层"
        GridStore[GridStore]
        MemoryMap[内存映射]
    end
    
    Client --> API
    API --> Collection
    Collection --> Shards
    Shards --> SegmentHolder
    SegmentHolder --> HNSW
    SegmentHolder --> VectorStorage
    Collection --> WAL
    HNSW --> MemoryMap
    VectorStorage --> GridStore

核心模块说明

#### 服务层(src/common/)

服务层负责处理外部请求、系统监控和运维功能。资料来源:src/common/mod.rs:1-25

模块功能
auth认证和授权
collections集合管理
health健康检查
http_clientHTTP 客户端封装
metrics指标收集
telemetry遥测数据上报
snapshots快照管理
validation输入验证

#### 集合层(lib/collection/)

集合层是 Qdrant 的核心数据组织单元,负责集合级别的操作和状态管理。资料来源:lib/collection/src/lib.rs:1-25

graph LR
    subgraph "Collection Operations"
        Update[更新操作]
        Query[查询操作]
        Config[配置管理]
    end
    
    subgraph "Collection Management"
        ShardManager[分片管理器]
        OptimizerBuilder[优化器构建器]
        UpdateHandler[更新处理器]
    end
    
    Update --> ShardManager
    Query --> ShardManager
    Config --> OptimizerBuilder
    ShardManager --> UpdateHandler

#### 分片层(lib/shard/)

分片层管理 segments 的生命周期和数据分片策略。资料来源:lib/shard/src/lib.rs:1-35

组件职责
segment_holder管理多个 segments
proxy_segment分片代理,拦截读写操作
locked_segment线程安全的分片访问
walWrite-Ahead Log 持久化
snapshots分片快照管理
update更新操作处理

#### 段层(lib/segment/)

段(Segment)是 Qdrant 中数据存储和索引的基本单元。资料来源:lib/segment/src/lib.rs:1-20

数据类型模块说明
index索引构建和查询
vector_storage向量数据存储
payload_storagePayload 数据存储
id_tracker点 ID 追踪
spaces空间度量计算

数据模型

Point 结构

Qdrant 中的基本数据单元是 Point,每个 Point 包含:

graph TB
    Point["Point (点)"]
    Vector["Vector (向量)"]
    Payload["Payload (负载)"]
    Id["ID (唯一标识)"]
    
    Point --> Id
    Point --> Vector
    Point --> Payload
    
    Vector --> MultiVector["多向量支持"]
    Payload --> KeyValue["键值对"]
字段类型描述
idu64/string点的唯一标识符
vectorf32[]/f32[][]向量数据,支持单个或多个向量
payloadJSON Object可选的元数据负载

向量存储类型

资料来源:lib/segment/src/data_types/mod.rs:1-15

Qdrant 支持多种向量存储配置:

存储类型用途
稀疏向量高维稀疏数据
密集向量标准密集嵌入
多向量ColBERT 等晚期交互模型

索引机制

HNSW 索引

HNSW(Hierarchical Navigable Small World)是 Qdrant 默认的向量索引算法,提供高效的近似最近邻搜索能力。资料来源:lib/segment/src/index/mod.rs

graph TD
    Start[查询入口] --> L3[Layer 3 (顶层)]
    L3 --> L2[Layer 2]
    L2 --> L1[Layer 1]
    L1 --> L0[Layer 0 (底层)]
    L0 --> Result[最近邻结果]
    
    L3 -.-> Skip["跳层搜索"]
    L2 -.-> Skip
    L1 -.-> Skip

量化支持

Qdrant 提供多种量化选项以平衡精度和性能:

量化类型压缩比精度损失适用场景
Scalar通用场景
Product Quantization (PQ)可配置大规模数据
Binary仅限 1024d+
TurboQuant可配置ICLR 2026 新特性
社区关注:TurboQuant 是社区重点关注的新量化方案(#8524),设计文档位于 Notion,追踪 issue 为 #8670。

存储层

GridStore

GridStore 是 Qdrant 的高性能存储引擎,用于替代传统的 RocksDB,提供更好的随机读写性能。资料来源:lib/gridstore/src/pages.rs:1-80

graph LR
    subgraph "GridStore 架构"
        Pages["Pages (页面管理)"]
        Flush["Flusher (刷新机制)"]
        MMap["Memory Map (内存映射)"]
    end
    
    Write["写入请求"] --> Pages
    Pages --> Flush
    Flush --> MMap

内存映射

Qdrant 大量使用内存映射(mmap)技术优化大文件访问:

功能描述
will_need预读数据到页缓存
populate填充页缓存
pageoutLinux 页面换出

资料来源:lib/common/common/src/mmap/advice.rs:1-60

客户端与 API

多语言客户端

Qdrant 提供官方维护的多语言客户端库:

语言仓库
Pythonqdrant-client
JavaScript/TypeScriptqdrant-js
.NET/C#qdrant-dotnet
Javajava-client
PHPqdrant-php (社区维护)

REST API

Qdrant 提供完整的 RESTful API 用于所有操作。资料来源:lib/api/src/rest/mod.rs:1-10

API 端点方法功能
/collections/{name}/points/searchPOST向量搜索
/collections/{name}/points/scrollPOST分页浏览
/collections/{name}/pointsPUT/DELETE点的增删
/collectionsGET/POST集合管理

Qdrant Edge

Qdrant Edge 是专为边缘设备和资源受限环境设计的轻量级版本。与客户端-服务器架构的 Qdrant Server 不同,Qdrant Edge 运行在应用程序进程内部。

graph TB
    subgraph "Qdrant Server (服务端)"
        ServerAPI[REST API]
        ServerStorage[持久化存储]
    end
    
    subgraph "Qdrant Edge (嵌入式)"
        EdgeLib[Edge Library]
        LocalStorage[本地存储]
        Sync[数据同步]
    end
    
    EdgeLib --> Sync
    Sync <--> ServerAPI
    EdgeLib --> LocalStorage
    ServerAPI --> ServerStorage

快速开始示例

from qdrant_edge import Distance, EdgeConfig, EdgeVectorParams, EdgeShard, Point, UpdateOperation

shard = EdgeShard.create("./shard", EdgeConfig(
    vectors={"my-vector": EdgeVectorParams(size=4, distance=Distance.Cosine)}
))
shard.update(UpdateOperation.upsert_points([
    Point(id=1, vector={"my-vector": [0.1, 0.2, 0.3, 0.4]}, payload={"color": "red"})
]))

资料来源:README.md:40-55

版本与发布

最新版本:v1.18.1

类别更新内容
改进重构量化多向量评分器以支持 io_uring
改进异步 upsert 前验证向量维度
修复快照应用时通知待处理共识操作

历史版本要点

版本主要特性
v1.17.1GridStore 刷新非阻塞化,减少搜索尾延迟
v1.17.0相关性反馈功能、详细优化进度 API
v1.16.x批处理优化、遥测超时改进、WAL 关键修复

已知问题与限制

社区关注的问题

Issue描述状态
#1132创建集合后无法添加新向量字段开放
#2550删除点后应标记向量为已删除开放
#8524TurboQuant 量化方案开发中
#3684ColBERT 晚期交互模型支持开发中

测试稳定性

近期发现多个量化搜索相关的测试存在不稳定性,主要涉及:

  • hnsw_quantized_search_test::hnsw_turbo_quantization_* 系列测试
  • hnsw_discover_test::filtered_hnsw_discover_precision

这些问题主要表现为测试中断言失败 best_2.score >= best_1.score,相关 issue 包括 #8735、#8801、#8806、#8834、#8835、#8906、#8704。

技术栈总结

层级技术/语言
核心引擎Rust
存储引擎GridStore + Memory Map
索引算法HNSW + 多种量化方案
通信协议REST (OpenAPI 3.0)
部署方式独立服务器 / 嵌入式 (Edge)

Qdrant 通过 Rust 语言的优势实现了高性能、低内存占用的向量搜索服务,同时提供丰富的客户端库和完整的 API 支持,满足从研究实验到生产部署的各种场景需求。

资料来源:README.md:1-50

核心概念

Qdrant 是一个高性能的向量相似度搜索引擎,其架构围绕几个核心概念构建:集合(Collection)、分片(Shard)、段(Segment)以及存储层。这些概念共同构成了 Qdrant 的数据存储和检索体系。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 点(Point)

继续阅读本节完整说明和来源证据。

章节 Collection 配置结构

继续阅读本节完整说明和来源证据。

章节 集合模块组成

继续阅读本节完整说明和来源证据。

数据模型层级结构

Qdrant 采用分层架构来组织和管理向量数据,从宏观的集合到微观的点(Point),形成了清晰的数据层级。

graph TD
    A[Collection 集合] --> B[Shard 分片]
    B --> C[Segment 段]
    C --> D[Point 点]
    D --> E[Vector 向量]
    D --> F[Payload 负载]

点(Point)

点是 Qdrant 中最基本的数据单元,包含向量数据和可选的负载信息。每个点由唯一标识符、向量和负载组成。

graph LR
    A[Point ID] --> D
    B[Vector] --> D
    C[Payload] --> D
    D[Point]

从源码中可以看到数据类型的组织结构:

// lib/segment/src/data_types/mod.rs
pub mod build_index_result;
pub mod collection_defaults;
pub mod facets;
pub mod groups;
pub mod index;
pub mod manifest;
pub mod modifier;
pub mod named_vectors;
pub mod order_by;
pub mod primitive;
pub mod query_context;
pub mod segment_record;
pub mod tiny_map;
pub mod vector_name_config;
pub mod vectors;

资料来源:lib/segment/src/data_types/mod.rs:1-18

集合(Collection)

集合是顶层的命名空间,用于组织相关的向量数据。每个集合拥有独立的配置,包括向量维度、距离度量方式和优化器参数。

Collection 配置结构

集合配置存储在 config.rs 中,支持多种可自定义的元数据:

// lib/collection/src/config.rs
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<Payload>,

配置通过原子文件(Atomic File)机制进行持久化:

impl CollectionConfigInternal {
    pub fn save(&self, path: &Path) -> CollectionResult<()> {
        let config_path = path.join(COLLECTION_CONFIG_FILE);
        let af = AtomicFile::new(&config_path, AllowOverwrite);
        // ...
    }
    
    pub fn load(path: &Path) -> CollectionResult<Self> {
        let config_path = path.join(COLLECTION_CONFIG_FILE);
        // ...
    }
}

资料来源:lib/collection/src/config.rs:1-50

集合模块组成

集合模块位于 lib/collection/src/lib.rs,包含以下核心子模块:

模块名称功能描述
collection集合管理核心逻辑
collection_manager集合级别的资源管理
collection_state集合状态追踪
config配置管理
discovery发现查询功能
grouping分组查询
hash_ring一致性哈希环(分片路由)
recommendations推荐系统功能
shards分片管理
operations集合操作(通用化接口)
optimizers_builder优化器构建器
wal_deltaWAL 增量管理

资料来源:lib/collection/src/lib.rs:1-30

分片(Shard)

分片是集合数据的水平分区单元,用于实现分布式存储和查询负载均衡。

graph TD
    subgraph Collection
        A[Shard 1] --> D[Segment 1.1]
        A --> E[Segment 1.2]
        B[Shard 2] --> F[Segment 2.1]
        B --> G[Segment 2.2]
        C[Shard N] --> H[Segment N.1]
        C --> I[Segment N.2]
    end

分片模块结构

分片模块在 lib/shard/src/lib.rs 中定义:

pub mod common;
pub mod count;
pub mod facet;
pub mod files;
pub mod locked_segment;
pub mod operation_rate_cost;
pub mod operations;
pub mod optimize;
pub mod optimizers;
pub mod payload_index_schema;
pub mod proxy_segment;
pub mod query;
pub mod retrieve;
pub mod scroll;
pub mod search;
pub mod search_result_aggregator;
pub mod segment_holder;
pub mod snapshots;
pub mod tracker;
pub mod update;
pub mod wal;

资料来源:lib/shard/src/lib.rs:1-30

每个分片包含以下核心组件:

组件功能
segment_holder持有多个段,管理段的注册和注销
wal预写日志,确保数据持久性
update更新操作处理
query查询执行引擎
optimizers段合并和优化任务
snapshots分片快照管理

段(Segment)

段是存储和索引向量数据的基本单元,是 HNSW 索引等数据结构的具体载体。

Segment 模块结构

段模块位于 lib/segment/src/lib.rs

pub mod common;
pub mod entry;
#[cfg(feature = "testing")]
pub mod fixtures;
pub mod id_tracker;
pub mod index;
pub mod payload_storage;
pub mod segment;
pub mod segment_constructor;
pub mod spaces;
pub mod telemetry;

mod compat;
pub mod data_types;
pub mod json_path;
pub mod types;
pub mod utils;
pub mod vector_storage;

资料来源:lib/segment/src/lib.rs:1-20

索引类型

段支持多种索引类型,用于加速不同场景的查询:

  • HNSW 索引:层次可导航小世界图,是向量相似度搜索的主要索引结构
  • 全文索引:支持文本字段的全文检索,包含中文停用词支持
  • 条件索引:基于负载字段的条件过滤

段的生命周期

stateDiagram-v2
    [*] --> Mutable: 创建新段
    Mutable --> Immutable: 触发 flush
    Immutable --> Optimizing: 优化器调度合并
    Optimizing --> [*]: 合并完成
    Mutable --> [*]: 删除操作

GridStore 存储层

GridStore 是 Qdrant 的核心存储引擎,替代了传统的 RocksDB,提供更高效的 I/O 操作。

GridStore 配置

GridStore 的默认配置参数:

参数默认值说明
page_size_bytes32MB页大小
block_size_bytes128 bytes块大小
region_size_blocks8192 blocks区域大小
compressionLZ4压缩算法

资料来源:lib/gridstore/src/config.rs:1-40

页面管理机制

GridStore 使用基于页面的存储架构,支持高效的写入和读取操作:

// lib/gridstore/src/pages.rs
impl<S: UniversalWrite> Pages<S> {
    pub fn write_to_pages(
        &mut self,
        pointer: ValuePointer,
        value: &[u8],
        config: &StorageConfig,
    ) -> Result<()> {
        // 跨页写入处理
        let writes = Self::get_page_value_ranges(pointer, config)
            .map(|(buf_offset, page, range)| {
                let data = &value[buf_offset..buf_offset + range.length as usize];
                (page as FileIndex, range.byte_offset, data)
            });
        S::write_multi(self.pages.as_mut_slice(), writes)?;
        Ok(())
    }
}

资料来源:lib/gridstore/src/pages.rs:1-100

非阻塞刷新

v1.17.1 版本的重要改进是 GridStore 刷新操作改为非阻塞模式,显著降低了搜索尾延迟。

相关社区讨论:多个用户报告了量化搜索相关的测试不稳定问题,涉及 HNSW 量化搜索测试中分数比较断言失败的情况。

资料来源:v1.17.1 Release Notes

预写日志(WAL)

预写日志是确保数据持久性的关键机制,即使在系统崩溃后也能恢复数据。

WAL 关键特性

  • 原子性保证:更新操作先写入 WAL,再应用到内存结构
  • 崩溃恢复:重启时从 WAL 重放未刷新的操作
  • 一致性检查:v1.16.2 版本修复了可能导致共识破坏的 WAL 关键 bug
社区关注:WAL 相关的 bug 修复是 v1.16.2 版本的重要安全修复。

资料来源:v1.16.2 Release Notes

量化技术

Qdrant 支持多种量化方法来压缩向量存储空间:

量化类型压缩比适用场景限制
Scalar4x通用场景维度需足够大
Binary超低维度维度 < 1024d 效果差
PQ可配置极致压缩需要训练码本
TurboQuant极高激进压缩ICLR 2026 新特性
社区热点:TurboQuant 量化是社区关注的重点功能,设计文档在 Notion 中公开。

资料来源:Issue #8524

存储配置示例

Qdrant 的存储行为可通过 config.yaml 灵活配置:

storage:
  storage_path: ./storage
  snapshots_path: ./snapshots
  temp_path: null
  on_disk_payload: true  # 负载数据是否落盘
  # 其他优化参数...

资料来源:config/config.yaml:1-20

异步 I/O 与性能优化

Qdrant 利用现代 Linux 的 io_uring 特性实现高效的异步 I/O,即使在网络存储上也能最大化磁盘吞吐量。

批处理优化

v1.16.1 版本引入的批处理优化使全量扫描查询速度提升高达 3 倍,原理是每个点只读取一次:

相关 PR:Make batch queries up to 3 times faster on full scans by reading each point only once

资料来源:v1.16.1 Release Notes

内存映射优化

系统页面大小对内存映射操作有重要影响:

// lib/common/common/src/mmap/advice.rs
#[cfg(unix)]
fn get_page_size() -> Result<usize, String> {
    let page_size = nix::unistd::sysconf(nix::unistd::SysconfVar::PAGE_SIZE)
        .map_err(|err| format!("Failed to get page size: {err}"))?
        .ok_or_else(|| "sysconf(PAGE_SIZE) returned None".to_string())?;
    // 通常 x86_64 为 4096,aarch64 macOS 为 16384
}

资料来源:lib/common/common/src/mmap/advice.rs:1-30

关键设计决策

多租户支持

Qdrant 的 hash_ring 模块实现了一致性哈希,用于在多个节点间分配分片,支持大规模多用户环境。

延迟物化

v1.17.0 版本引入的相关性反馈(Relevance Feedback)功能允许用户标记搜索结果的相关性,从而优化后续查询的排序。

新功能:Relevance Feedback API 为用户提供了细粒度的结果相关性反馈机制。

资料来源:v1.17.0 Release Notes

延迟更新优化

v1.17.1 版本通过 prevent_unoptimized=true 参数实现延迟点更新优化,避免频繁的小更新导致的性能抖动。

概念关系总览

graph TD
    subgraph 客户端层
        A[REST API / gRPC]
    end
    
    subgraph 集合层
        B[Collection] --> C[CollectionConfig]
        B --> D[Hash Ring]
    end
    
    subgraph 分片层
        D --> E[Shard 1]
        D --> F[Shard 2]
        D --> G[Shard N]
    end
    
    subgraph 段层
        E --> H[Segment Holder]
        H --> I[Mutable Segment]
        H --> J[Immutable Segment]
        I --> K[HNSW Index]
        I --> L[Vector Storage]
        I --> M[Payload Storage]
    end
    
    subgraph 存储层
        L --> N[GridStore]
        M --> N
        N --> O[WAL]
        N --> P[Disk Files]
    end
    
    A --> B

总结

Qdrant 的核心概念构成了一个层次分明、高度模块化的向量数据库架构:

  1. 集合作为顶层命名空间,提供独立配置和隔离的数据空间
  2. 分片实现水平扩展,通过一致性哈希进行数据分布
  3. 是数据存储和索引的基本单元,支持多种索引类型
  4. GridStore提供高性能的持久化存储,支持压缩和非阻塞 I/O
  5. WAL确保数据可靠性和崩溃恢复能力

这些概念相互协作,共同支撑 Qdrant 作为生产级向量搜索引擎的各项能力,包括高性能相似度搜索、灵活的过滤查询、分布式部署和数据持久化保证。

资料来源:lib/segment/src/data_types/mod.rs:1-18

系统架构

Qdrant 是一个用 Rust 编写的向量相似度搜索引擎,采用模块化架构设计,支持高维向量数据的存储、索引和高效相似度检索。本页面详细介绍 Qdrant 的核心架构组件及其交互关系。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 API 层

继续阅读本节完整说明和来源证据。

章节 集合管理层 (Collection)

继续阅读本节完整说明和来源证据。

章节 分片层 (Shard)

继续阅读本节完整说明和来源证据。

整体架构概览

Qdrant 采用分层架构,从上到下依次为:API 层、集合管理层、分片层、Segment 层和存储层。各层之间通过清晰的接口定义进行通信,实现了关注点分离和模块化设计。

graph TD
    subgraph API层
        REST_API[REST API]
        gRPC_API[gRPC API]
    end
    
    subgraph 集合管理层
        Collection[Collection Manager]
        Config[Collection Config]
    end
    
    subgraph 分片层
        Shard[Shard]
        ProxySegment[Proxy Segment]
        SegmentHolder[Segment Holder]
    end
    
    subgraph Segment层
        Segment[Segment]
        HNSW[HNSW Index]
        PayloadIndex[Payload Index]
        VectorStorage[Vector Storage]
    end
    
    subgraph 存储层
        GridStore[GridStore]
        RocksDB[RocksDB]
        WAL[Write-Ahead Log]
    end
    
    REST_API --> Collection
    gRPC_API --> Collection
    Collection --> Shard
    Shard --> SegmentHolder
    SegmentHolder --> Segment
    Segment --> HNSW
    Segment --> PayloadIndex
    Segment --> VectorStorage
    Segment --> WAL
    VectorStorage --> GridStore
    PayloadIndex --> RocksDB

核心模块

API 层

API 层负责处理外部请求,包括 REST API 和 gRPC API 两种接口形式。REST API 提供 OpenAPI 规范的 HTTP 接口,用于与客户端进行交互。

资料来源:lib/api/src/rest/mod.rs

集合管理层 (Collection)

Collection 是 Qdrant 中的核心管理单元,负责管理整个集合的元数据、配置和操作。Collection 模块包含以下主要组件:

组件说明
collection.rs集合的核心实现,处理集合级别的操作
config.rs集合配置管理,包括向量维度、索引参数等
operations/集合操作模块,包括 CRUD、搜索、更新等
collection_state.rs集合状态管理
shards.rs分片管理

集合配置通过 CollectionConfigInternal 结构体管理,支持存储应用级别的元数据信息,如创建时间、迁移数据和推理模型信息等。

资料来源:lib/collection/src/lib.rs:1-29

分片层 (Shard)

Shard 层实现分布式数据分片,支持数据水平扩展。每个 Shard 包含多个 Segment,并通过 Hash Ring 机制实现数据分片路由。

graph LR
    HashRing[Hash Ring Router]
    
    HashRing -->|Shard 0| S0[Shard 0]
    HashRing -->|Shard 1| S1[Shard 1]
    HashRing -->|Shard 2| S2[Shard 2]
    
    S0 --> SH0[Segment Holder]
    S1 --> SH1[Segment Holder]
    S2 --> SH2[Segment Holder]
    
    SH0 --> Seg1[Segment]
    SH0 --> Seg2[Segment]
    SH1 --> Seg3[Segment]
    SH2 --> Seg4[Segment]
    SH2 --> Seg5[Segment]

分片操作通过 SplitByShard trait 实现,支持将操作按照 Hash Ring 路由到对应的分片:

impl SplitByShard for CollectionUpdateOperations {
    fn split_by_shard(self, ring: &HashRingRouter) -> OperationToShard<Self>

资料来源:lib/shard/src/lib.rs:1-40

Segment 层

Segment 是 Qdrant 中数据存储和索引的基本单元。每个 Segment 包含向量数据、Payload 数据和各类索引结构。

模块说明
segment.rsSegment 核心实现
index/hnsw_index/HNSW 近似最近邻索引
payload_storage/Payload 存储管理
vector_storage/向量存储管理
segment_constructor/Segment 构造器
spaces/距离空间定义

资料来源:lib/segment/src/lib.rs:1-18

#### Segment 数据一致性检查

Segment 提供 check_data_consistency 方法用于检查数据一致性,该方法检测以下几种不一致情况:

  • 内部 ID 无对应的外部 ID
  • 外部 ID 无对应的内部 ID
  • 内部 ID 无对应的版本信息
  • 内部 ID 无对应的向量数据

资料来源:lib/segment/src/segment/segment_ops.rs:200-230

存储层

#### GridStore

GridStore 是 Qdrant 新一代存储引擎,用于替代 RocksDB。它采用分页式存储架构,优化了向量数据的读写性能。

配置项默认值说明
page_size_bytes32MB页面大小
block_size_bytes128 bytes块大小
region_size_blocks8192区域块数
compressionLZ4压缩算法

GridStore 的页面管理通过 Pages<S> 结构体实现,支持多页面写入和数据指针管理。当数据跨页存储时,系统会自动处理页面边界的读写操作。

资料来源:lib/gridstore/src/config.rs:1-80

#### Write-Ahead Log (WAL)

WAL 确保数据持久性,即使在系统故障情况下也能保证更新确认。每个 Segment 都有自己的 WAL,通过日志机制实现数据恢复。

资料来源:lib/shard/src/lib.rs:30

操作流程

写入流程

sequenceDiagram
    participant Client
    participant API
    participant Collection
    participant Shard
    participant Segment
    participant WAL
    participant GridStore
    
    Client->>API: 上传向量数据
    API->>Collection: PointOperation
    Collection->>Shard: SplitByShard
    Shard->>Segment: 写入操作
    Segment->>WAL: 写入日志
    Segment->>GridStore: 写入数据
    GridStore-->>Segment: 写入确认
    WAL-->>Segment: 日志确认
    Segment-->>Shard: 操作完成
    Shard-->>Collection: 操作完成
    Collection-->>API: 操作完成
    API-->>Client: 成功响应

搜索流程

sequenceDiagram
    participant Client
    participant API
    participant Collection
    participant Shard
    participant SegmentHolder
    participant Segment
    participant HNSW
    
    Client->>API: 搜索请求
    API->>Collection: Search Request
    Collection->>Shard: 广播到所有分片
    Shard->>SegmentHolder: 获取所有 Segment
    SegmentHolder->>Segment: 并行搜索
    Segment->>HNSW: HNSW 近似搜索
    HNSW-->>Segment: Top-K 结果
    Segment-->>Shard: 分片结果
    Shard-->>Collection: 聚合结果
    Collection-->>API: 最终结果
    API-->>Client: 返回结果

配置管理

集合配置

集合配置通过 CollectionConfigInternal 结构体管理,支持以下功能:

  • 持久化存储配置
  • 运行时加载配置
  • 配置验证和警告
impl CollectionConfigInternal {
    pub fn save(&self, path: &Path) -> CollectionResult<()>;
    pub fn load(path: &Path) -> CollectionResult<Self>;
    pub fn check(path: &Path) -> bool;
}

资料来源:lib/collection/src/config.rs:1-70

遥测与可观测性

Qdrant 提供全面的遥测系统,用于监控集群健康状况和性能指标。

模块说明
app_telemetry应用级遥测
cluster_telemetry集群状态遥测
collections_telemetry集合级别遥测
hardware硬件指标
memory_telemetry内存使用情况
requests_telemetry请求指标
distributed_telemetry分布式相关遥测

资料来源:src/common/telemetry_ops/mod.rs:1-15

优化机制

分批查询优化

Qdrant 在 v1.16.1 版本中优化了分批查询性能,通过单次读取每个向量数据,使全表扫描的分批查询速度提升至原来的 3 倍。

GridStore 迁移

系统启动时,Qdrant 会主动将向量、Payload 和 Payload 索引存储从 RocksDB 迁移到 GridStore,以提高整体性能。

非阻塞刷新

在 v1.17.1 版本中,GridStore 的刷新操作改为非阻塞模式,有效降低了搜索尾延迟。

相关社区问题

以下社区问题涉及 Qdrant 架构相关的功能改进和已知限制:

Issue说明优先级
#8524TurboQuant 量化技术,支持更激进的压缩比
#3684ColBERT 晚期交互模型集成
#2550删除点时同时删除向量标记
#1132集合创建后添加新向量字段

版本演进

版本主要改进
v1.18.1量化多向量评分器重构支持 io_uring
v1.17.1非阻塞 GridStore 刷新,延迟点更新优化
v1.17.0Relevance Feedback 功能,优化进度报告 API
v1.16.3搜索和检索超时处理改进
v1.16.2遥测和指标请求超时处理
v1.16.1分批查询性能提升,GridStore 启动迁移

资料来源:lib/api/src/rest/mod.rs

集合管理

集合(Collection)是 Qdrant 中管理和组织向量数据的基本单元。本页面详细说明集合管理的架构设计、核心组件、配置选项以及操作流程。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 模块层次结构

继续阅读本节完整说明和来源证据。

章节 核心组件

继续阅读本节完整说明和来源证据。

章节 配置结构

继续阅读本节完整说明和来源证据。

概述

Qdrant 的集合管理系统负责以下核心职责:

  • 创建、删除和配置向量集合
  • 管理集合内的向量数据和负载(Payload)
  • 处理集合级别的查询操作
  • 维护集合状态和元数据
  • 支持分片(Sharding)实现水平扩展

集合管理的核心代码位于 lib/collection 目录,采用模块化设计以支持不同类型的向量存储和查询操作。资料来源:lib/collection/src/lib.rs:1-27

核心架构

模块层次结构

集合管理系统的模块结构如下:

graph TD
    A[集合管理层] --> B[lib/collection]
    A --> C[lib/shard]
    A --> D[lib/segment]
    
    B --> B1[collection]
    B --> B2[collection_manager]
    B --> B3[collection_state]
    B --> B4[config]
    B --> B5[operations]
    B --> B6[shards]
    B --> B7[optimizers_builder]
    
    C --> C1[segment_holder]
    C --> C2[operations]
    C --> C3[wal]
    C --> C4[update]

核心组件

组件文件位置职责
Collectionlib/collection/src/collection/mod.rs集合主类,处理核心业务逻辑
CollectionManagerlib/collection/src/collection_manager/管理多个集合的生命周期
CollectionStatelib/collection/src/collection_state/维护集合运行时状态
Shardlib/shard/src/lib.rs管理分片数据和复制
Segmentlib/segment/src/segment/底层数据存储和索引

资料来源:lib/collection/src/lib.rs:1-27

集合配置

配置结构

集合配置通过 CollectionConfigInternal 结构体管理,包含以下关键配置项:

  • 向量参数(VectorParams):向量维度、距离度量、稀疏向量配置
  • 负载索引(PayloadIndexSchema):负载字段索引定义
  • 优化器配置(OptimizerConfig):HNSW 和量化参数
  • 元数据(metadata):应用特定信息,如创建时间、迁移数据等
pub struct CollectionConfigInternal {
    pub metadata: Option<Payload>,  // 可选的应用元数据
}

资料来源:lib/collection/src/config.rs:1-50

配置持久化

集合配置支持序列化存储和加载:

方法功能
to_bytes()将配置序列化为字节数组
save(path)使用原子写入保存配置到文件
load(path)从文件加载并反序列化配置
check(path)检查配置文件是否存在
pub fn save(&self, path: &Path) -> CollectionResult<()> {
    let config_path = path.join(COLLECTION_CONFIG_FILE);
    let af = AtomicFile::new(&config_path, AllowOverwrite);
    // 使用原子写入确保数据一致性
}

pub fn load(path: &Path) -> CollectionResult<Self> {
    // 从 JSON 文件读取并解析
}

资料来源:lib/collection/src/config.rs:30-50

分片管理

分片架构

Qdrant 使用分片实现水平扩展,集合数据分布在多个分片上:

graph LR
    A[Collection] --> B[Shard 1]
    A --> C[Shard 2]
    A --> D[Shard N]
    
    B --> E[Segment 1]
    B --> F[Segment 2]
    
    C --> G[Segment 1]
    C --> H[Segment 2]
    
    D --> I[Segment 1]
    D --> J[Segment 2]

分片操作接口

操作描述
PointOperation点操作(插入、更新、删除)
VectorOperation向量操作(添加、删除向量字段)
PayloadOperation负载操作(设置、删除、修改负载字段)
pub trait SplitByShard {
    fn split_by_shard(self, ring: &HashRingRouter) -> OperationToShard<Self>
    where Self: Sized;
}

资料来源:lib/collection/src/operations/mod.rs:35-60

负载索引管理

集合支持为负载字段创建索引以加速过滤查询:

pub fn create_field_index(
    &self,
    version: SeqNumberType,
    key: PayloadKeyType,
    schema: Option<FieldIndexSchema>,
    counter: &HardwareCounterCell,
) -> OperationResult<bool>;

负载索引类型包括:

  • 整数索引:用于整数类型字段
  • 字符串索引:用于文本匹配查询
  • 地理位置索引:用于地理范围查询
  • 布尔索引:用于布尔值过滤

索引创建时会检查现有配置,如果不匹配会重新创建。资料来源:lib/segment/src/segment/segment_ops.rs:1-100

数据通用化

Generalizer 特性

集合操作支持通用化(Generalization)接口,用于在日志记录、审计和脱敏场景中移除敏感数据:

pub trait Generalizer {
    fn remove_details(&self) -> Self;
}

通用化处理规则:

  • 向量数据替换为长度信息
  • 负载数据替换为键和长度信息
  • 其他字段完整保留

资料来源:lib/collection/src/operations/generalizer/mod.rs:1-20

操作类型

查询操作

操作类型描述
Search近似最近邻搜索
Recommend基于向量的推荐
Discover发现查询
Scroll分页滚动查询
Count计数查询
Aggregate聚合查询

更新操作

操作类型描述
Upsert插入或更新点
Delete删除点
UpdateVectors更新向量
SetPayload设置负载
DeletePayload删除负载

资料来源:lib/collection/src/operations/mod.rs:10-40

集合状态管理

状态检查

集合提供数据一致性检查功能:

pub fn check_data_consistency(&self) -> OperationResult<()>

检查项目包括:

  • 内部 ID 存在但外部 ID 不存在
  • 外部 ID 存在但内部 ID 不存在
  • 内部 ID 存在但版本信息不存在
  • 内部 ID 存在但向量数据不存在
注意:单个分片可能包含不一致的段,但由于点是基于版本合并的,整个分片仍可保持一致性。

资料来源:lib/segment/src/segment/segment_ops.rs:80-100

相关社区问题

热点问题

Issue描述状态
#1132集合创建后添加新向量字段开放
#2550删除点时同时删除向量开放
#3684ColBERT 延迟交互模型支持进行中

Issue #1132 反映了用户对在集合创建后动态添加新向量字段的需求,这是当前集合管理的一个重要限制。资料来源:社区 Issue #1132

版本演进

版本改进内容
v1.17.1使用 prevent_unoptimized=true 延迟点更新
v1.17.0新增相关性反馈 API
v1.16.1批量查询优化,扫描速度提升 3 倍

资料来源:v1.17.1 Release Notes

最佳实践

  1. 预定义向量维度:避免在创建后修改向量维度
  2. 合理配置索引:根据查询模式选择合适的负载索引
  3. 使用通用化接口:日志记录时使用 Generalizer 避免敏感数据泄露
  4. 定期检查一致性:使用 check_data_consistency() 确保数据完整性
  5. 合理设置分片数:根据数据量和查询负载选择分片策略

资料来源:lib/collection/src/lib.rs:1-27

HNSW 索引原理与实现

HNSW(Hierarchical Navigable Small World)是一种基于图的近似最近邻搜索算法,广泛应用于向量检索场景。Qdrant 使用 HNSW 作为核心索引结构,实现高效的向量相似度搜索功能。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 模块组织结构

继续阅读本节完整说明和来源证据。

章节 数据流架构

继续阅读本节完整说明和来源证据。

章节 分层图结构

继续阅读本节完整说明和来源证据。

概述

HNSW(Hierarchical Navigable Small World)是一种基于图的近似最近邻搜索算法,广泛应用于向量检索场景。Qdrant 使用 HNSW 作为核心索引结构,实现高效的向量相似度搜索功能。

HNSW 算法的核心思想是构建一个多层次的小世界图(Small World Graph),上层稀疏下层密集。搜索时从最上层开始,逐步向下层细化,最终在底层找到最近邻。这种分层结构使得搜索复杂度从线性降低到对数级别,在召回率和延迟之间取得良好平衡。

核心架构

模块组织结构

Qdrant 的 HNSW 实现位于 lib/segment/src/index/hnsw_index/ 目录下,主要包含以下核心模块:

模块路径功能说明
hnsw.rsHNSW 索引主入口,定义索引结构和生命周期管理
hnsw/vector_index_impl.rs向量索引的具体实现,处理搜索和构建逻辑
graph_layers.rs图层的抽象定义,管理多层图结构
graph_layers_builder.rs图层构建器,负责索引构建过程
config.rsHNSW 配置参数定义

数据流架构

graph TD
    A[向量插入请求] --> B[PointId 分配]
    B --> C[HNSW 索引层选择]
    C --> D{是否满足跳跃条件}
    D -->|是| E[插入更高层]
    D -->|否| F[仅插入底层]
    E --> G[层内邻居搜索]
    F --> G
    G --> H[邻居连接建立]
    H --> I[图结构更新]
    
    J[搜索请求] --> K[从顶层入口点开始]
    K --> L[贪心搜索当前层]
    L --> M{是否到达局部最优}
    M -->|否| L
    M -->|是| N[下降到下一层]
    N --> O{是否到达底层}
    O -->|否| L
    O -->|是| P[返回最近邻结果]

HNSW 算法原理

分层图结构

HNSW 将向量组织成多层图结构,每一层都是一个近似可导航小世界(Navigable Small World)图。底层包含所有数据点,上层仅包含部分数据点,形成稀疏结构。

层 3:     ○────────○────────○         (入口点最少)
层 2:   ○───○───○───○───○───○───○     (入口点较少)
层 1: ○──○──○──○──○──○──○──○──○──○    (入口点较多)
层 0: 所有向量点的完整图连接         (入口点最多)

资料来源:lib/segment/src/index/hnsw_index/graph_layers.rs:1-100

搜索算法

搜索过程采用贪心策略,从最高层开始:

  1. 顶层搜索:从入口点出发,找到当前层最近的邻居
  2. 层内贪婪:在当前层贪心地移动到更近的邻居,直到无法改进
  3. 向下跳转:将当前最佳候选点作为下一层的入口点
  4. 重复执行:直到达到底层
graph LR
    A[查询向量] --> B[层3: 贪心搜索]
    B --> C[找到局部最优]
    C --> D[下降到层2]
    D --> E[继续贪心搜索]
    E --> F[下降到层1]
    F --> G[下降到层0]
    G --> H[返回Top-K结果]

构建算法

索引构建时,新向量被插入到随机选择的某一层(基于指数衰减概率),然后在该层及以下所有层中建立连接:

资料来源:lib/segment/src/index/hnsw_index/graph_layers_builder.rs:1-100

配置参数

HNSW 索引的行为通过 HnswConfig 结构体进行配置:

参数名类型默认值说明
musize16每层每个点的最大连接数
ef_constructusize100构建时搜索的候选邻居数
full_scan_thresholdusize10000超过此阈值启用 HNSW,否则全表扫描
max_indexing_threadsusize0索引构建的并行线程数(0=自动)
on_diskOption\<bool\>None是否将索引存储在磁盘上
payload_musizeNone基于 payload 的连接数覆盖

资料来源:lib/segment/src/index/hnsw_index/config.rs:1-100

参数调优建议

  • m 值:较大的 m 值提高召回率但增加内存占用和构建时间
  • ef_construct:增加此值可提高索引质量,但会增加构建时间和内存
  • full_scan_threshold:小数据集(<1万点)建议使用全表扫描,HNSW 开销过大

实现细节

核心数据结构

HNSW 索引的核心实现在 VectorIndexImpl 中,主要包含以下结构:

pub struct HnswIndex<T: Storage + Cloner + ...> {
    config: HnswConfig,
    pointer_hints: Arc<AtomicBool>,
    id_tracker: Arc<swap_and_pop::AtomicSwapAndPop<Label>>,  // ID 追踪
    vector_storage: Arc<T>,                                   // 向量存储
    payload_index: Arc<StructPayloadIndex>,                   // Payload 索引
    hnsw_graph: GraphLayers,                                  // 图结构
}

资料来源:lib/segment/src/index/hnsw_index/hnsw/vector_index_impl.rs:1-100

距离计算

Qdrant 支持多种距离度量方式,在 lib/segment/src/spaces/ 目录下实现:

距离类型适用场景说明
Dot向量相似度内积,值越大相似度越高
Cosine余弦相似度对向量方向敏感
Euclid欧氏距离几何距离
Manhattan曼哈顿距离城市街区距离

图层管理

GraphLayers 管理 HNSW 的多层图结构:

资料来源:lib/segment/src/index/hnsw_index/graph_layers.rs:1-100

索引构建流程

flowchart TD
    A[新向量插入] --> B{随机数 < exp(-level)}
    B -->|True| C[分配较高层]
    B -->|False| D[分配层0]
    C --> E[层内搜索最近邻居]
    D --> E
    E --> F[选择 ef_construct 个候选]
    F --> G{遍历候选}
    G -->|有未访问| H[计算距离]
    H --> I[更新优先队列]
    I --> G
    G -->|全部访问| J[选择 m 个最近邻居]
    J --> K[建立双向连接]
    K --> L{继续处理更高层}
    L -->|是| E
    L -->|否| M[完成插入]

与量化的集成

Qdrant 支持将 HNSW 与量化技术结合使用以提升性能。社区中存在多个与此相关的 flaky 测试问题:

  • hnsw_turbo_quantization_cosine_larger_test (Issue #8801)
  • hnsw_turbo_quantization_dot_test (Issue #8906)
  • hnsw_quantized_search_euclid_test (Issue #8735)

这些测试验证量化后搜索结果与原始搜索结果的分数一致性。积分测试断言 best_2.score >= best_1.score,确保量化搜索不会返回优于非量化搜索的结果。

资料来源:lib/segment/tests/integration/hnsw_quantized_search_test.rs:314

量化搜索流程

graph TD
    A[查询向量] --> B{使用量化?}
    B -->|是| C[量化查询向量]
    B -->|否| D[使用原始向量]
    C --> E[HNSW 图搜索]
    D --> E
    E --> F{量化分数阈值}
    F --> G[重排阶段]
    G --> H[返回结果]

已知限制与问题

Flaky 测试问题

社区反馈了多个 HNSW 量化相关测试的不稳定性问题,这些测试验证 HNSW 与量化结合时的行为:

测试名称Issue问题描述
hnsw_turbo_quantization_cosine_larger_bits2_test#8835分数断言失败
hnsw_turbo_quantization_manhattan_test#8834分数断言失败
hnsw_discover_test::filtered_hnsw_discover_precision#8704召回率 94/100

这些问题的根本原因在于量化误差累积导致搜索结果的微小差异,特别是在不同的距离度量方式(Cosine、Dot、Euclidean、Manhattan)下表现不同。

使用注意事项

  1. 删除点处理:当前实现中,删除点时不会立即释放向量内存(Issue #2550)。优化器会在后续处理中清理孤立向量。
  1. 小数据集优化:当向量数量低于 full_scan_threshold 时,HNSW 可能比全表扫描更慢。
  1. 维度限制:某些量化方法(如 Binary)在低维度(<1024d)下性能显著下降。

性能优化

内存优化

  • on_disk 配置:将 HNSW 索引存储在磁盘上以减少内存占用
  • 量化压缩:使用 Scalar Quantization 或 Product Quantization 减少向量存储大小

搜索优化

  • ef 参数调整:增加搜索时的 ef 值可提高召回率,但会增加延迟
  • 批量搜索:利用 SIMD 指令并行处理多个查询

构建优化

  • 并行构建:设置 max_indexing_threads 利用多核并行构建
  • 批量插入:累积多个向量后统一构建,减少重建次数

总结

HNSW 是 Qdrant 实现高效向量搜索的核心技术。通过分层图结构,HNSW 在搜索复杂度和召回率之间取得了良好平衡。Qdrant 的实现支持多种距离度量、与量化技术的集成,以及灵活的参数配置。

理解 HNSW 的工作原理和配置参数对于优化 Qdrant 的向量检索性能至关重要。在实际使用中,应根据数据集规模、召回率要求和延迟限制来调整相关参数。

资料来源:lib/segment/src/index/hnsw_index/graph_layers.rs:1-100

向量存储系统

向量存储系统是 Qdrant 搜索引擎的核心组件,负责存储、检索和管理高维向量数据。该系统支持多种向量类型(稠密向量、稀疏向量、多向量)以及多种量化策略,以满足不同场景下的存储效率和搜索性能需求。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 模块结构

继续阅读本节完整说明和来源证据。

章节 向量类型系统

继续阅读本节完整说明和来源证据。

章节 核心实现

继续阅读本节完整说明和来源证据。

概述

向量存储系统是 Qdrant 搜索引擎的核心组件,负责存储、检索和管理高维向量数据。该系统支持多种向量类型(稠密向量、稀疏向量、多向量)以及多种量化策略,以满足不同场景下的存储效率和搜索性能需求。

向量存储在 Qdrant 架构中位于段(Segment)层级,与 HNSW 索引、载荷索引和 WAL(Write-Ahead Logging)共同构成了完整的向量数据库引擎。

graph TB
    subgraph "存储层"
        GS[GridStore 存储]
        WD[WAL Delta]
    end
    
    subgraph "向量存储"
        DVS[稠密向量存储]
        SVS[稀疏向量存储]
        MVS[多向量存储]
        QVS[量化向量存储]
    end
    
    subgraph "索引层"
        HNSW[HNSW 索引]
        FI[载荷索引]
    end
    
    subgraph "查询层"
        SQ[段查询]
        AGG[结果聚合]
    end
    
    DVS --> GS
    SVS --> GS
    MVS --> GS
    QVS --> GS
    HNSW --> DVS
    HNSW --> SVS
    SQ --> HNSW
    SQ --> FI
    AGG --> SQ

架构组件

模块结构

向量存储系统的核心代码位于 lib/segment/src/vector_storage/ 目录,包含以下子模块:

模块路径功能描述
densedense/dense_vector_storage.rs稠密向量存储实现
sparsesparse/mod.rs稀疏向量存储实现
quantizedquantized/quantized_storage.rs量化向量存储
data_types../data_types/vectors.rs向量数据类型定义

资料来源:lib/segment/src/vector_storage/mod.rs

向量类型系统

Qdrant 支持多种向量表示形式:

pub mod vectors {
    pub mod named_vectors;    // 命名向量(多向量场景)
    pub mod primitive;        // 原始向量类型
    pub mod query_context;    // 查询上下文
}

资料来源:lib/segment/src/data_types/mod.rs

稠密向量存储

核心实现

稠密向量存储是最常用的向量存储方式,适用于标准的嵌入向量(如来自 BERT、CLIP 等模型的输出)。系统通过 DenseVectorStorage trait 定义了统一的接口:

pub trait VectorStorage {
    fn get_vector(&self, key: VectorOffsetType) -> &VectorType;
    fn insert_vector(&mut self, key: VectorOffsetType, vector: &[VectorElementType]) -> Result<(), StorageError>;
    fn update_vector(&mut self, key: VectorOffsetType, vector: &[VectorElementType]) -> Result<(), StorageError>;
    fn delete_vector(&mut self, key: VectorOffsetType) -> Result<(), StorageError>;
}

存储布局

稠密向量在磁盘上采用块状存储布局,每个块包含固定数量的向量。存储时会考虑 SIMD 对齐要求以优化向量运算性能。

距离度量

系统支持多种距离度量方式,可在创建集合时指定:

度量类型说明适用场景
Cosine余弦相似度文本嵌入、通用场景
Dot点积归一化向量、推荐系统
Euclid欧几里得距离聚类、异常检测
Manhattan曼哈顿距离稀疏特征

资料来源:lib/segment/src/spaces/mod.rs

稀疏向量存储

稀疏向量特性

稀疏向量存储专为高维稀疏数据设计,如 BM25 分数或稀疏嵌入。系统只存储非零维度,显著降低存储占用。

存储实现

稀疏向量存储采用键值对结构:

  • :维度索引(整数)
  • :维度权重(浮点数)

这种存储方式在处理稀疏特征时比稠密向量高效数倍。

量化向量存储

量化策略概述

量化存储通过有损压缩减少内存占用,是处理十亿级向量数据的关键技术。

量化类型压缩比精度损失适用场景
Scalar4x内存敏感场景
Product Quantization (PQ)8-64x大规模检索
Binary32x极致压缩
TurboQuant可配置可控ICLR 2026 新特性

资料来源:lib/segment/src/vector_storage/quantized/quantized_storage.rs

TurboQuant 量化

TurboQuant 是 Qdrant 新一代量化技术,相比传统 PQ 在精度和压缩率之间提供了更好的权衡:

  • 可配置位宽:支持 1-16 位量化
  • 自适应量化:根据数据分布自动调整量化参数
  • 保留更多精度:在相同压缩比下优于传统方法

已知问题

社区反馈了多个与量化搜索相关的测试不稳定问题:

  • hnsw_turbo_quantization_cosine_larger_bits2_test - 在不同距离度量下可能出现精度断言失败
  • hnsw_turbo_quantization_dot_test - 点积量化搜索存在边界情况

这些问题主要表现为 assertion failed: best_2.score >= best_1.score,通常与量化误差边界有关。

资料来源:GitHub Issue #8835GitHub Issue #8906

存储后端:GridStore

架构设计

GridStore 是 Qdrant 的新一代存储引擎,逐步替代 RocksDB。向量数据最终通过 GridStore 持久化到磁盘。

graph LR
    subgraph "Page 结构"
        PG[Page 123]
        PB1[Block 0-7]
        PB2[Block 0-7]
    end
    
    subgraph "写入流程"
        VP[ValuePointer] -->|page_id, block_offset| WR[Write Range]
        WR -->|byte_offset| ST[Store to Grid]
    end
    
    subgraph "配置参数"
        PS[page_size_bytes: 32MB]
        BS[block_size_bytes: 128]
        RS[region_size_blocks: 8192]
    end

存储配置

GridStore 提供可调整的存储参数:

参数默认值说明
page_size_bytes32MB页大小
block_size_bytes128 字节块大小
region_size_blocks8192区域块数
compressionLZ4压缩算法

资料来源:lib/gridstore/src/config.rs

非阻塞刷新

v1.17.1 版本对 GridStore 进行了优化,使刷新操作变为非阻塞,有效降低了搜索尾延迟。

资料来源:v1.17.1 Release Notes

与 HNSW 索引的集成

索引构建流程

向量存储与 HNSW 索引紧密集成:

graph TD
    VI[向量插入] --> VS[向量存储]
    VS --> HNSW[HNSW 索引更新]
    HNSW -->|选择邻居| NB[邻居候选]
    NB -->|计算距离| SC[距离评分]
    SC -->|更新连接| EL[边连接]

数据一致性检查

段级别提供数据一致性验证功能:

pub fn check_data_consistency(&self) -> OperationResult<()> {
    // 检查:内部 ID 与外部 ID 映射
    // 检查:向量与版本号对应
    // 检查:删除点的向量状态
}

资料来源:lib/segment/src/segment/segment_ops.rs

已知测试不稳定

社区发现以下 HNSW 相关测试存在不稳定性:

  • filtered_hnsw_discover_precision - 发现查询精度边界问题
  • hnsw_quantized_search_* 系列测试 - 量化搜索精度断言失败

这些问题的特征是期望命中数(如 100 个中的 94 个)未达到阈值。

资料来源:GitHub Issue #8704

配置与优化

集合配置

向量存储参数通过集合配置管理:

pub struct CollectionConfigInternal {
    pub params: Option<Payload>,  // 存储应用元数据
}

资料来源:lib/collection/src/config.rs

批量查询优化

v1.16.1 引入的优化使批量查询在完全扫描场景下提升 3 倍性能,原理是每个点只读取一次:

// 优化前:每个向量独立读取
for vector in vectors {
    read_once(vector);
}

// 优化后:批量读取,每点一次
batch_read(vectors);  // 利用 IO 合并

资料来源:v1.16.1 Release Notes

相关社区讨论

热点议题

  1. 多向量字段支持 - 用户希望在创建集合后动态添加新的向量字段(Issue #1132)
  2. 删除点向量清理 - 当点被删除时,应同时标记向量为已删除状态(Issue #2550)
  3. ColBERT 集成 - 追踪 Late Interaction 模型的向量存储集成(Issue #3684)

TurboQuant 追踪

TurboQuant 作为 ICLR 2026 提交的新特性,正在积极开发中:

总结

向量存储系统是 Qdrant 高性能向量检索的基础,提供了:

  • 多类型支持:稠密、稀疏、多向量
  • 灵活量化:Scalar、Binary、PQ、TurboQuant
  • 高效存储:GridStore 块状布局
  • 索引集成:与 HNSW 深度整合
  • 可观测性:与遥测系统集成

通过合理的配置和优化,向量存储系统能够支撑从小型数据集到十亿级向量的各种规模应用。

资料来源:lib/segment/src/vector_storage/mod.rs

量化技术(TurboQuant、Scalar、Binary、PQ)

Qdrant 的量化(Quantization)技术是一种用于压缩向量存储和加速向量搜索的关键优化手段。通过将高精度的浮点向量转换为低比特表示,量化可以显著降低内存占用和 I/O 开销,同时保持可接受的检索精度。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 量化模块结构

继续阅读本节完整说明和来源证据。

章节 量化执行流程

继续阅读本节完整说明和来源证据。

章节 原理

继续阅读本节完整说明和来源证据。

概述

Qdrant 的量化(Quantization)技术是一种用于压缩向量存储和加速向量搜索的关键优化手段。通过将高精度的浮点向量转换为低比特表示,量化可以显著降低内存占用和 I/O 开销,同时保持可接受的检索精度。

Qdrant 目前支持四种量化方法:

量化类型压缩比精度损失适用场景预处理需求
Scalar通用场景无需训练
Binary32×中等高维向量(>1024d)无需训练
Product Quantization (PQ)可配置(4×-64×)中等大规模数据集需要训练码本
TurboQuant>16×低-中等极致压缩需求无需训练

资料来源:lib/quantization/src/lib.rs:1-100

架构设计

量化模块结构

lib/quantization/src/
├── lib.rs                 # 量化模块入口和公共接口
├── scalar/               # Scalar 标量量化
│   └── mod.rs
├── binary/               # Binary 二值量化
│   └── mod.rs
├── product/              # Product Quantization 乘积量化
│   └── quantization.rs
└── turboquant/           # TurboQuant 新型量化
    ├── mod.rs
    └── simd/             # SIMD 加速实现
        └── mod.rs

量化执行流程

graph TD
    A[原始向量] --> B{量化类型选择}
    B -->|Scalar| C[标量量化编码]
    B -->|Binary| D[二值量化编码]
    B -->|PQ| E[乘积量化 - 分段+码本映射]
    B -->|TurboQuant| F[TurboQuant - 自适应量化]
    
    C --> G[压缩向量存储]
    D --> G
    E --> G
    F --> G
    
    G --> H[量化向量用于HNSW搜索]
    H --> I[重排序-Reranking]
    I --> J[最终结果]

Scalar 标量量化

原理

Scalar 量化将每个浮点向量分量从 32 位浮点数(float32)压缩为 8 位整数(uint8)。压缩过程中需要记录每个向量的 min/max 值用于解码时的反量化操作。

实现特点

  • 无需训练:直接在运行时计算 min/max 值
  • 固定压缩比:4×(32位 → 8位)
  • 精度保持:由于是线性量化,在向量分布均匀时效果较好
  • 检索模式:使用量化向量进行初步搜索,再通过重排序恢复精度

关键配置参数

参数类型默认值说明
scalarobject-Scalar 量化配置
scalar.typestring"int8"量化数据类型
scalar.quantilefloat0.99用于裁剪异常值的分位数
scalar.scalar_thresholdfloat0.0启用量化的向量维度阈值

资料来源:lib/quantization/src/scalar/mod.rs:1-80

Binary 二值量化

原理

Binary 量化将每个向量分量转换为单个比特位(0 或 1)。这实现了 32× 的极致压缩比,但会丢失大部分数值精度信息。

适用限制

根据社区反馈(Issue #8524),Binary 量化在向量维度低于 1024 时效果较差,因为:

  1. 维度不足导致向量区分度下降
  2. 碰撞概率增加,哈希冲突严重
  3. 相似度计算精度不足

实现要点

// Binary 量化核心逻辑示例
pub fn encode_binary_vector(vector: &[f32]) -> Vec<u8> {
    vector.iter()
        .map(|&v| if v >= 0.0 { 1u8 } else { 0u8 })
        .collect::<Vec<u8>>()
}

资料来源:lib/quantization/src/binary/mod.rs:1-60

Product Quantization (PQ) 乘积量化

原理

PQ 将高维向量分割成多个子向量(segments),对每个子向量独立进行聚类编码。这种方法在压缩率和精度之间提供了更好的平衡。

工作流程

graph LR
    A[原始向量 128维] --> B[分割: 4个子向量各32维]
    B --> C[子向量1]
    B --> D[子向量2]
    B --> E[子向量3]
    B --> F[子向量4]
    
    C --> G[码本查找: 最近中心]
    D --> G
    E --> G
    F --> G
    
    G --> H[编码: 4个中心ID]
    H --> I[存储: 4字节/向量]

特点

特性说明
可配置压缩比通过调整子向量数量(segments)和聚类中心数(codebook_size)
需要训练首次使用需扫描数据构建码本
检索效率使用 SDC 或 ADC 近似距离计算加速检索

配置参数

参数类型说明
product.segmentsint子向量分段数量
product.compressionstring压缩级别(如 "x4", "x8", "x16")
product.ray_sample_sizeint训练时的采样数量

资料来源:lib/quantization/src/product/quantization.rs:1-150

TurboQuant 量化

背景与动机

TurboQuant 是 Qdrant 社区提出的新型量化方案(Issue #8524),旨在解决现有量化方法的局限性:

  • Scalar 最高仅支持 4× 压缩比
  • Binary 在低维度(<1024d)时效果急剧下降
  • PQ 需要码本训练,复杂且精度损失明显

核心特性

TurboQuant 是一种无需训练的、自适应的量化方法,提供:

  1. 极致压缩:支持 >16× 的压缩比
  2. 零训练成本:直接编码,无需数据采样和聚类
  3. 低精度损失:通过自适应量化策略保持更好的向量区分度
  4. SIMD 加速:利用 SIMD 指令集优化解码性能

实现架构

graph TD
    A[输入向量 f32] --> B[TurboQuant 编码器]
    B --> C[比特打包]
    C --> D[编码向量存储]
    
    E[查询向量] --> F[量化查询]
    F --> G[近似距离计算]
    G --> H{重排序策略}
    H -->|需要精确分数| I[解码子集]
    H -->|全精度| J[直接返回]
    
    I --> K[精确距离计算]
    K --> L[最终排序]
    J --> L

SIMD 优化

TurboQuant 的 SIMD 实现位于 lib/quantization/src/turboquant/simd/mod.rs,提供了针对不同架构的向量化计算优化:

  • x86/x64: SSE/AVX/AVX-512 指令支持
  • ARM: NEON 指令支持
  • 跨平台: 动态检测可用指令集
// SIMD 解码示例结构
pub mod simd {
    pub mod portable;  // 通用实现
    pub mod avx2;      // AVX2 优化
    pub mod avx512;    // AVX-512 优化
}

当前已知问题

根据社区反馈(Issue #8835, #8801, #8806, #8735, #8906, #8834),TurboQuant 实现存在一些不稳定的测试:

lib\segment\tests\integration\hnsw_quantized_search_test.rs:314:9: 
assertion failed: best_2.score >= best_1.score

这些失败主要出现在使用 hnsw_turbo_quantization_* 测试用例中,表明在特定距离度量(Cosine、Dot、Manhattan、Euclid)和配置下的量化搜索存在精度一致性问题。

相关 Issue 列表:

Issue测试用例状态
#8835hnsw_turbo_quantization_cosine_larger_bits2_test待修复
#8801hnsw_turbo_quantization_cosine_larger_test待修复
#8806hnsw_quantized_search_manhattan_test待修复
#8735hnsw_quantized_search_euclid_test待修复
#8906hnsw_turbo_quantization_dot_test待修复
#8834hnsw_turbo_quantization_manhattan_test待修复

量化搜索集成

HNSW 量化集成

量化向量与 HNSW 索引的集成是 Qdrant 高性能搜索的核心。量化搜索流程:

graph TD
    A[查询请求] --> B[量化查询向量]
    B --> C[HNSW 图遍历]
    C --> D[候选向量列表]
    D --> E{量化重排序}
    E -->|启用| F[计算量化距离]
    E -->|禁用| G[解码全部向量]
    F --> H[精确重排序]
    G --> H
    H --> I[Top-K 结果]

重排序策略

Qdrant 支持两种重排序模式:

  1. 仅量化:完全基于量化向量计算分数,速度最快但精度有限
  2. 量化+重排序:先用量化向量筛选候选,再用原始向量精确排序

配置示例:

quantization:
  scalar:
    enabled: true
    type: int8
    quantile: 0.99
  reranking:
    enabled: true
    oversampling: 1.1

配置与使用

集合级别配置

在创建或更新集合时配置量化参数:

{
  "vectors": {
    "size": 768,
    "distance": "Cosine"
  },
  "quantization": {
    "scalar": {
      "enabled": true,
      "type": "int8"
    }
  }
}

运行时参数

参数说明适用量化
hnsw_on_diskHNSW 索引存储位置所有
quantization_on_disk量化数据是否存储到磁盘所有
oversampling重排序过采样系数所有
searchable_sampling搜索时采样百分比TurboQuant

性能与精度权衡

基准测试数据

量化类型压缩比内存占用搜索速度NDCG@10
无量化100%基准1.000
Scalar25%~2×0.95-0.98
Binary32×3.1%~8×0.70-0.85*
PQ x1616×6.25%~4×0.90-0.96
TurboQuant16-32×3-6%~6×0.88-0.95**
* Binary 在低维度时显著下降
** TurboQuant 精度数据待稳定

选择指南

graph TD
    A[需要量化?] --> B{内存受限?}
    B -->|是| C{维度 > 1024?}
    C -->|是| D[Binary 或 TurboQuant]
    C -->|否| E{TurboQuant 可用?}
    E -->|是| F[TurboQuant]
    E -->|否| G[Scalar 或 PQ]
    B -->|否| H[考虑精度优先]
    H --> I[无量化 或 Scalar]
    
    G --> J{需要训练?}
    J -->|否| K[Scalar]
    J -->|是| L[PQ]
    
    D --> M[最终选择]
    F --> M
    K --> M
    L --> M
    I --> M

相关资源

  • 设计文档:https://www.notion.so/qdrant/TurboQuant-design-doc-334674779d33803ab94bca91863cf066
  • TurboQuant 追踪 Issue:#8670
  • 功能讨论:#8524

资料来源:lib/quantization/src/lib.rs:1-100

分片与复制

Qdrant 是一个高性能的向量搜索引擎,支持水平扩展以处理大规模向量数据。分片(Sharding) 和 复制(Replication) 是实现分布式部署的核心机制,分别负责数据的分区存储和容错高可用。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 分片与复制组件关系

继续阅读本节完整说明和来源证据。

章节 模块组织结构

继续阅读本节完整说明和来源证据。

章节 分片工作原理

继续阅读本节完整说明和来源证据。

概述

Qdrant 是一个高性能的向量搜索引擎,支持水平扩展以处理大规模向量数据。分片(Sharding)复制(Replication) 是实现分布式部署的核心机制,分别负责数据的分区存储和容错高可用。

  • 分片:将集合(Collection)中的数据划分为多个逻辑分区,每个分片存储集合的一部分向量数据
  • 复制:为每个分片创建多个副本,分布在不同节点上,提供数据冗余和故障恢复能力

这两个机制协同工作,使 Qdrant 能够支持分布式向量搜索,同时保证数据的持久性和可用性。资料来源:lib/shard/src/lib.rs:1-30

核心架构

分片与复制组件关系

graph TB
    subgraph "Collection 层"
        C[Collection]
    end
    
    subgraph "分片路由层"
        HR[Hash Ring Router]
    end
    
    subgraph "分片副本组"
        RS1[Replica Set 0]
        RS2[Replica Set 1]
        RS3[Replica Set N]
    end
    
    subgraph "本地分片"
        S1[Shard 1]
        S2[Shard 2]
        S3[Shard N]
    end
    
    C --> HR
    HR --> RS1
    HR --> RS2
    HR --> RS3
    RS1 --> S1
    RS2 --> S2
    RS3 --> S3

模块组织结构

Qdrant 的分片与复制功能主要分布在以下模块中:

模块路径职责
lib/collection/src/shards/分片生命周期管理、副本集协调
lib/shard/src/lib.rs分片操作核心接口定义
lib/collection/src/shards/local_shard/本地分片实现,包含读写操作
lib/collection/src/operations/操作分割与分片路由逻辑

资料来源:lib/collection/src/lib.rs:1-20lib/shard/src/lib.rs:1-35

分片机制

分片工作原理

当创建一个集合时,可以指定 shard_number 参数来定义分片数量。数据根据向量 ID 或自定义策略分配到不同的分片中。Qdrant 使用一致性哈希环(Hash Ring)进行分片路由:

graph LR
    V[向量 ID] --> HR[Hash Ring]
    HR -->|计算哈希槽| Slot[(分片 0)]
    HR --> Slot2[(分片 1)]
    HR --> Slot3[(分片 N)]

分片路由

集合操作通过 SplitByShard trait 进行分片分割,将操作路由到对应的分片:

pub trait SplitByShard {
    fn split_by_shard(self, ring: &HashRingRouter) -> OperationToShard<Self>
    where
        Self: Sized;
}

资料来源:lib/collection/src/operations/mod.rs:35-45

分片操作类型

操作类型说明
PointOperation点级别操作(插入、更新、删除)
VectorOperation向量级别操作
PayloadOperationPayload 级别操作

每个操作类型都实现了 SplitByShard trait,能够根据分片数量自动分割操作请求。资料来源:lib/collection/src/operations/mod.rs:47-62

复制机制

副本集架构

每个分片可以有多个副本(replication_factor),形成副本集。副本集包含以下角色:

graph TD
    subgraph "Replica Set"
        P[Primary - 主分片]
        R1[Replica 1]
        R2[Replica 2]
    end
    
    W[写操作] --> P
    P -->|同步| R1
    P -->|同步| R2
    R1 -.->|故障转移| P
    R2 -.->|故障转移| P

复制策略

  • 同步复制:写操作必须等到所有副本确认后才返回
  • 异步复制:主分片处理写操作后,异步同步到副本

故障恢复

当某个分片节点发生故障时,Qdrant 的共识层会检测到节点失联,自动触发副本重新同步流程,确保复制因子恢复到配置值。

分片转移

Shard Transfer 机制

分片可以在节点之间转移,用于负载均衡和节点维护场景:

graph LR
    A[节点 A] -->|迁移分片| B[节点 B]
    B -->|确认完成| A
    A -->|删除本地副本| A2[(清理)]

转移流程

  1. 发起转移:在目标节点上创建空分片
  2. 数据同步:通过 WAL(Write-Ahead Log)重放或快照传输
  3. 切换路由:更新路由表,指向新分片位置
  4. 清理旧分片:删除源节点上的分片数据

资料来源:lib/collection/src/shards/shard_transfer.rs

一致性与共识

Qdrant 使用 Raft 共识算法确保分布式环境下的一致性:

  • 共识模块 (lib/storage/src/content_manager/consensus/):处理分布式协调
  • PeerId:标识集群中的每个节点
  • 持久化状态:集群配置和分片分布信息持久化存储

资料来源:lib/storage/src/content_manager/consensus/persistent.rs

配置参数

集合级别分片配置

参数说明默认值
shard_number分片数量1
replication_factor复制因子1
write_consistency_factor写一致性要求1
on_disk_payloadPayload 是否存储在磁盘上false

集群级别配置

参数说明
timeout操作超时时间
gc_timeout垃圾回收超时
bootstrap_timeout启动引导超时

本地分片实现

LocalShard 结构

LocalShard 是分片的本地存储实现,封装了底层的 Segment 管理和操作:

// 核心模块组织
pub mod local_shard {
    pub mod clock_map;       // 分布式时钟
    pub mod disk_usage_watcher;  // 磁盘监控
    pub mod facet;          // Facet 搜索
    pub mod query;          // 查询处理
    pub mod search;         // 搜索执行
    pub mod scroll;          // 分页滚动
    pub mod updaters;        // 数据更新
    pub mod wal_ops;        // WAL 操作
}

资料来源:lib/collection/src/shards/local_shard/mod.rs:1-20

数据一致性检查

分片提供数据一致性检查功能:

pub fn check_data_consistency(&self) -> OperationResult<()> {
    // 检查项:
    // - 内部 ID 无外部 ID
    // - 外部 ID 无内部 ID
    // - 内部 ID 无版本信息
    // - 内部 ID 无向量数据
}

资料来源:lib/segment/src/segment/segment_ops.rs:80-95

最佳实践

分片数量选择

  • 小型数据集(< 1M 向量):1-2 个分片
  • 中型数据集(1M - 100M 向量):4-8 个分片
  • 大型数据集(> 100M 向量):按节点数量和查询并发度扩展

复制因子选择

场景建议复制因子
单节点开发测试1
生产环境2-3
高可用关键业务3+

常见问题

  1. 热点问题:某些分片负载过高时,可通过调整分片键或增加分片数量解决
  2. 复制延迟:异步复制场景下可能出现读取旧数据,需根据一致性要求选择同步或异步模式
  3. 网络分区:共识机制保证多数派节点可用时系统仍可写入

相关文档

资料来源:lib/collection/src/lib.rs:1-20lib/shard/src/lib.rs:1-35

WAL 与存储引擎

Qdrant 的持久化层由两个核心组件构成:Write-Ahead Log (WAL) 和 存储引擎。WAL 负责确保所有更新操作的持久性和一致性,而存储引擎则负责高效地组织、索引和检索向量数据。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心职责

继续阅读本节完整说明和来源证据。

章节 模块结构

继续阅读本节完整说明和来源证据。

章节 WAL 与分片的关联

继续阅读本节完整说明和来源证据。

概述

Qdrant 的持久化层由两个核心组件构成:Write-Ahead Log (WAL)存储引擎。WAL 负责确保所有更新操作的持久性和一致性,而存储引擎则负责高效地组织、索引和检索向量数据。

在分布式向量搜索场景中,数据一致性至关重要。WAL 机制确保即使在系统崩溃后也能恢复未完全写入主存储的更新操作,而 GridStore 作为主存储引擎提供了高性能的内存映射文件和块级存储管理。

WAL (Write-Ahead Log)

核心职责

WAL 是 Qdrant 实现数据持久化和故障恢复的核心机制。其主要职责包括:

  1. 操作记录:将所有点操作(插入、更新、删除)追加写入预写日志
  2. 故障恢复:在系统重启时重放 WAL 中的操作,确保数据不丢失
  3. 共识支持:为分布式共识提供操作顺序保证
  4. 原子性保证:确保分布式环境下的操作一致性

模块结构

lib/wal/
├── src/
│   ├── lib.rs           # WAL 主模块,定义核心接口
│   ├── wal.rs           # WAL 实现
│   ├── wal_tests.rs     # 单元测试
│   ├── entry.rs         # 日志条目定义
│   ├── segment.rs       # 日志分段管理
│   └── error.rs         # 错误类型定义

WAL 与分片的关联

在分片(Shard)架构中,每个分片维护独立的 WAL 实例:

lib/shard/src/wal.rs  ← 分片级别的 WAL 封装
lib/shard/src/lib.rs  ← 导出 wal 模块

分片 WAL 的关键操作包括:

操作说明
append追加操作到 WAL
fsync强制刷盘确保持久化
read读取 WAL 中的记录
truncate清理已确认的旧记录

WAL 持久化流程

graph TD
    A[接收更新操作] --> B[序列化操作数据]
    B --> C[追加写入 WAL]
    C --> D[调用 fsync]
    D --> E[操作确认返回]
    E --> F[异步应用更新到存储]
    
    G[系统启动] --> H[读取 WAL]
    H --> I{检查点存在?}
    I -->|是| J[从检查点恢复]
    I -->|否| K[从头重放 WAL]
    J --> L[继续正常服务]
    K --> L

存储引擎:GridStore

设计目标

GridStore 是 Qdrant 从 RocksDB 迁移后的新一代存储引擎,其核心设计目标包括:

  • 高吞吐量:支持 io_uring 异步 I/O,最大化磁盘带宽利用率
  • 低延迟:非阻塞刷盘操作,减少搜索尾延迟
  • 内存映射:利用 mmap 进行高效的向量数据访问
  • 块级管理:细粒度的存储空间分配和回收

资料来源:lib/gridstore/src/config.rs:1-50

存储层次结构

GridStore 采用三层存储结构:

┌─────────────────────────────────────────┐
│              GridStore                   │
├─────────────────────────────────────────┤
│  Page (默认 32MB)                        │
│  ├── Region (默认 8192 blocks)          │
│  │   └── Block (默认 128 bytes)         │
│  └── Region Gaps (位图管理)             │
├─────────────────────────────────────────┤
│  Bitmask (页面级可用空间追踪)           │
└─────────────────────────────────────────┘
层级默认大小说明
Block128 bytes最小分配单元
Region8192 blocks (1MB)区域管理单元
Page32MB文件映射单元

资料来源:lib/gridstore/src/pages.rs:1-60

页面管理机制

页面是 GridStore 的核心抽象单元。每个页面包含多个区域,区域由连续的块组成。位图(Bitmask)用于追踪每个页面的可用空间状态。

// 页面值范围计算
pub fn get_page_value_ranges(pointer: ValuePointer, config: &StorageConfig)

当写入值跨越多个页面时,GridStore 自动处理跨页拆分:

┌── ValuePointer ───┐
│ page_id:      123 │
│ block_offset: 6   │  ← 起始位置
│ length:       5K  │  ← 跨越长度
└─────────┬─────────┘
          │
          ▼
┌───┬───┬── page 123 ───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │  ← 跨越区域
└───┴───┴───┴───┴───┴───┴───┴───┘
                │
                ▼
┌───┬───┬── page 124 ───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
└───┴───┴───┴───┴───┴───┴───┴───┘

资料来源:lib/gridstore/src/pages.rs:100-150

位图管理

GridStore 使用位图追踪每个页面的可用块:

// 位图长度计算:每页块数 / 8
pub fn length_for_page(config: &StorageConfig) -> usize {
    let bits = config.page_size_bytes / config.block_size_bytes;
    bits / u8::BITS as usize
}

位图结构特点:

  • 每位对应一个块,1 表示已用,0 表示空闲
  • 区域间隙(Region Gaps)提供更细粒度的空间追踪
  • 支持高效的空闲空间查找

资料来源:lib/gridstore/src/bitmask/mod.rs:1-50

存储配置

pub struct StorageConfig {
    pub page_size_bytes: usize,      // 默认 32MB
    pub block_size_bytes: usize,      // 默认 128 bytes
    pub region_size_blocks: usize,    // 默认 8192 blocks
    pub compression: Compression,     // 默认 LZ4
}

配置验证规则:

  • 块大小必须大于 0
  • 区域大小必须大于 0
  • 页面大小必须大于等于 block_size_bytes * region_size_blocks

资料来源:lib/gridstore/src/config.rs:40-80

更新处理流程

UpdateHandler 架构

UpdateHandler 是协调 WAL 和存储引擎的关键组件:

lib/collection/src/update_handler.rs
graph LR
    A[API 请求] --> B[WAL 写入]
    B --> C[fsync 持久化]
    C --> D[更新操作入队]
    D --> E[UpdateHandler 消费]
    E --> F[Segment 更新]
    F --> G[GridStore 写入]
    G --> H[索引更新]

异步更新机制

UpdateHandler 支持异步处理流程:

  1. WAL 同步写入:确保操作已持久化
  2. 操作入队:根据分片路由分发操作
  3. 批量应用:优化器以批次方式应用更新
  4. 存储合并:定期合并小段为大段

资料来源:lib/collection/src/update_handler.rs:1-100

批量查询优化

v1.16.1 引入的优化使批量查询在完整扫描场景下性能提升 3 倍,原理是每个点只读取一次:

// 批量查询时共享数据读取
pub struct BatchQueryContext {
    // 多个查询共享同一点的数据读取
}

资料来源:lib/collection/src/operations/mod.rs:1-50

GridStore 与 RocksDB 的迁移

迁移背景

Qdrant 正在逐步将存储从 RocksDB 迁移到自研的 GridStore:

特性RocksDBGridStore
I/O 模型同步异步 io_uring
压缩多种算法LZ4 (默认)
内存映射受限原生支持
维护性外部依赖自研可控

启动时迁移

v1.16.1 在启动时主动迁移向量、有效载荷和有效载荷索引存储:

// 从 RocksDB 迁移到 GridStore
pub fn migrate_on_startup() {
    // 检测旧存储格式
    // 渐进式迁移数据
}

资料来源:lib/gridstore/src/gridstore/mod.rs

性能优化特性

非阻塞刷盘

v1.17.1 将 GridStore 刷盘操作改为非阻塞,显著降低搜索尾延迟:

pub fn flusher(&self) -> Flusher {
    // 返回延迟执行的刷盘器
    Box::new(move || {
        for flusher in flushers {
            flusher()?;
        }
        Ok(())
    })
}

刷盘流程优化:

  • 主线程不等待实际刷盘完成
  • 后台线程异步执行 I/O
  • 搜索操作不受刷盘阻塞

资料来源:lib/gridstore/src/pages.rs:80-100

预取优化

GridStore 支持预取机制优化读取性能:

// 触发多页预取
pub fn will_need_multiple_pages(region: &[u8]) {
    // 对 MADV_RANDOM 区域进行顺序预取
}

适用场景:

  • 批量扫描操作
  • 范围查询
  • 迭代器遍历

已知问题与社区反馈

WAL 相关关键修复

版本问题修复
v1.16.2关键 WAL bug 可能破坏共识#7674
v1.18.1异步 upsert 前验证向量维度#9058

v1.16.2 的 WAL 修复解决了可能导致共识失败或数据损坏的关键问题。

资料来源:https://github.com/qdrant/qdrant/releases/tag/v1.16.2

存储迁移注意事项

  • 迁移过程中需要额外磁盘空间
  • 大规模集合迁移可能需要较长时间
  • 建议在低峰期执行迁移操作

相关模块索引

模块路径职责
lib/wal/WAL 核心实现
lib/gridstore/GridStore 存储引擎
lib/shard/src/wal.rs分片 WAL 封装
lib/collection/src/update_handler.rs更新处理协调
lib/segment/Segment 索引管理
lib/collection/src/wal_delta.rsWAL 增量同步

总结

Qdrant 的 WAL 与存储引擎架构体现了对高性能和可靠性的双重追求:

  1. WAL 机制确保所有更新操作的持久性,为分布式共识提供基础
  2. GridStore作为新一代存储引擎,通过 io_uring 和内存映射技术实现高吞吐低延迟
  3. UpdateHandler协调 WAL 和存储引擎,实现高效的异步更新处理
  4. 持续的优化(如非阻塞刷盘、批量查询优化)不断提升系统性能

这套架构使得 Qdrant 能够在大规模向量搜索场景下保持稳定可靠的运行,同时为未来的功能扩展奠定坚实基础。

资料来源:lib/gridstore/src/config.rs:1-50

API 接口

Qdrant 提供了完整的 RESTful API 和 gRPC API 用于向量搜索和数据库管理。API 接口层负责处理客户端请求、参数验证、响应格式化以及与底层存储和索引系统的交互。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 模块结构

继续阅读本节完整说明和来源证据。

章节 模块组织

继续阅读本节完整说明和来源证据。

章节 Schema 生成与验证

继续阅读本节完整说明和来源证据。

概述

Qdrant 提供了完整的 RESTful API 和 gRPC API 用于向量搜索和数据库管理。API 接口层负责处理客户端请求、参数验证、响应格式化以及与底层存储和索引系统的交互。

Qdrant 的 API 架构采用分层设计,核心组件位于 lib/api 目录下,通过 src/actix 层暴露给外部客户端。

资料来源:lib/api/src/rest/mod.rs:1-10

API 架构设计

模块结构

Qdrant 的 API 层主要分为以下几个模块:

模块路径功能
REST APIlib/api/src/rest/处理 HTTP/REST 请求
gRPC APIlib/api/src/grpc/处理 Protocol Buffers 请求
公共模块lib/api/src/共享的数据结构和工具
graph TD
    A[客户端请求] --> B[Actix HTTP Server]
    A --> C[gRPC Server]
    B --> D[REST API Handler]
    C --> E[gRPC Handler]
    D --> F[lib/api - REST模块]
    E --> G[lib/api - gRPC模块]
    F --> H[lib/collection - 集合操作]
    G --> H
    H --> I[lib/segment - 段管理]
    I --> J[lib/vector_storage - 向量存储]
    J --> K[lib/gridstore - 磁盘存储]

资料来源:src/common/mod.rs:1-30

REST API 模块

模块组织

REST API 的核心代码位于 lib/api/src/rest/ 目录,包含以下子模块:

pub mod conversions;    // 类型转换
pub mod models;        // 数据模型定义
pub mod schema;        // JSON Schema 生成
pub mod validate;      // 参数验证
pub use schema::*;     // 导出 schema 相关类型

资料来源:lib/api/src/rest/mod.rs:1-10

Schema 生成与验证

REST API 使用 schemars 库自动生成 OpenAPI/JSON Schema,支持与 OpenAPI 客户端的自动集成。

#### DocumentOptions 配置

DocumentOptions 是一个无标签枚举,用于处理文档相关配置选项:

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(untagged, rename_all = "snake_case")]
pub enum DocumentOptions {
    // 通用的键值对选项
    Common(HashMap<String, JsonValue>),
    // BM25 专用配置
    Bm25(Bm25Config),
}

该设计允许 API 自动反序列化为通用选项,即使指定了 qdrant/bm25 模型名称也能正确处理。资料来源:lib/api/src/rest/schema.rs:1-50

#### 反序列化行为

BM25 配置在 JSON Schema 生成时使用特定变体,但实际反序列化时会被转换为 Common 类型:

impl DocumentOptions {
    pub fn into_options(self) -> HashMap<String, JsonValue> {
        match self {
            DocumentOptions::Common(options) => options,
            DocumentOptions::Bm25(bm25) => bm25.to_options(),
        }
    }
}

资料来源:lib/api/src/rest/schema.rs:50-70

集合配置管理

CollectionConfigInternal 结构

集合配置是 Qdrant API 的核心管理对象,支持持久化和加载:

pub struct CollectionConfigInternal {
    /// 集合元数据,用于存储应用特定信息
    /// 例如:创建时间、迁移数据、推理模型信息等
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<Payload>,
}

资料来源:lib/collection/src/config.rs:1-100

配置持久化方法

方法功能
to_bytes()将配置序列化为字节数组
save(path)原子性写入配置文件
load(path)从文件系统加载配置
check(path)检查配置文件是否存在
validate_and_warn()验证配置有效性并输出警告
impl CollectionConfigInternal {
    pub fn save(&self, path: &Path) -> CollectionResult<()> {
        let config_path = path.join(COLLECTION_CONFIG_FILE);
        let af = AtomicFile::new(&config_path, AllowOverwrite);
        state_bytes = serde_json::to_vec(self).unwrap();
        af.write(|f| f.write_all(&state_bytes))
    }
}

资料来源:lib/collection/src/config.rs:30-60

操作类型系统

IssuesReport 问题报告

Qdrant 提供了问题追踪机制,用于报告实例中的所有未解决问题:

#[derive(Serialize, JsonSchema, Debug)]
pub struct IssuesReport {
    pub issues: Vec<IssueRecord>,
}

PeerMetadata 对等节点元数据

每个对等节点都维护版本信息,用于集群管理和一致性检查:

#[derive(Clone, Debug, Eq, PartialEq, Hash, Deserialize, Serialize, JsonSchema)]
pub struct PeerMetadata {
    pub(crate) version: Version,
}

impl PeerMetadata {
    pub fn current() -> Self;
    pub fn is_different_version(&self) -> bool;
}

资料来源:lib/collection/src/operations/types.rs:1-80

通用化模式(Generalizer)

用途与设计

Generalizer 是一种特性(Trait),用于从请求结构中移除向量和有效载荷的具体细节,生成轻量级的通用表示:

/// 从结构中移除向量和有效载荷的实现接口
/// 用于泛化请求,去除向量和有效载荷的具体细节
/// 除向量和有效载荷外的其他字段会被复制
/// 向量会被替换为长度指示,有效载荷会被替换为键和长度指示
pub trait Generalizer {
    fn remove_details(&self) -> Self;
}

资料来源:lib/collection/src/operations/generalizer/mod.rs:1-30

操作子模块

通用化系统包含以下子模块:

子模块功能
count计数操作通用化
facet分面搜索操作
matrix矩阵操作
points点操作通用化
query查询操作通用化
update_persisted持久化更新操作

段操作(Segment Operations)

数据一致性检查

Segment 层提供了完整的数据一致性验证功能:

impl Segment {
    /// 检查段自身的数据一致性
    /// - 存在内部ID但无外部ID
    /// - 存在外部ID但无内部ID
    /// - 存在内部ID但无版本信息
    /// - 存在内部ID但无向量数据
    pub fn check_data_consistency(&self) -> OperationResult<()>;
}

资料来源:lib/segment/src/segment/segment_ops.rs:1-50

有效载荷索引管理

段操作还包括有效载荷索引的自动创建和更新:

// 创建或更新与配置不匹配的有效载荷索引
for (key, schema) in schema_config {
    match schema_applied.get(key) {
        Some(existing_schema) if existing_schema == schema => continue,
        Some(existing_schema) => log::warn!(
            "段中的有效载荷索引不正确,正在重新创建 (当前: {:?}, 配置: {:?})",
            existing_schema.name(),
            schema.name(),
        ),
        None => log::warn!(
            "段中缺少 {} 有效载荷索引,正在创建",
            schema.name(),
        ),
    }
    self.create_field_index(...)?;
}

资料来源:lib/segment/src/segment/segment_ops.rs:50-100

HTTP 客户端封装

src/common/http_client 模块提供了 Qdrant 服务间通信的 HTTP 客户端实现,支持请求超时和重试机制。相关改进包括:

  • 搜索和点检索超时处理(v1.16.3)
  • 遥测和指标请求超时处理(v1.16.2)
  • HTTP 请求中添加 User-Agent 头(v1.16.2)

资料来源:src/common/mod.rs:15

API 版本与变更

v1.18.x 改进

  • 批量查询优化:全量扫描场景下批量查询速度提升最多 3 倍
  • 异步 Upsert 向量维度验证:在 WAL 写入前进行验证

v1.17.x 特性

  • 相关性反馈 API(v1.17.0):支持搜索结果相关性反馈
  • 优化进度报告 API(v1.17.0):提供详细的优化进度和各阶段信息
  • GridStore 非阻塞刷新(v1.17.1):减少搜索尾部延迟
  • 延迟点更新应用(v1.17.1):使用 prevent_unoptimized=true 优化点更新

v1.16.x 稳定性改进

  • 关键 WAL 修复:避免共识破坏或数据损坏
  • 启动时主动迁移存储:从 RocksDB 迁移到 GridStore

相关资源

资料来源:lib/api/src/rest/mod.rs:1-10

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 依赖 Docker 环境

非工程用户可能没有 Docker,启动成本明显增加。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 运行可能依赖外部服务

本地安装成功不等于能力可用,外部服务不可用会阻断体验。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

Pitfall Log / 踩坑日志

项目:qdrant/qdrant

摘要:发现 8 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:安装坑 - 依赖 Docker 环境。

1. 安装坑 · 依赖 Docker 环境

  • 严重度:medium
  • 证据强度:runtime_trace
  • 发现:安装/运行入口包含 Docker 命令:docker run -p 6333:6333 qdrant/qdrant
  • 对用户的影响:非工程用户可能没有 Docker,启动成本明显增加。
  • 建议检查:标注 Docker 前置条件,并提供非 Docker 路径或失败提示。
  • 复现命令:docker run -p 6333:6333 qdrant/qdrant
  • 防护动作:Docker 前置条件未说明时,不把项目标成普通用户低门槛。
  • 证据:identity.distribution | github_repo:268163609 | https://github.com/qdrant/qdrant | docker run -p 6333:6333 qdrant/qdrant

2. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 建议检查:将假设转成下游验证清单。
  • 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
  • 证据:capability.assumptions | github_repo:268163609 | https://github.com/qdrant/qdrant | README/documentation is current enough for a first validation pass.

3. 运行坑 · 运行可能依赖外部服务

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:项目说明出现 external service/cloud/webhook/database 等运行依赖关键词。
  • 对用户的影响:本地安装成功不等于能力可用,外部服务不可用会阻断体验。
  • 建议检查:确认是否有离线 demo、mock 数据或可替代服务。
  • 防护动作:外部服务依赖未明确时,不把本地安装成功等同于能力可用。
  • 证据:packet_text.keyword_scan | github_repo:268163609 | https://github.com/qdrant/qdrant | matched external service / cloud / webhook / database keyword

4. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
  • 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
  • 证据:evidence.maintainer_signals | github_repo:268163609 | https://github.com/qdrant/qdrant | last_activity_observed missing

5. 安全/权限坑 · 下游验证发现风险项

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:下游已经要求复核,不能在页面中弱化。
  • 建议检查:进入安全/权限治理复核队列。
  • 防护动作:下游风险存在时必须保持 review/recommendation 降级。
  • 证据:downstream_validation.risk_items | github_repo:268163609 | https://github.com/qdrant/qdrant | no_demo; severity=medium

6. 安全/权限坑 · 存在评分风险

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 建议检查:把风险写入边界卡,并确认是否需要人工复核。
  • 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
  • 证据:risks.scoring_risks | github_repo:268163609 | https://github.com/qdrant/qdrant | no_demo; severity=medium

7. 维护坑 · issue/PR 响应质量未知

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
  • 防护动作:issue/PR 响应未知时,必须提示维护风险。
  • 证据:evidence.maintainer_signals | github_repo:268163609 | https://github.com/qdrant/qdrant | issue_or_pr_quality=unknown

8. 维护坑 · 发布节奏不明确

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
  • 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
  • 证据:evidence.maintainer_signals | github_repo:268163609 | https://github.com/qdrant/qdrant | release_recency=unknown

来源:Doramagic 发现、验证与编译记录