Multi-field 是什么
Multi-field 让同一份内容以两种方式索引:主字段用 text 分词供全文检索,附带的 keyword 子字段保存原始字符串供排序与聚合。日志平台里 service、level 这类字段几乎都用这个组合——既能对内容做分词搜索,又能按原始值精确分组。ignore_above 参数可以避免超长文本进入 keyword 索引,防止索引体积失控。
基本信息
| 配置位置 | 索引 mapping 中字段的 fields 属性 |
|---|---|
| 常见组合 | text 主字段加 keyword 子字段 |
| 关键参数 | ignore_above |
| 查询差异 | 检索用主字段,聚合与排序用 .keyword |
| 适用版本 | Elasticsearch 7.x / 8.x |
典型使用场景
- 服务名聚合:按 service.keyword 做 Terms 聚合看各服务日志量
- 级别过滤:用 level.keyword 精确匹配 error 与 warn
- 排序展示:按字符串值排序时必须用 keyword 子字段
- 全文检索:正文仍用 text 字段做分词匹配
- 兼容迁移:从全 keyword 结构迁到多字段结构的过渡方案
使用要点
- 只给需要聚合或排序的字段加 keyword 子字段,避免索引体积膨胀
- ignore_above 设一个合理上限,超长内容不进 keyword 索引
- 聚合报 fielddata 相关错误时,几乎都是把 text 字段当成了聚合键
- 在索引模板里统一设定,避免每个索引各写一套映射
- 已有索引修改映射只能新增字段,历史数据需要重建索引才生效
映射与聚合示例
映射与聚合示例
PUT /logs-app/_mapping
{
"properties": {
"service": {
"type": "text",
"fields": {
"keyword": { "type": "keyword", "ignore_above": 256 }
}
}
}
}
GET /logs-app/_search
{ "size": 0, "aggs": { "by_service": { "terms": { "field": "service.keyword", "size": 10 } } } }字段选择
| 用途 | 用哪个字段 | 原因 |
|---|---|---|
| 全文检索 | 主字段(text) | 分词后可匹配部分内容 |
| 精确过滤 | keyword 子字段 | 按原始值精确匹配 |
| 聚合分组 | keyword 子字段 | text 聚合会报 fielddata 错误 |
| 排序 | keyword 子字段 | 需要 doc values 支持 |
| 高亮显示 | 主字段 | 高亮依赖分词结果 |
ignore_above 超过长度的值不会进入 keyword 子字段,能防止超长文本撑爆索引,代价是这部分数据无法参与聚合。
实施与排查要点
- 先在索引模板里定好映射,再让新索引按模板创建,避免每个索引各写一套
- 聚合字段写错时先看报错信息,fielddata 相关字样基本都指向 text 字段
- 历史索引无法直接改映射,需要重建索引后才能获得 keyword 子字段
- 上线前在小批量数据上验证聚合与排序,确认字段名与取值都符合预期
- 把常用聚合字段清单写进团队文档,避免每人各自摸索不同写法