Elasticsearch Mapping 设计:搜索质量与性能从建模开始
Elasticsearch 的查询性能和结果质量很大程度在写入前就被 Mapping 决定。动态映射虽然方便,但可能把标识符识别成数字、把日期误判、为大量随机字段创建 Mapping,最终引发字段爆炸和不可控查询。
text 与 keyword 分工
需要全文检索的标题、正文使用 text;用于精确过滤、聚合、排序的状态、标签和用户 ID 使用 keyword:
{
"mappings": {
"dynamic": "strict",
"properties": {
"title": {
"type": "text",
"fields": {"raw": {"type": "keyword", "ignore_above": 256}}
},
"status": {"type": "keyword"},
"publish_time": {"type": "date"}
}
}
}
不要对 text 直接做排序和聚合,也不要把文章正文同时保存大量无用子字段。keyword 的 ignore_above 可以避免异常超长值进入倒排结构,但原始 _source 仍可能保存它。
分词器必须用真实语料验证
中文搜索需要根据产品选择分词插件或自定义 Analyzer。先准备几十到几百条真实 Query 和期望结果,用 _analyze 检查分词,再决定同义词、停用词和 Edge N-gram。不要因为 Demo 搜到了一个词就直接上线。
索引时 Analyzer 与查询时 Search Analyzer 可以不同,例如写入做更细分词,查询保持较稳健。改 Analyzer 通常需要新建索引并 Reindex,不能把它当作随时可改的普通配置。
对象、Nested 与扁平字段
普通 Object 数组会被扁平化,字段之间的配对关系可能丢失。需要“同一个子对象同时满足多个条件”时使用 nested,但 Nested 会增加隐藏文档与查询成本。任意 Key-Value 元数据可评估 flattened,避免每个 Key 都成为新字段。
控制索引规模
- 不参与搜索、聚合的字段可关闭索引。
- 大正文如果只展示而不搜索,不必建立倒排。
- 避免每个租户、每天都创建小索引,Shard 有固定成本。
- Bulk 写入按响应大小和处理时间压测,过大批次会抬高内存峰值。
- 初次批量导入可适当增大 Refresh Interval,完成后恢复。
查询技巧
精确过滤放在 filter 上下文,避免无意义评分并利于缓存;全文相关性放 must。深分页不要无限使用 from + size,大量结果遍历使用 search_after 和稳定排序键。聚合前确认字段基数,超高基数 Terms 聚合可能消耗大量内存。
零停机变更
使用版本化索引与 Alias:
- 创建
article-v2新 Mapping。 - 从数据库或旧索引 Reindex。
- 对比文档数、抽样搜索和延迟。
- 原子切换读写 Alias。
- 保留旧索引一段回退窗口后删除。

评论
0 条讨论