DiskANN数据布局

_mem.index.data:和sift_base.fbin一模一样。0-3字节是总向量数,4-7是每个向量的特征数。后面就是依次放置的每个向量。

_disk.index:是存储的图,但是不光包含图也包含原始向量。前4KB不知道存的是啥。从第0x1000开始存放的是原始向量,存放顺序和 _mem.index.data一致。每个原始向量后紧跟着的是4B的整数,代表邻居数。然后就是依序存放的邻居,每个邻居是4B的整形。然后就是下一个向量。存放原始向量的目的是为了遍历图的时候能够获取原始向量进行二次排序,与论文说的一致。然后DiskANN会对所有向量进行4K对齐,一个向量不会横跨两个4K块。所以每个4K块的末尾都会有一些为0的数据。

开头的字段定义在pq_flash_index.cpp中第1045行,对我们没有太大意义。包含了向量数量08-0F,向量维数10-17,pq中心数量18-1F,每个向量占的字节数20-27,每个4K块占包含的向量数量28-2F。文件的总大小48-4F

_pq_compressed.bin:存储的是DiskANN要放在内存中的压缩向量。0-3是向量总数,4-7是每个向量的字节数。后面就依次存放每个向量。至于这些PQ向量的中心在哪,被分成了几段什么的不知道。

_pq_pivots.bin:加载这个文件的代码在pq.cpp的load_pq_centroid_bin函数中。第一个4KB主要表示后面有几个偏移量。

首先从第4096开始读,4096开始的前4个字节是pq_file_num_centroids,并且会判断该值是否是256,这个值应该是代表有接下来有多少个向量。后面4个字节是pq_file_dim,应该是向量的维数。解析该文件的时候会和_pq_compressed.bin结合起来看。至于为什么256个向量就够了,这和PQ的原理有关。PQ压缩把他分为nchunk个类别,那么每个聚类的维数就是(维数/nchunk)。然后每个聚类内部有256个类别,即需要256个聚类中心。结合前两个,存储每个聚类中聚类中心的大小是256*(维数/nchunk)*特征大小。然后所有聚类需要的总大小就是256*(维数/nchunk)*特征大小*nchunk = 256*维数*特征大小 = 256个原始特征的大小。

256正好是2^8,那么PQ压缩的时候应该是每个聚类都最多有256个向量,_pq_compressed.bin存储PQ向量的时候每个聚类就最多只需要1B,也就是为什么不管内存设置为多大,_pq_compressed.bin的大小最多就是(维数*向量数)个字节。

然后第二个偏移量开始表示读取centroid,在pq.cpp的105行。centroid of each dimension。

然后第三个偏移量开始表示读取chunk_offsets,在pq.cpp的124行。表示偏移量,the offset of each chunk, start from 0。

_sample_data.bin_sample_ids.bin:应该是采样的邻居,但是具体用途未知,经过测试和检索过程无关。_data是存放的原始向量,_ids是这些向量对应的id。这两个文件都是0-3字节表示这个文件包含多少个向量,4-7表示这些向量的维数。

​​​​​​​

关于入口点:

为SIFT1M构建索引时,包含的文件就上面几个。但是为bigann构建索引时,包含的文件中多出来了_disk.index_medoids.bin和_disk.index_centroids.bin。加载入口点的函数在pq_flash_index.cpp的第1128行。

他首先判断是否存在_disk.index_medoids.bin文件,如果存在则把其中的点(可能有很多个)加载为入口点,同时去_disk.index_centroids.bin读这些入口点对应的向量(如果不存在centroids文件则把_disk.index_medoids.bin里面的id对应的向量作为入口向量,顺带一提根据id读向量的函数read_nodes在pq_flash_index.cpp的第144行)。

如果不存在_disk.index_medoids.bin文件,那么流程如下图所示。首先默认只有一个入口点medoid_id_on_file,这个id是从_disk.index中加载出来的,是第24-31个字节。

