第三阶段 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-管道聚合 →

相关推荐
爱吃苹果的梨叔28 分钟前
训练集群网络中断怎么办?智算机房的 Console 串口排障方案
网络·python·智能路由器·php
李妍.4 小时前
02Numpy基础(上)
开发语言·python
TheBestRucy4 小时前
Python 九阳神功之贰:面向对象(下)
开发语言·python
2601_965958464 小时前
口腔黏膜脱皮超2周未愈建议及时就医
人工智能·python
笃行3505 小时前
向量数据库单独建一套,这笔账划不划算
后端
微小冷5 小时前
在不同空间中展示数据(欧式、球面、庞加莱圆盘)
python·双曲空间·微分几何·geomstats·庞加莱圆盘·球面
weixin_431600446 小时前
Agent Workflow 学习向:Code 节点,比模板更强的变量加工
后端·python·学习·ai·
讲温控就好了6 小时前
从医疗影像到能源存储——芯片冷却温控技术的跨行业赋能
人工智能·python·能源
Rain的Java大神之路6 小时前
短信接口被狂刷怎么处理
java·运维·后端·web安全·面试·架构·xss
DeepVisionary6 小时前
从 Qwen3.8-27B 把原生多模态、原生 FP8、桌面级 Agent 三件事一次集齐,看开源大模型的“工业化拐点“
python·自动化