前言

本文的目的不在介绍 ES 的三种高亮文本的策略,因此在阅读本文之前假设你已经

  • 熟悉 ES 的使用
  • 熟悉 ES 高亮的三种策略:Unified,Plain,FVH
  • 需要对 nested field 的大文本进行高亮显示

提出问题

一般情况下,ES 的文本搜索结果高亮默认的策略是 Unified,这种高亮策略对于大部分文本是够用的,但是如果文本的长度比较长,比如达到几十兆甚至上百兆的文本数据,那么 ES 在 FETCH 阶段去解析文本并准备文本高亮的时候会非常耗时,并且很可能请求超时。从官网的文档中我们知道有一种 Fast Vector Highlighting (FVH) 策略,主要是针对大文本高亮准备的,也是一种典型的空间换时间的策略,但这需要我们文本属性的 term_vector 设置为 with_positions_offsets

不过,当一切准备就绪,而你的文本字段是 nested 数据类型的时候,确发现搜素出的结果中没有了 highlight 这一项。因此提出问题:FVH 策略如何高亮 nested field 的字段?

解决办法

FHV 需要索引位置信息和偏移量信息。高亮操作是在顶层文档执行的,对于嵌套文档来说,位置和偏移量信息是保存在嵌套文档中的,因此高亮操作无法访问这些信息。

同时,在顶层高亮嵌套文档会导致错误的结果,比如下面例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 创建一个文档的 mapping
PUT t
{
"mappings": {
"t": {
"properties": {
"foo": {
"type": "nested",
"properties": {
"text": {
"type": "text"
},
"num": {
"type": "integer"
}
}
}
}
}
}
}

# 插入数据
PUT t/t/1
{
"foo": [
{
"text": "brown",
"num": 1
},
{
"text": "cow",
"num": 2
}
]
}

# 搜索结果
GET t/_search
{
"query": {
"nested": {
"path": "foo",
"query": {
"bool": {
"must": [
{
"match": {
"foo.text": "brown cow"
}
},
{
"match": {
"foo.num": 1
}
}
]
}
}
}
},
"highlight": {
"fields": {
"foo.text": {}
}
}
}

得到的高亮结果是 browncow ,然而 cow 是不应该是被高亮的。

但是通过 inner_hits 便可以得到正确的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 通过 inner_hits 进行搜索
GET t/_search
{
"query": {
"nested": {
"path": "foo",
"inner_hits": { # 通过 inner_hits 进行搜索
"_source": false, # 不返回正文文本
"highlight": { # 高亮设置
"fields": {
"foo.text": {}
}
}
},
"query": {
"bool": {
"must": [
{
"match": {
"foo.text": "brown cow"
}
},
{
"match": {
"foo.num": 1
}
}
]
}
}
}
}
}

总结

对于嵌套文本来说,我们可以借助 inner_hits 和 FVH 来针对大文本进行快速的高亮显示。但是这也是一种通过空间换时间的做法,要针对具体的业务场景进行衡量选择。

参考文档

[1] Search your data » Highlighting https://www.elastic.co/guide/en/elasticsearch/reference/current/highlighting.html#highlighting
[2] Mapping parameters » term_vector https://www.elastic.co/guide/en/elasticsearch/reference/current/term-vector.html
[3] 白话Elasticsearch62-进阶篇之Highlighting高亮显示 https://cloud.tencent.com/developer/article/1862466
[4] ElasticSearch 高亮显示大文档搜索结果的策略和性能对比 https://cloud.tencent.com/developer/article/1491129
[5] Elastic Search: Highlighting Text That Contains HTML Tags https://hamidmosalla.com/2021/06/06/elastic-search-highlighting-text-that-contains-html-tags/
[6] FVH doesn’t highlight nested fields https://github.com/elastic/elasticsearch/issues/19265
[7] Elasticsearch highlight with nested objects https://stackoverflow.com/questions/15230580/elasticsearch-highlight-with-nested-objects