向量数据库索引升级方案
1)通过复制知识库或者知识库内复制向量,使得可以同时使用用多索引IVF_FLAT(省内存性能高、召回较高、可以实时更新索引,nlist=1024,nprobe=64)、HNSW_FLAT(耗内存性能高、召回为ANN方案中最高0.958-1.0、不能实时更新索引、索引初始化速度较慢,M=64,econstruction=64,efsearch=128 )。
2)在大文档库情况下,可以根据检索历史反馈,针对热门文档(不得超过1万个chunk)和新增文档,单独加一路KNN暴力检索(FLAT_IP)。
3)升级到Milvus** **2.3.x,支持Arm64架构机器和Flat on GPU新特性,可以全用FLATIP。
4)针对新增文档和用户库文档改为采用FlatIP/FlatonGPU方案,针对文档较多的组(文档1万以上量级)/管理员库改为采用HNSW与IVFFLAT并行方案。如果内存不够,可以牺牲召回率,只用IVFPQ索引;或者采用DiskANN方案。
5)HNSW需要注意内存占用,想要召回率大于95%一般要设定M值为64或128。需要考虑1000万条chunk向量的存储大小问题:1000w * 4Byte * 1024维 = 38G内存。HNSW 内存的开销较高,通常需要原始向量的 1.5 - 2 倍以上内存,因此有可能需要80G内存。
6)1M数据复合索引最优方案:
IVF4096+HNSW, FLAT,如果再叠加PQ会召回骤降。
在大数据量内存不足的场景下:要求高性能用IVFPQ,要求高召回用DiskANN;
在内存充足的场景下:性能和效果优先,选HNSW;资源优先选IVF_FLAT。
7)合理选择流式插入和批量导入
如果有大量离线写入的场景,建议使用 BulkInsert,原因是 BulkInsert 不会对查询性能造成太大的影响,并且也大大减少了流式写入对消息队列产生的压力。
单次写入超过 100MB 以上,建议选择批式写入;
希望尽可能减少写入对线上查询的影响,建议选择批式写入;
希望写入实时可见,建议选择流式写入;
单次写入小于 10MB 以下,建议选择流式写入。
尽可能批量写入,整体吞吐会更高,建议每次写入的大小控制在 10M,单个 Shard 的流式写入量不建议超过 10M/s,Datanode 多于 Shard 的情况下,部分 DataNode 可能无法获得负载。导入目前支持的文件大小上限是 1GB,接下来会支持更大的导入文件大小上限。不建议频繁导入小文件,会给 compaction 带来比较大的压力。
除了每个节点的 CPU 使用率,内存使用量信息,以下是一些建议你关注的监控指标:
Proxy
查询延迟:milvus_proxy_sq_latency/milvus_proxy_collection_sq_latency
写入 / 删除延迟:milvus_proxy_mutation_latency
写入流量:milvus_proxy_receive_bytes_count
查询返回流量:milvus_proxy_send_bytes_count
QueryNode
加载的数据量:milvus_querynode_entity_num
查询请求排队时间:milvus_querynode_sq_queue_latency
单个 Segment 的查询时间:milvus_querynode_sq_segment_latency
IndexNode
构建索引的时间:milvus_indexnode_build_index_latency
DataNode
Flush 花费的时间:milvus_datanode_save_latency
Compaction 花费的时间:milvus_datanode_compaction_latency
8)谨慎使用标量过滤,删除特性等特性
作为数据库,Milvus 支持了删除、标量过滤、TimeTravel 等高级特性。如果不了解底层原理,使用这些高级功能可能会对稳定性和性能造成比较严重的影响,以下是一些使用注意事项:
Milvus 使用的是前过滤,即先做标量过滤生成 Bitset,在向量检索的过程中基于 Bitset 去除掉不满足条件的 entity。对于 HNSW 这一类的图索引而言,标量过滤并不会加速查询,反而可能导致性能变差。特别是对于过滤性很强的条件(比如 PK=1 这种全局唯一的条件),标量过滤甚至会导致单次查询的时间长于爆搜。针对这种情况,用户也可以选择通过后过滤的方式绕过,先基于 Milvus 查出 TopK 的数据,再基于其他数据库进行过滤。
对于过滤条件相对比较确定的场景,使用 Partition 把数据进行物理分区,在查询的时候指定 Partition 性能更好。
Milvus 的删除是标记删除,在 compaction 时会清理,因此删除的数据依然会占据内存。大量删除也会造成查询性能下降,同时大量 compaction 可能造成建索引压力变大等一系列影响。在需要大量频繁删除的场景,可能需要进行一些 compaction 参数的调整,保证删除的数据能够被及时清理。
Milvus 支持了数据自动过期功能(TTL),可以定时清理过期数据。
如果需要全量更新一个 Collection 的数据,推荐使用新建表 + 导入数据 + Alias 切换的方案。
制定 Output field 时,如果要获取标量字段,会从对象存储上获取,吞吐和延迟都会受到较大影响。
向量检索索引对比
2.1 索引类型与参数
2.1.1 精准召回
1)LSH也是精准召回,但是对于d>=64的性能即有维度灾难,性能不如FLAT,而我们的向量有1024维。
2.1.2 倒排索引 IVF
1)IVF_FLAT、IVFPQ需要训练聚类,不支持增量索引。
2)IVF 参数
nlist:一般建议 nlist = 4*sqrt(N),对于 Milvus 而言,一个 Segment 默认是 512M 数据,对于 128dim 向量而言,一个 segment 包含 100w 数据,因此最佳 nlist 在 1000 左右。
所以对1024dim的向量。最佳nlist应该为2800左右。
nprobe:nprobe 可以 Search 时调整搜索的数据量,nprobe 越大,recall 越高,但性能越差。具体的 nprobe 需要根据查询的精度要求决定,从 nprobe = 16 开始会是一个不错的尝试。
2.1.3 小世界网络 HNSW
1)支持增量索引。
2)HNSW需要注意内存占用,想要召回率大于95%一般要设定M值为64或128。
3)ef必须大于K
4)常见的ef_construction = 128内存消耗越大。
5)M通常在8-32之间,M越大
2.1.4 量化类索引 PQ、SQ8
1)PQ、IVFPQ需要进行训练量化,不支持增量索引。
2)速度最快,召回率损失较大。
3)对于大数据量、内存不足但是性能要求高的场景
4)IVF_SQ8 相比 IVF,将向量数据从 float32 转换为了 int8,可以减少 4 倍的内存用量,但对召回率有较大影响,如果要求 95% 以上的召回精度不建议使用。
2.1.5 ScaNN
见4.1.1(5) 新增ScaNN索引支持
2.1.6 DiskANN
1)DiskANN 依赖高性能的磁盘索引,借助 NVMe 磁盘缓存全量数据,在内存中只存储了量化后的数据。
2)DiskANN 适用于对于查询 Recall 要求较高,QPS 不高,大数据量,内存不足的场景。
3)DiskANN 的关键参数search_list:
search_list 越大,recall 越高而性能越差。search_list 的大小不应该小于 K。而对于较小的 K,推荐把 search_list 和 K 的比值设置得相对大一些, 这个比值随着 K 增大可以逐渐靠近。
2.1.7 复合索引
将下列各项单一索引方式自由组合,就可以构成复合索引。
向量变换 (Vector transform) :
在索引(PCA、OPQ)之前,应用于向量的预处理步骤。
粗量化器 (Coarse quantizer) :
粗略地将向量集合组织为一个个子域(用于减小搜索范围,包括 IVF、IMI 和 HNSW)。
精细量化器 (Fine quantizer) :
将向量更精细地压缩到更小的域中(用于压缩索引大小,例如 PQ)。
细化 (Refinement) :
搜索时的最后一步,它使用原始向量的距离计算对结果进行重新排序。或者使用其他非穷举的索引。
2.2 ANN-Benchmark
ANN-Benchmark网站对现有流行的向量检索产品进行了性能测试,其测试结果在其官网上展示。
ANN-Benchmark官网
指标:** **
1)Recall/Queries per second** **
1s内召回数量;按照100ms的响应时间计算的话,需要关注1s召回 10 * 100个向量(=下图中1e+2 query(k=10))的召回率。
向量检索测试方案
3.1 效果测试方案
3.1.1 Recall@K指标
例子:单个query 在 4000篇公务文档中的召回率对比:
IVF_Flat,IP 参数为 nlist = 1024, nprobe = 64
公式:
Recall@k = intersect(IVF_Flat(k),FlatIP(k)) / FlatIP(k) ; k = 10,20,30,40, 50,100,200,300,400,500,1000
Recall@10 = 100%
Recall@20 = 90%
Recall@30 = 86.7%
Recall@40 = 85%
Recall@50 = 88%
Recall@100 = 85%
Recall@200 = 80.5%
Recall@300 = 74.7%
Recall@400 = 68.5%
Recall@500 = 63.4%
Recall@1000 = 55.7%
3.1.2 索引软删除对召回率的影响
3.2 性能测试方案
3.2.1 单条Query 召回TopK结果的平均响应时间 与 超时率指标
3.2.2 QPS (QueryPerSecond)
3.2.3 索引构建时间
3.2.4 索引占用内存
3.2.5 索引占用显存(Flat on GPU方案)
3.2.6 索引是否支持增量增加数据,以及增量增加每条数据的响应时间开销
3.2.7 索引是否支持增量软删除数据,以及软删除对QPS、响应时间的影响
Milvus版本对比
4.1 Milvus v2.3.x
4.1.1 新特性
1)Flat on GPU
可以加速0.95召回率的IVF-Flat 和 遍历检索FlatIP。需要支持CUDA的GPU设备。
经测试,GPU 版本相较于 CPU HNSW 索引有了 3 倍以上的 QPS 提升,部分数据集有近 10 倍的提升。下表是 GPU-IVF-FLAT 和 HNSW 在 Milvus E2E 上的 QPS 数据,host 的 size 是 8c32g,NVIDIA A100 GPU。NQ 为 100:
Nvidia贡献了Rapid RAFT中的GPU_FLAT和GPU_IVFPQ索引,A100上吞吐量相对于CPU提升10~70倍。
GPU 版 Milvus 在 CPU 版的基础上进行了 GPU 加速:支持同时进行索引创建和搜索计算以提高查询效率。可以在同一时间内使用 GPU 建索引,使用 CPU 搜索向量。
GPU版本Milvus支持的索引类型:浮点型向量
索引类型 | CPU 建索引 | GPU 建索引 | CPU 搜索 | GPU 搜索 |
---|---|---|---|---|
FLAT | N/A | N/A | ✔️ | ✔️ |
IVF_FLAT | ✔️ | ✔️ | ✔️ | ✔️ |
IVF_SQ8 | ✔️ | ✔️ | ✔️ | ✔️ |
IVF_SQ8H | ✔️ | ✔️ | ✔️ | ✔️ |
IVF_PQ | ✔️ | ✔️ | ✔️ | ✔️ |
RNSG | ✔️ | ❌ | ✔️ | ❌ |
HNSW | ✔️ | ❌ | ✔️ | ❌ |
ANNOY | ✔️ | ❌ | ✔️ | ❌ |
CPU 和 GPU 创建的索引完全一致,只是一般情况下 GPU 的创建索引速度快于 CPU 的创建速度。
top_k > 2048 或nprobe > 2048时,Milvus 由 GPU 查询切换为 CPU 查询。
GPU版本Milvus支持的索引类型:二值型向量
索引类型 | CPU 建索引 | GPU 建索引 | CPU 搜索 | GPU 搜索 |
---|---|---|---|---|
FLAT | N/A | N/A | ✔️ | ❌ |
IVF_FLAT | ✔️ | ❌ | ✔️ | ❌ |
2)新增RangeSearch
最大返回结果不超16384
3)新增原生cosine距离
4)新增返回原始向量功能
(PQ/SQ8量化索引不支持),但是会有二次查询的性能开销产生
5)新增ScaNN(Faiss-FastScan算法)
在各项 benchmark 中有着不俗的表现,对比 HNSW 有 20% 左右提升,约为 IVFFlat 的 7 倍,同时构建索引速度更快。ScaNN 在算法上跟 IVFPQ 比较类似,聚类分桶,然后桶里的向量使用 PQ 做量化,区别是 ScaNN 对于量化比较激进,搭配上 SIMD 计算效率较高,但是精度损失会比较大,需要有原始向量做 refine 的过程。下表是 ScaNN、HNSW 和 IVFFLAT 在 Cohere1M(768 维)的数据集下的性能表现,数据来自于 VectorDBBench。
6)新增Arm64CPU支持
7)Growing 索引
Milvus 的数据分为两类,分别为已索引的数据和流式数据。对于已索引的数据自然可以使用索引加速查询,但流式数据只能使用逐行暴力检索,对性能影响较大,为了解决此类问题在 2.3.0 中加入了 Growing index,自动为流式数据建立实时索引,保障查询性能。
4.1.2 限制
1)Milvus 2.3 不再支持CentOS,需要改用Ubuntu
2)Milvus限制每个collection(知识库)只能有一个索引
因此要有同时用多索引的需求的话,例如IVF_FLAT(省内存性能高、召回较高)+HNSW_FLAT(耗内存性能高、召回0.958-1.0 ),需要复制多个collections或者在collections里面复制多遍emb。
Number of resources
Resource | Limit |
---|---|
Collection | 65,536 |
Connection / proxy | 65,536 |
Number of resources in a collection
Resource | Limit |
---|---|
Partition | 4,096 |
Shard | 16 |
Field | 64 |
Index | 1 |
Entity | unlimited |
4.2 Milvus v2.0.x
开源向量数据库对比
5.1 Milvus Vs Faiss
Faiss不支持Flat、IVF、IDMap以外的删除索引操作;线上Milvus应该是自己实现了一些删除操作。(Milvus软删除数据的布隆过滤器方案)
5.2 Milvus Vs ES
5.3 向量数据库对比
序号 | 产品名 | 是否开源 | 开发者 | Github Star数 | 优点 | 缺点 |
---|---|---|---|---|---|---|
1 | Milvus | 是 | Zilliz(上海) | 9.1k | 索引类型多,社区活跃 | 不支持数据分片,架构复杂(现在可支持数据分区分片了;已经有分布式架构Mishards ) |
2 | Faiss | 是 | 15.9k | 性能好,索引类型多, 成熟 | 不支持服务化 | |
3 | HNSWlib | 是 | nmslib | 1.8k | 性能好,召回率高 | 不支持服务化 |
4 | ScaNN | 是 | 21.4k | 性能好,召回率高 | 不支持服务化 | |
5 | SPTAG | 是 | Microsoft | 4.1k | 性能好 | 索引类型少 |
6 | Vearch | 是 | 京东 | 1.3k | 性能好 | 不能实时更新 |
7 | Zsearch | 否 | 蚂蚁金服 | / | 索引类型多 | 不开源 |
8 | Proxima | 是 | 阿里达摩院 | / | 索引类型多 | 不开源(后来开源了?) |
序号 | 产品 | 实时更新 | 过滤功能 | CPU和GPU | 集群模式 | 可服务化 | 开发语言 | SDK |
---|---|---|---|---|---|---|---|---|
1 | Milvus | 是 | 是 | 是 | 是 | 是 | Go/Python | Python/Go/Java/Node |
2 | Faiss | 是 | 否 | 是 | 否 | 否 | C++ | C++/Python |
3 | HNSWlib | 是 | 否 | 是 | 否 | 否 | C++ | C++/Python |
4 | ScaNN | 是 | 否 | 是 | 否 | 否 | C++/Python | C++/Python |
5 | SPTAG | 是 | 否 | 是 | 是 | 是 | C++ | Python/C# |
6 | Vearch | 否 | 否 | 是 | 是 | 是 | Go | Python |
OpenSearch | Pinecone | Milvus | ElasticSearch | |
---|---|---|---|---|
首次发布时间 | 2021年12月31日 | 2021年1月 | 2019年10月22日 | 2023年7月26日 |
定位 | 大规模向量实时检索 | 向量数据库(强调AI模型长期记忆) | 向量数据库(集成了Faiss IVF,Faiss HNSW,SPTAG);一种高性能的向量检索引擎,支持多模态数据。它的主要特点是支持高维度向量的索引和搜索,并提供高效的API访问。但是,milvus在处理大规模数据时可能存在一些挑战。 | 检索和分析引擎(支持向量检索,被Langchain Server支持,自带RRF,自带Okapi-BM25,自带条件向量检索) |
开源 | 否 | 否 | 是 | 是 |
运维方式 | 全托管 | 全托管 | 自运维 | 自运维 |
向量算法 | Linear(暴力检索)QC(聚类)HNSW | PQ、LSH、HNSW产品自动选择合适算法 | FLAT、IVF_FLAT、IVF_PQ、IVF_SQ8、HNSW、ANNOY | Brute-Force kNNHNSW |
向量维度 | 无限制 | 1-20000维 | 最大32768 | 建索引:1024 不建索引:2048 |
向量化 | 支持文本、图片向量化 | 不支持 | 不支持(支持多模态?) | 不支持 |
标签过滤 | 支持 | 支持 | 支持 | 支持 |
全文索引 | 支持 | 不支持 | 不支持 | 支持 |
标签向量混合查询 | 支持 | 支持 | 支持;支持在向量检索过程中进行标量字段过滤,实现混合查询;但是标量过滤为前过滤,有损向量召回性能 | 支持 |
实时索引构建 | 支持 | 支持 | 支持 | 支持 |
索引版本热切换 | 支持 | 不支持 | 不支持 | 不支持 |
副本数变更(replica) | 支持 | 支持 | 支持 | 支持 |
分片数变更(shard) | 支持 | 支持 | 支持 | 支持 |
GPU加速 | 支持(QC) | 不支持 | 支持(IVF系列) | 不支持 |
数据源支持 | ODPS、OSS、HDFS | 无 | 无 | 无 |
开发接入 | Java SDK、Python SDK、GO SDK、REST API | Python、NodeJS Client | Python、Java、Go、Node、REST API | REST API |
查询语法 | SQL、HA3 | 自定义SDK | 自定义SDK | ES Query DSL、SQL |
产品优势 | 简单易用大规模向量数据检索内置文本、图片向量化索引版本热切换GPU加速支持多数据源阿里巴巴内部场景打磨大模型生态结合 | 简单易用动态算法选择大模型生态结合 | 依托开源社区生态向量领域品牌影响力大;支持使用Kubernetes部署,支持在云上扩展。其容灾能力能够保证服务的高可用。Milvus依照日志及数据的理念,使用如Pulsar、Kafka等消息队列的技术实现组件间的通信,对组件进行解耦,拥抱云原生;单节点主从式架构 | 依托开源社区生态检索和分析领域品牌影响力大 |
OpenSearch | Milvus | ElasticSearch | |
---|---|---|---|
测试集 | ANN_GIST1M 960维 | ||
产品版本 | 向量检索版2023.8(VectorStore引擎) | v2.2.12 | v8.9 |
机器规格 | 16核64G | 16核64G | 16核64G |
测试工具 | wrk压测参数:线程:8 连接数:24 | Milvus Python SDK:压测参数:线程:8 连接数:24 | wrk 压测参数:线程:8 连接数:24 |
参数配置 | m:64 ef_construction:512 | m:64 ef_construction:512 | m=64 ef_construction: 512 JVM内存:32G |
向量算法 | HNSW | HNSW | HNSW |
数据导入耗时 | 1103s | 1437s | 7389s |
索引大小 | 3.8G | 2.44G | 8G |
top10 recall@95 | 查询参数:ef=142 | 查询参数:ef=40 | 查询参数:k=10num_candidates=20 |
QPS | QPS: 1619.2 Latency:14.95ms CPU负载:92.4% 内存占用:8.4G | QPS: 827.36 Latency: 28.96ms CPU负载:91.3% 内存占用:5.6G(号称QPS为ES的10倍) | QPS: 547.63 Latency:46.45ms CPU负载:97% 内存占用:32G(JVM) |
top10 recall@99 | 查询参数:ef=450 | 查询参数:ef=100 | 查询参数: k=10 num_candidates=55 |
QPS: 863.43 Latency:28.16ms CPU负载:95.7% 内存占用:8.4G | QPS: 475.61 Latency:50.44ms CPU负载:98.2% 内存占用:5.5G | QPS: 305.90 Latency:79.24ms CPU负载:97.5% 内存占用:32G(JVM) |