第三阶段 26 · highlight 高亮(返回命中片段)

26 · highlight 高亮(返回命中片段)

阶段:第三阶段补充 / 查询结果增强

ES:highlight | PostgreSQL:ts_headline()(全文检索高亮)


1. 概念

搜索结果里把命中的关键词 用标签标出来(默认 <em>...</em>),

前端渲染成高亮,就是 highlight。它作用在参与打分的查询 命中的字段上,

返回的是「带标记的片段(fragment)」,而不是整段原文。


2. PostgreSQL 对照

sql 复制代码
-- PG 全文检索的高亮:ts_headline
SELECT ts_headline('english', description,
                   to_tsquery('english', 'carbon'))
FROM salesdata
WHERE to_tsvector('english', description) @@ to_tsquery('english', 'carbon');

ts_headline 就是 PG 版的 highlight:把匹配词包成 <b>...</b> 并截取片段。


3. ES DSL

基本高亮

复制代码
GET salesdata_idx/_search
{
  "query": { "match": { "description": "carbon laptop" } },
  "highlight": {
    "fields": { "description": {} }
  }
}

返回里每个 hit 多一个 highlight 段:

json 复制代码
"highlight": {
  "description": [ "super light <em>carbon</em> <em>laptop</em>" ]
}

自定义标签 + 片段控制

复制代码
GET salesdata_idx/_search
{
  "query": { "match": { "description": "carbon" } },
  "highlight": {
    "pre_tags":  ["<mark>"],
    "post_tags": ["</mark>"],
    "fragment_size": 120,          // 每个片段长度
    "number_of_fragments": 3,      // 最多返回几个片段
    "fields": { "description": {} }
  }
}

多字段 + 整字段返回(不截断)

复制代码
"highlight": {
  "fields": {
    "title":       { "number_of_fragments": 0 },   // 0 = 返回整段并高亮,不切片
    "description": { "fragment_size": 100 }
  }
}

4. Spring Boot 实现

java 复制代码
@Component
public class Doc26Highlight {

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    /** 返回每条命中的高亮片段:Map<文档source, 高亮片段列表> */
    public List<HighlightHit> search(String indexName, String field, String keyword)
            throws IOException {
        SearchResponse<Map> resp = elasticsearchClient.search(s -> s
                .index(indexName)
                .query(q -> q.match(m -> m.field(field).query(keyword)))
                .highlight(h -> h
                        .preTags("<mark>")
                        .postTags("</mark>")
                        .fields(field, hf -> hf.fragmentSize(120).numberOfFragments(3))),
                Map.class);

        List<HighlightHit> result = new ArrayList<>();
        for (Hit<Map> hit : resp.hits().hits()) {
            // 命中的高亮片段在 hit.highlight() 里,key 是字段名
            List<String> fragments = hit.highlight().getOrDefault(field, List.of());
            result.add(new HighlightHit(hit.source(), fragments));
        }
        return result;
    }

    public record HighlightHit(Map<String, Object> source, List<String> fragments) {}
}

高亮片段不在 _source 里,而在 hit.highlight()(Map<String, List<String>>,key=字段名)。

import:co.elastic.clients.elasticsearch.core.search.Hit。


5. 坑与最佳实践

  1. 高亮只对"参与查询的字段"生效 :highlight.fields 里的字段要和 query 命中的字段对应,否则片段为空。
  2. filter 上下文不高亮 :filter 不算分、不记录命中位置;要高亮就把该条件放 must/match。
  3. keyword 高亮意义有限 :整串精确匹配没有"词"的概念,高亮通常给 text 字段用。
  4. number_of_fragments: 0 返回整段并高亮(适合短标题);大文本用切片避免返回过长。
  5. 性能 :高亮要重新分析字段内容,字段很大时开销明显;必要时用 fvh(fast vector highlighter)+ term_vector 加速。

下一篇

28-collapse-字段折叠去重.md(列表去重),随后 29-suggester-自动补全.md。


← 上一篇:25-nested-嵌套对象与查询 | 总览 | 下一篇:27-pipeline-管道聚合 →

相关推荐
海绵宝宝转agent3 小时前
learn-claude-code第1-5章开源学习笔记分享
人工智能·笔记·python·学习
小奇不哭3 小时前
ROS2 单节点,RGB-D 深度相机局部路径提取 + B 样条平滑路径 + YOLOv8 障碍物检测 + 深度测距,用于移动机器人视觉局部循迹。
python·yolov8·ros2·cv2·路径探索循迹
小小龙学IT3 小时前
Python scikit-learn 机器学习库深度解析
python·机器学习·scikit-learn
2601_962071574 小时前
类变量和全局变量的查找路径有什么区别?
开发语言·python
卷无止境5 小时前
独立开发者的"富矿地带":哪些垂直领域值得你押注一辈子?
后端·python
Java后端的Ai之路5 小时前
Python进阶探索29_eval内置函数
开发语言·python·探索·eval·内置函数
计算机毕业编程指导师5 小时前
计算机毕设选题推荐:基于Hadoop与Spark的Steam游戏数据分析系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 深度学习
大数据·hadoop·python·计算机·spark·毕业设计·steam游戏
计算机毕业编程指导师5 小时前
【计算机毕设选题推荐】基于Hadoop+Spark的白鹿抖音评论大数据分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 深度学习
大数据·hadoop·python·计算机·spark·毕业设计·抖音评论
Zootopia6265 小时前
飞行力学知识梳理1|飞行性能与稳定性
人工智能·python·算法·机器学习·无人机·学习方法·信息与通信
Y3815326625 小时前
搜索 API 延迟优化:并发数、超时与超时的真实代价
python·搜索引擎