Elasticsearch 8.13.4 关键词如何高亮显示

在构建搜索功能时,"高亮显示"绝对是提升用户体验的"神来之笔"。当用户在海量数据中搜索关键词时,如果结果列表里密密麻麻全是黑字,用户需要逐行阅读去寻找匹配项,这简直是一场灾难。

在 Elasticsearch 8.13.4 中,高亮(Highlighting)机制已经非常成熟,但也隐藏着许多容易被忽视的细节和性能陷阱。本文将带你从入门到精通,玩转 ES 8.13.4 的高亮功能。


一、 核心原理:不仅仅是"标红"

首先要明白,ES 的高亮不是在返回结果后由应用层做的字符串替换,而是在倒排索引检索阶段就已经介入的分析过程。

当你的查询命中文档后,ES 会从原始存储的 _source 或专门的高亮存储中提取文本片段,根据你的查询词进行标记。

基础配置(Hello World 版)

json 复制代码
GET /my-index-8.13/_search
{
  "query": {
    "match": {
      "content": "elasticsearch 高亮"
    }
  },
  "highlight": {
    "fields": {
      "content": {} 
    }
  }
}

默认返回结果

ES 会默认使用 <em></em> 包裹关键词,并在结果中增加一个 highlight 字段:

json 复制代码
"hits": {
  "hits": [
    {
      "_source": { "content": "学习 Elasticsearch 的高亮显示功能..." },
      "highlight": {
        "content": [
          "学习 <em>Elasticsearch</em> 的<em>高亮</em>显示功能..."
        ]
      }
    }
  ]
}

二、 进阶玩法:定制你的"荧光笔"

默认的 <em> 标签可能不符合你的前端 UI 框架(比如 Vue 或 React 可能需要 <span class="red">)。在 8.13.4 中,我们可以深度定制。

1. 自定义标签与样式

如果你不喜欢斜体,想要加粗并带背景色:

json 复制代码
"highlight": {
  "fields": {
    "content": {
      "pre_tags": ["<mark style='background:#ffeb3b; font-weight:bold;'>"],
      "post_tags": ["</mark>"],
      "fragment_size": 100 
    }
  }
}
  • pre_tags / post_tags:支持数组,可定义多组标签实现复杂逻辑(如不同关键词不同颜色,需配合 Encoder,较复杂)。
  • fragment_size:片段长度。默认 100 个字符。太短看不全上下文,太长影响性能。
2. 碎片数量控制 (number_of_fragments)

默认情况下,ES 会返回 5 个高亮片段。如果你只需要最精彩的那一段,或者需要全部展示:

json 复制代码
"content": {
  "number_of_fragments": 1,  // 只返回最相关的 1 个片段
  "fragment_size": 200
}
3. 边界扫描器 (boundary_scanner) ------ 8.x 推荐

这是 ES 8.x 非常实用的功能。默认按字符截断(chars)可能会切断 HTML 标签或把单词切成两半。使用 sentence 可以按句子截断,体验更好:

json 复制代码
"content": {
  "boundary_scanner": "sentence", // 按句子边界截断
  "boundary_max_scan": 10,        // 最多向前扫描 10 个字符找边界
  "fragment_offset": 0            // 从匹配词开头处开始截取
}

三、 避坑指南:性能与安全的博弈

高亮虽好,但它是内存和 CPU 杀手。因为高亮需要访问原始文本并进行分析,在大文本字段上开启高亮极易引发 OOM。

1. 必须开启 require_field_match

默认情况下,只要 Query 命中了文档,highlight 会对你指定的所有字段(如 content, title, summary)都做高亮处理,哪怕 Query 只查了 content
这是巨大的浪费!

json 复制代码
"highlight": {
  "require_field_match": true, // 强烈建议开启
  "fields": {
    "content": {}, // 只有 query 涉及 content 时才高亮它
    "title": {}
  }
}
2. 警惕 max_analyzed_offset