入口点会在缓存的时候作为第一层缓存进来,然后逐层向外扩展,如下图所示。

在检索的时候,会把入口点都遍历一遍,找到距离查询点最近的一个best_medoid,然后以这个点开始查询。

<think>好的,我现在需要详细介绍一下DiskANN这个算法。首先,用户之前问过HNSW,现在又问DiskANN,可能是在比较不同的ANN算法。DiskANN我记得是基于图的近似最近邻搜索算法,但和HNSW有什么不同呢? 首先,我应该回忆DiskANN的核心思想。DiskANN强调在磁盘上进行高效搜索,减少内存占用,适合大规模数据。HNSW主要在内存中处理,而DiskANN可能结合内存和磁盘的层次结构。需要确认这一点是否正确。 接下来,我需要分解DiskANN的原理。可能包括索引构建、搜索过程、优化点等。需要查证DiskANN的分层结构,比如是否像HNSW那样多层,或者有其他结构。比如,DiskANN可能使用Vamana图结构,这点我记得没错。 然后,参数部分,比如内存和磁盘的使用方式,如何平衡速度与准确性。用户可能关心如何调参,比如内存中缓存的部分大小,搜索时的策略等。同时,可能涉及压缩技术,比如量化方法,如PQ(Product Quantization),是否在DiskANN中使用? 应用场景方面,用户可能想知道什么时候选择DiskANN而不是HNSW。比如数据量极大,无法完全放入内存时,DiskANN的优势。例如推荐系统、图像检索等大规模场景。 需要对比DiskANN和其他算法的优缺点,比如与HNSW、FAISS的IVF等。DiskANN的卖点是在保持较高召回率的同时,减少内存需求,但可能搜索速度稍慢,因为涉及磁盘I/O。 可能还需要提到实际应用中的配置,比如如何设置缓存大小,如何优化磁盘访问模式,或者结合SSD的优势。另外,是否支持动态更新,或者主要用于静态数据集? 需要确保技术细节准确,比如Vamana图的构建过程,贪心搜索策略,以及如何通过延迟加载减少内存占用。可能涉及论文中的关键点,如“贪香草路径”或“鲁棒的剪枝策略”。 最后,总结DiskANN的适用场景、参数调优建议以及实际案例,比如微软的SPTAG实现等。确保语言口语化,结构清晰,分点说明。</think>以下是关于 **DiskANN(Disk-based Approximate Nearest Neighbor Search)** 的深度解析,涵盖其核心原理、技术实现、性能优化及实际应用场景: --- ### **1. 核心思想** DiskANN 是微软提出的一种**基于磁盘的高效近似最近邻搜索算法**,专为**超大规模高维向量数据集**设计。其核心目标是通过 **“内存-磁盘混合架构”**,在有限内存条件下实现高效检索,解决传统内存索引(如 HNSW)无法处理超大规模数据的问题。 #### **关键创新** - **磁盘为主,内存为辅**: 索引数据主要存储在磁盘,仅缓存关键结构(如导航图)到内存。 - **高效压缩**: 结合**向量量化(PQ)** 压缩技术,减少磁盘 I/O 开销。 - **延迟加载**: 搜索时按需从磁盘加载数据块,避免全量数据驻留内存。 --- ### **2. 算法原理** #### **索引结构:Vamana 图** DiskANN 基于改进的 **Vamana 图结构**(一种确定性可导航小世界图),核心特点如下: - **贪心路径构建**: 插入新节点时,通过贪心策略选择最短路径连接邻近节点。 - **鲁棒剪枝**: 动态剪除冗余边,保持图的稀疏性和导航效率。 - **分层缓存**: 将高频访问的“导航节点”缓存在内存,低频节点存储在磁盘。 #### **索引构建流程** 1. **数据预处理**: 使用 PCA 或随机投影降低维度(可选)。 2. **图构建**: 通过迭代优化构建 Vamana 图,控制节点最大度数(`R` 参数)。 3. **量化压缩**: 对原始向量进行乘积量化(PQ),生成压缩编码。 4. **持久化存储**: 将图结构和量化后的向量分块写入磁盘。 #### **搜索流程** 1. **内存导航**: 从内存中的缓存节点出发,沿图进行贪婪搜索。 2. **磁盘加载**: 当搜索路径触及未缓存的节点时,按需从磁盘加载对应数据块。 3. **距离计算**: 对加载的压缩向量进行近似距离计算,快速筛选候选集。 4. **结果精炼**: 对 top-K 候选解压原始向量(可选),进行精确距离排序。 --- ### **3. 性能优势** | **维度** | **DiskANN 优势** | |-------------------|---------------------------------------------------------------------------------| | **内存占用** | 内存需求仅为 HNSW 的 1/10~1/100(依赖缓存大小) | | **扩展性** | 支持十亿级向量检索(如 1TB+ 数据集) | | **速度与精度** | 通过 PQ 压缩和缓存策略,平衡检索速度与召回率(典型 90%+ 召回率) | | **硬件兼容性** | 充分利用 SSD 高吞吐特性,规避内存容量瓶颈 | --- ### **4. 关键参数** | **参数** | **作用** | **典型值** | |-------------------|-------------------------------------------------------------------------------|------------------| | `R` | 图中节点的最大度数,影响图的连通性和搜索效率 | 50-200 | | `L` | 搜索时的候选列表大小,值越大召回率越高 | 75-200 | | `PQ维度` | 乘积量化的子空间划分维度,影响压缩误差和计算速度 | 8-32 | | **缓存比例** | 内存中缓存的导航节点比例,值越大搜索越快 | 1%-10% | --- ### **5. 对比其他 ANN 算法** | **算法** | **适用场景** | **内存需求** | **磁盘支持** | |---------------|----------------------------|--------------------|-------------------| | **DiskANN** | 十亿级数据,内存有限 | 极低(依赖缓存) | 原生支持 | | **HNSW** | 千万级数据,低延迟 | 高(全内存) | 不支持 | | **FAISS-IVF** | 十亿级数据,需 GPU 加速 | 中(压缩索引) | 需自定义分片 | | **SCANN** | 高精度检索,TPU 优化 | 中 | 不支持 | --- ### **6. 应用场景** #### **典型案例** - **互联网搜索**: 千亿级网页嵌入向量的实时检索(如 Bing 搜索引擎)。 - **生物信息学**: 蛋白质/基因序列数据库的相似性搜索。 - **工业级推荐系统**: 用户/商品向量库的在线匹配(需 TB 级存储支持)。 #### **部署建议** - **硬件配置**: SSD 硬盘(高随机读性能) + 中等内存(缓存 1%-5% 热点数据)。 - **数据预处理**: 建议先进行 PCA 降维(如 128 维 → 64 维)再构建索引。 - **冷启动优化**: 首次搜索前预加载高频导航节点,减少磁盘 I/O 延迟。 --- ### **7. 代码示例(SPTAG 库)** 微软开源的 [SPTAG](https://github.com/microsoft/SPTAG) 库支持 DiskANN 实现: ```python from SPTAG import AnnIndex # 构建索引 index = AnnIndex('BKT', 'Float', 128) index.SetBuildParam("NumberOfThreads", "16") index.SetBuildParam("DistCalcMethod", "L2") index.Build(vectors, num_samples) # 保存到磁盘 index.Save("diskann_index") # 加载索引(仅加载内存导航结构) index.Load("diskann_index", load_data=False) # 搜索 results = index.Search(query_vector, k=10, search_param={"MaxCheck": 1024}) ``` --- ### **8. 总结** - **选择 DiskANN 当**:数据规模超过内存容量(十亿级+),且对召回率要求较高。 - **避免场景**:超低延迟需求(如 <1ms)或频繁更新的动态数据集。 - **调优方向**:通过增加缓存比例和调整 `L`/`R` 参数平衡速度与精度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值