本文介绍阿里云 Elasticsearch native_hnsw 向量检索的性能测试环境、VectorDBBench 测试流程和测试结果。测试以 Cohere10M 为主要数据集,并给出双 16 vCPU、1 主 1 副本的完整复现流程及其他数据集的参考结果。
测试环境
客户端 ECS 规格
|
实例规格 |
CPU |
内存 |
网络 |
|
|
96 vCPU |
384 GiB |
与 Elasticsearch 实例位于同一 VPC,使用内网连接 |
服务端 Elasticsearch 规格
|
产品数据节点规格 |
实际 ECS 规格 |
节点数 |
索引拓扑 |
|
|
|
2 |
1 个主分片、1 个副本 |
测试前关闭访问日志,避免日志开销影响结果:
PUT /_cluster/settings
{
"persistent": {
"apack.accesslog.enabled": false,
"apack.accesslog.search.enabled": false,
"logger.index.search.accesslog": "OFF"
}
}
测试工具准备
本文使用 zilliztech/VectorDBBench PR #835 中的 Aliyun Elasticsearch 适配代码进行性能评估。
-
准备 Python 3.11 或以上版本的环境。
-
获取 VectorDBBench PR #835 并安装 Aliyun Elasticsearch 依赖。
git clone https://github.com/zilliztech/VectorDBBench.git
cd VectorDBBench
git fetch origin pull/835/head:pr-835
git checkout pr-835
python3.11 -m venv venv
source venv/bin/activate
python -m pip install -U pip
python -m pip install -e '.[aliyun_elasticsearch]'
性能测试
测试数据集
|
数据集 |
Base 向量数 |
向量维度 |
距离度量 |
返回条数 |
|
Cohere10M |
10,000,000 |
768 |
Cosine Similarity |
Top10 / Top100 |
创建 native_hnsw 索引
本轮结果使用以下 native_hnsw 图参数。正式测试索引包含 1 个主分片、1 个副本和 10,000,000 docs;主副本分别位于两个数据节点,每个 shard 只有一个 segment。
PUT /cohere10m_native_hnsw
{
"settings": {
"index.havenask.engine.enabled": true,
"index.sort.field": "id",
"index.native.index.queries.cache.enabled": false,
"index.native.index.queries.cache.knn.enabled": false,
"index.requests.cache.enable": false
},
"mappings": {
"_source": { "enabled": false },
"properties": {
"id": { "type": "long" },
"vector": {
"type": "dense_vector",
"dims": 768,
"index_options": {
"type": "native_hnsw",
"builder": {
"add_chunk_size": 100000,
"prune_headroom": 0.0
}
}
}
}
}
}
查询参数
|
TopK |
numCandidates |
rescore oversample |
测试并发 |
|
10 |
90 |
4.6 |
212 / 216 |
|
100 |
408 |
4.02 |
60 / 64 |
通过命令行运行 Cohere10M 测试
以下命令展示 Top10 的两档并发吞吐测试。连接参数、用户名和密码按实例实际配置填写。
set -euo pipefail
export ES_SCHEME='http'
export ES_HOST='<Elasticsearch endpoint>'
export ES_PORT='9200'
export ES_INDEX='cohere10m_native_hnsw'
export ES_USER='<Elasticsearch 用户名>'
export VDBBENCH_ES_QUERY_WIRE_FORMAT='cbor-f32le'
read -rsp 'Elasticsearch password: ' ES_PASSWORD
echo
VDB_COMMON=(
--scheme "$ES_SCHEME" --host "$ES_HOST" --port "$ES_PORT"
--user "$ES_USER" --password "${ES_PASSWORD:?ES_PASSWORD is required}"
--index-name "$ES_INDEX"
--case-type Performance768D10M
--skip-drop-old --skip-load
--m 32 --ef-construction 400
--skip-search-serial --search-concurrent
--concurrency-duration 220
)
# Top10:运行 c212 和 c216 两档并发。
vectordbbench aliyunelasticsearch "${VDB_COMMON[@]}" \
--k 10 --num-candidates 90 \
--use-rescore --oversample-ratio 4.6 \
--num-concurrency 212,216 \
--db-label cohere10m-top10-dual16-c212-c216
运行双 16 vCPU、1 主 1 副本扩展测试
两个 16 vCPU 数据节点各持有一份完整 Cohere10M 图。用户通过实例页面完成 ES YML 配置,然后运行压测。
用户页面创建实例
-
在阿里云 Elasticsearch 控制台创建杭州 J 区实例:普通 turbo2、16 vCPU / 64 GiB、2 个数据节点和 1 个 Kibana 节点,并打开 FalconSeek 高性能检索引擎。
-
等待实例和两个数据节点均进入正常状态,然后进入下一节配置 ES YML。
用户页面修改 YML 配置并重启
进入目标实例的 配置与管理 > ES 集群配置,在 YML 文件配置右侧单击 修改配置,然后执行以下操作:
-
在弹窗底部的 其他 Configure 配置编辑器中粘贴以下 YAML。配置由平台统一下发到两个数据节点,无需逐节点填写;
-
提交时选择 原地变更并确认 重启;
-
等待变更完成、两个数据节点恢复、目标索引为 green 后,再开始压测。
index.native.native_hnsw.search_worker_thread_count: "12"
index.native.native_hnsw.native_search_pool.enabled: "true"
index.native.native_hnsw.native_search_queue_capacity: "208"
index.native.native_hnsw.cpu_lending.mode: "static"
native.indices.queries.cache.enabled: "false"
native.indices.queries.cache.knn.enabled: "false"
indices.queries.cache.size: "0"
以上配置需要通过工单联系我们完成变更。
该组配置包含启动期设置,不能使用 PUT /_cluster/settings 替代,必须通过 YML 配置并完成节点重启。
结果表中的 QPS 使用较高档并发,取两次独立运行的 VectorDBBench 220 秒全程 QPS 均值。Serial P95/P99 通过单独运行串行查询获得。
测试结果
测试指标说明
|
测试指标 |
说明 |
|
QPS |
较高档并发下两次独立运行的 VectorDBBench 全程 QPS 均值,单位为次/秒。 |
|
Recall@K |
查询结果中正确 TopK 最近邻向量的比例。 |
|
NDCG@K |
对 TopK 结果顺序进行加权的归一化折损累计增益。 |
|
Serial P95 |
95% 的热态串行查询延迟低于该值,单位为毫秒。 |
|
Serial P99 |
99% 的热态串行查询延迟低于该值,单位为毫秒。 |
native_hnsw 检索性能
|
数据集 |
TopK |
M / efConstruction |
numCandidates |
Recall / NDCG |
QPS |
Serial P95/P99 |
|
Cohere10M(768D) |
10 |
32 / 400 |
90 |
0.9797 / 0.9804 |
82,520.18 |
0.8 / 0.9 ms |
|
Cohere10M(768D) |
100 |
32 / 400 |
408 |
0.9801 / 0.9833 |
21,658.53 |
1.9 / 2.0 ms |
|
Cohere1M(768D) |
10 |
32 / 800 |
98 |
0.9901 / 0.9902 |
69,083.28 |
0.8 / 1.0 ms |
|
Cohere1M(768D) |
100 |
32 / 800 |
322 |
0.9902 / 0.9919 |
24,482.57 |
1.5 / 1.7 ms |
|
BioASQ1M(1024D) |
10 |
16 / 400 |
244 |
0.9504 / 0.9513 |
41,701.77 |
1.0 / 1.0 ms |
|
BioASQ1M(1024D) |
100 |
24 / 400 |
320 |
0.9499 / 0.9544 |
23,464.42 |
1.6 / 1.7 ms |
|
BioASQ10M(1024D) |
10 |
24 / 400 |
152 |
0.9409 / 0.9399 |
46,666.70 |
1.0 / 1.1 ms |
|
BioASQ10M(1024D) |
100 |
24 / 400 |
320 |
0.9381 / 0.9423 |
23,927.61 |
2.5 / 3.2 ms |