本文总结自https://www.elastic.co/guide/en/elasticsearch/reference/7.10/highlighting.html#offsets-strategy
一、高亮功能核心概述
- 核心作用 :从搜索结果的指定字段中提取「查询词匹配片段」并添加标记(如
<em>),响应中新增highlight字段返回高亮结果,帮助用户直观看到匹配位置。 - 依赖条件 :高亮需要字段的实际内容 ------ 若字段未设置
store: true,则从_source中提取字段内容。 - 核心限制 :高亮器不会反映查询的布尔逻辑(如嵌套布尔查询、
minimum_should_match),可能出现「非查询匹配部分被高亮」的情况。
二、三种高亮器类型(核心)
ES7.10 支持 3 种高亮器,可按字段指定类型(默认使用unified):
| 高亮器类型 | 底层实现 | 核心特性 | 适用场景 | 局限 / 注意事项 |
|---|---|---|---|---|
| Unified(默认) | Lucene Unified Highlighter | 1. 按句子拆分文本,用 BM25 算法给句子评分;2. 支持精准短语 / 多词(模糊、前缀、正则)高亮;3. 优先级使用 postings/term vectors 提升性能 | 大多数通用场景(复杂查询、大文本、多词高亮) | 无核心局限,默认推荐 |
| Plain | Lucene 标准高亮器 | 1. 轻量简单,贴合简单查询逻辑;2. 重建内存索引获取匹配信息 | 简单查询、小文本高亮 | 1. 大文本 / 多字段 / 复杂查询场景性能差;2. 需重复分析每个文档 / 字段 |
| FVH(Fast Vector) | Lucene Fast Vector Highlighter | 1. 需字段开启term_vector: with_positions_offsets;2. 支持多字段匹配合并、位置权重调整;3. 可自定义边界扫描器 |
超大文本、多字段联合高亮、需位置权重场景 | 1. 增加索引体积;2. 不支持 span 查询;3. 需显式开启 term vector |
三、偏移策略(Offsets Strategy)
高亮器需获取文本中单词的「起始 / 结束字符偏移量」,共 3 种获取方式(Unified 按优先级自动选择,Plain 仅用第 3 种,FVH 仅用第 2 种):
| 方式 | 启用条件 | 核心优势 | 局限 / 风险 |
|---|---|---|---|
| Postings List | 字段 mapping 中index_options: offsets |
1. 无需重新分析文本,直接从索引提取偏移量;2. 磁盘占用比 term vectors 少;3. 适配大文本 | 无核心局限,推荐优先使用 |
| Term Vectors | 字段 mapping 中term_vector: with_positions_offsets |
1. 速度极快(尤其 >1MB 大文本 / 前缀 / 通配符查询);2. 可直接访问文档术语字典 | 增加索引体积 |
| Plain Highlighting | 无 postings/term vectors 时兜底启用 | 无需提前配置,兼容性强 | 1. 大文本场景耗时 / 耗内存;2. 默认限制分析 100 万字符(可通过index.highlight.max_analyzed_offset调整) |
四、高亮配置参数(全局 / 字段级)
所有配置可全局设置,字段级配置会覆盖全局,分为「通用参数」和「专属参数」:
1. 通用参数(所有高亮器支持)
| 参数名 | 含义 | 默认值 |
|---|---|---|
pre_tags/post_tags |
高亮文本的前后标签 | <em>/</em> |
require_field_match |
是否仅高亮查询匹配的字段 | true |
highlight_query |
自定义高亮查询(默认复用主查询,适配重打分场景) | 主查询 |
fragment_size |
高亮片段的字符长度 | 100 |
number_of_fragments |
返回的最大高亮片段数(设为 0 则返回完整字段文本,忽略fragment_size) |
5 |
no_match_size |
无匹配时返回的文本长度(从字段开头截取) | 0(不返回) |
encoder |
是否 HTML 编码片段(default/html) |
default(不编码) |
force_source |
强制从_source提取文本高亮(即使字段单独存储) |
false |
tags_schema |
启用内置样式标签(设为styled则用<em class="hlt1">等 10 种样式) |
无(用 pre/post_tags) |
fields |
指定要高亮的字段(支持通配符,仅文本 / 关键字字段生效) | - |
2. 专属参数(仅特定高亮器支持)
| 参数名 | 适用高亮器 | 含义 | 合法值 / 默认值 |
|---|---|---|---|
boundary_scanner |
Unified/FVH | 片段拆分方式 | - Unified:sentence(默认)/word/none;- FVH:chars(默认)/sentence/word |
boundary_chars |
FVH | 拆分片段的边界字符 | .,!? \t\n |
boundary_max_scan |
Unified/FVH | 扫描边界字符的最大范围 | 20 |
boundary_scanner_locale |
Unified/FVH | 句子 / 单词边界拆分的区域设置(如en-US/ja-JP) |
Locale.ROOT |
fragmenter |
Plain | 文本分片方式(simple按固定长度 /span避免拆分高亮术语) |
span(默认) |
fragment_offset |
FVH | 高亮起始位置的偏移量 | - |
matched_fields |
FVH | 合并多字段匹配结果到单个字段高亮 | - |
phrase_limit |
FVH | 单个文档中分析的匹配短语数量(防止内存溢出) | 256 |
order |
Unified/FVH | 片段排序方式(score按匹配度 /none按原文顺序) |
none(默认) |
type |
所有 | 指定高亮器类型(unified/plain/fvh) |
unified(默认) |
五、核心使用示例(覆盖高频场景)
1. 基础高亮(默认 Unified)
json
GET /_search
{
"query": { "match": { "content": "kimchy" } },
"highlight": { "fields": { "content": {} } }
}
2. 全局 / 字段级参数覆盖
json
GET /_search
{
"query": { "match": { "user.id": "kimchy" } },
"highlight": {
"number_of_fragments": 3, // 全局配置
"fragment_size": 150,
"fields": {
"body": { "pre_tags": ["<em>"], "post_tags": ["</em>"] }, // 字段级覆盖
"blog.title": { "number_of_fragments": 0 } // 返回完整字段高亮
}
}
}
3. 自定义高亮查询(适配重打分场景)
json
GET /_search
{
"query": { "match": { "comment": "foo bar" } },
"rescore": { /* 重打分逻辑 */ },
"highlight": {
"fields": {
"comment": {
"highlight_query": { // 高亮查询包含主查询+重打分查询
"bool": { /* 组合查询逻辑 */ }
}
}
}
}
}
4. FVH 多字段匹配合并
json
GET /_search
{
"query": { "query_string": { "query": "comment.plain:running scissors", "fields": ["comment"] } },
"highlight": {
"fields": {
"comment": {
"matched_fields": ["comment", "comment.plain"], // 合并多字段匹配
"type": "fvh"
}
}
}
}
5. 配置字段启用 Postings/Term Vectors
json
// 启用 Postings(推荐)
PUT /example
{
"mappings": {
"properties": {
"comment": { "type": "text", "index_options": "offsets" }
}
}
}
// 启用 Term Vectors(FVH 必需)
PUT /example
{
"mappings": {
"properties": {
"comment": { "type": "text", "term_vector": "with_positions_offsets" }
}
}
}
六、高亮器内部工作原理
核心流程(所有高亮器通用)
- 文本分片 :将字段文本拆分为片段(按
fragment_size/boundary_scanner等规则); - 片段评分:对每个片段按查询匹配度打分(Unified 用 BM25,Plain/FVH 用术语匹配数);
- 术语高亮 :在高分片段中标记查询匹配的术语(用
pre/post_tags)。
Unified 高亮器执行示例(关键)
- 无 postings/term vectors 时,先分析文本并构建内存索引;
- 将查询转换为 span 查询(如
match_phrase→spanNear),匹配目标术语; - 用 Java
BreakIterator拆分文本为「完整句子级片段」(Passage); - 用 BM25 给片段打分,筛选高分片段;
- 标记片段中的匹配术语,返回高亮结果。
七、关键注意事项
- 性能优化 :大文本场景优先启用
index_options: offsets(Postings),避免 Plain Highlighting 兜底; - FVH 限制 :不支持 span 查询,需显式开启
term_vector: with_positions_offsets; - 片段控制 :
number_of_fragments: 0适合短文本(标题 / 地址),直接返回完整字段高亮; - 字符限制 :Plain Highlighting 默认分析 100 万字符,大文本需调整
index.highlight.max_analyzed_offset。
总结(核心要点回顾)
- ES7.10 高亮默认用 Unified 高亮器,兼顾性能和功能,是通用场景首选;
- 偏移策略决定高亮性能,大文本优先用 Postings List(
index_options: offsets); - 配置参数可全局 / 字段级灵活调整,
number_of_fragments: 0适合短文本完整高亮; - FVH 适配多字段 / 超大文本场景,但需开启 term vector 且不支持 span 查询。