在 8.13.4 中,为了防止深度分页时的内存爆炸,默认限制了分析的字符数(通常是 1MB)。如果你的文本非常长(如长文章、日志),且关键词在很后面,可能会因为超过限制而导致高亮失败(返回空)。
对策 :如果确实需要对超长文本高亮,需在索引 Mapping 中调整 index.highlight.max_analyzed_offset(但这会增加内存风险)。

3. 统一高亮器 (Unified Highlighter)

从 7.0 开始,ES 废弃了旧的 fast-vector-highlighter,统一使用 Unified Highlighter 。它在索引时不需要额外存储 term_vectors(除非你用 plain 模式),直接利用 _source 或 doc values。

  • 优势:索引体积更小。
  • 注意 :如果你没存 _source 且没开 store: true,高亮将无法工作,因为它没原始文本可分析!
4. XSS 安全漏洞

如果你允许用户自定义搜索词,且直接将高亮结果渲染到页面,务必小心 XSS 攻击。

虽然 ES 默认会转义 HTML,但如果你为了显示富文本而设置了 "escape_html": false,攻击者输入 <script>alert(1)</script> 作为搜索词,高亮结果就会执行脚本。
原则:除非万不得已,不要关闭 HTML 转义。


四、 实战案例:电商商品搜索高亮优化

假设我们有一个商品索引,需要对"标题"和"描述"进行高亮。

需求

  1. 标题高亮加粗。
  2. 描述只取一段,且按句子截断,防止截断到标签中间。
  3. 只有查询命中的字段才高亮。

请求 DSL

json 复制代码
GET /products/_search
{
  "query": {
    "multi_match": {
      "query": "智能降噪耳机",
      "fields": ["title^3", "description"]
    }
  },
  "highlight": {
    "require_field_match": true,
    "fields": {
      "title": {
        "pre_tags": ["<b>"],
        "post_tags": ["</b>"],
        "number_of_fragments": 1
      },
      "description": {
        "type": "unified",
        "boundary_scanner": "sentence",
        "fragment_size": 150,
        "number_of_fragments": 1
      }
    }
  }
}

前端处理逻辑

拿到 highlight.title[0]highlight.description[0] 后,直接使用 v-html (Vue) 或 dangerouslySetInnerHTML (React) 渲染即可。如果高亮字段不存在,则回退显示 _source 中的原始内容(不带高亮)。


总结

Elasticsearch 8.13.4 的高亮功能强大而精细。要用好它,请记住这三句口诀:

  1. 按需高亮 :开启 require_field_match,别做无用功。
  2. 保护体验 :长文本用 boundary_scanner: sentence,别把单词切两半。
  3. 守住底线 :除非你是内部系统且完全信任输入,否则别关 escape_html

掌握了这些,你的搜索结果就能像黑夜中的萤火虫一样,精准地把用户想要的信息"亮"出来!

相关推荐
LJ97951112 小时前
重塑媒体关系:你的品牌需要一个智能发布引擎
大数据
李迟2 小时前
2025年12月个人工作生活总结
大数据·elasticsearch·生活
小北方城市网2 小时前
第 10 课:Python 全体系实战整合与职业进阶指南(完结篇)
大数据·开发语言·数据库·python
licongmingli2 小时前
vue2 基于虚拟dom的下拉选择框,保证大数据不卡顿,仿antd功能和样式
大数据·前端·javascript·vue.js·anti-design-vue
ELI_He9993 小时前
SeaTunnel 编译
大数据·mysql·elasticsearch·database·flume
IT_xiao小巫3 小时前
2025年终总结
大数据·人工智能
电商API_180079052473 小时前
淘宝商品数据爬虫技术实践指南
大数据·数据库·人工智能·爬虫
humors2213 小时前
网络南京摄影合集(不定期更新)
大数据·程序人生
ClouGence3 小时前
数据实时迁移同步工具 CloudCanal-v5.3.1.0 发布,支持金仓数据库
大数据·数据库·mysql·数据分析·dba