本文介绍PolarDB-X智能搜索在索引设计、写入和查询方面的性能优化建议。
索引设计优化
分片数量规划
分片(Shard)是数据分布和并行处理的基本单元,合理规划分片数量对性能至关重要。
数据量 | 建议分片数 | 说明 |
< 10 GB | 1 | 单分片即可,避免过度分片带来的开销。 |
10 GB ~ 50 GB | 2-3 | 适度分片,平衡查询并行度和管理成本。 |
50 GB ~ 200 GB | 3-5 | 确保单分片 30-50 GB。 |
> 200 GB | 按每分片 30-50 GB 计算 | 避免单分片过大影响查询延迟。 |
关键原则:
每个分片建议保持在 30-50 GB 之间。
分片数量不宜超过节点数 × 20。
分片数在索引创建后不可修改,需提前规划。
过多分片会增加集群元数据开销和协调成本。
副本数量选择
场景 | 副本数 | 说明 |
开发测试 | 0 | 节省资源,不需要高可用。 |
标准生产 | 1 | 保证高可用,可容忍 1 节点故障。 |
高可用要求 | 2 | 允许同时失去 2 个节点。 |
读密集型场景 | 1-2 | 副本可分担读请求。 |
副本数可随时动态调整,无需重建索引。
Mapping 设计最佳实践
curl -XPUT "http://<Search引擎地址>:<port>/my-index" \
-u "<用户名>:<密码>" -k \
-H "Content-Type: application/json" \
-d '{
"settings": { "index.mapping.total_fields.limit": 1000 },
"mappings": {
"dynamic": "strict",
"properties": {
"title": { "type": "text", "analyzer": "ik_max_word" },
"status": { "type": "keyword" },
"price": { "type": "float" },
"created_at": { "type": "date" }
}
}
}'设置
"dynamic": "strict"禁止自动添加未定义字段,避免 mapping 膨胀。不需要搜索的字段设置
"index": false减少索引开销。不需要聚合/排序的
text字段不要添加keyword子字段。精确匹配字段使用
keyword而非text。数值字段选择合适的类型(不要所有数字都用
long)。
禁用不必要的特性
配置 | 作用 | 何时禁用 |
| 禁用长度归一化因子 | 不需要按相关度排序的字段 |
| 禁用列式存储 | 不需要排序/聚合的字段 |
| 不建立索引 | 只需要存储不需要搜索的字段 |
| 不单独存储 | 已在 |
写入性能优化
批量写入配置
单次
_bulk大小:5-15 MB,过大会导致内存压力。单次文档数:1000-5000 条,取决于单条文档大小。
并发写入线程:2-4,根据节点 CPU 核数调整。
写入期间索引配置优化
大批量导入数据前,临时调整索引参数以提升写入速度:
# 写入前:关闭副本、增大 refresh 间隔
curl -XPUT "http://<Search引擎地址>:<port>/my-index/_settings" \
-u "<用户名>:<密码>" -k \
-H "Content-Type: application/json" \
-d '{
"number_of_replicas": 0,
"refresh_interval": "-1",
"translog.durability": "async",
"translog.flush_threshold_size": "1gb"
}'
# === 执行批量数据导入 ===
# 写入后:恢复正常配置
curl -XPUT "http://<Search引擎地址>:<port>/my-index/_settings" \
-u "<用户名>:<密码>" -k \
-H "Content-Type: application/json" \
-d '{
"number_of_replicas": 1,
"refresh_interval": "1s",
"translog.durability": "request"
}'
curl -XPOST "http://<Search引擎地址>:<port>/my-index/_refresh" -u "<用户名>:<密码>" -k
curl -XPOST "http://<Search引擎地址>:<port>/my-index/_forcemerge?max_num_segments=1" -u "<用户名>:<密码>" -k查询性能优化
避免深度分页
// 不推荐:深度分页性能极差
{ "from": 10000, "size": 10 }
// 推荐:使用 search_after
{
"size": 10,
"sort": [ { "created_at": "desc" }, { "_id": "asc" } ],
"search_after": ["2025-05-25T10:00:00Z", "doc_id_123"]
}合理使用 filter context
filter 子句不参与评分,可利用缓存,性能优于 must。不需要影响相关度评分的条件,一律放在 filter 中。
限制返回字段
{
"query": { "match": { "content": "搜索" } },
"_source": ["title", "summary", "created_at"],
"size": 10
}避免返回大型字段(如全文 content、向量 embedding),只返回展示所需的字段。
避免昂贵查询
*abc前缀通配符:使用reverse token filter或ngram。复杂
script_score:使用预计算字段。嵌套层级过深的
nested query:反范式化设计。大量
should子句 (>100):使用terms query。match_all+ 大size:分页或scroll。
向量检索优化
向量维度选择
模型 | 维度 | 内存/百万文档 | 适用场景 |
小型模型 | 128-256 | ~0.5-1 GB | 推荐/分类等轻量场景 |
通用模型 | 768 | ~3 GB | 通用语义搜索 |
大型模型 | 1024-1536 | ~4-6 GB | 高精度语义/多模态 |
HNSW 参数调优
参数 | 默认 | 说明 |
| 100 | 建议 128-512,提高精度但增加索引时间 |
| 16 | 建议 8-32,每节点最大连接数 |
| 100 | 通过查询参数动态设置 |
监控关键指标
# 节点资源使用
curl -XGET "http://<Search引擎地址>:<port>/_cat/nodes?v&h=name,heap.percent,ram.percent,cpu,disk.used_percent" \
-u "<用户名>:<密码>" -k
# 线程池(关注 rejected)
curl -XGET "http://<Search引擎地址>:<port>/_cat/thread_pool?v&h=node_name,name,active,queue,rejected" \
-u "<用户名>:<密码>" -k性能告警阈值参考:
CPU 使用率 > 80% 警告 / > 90% 严重:需要扩容或优化查询。
磁盘使用率 > 75% 警告 / > 85% 严重:磁盘满会导致索引只读。