Elasticsearch-93-深入剖析搜索结果的高亮显示

搜索结果高亮显示

先来看一个最基本的高亮案例

首先创建一个索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PUT /blog_website
{
"mappings": {
"blogs": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}

加条数据进去

1
2
3
4
5
PUT /blog_website/blogs/1
{
"title": "我的第一篇博客",
"content": "大家好,这是我写的第一篇博客,特别喜欢这个博客网站!!!"
}

搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /blog_website/blogs/_search 
{
"query": {
"match": {
"title": "博客"
}
},
"highlight": {
"fields": {
"title": {}
}
}
}

返回值:

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
{
"took": 29,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.26742277,
"hits": [
{
"_index": "blog_website",
"_type": "blogs",
"_id": "1",
"_score": 0.26742277,
"_source": {
"title": "我的第一篇博客",
"content": "大家好,这是我写的第一篇博客,特别喜欢这个博客网站!!!"
},
"highlight": {
"title": [
"我的第一篇<em>博客</em>"
]
}
}
]
}
}

<em></em> 标签,会在网页中将内容变成红色,所以指定的field中,如果包含了那个搜索词的话,就会在那个field的文本中,对搜索词进行红色的高亮显示

多个filed高亮也是一样的

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
GET /blog_website/blogs/_search 
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "博客"
}
},
{
"match": {
"content": "博客"
}
}
]
}
},
"highlight": {
"fields": {
"title": {},
"content": {}
}
}
}

返回值:

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
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.6390219,
"hits": [
{
"_index": "blog_website",
"_type": "blogs",
"_id": "1",
"_score": 0.6390219,
"_source": {
"title": "我的第一篇博客",
"content": "大家好,这是我写的第一篇博客,特别喜欢这个博客网站!!!"
},
"highlight": {
"title": [
"我的第一篇<em>博客</em>"
],
"content": [
"大家好,这是我写的第一篇<em>博客</em>,特别喜欢这个<em>博客</em>网站!!!"
]
}
}
]
}
}

highlight中的field,必须跟query中的field是一一对应的

三种highlight介绍

plain highlight

默认的高亮就是用的这种,底层是lucene highlight

posting highlight

设置索引的 index_options = offset 后,高亮就是用的posting highlight

优点:

  • 性能比plain highlight要高,因为不需要重新对高亮文本进行分词
  • 对磁盘的消耗更少
  • 将文本分割为句子,并且对句子进行高亮,效果更好

删除之前的索引,然后重新建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PUT /blog_website
{
"mappings": {
"blogs": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"content": {
"type": "text",
"analyzer": "ik_max_word",
"index_options": "offsets"
}
}
}
}
}

content设置了 “index_options”: “offsets” ,然后还是把之前那条数据添加进去,对content搜索高亮

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /blog_website/blogs/_search 
{
"query": {
"match": {
"content": "博客"
}
},
"highlight": {
"fields": {
"content": {}
}
}
}

返回值:

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
{
"took": 33,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.37159908,
"hits": [
{
"_index": "blog_website",
"_type": "blogs",
"_id": "1",
"_score": 0.37159908,
"_source": {
"title": "我的第一篇博客",
"content": "大家好,这是我写的第一篇博客,特别喜欢这个博客网站!!!"
},
"highlight": {
"content": [
"大家好,这是我写的第一篇<em>博客</em>,特别喜欢这个<em>博客</em>网站!!!"
]
}
}
]
}
}

其实效果跟plain是一样的

fast vector highlight

index-time时候term vector设置在mapping中,就会用fast vector highlight

  • 在field值比较大(大于1MB)的情况下性能更高

还是将之前的删掉,重新建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PUT /blog_website
{
"mappings": {
"blogs": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"content": {
"type": "text",
"analyzer": "ik_max_word",
"term_vector" : "with_positions_offsets"
}
}
}
}
}

在content里面设置了term_vector,就可以使用了

强制使用某种highlight

比如,对于开启了term_vector的filed,强制使用plain highlight

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /blog_website/blogs/_search
{
"query": {
"match": {
"content": "博客"
}
},
"highlight": {
"fields": {
"content":{
"type":"plain"
}
}
}
}

自定义高亮html标签

默认是<em></em>,可以通过设置pre_tags和post_tags来自定义html标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /blog_website/blogs/_search
{
"query": {
"match": {
"content": "博客"
}
},
"highlight": {
"pre_tags": ["<tag>"],
"post_tags": ["</tag>"],
"fields": {
"content":{
"type":"plain"
}
}
}
}

高亮片段fragment的设置

fragment_size

先来添加一个比较长的数据

1
2
3
4
5
PUT /blog_website/blogs/2
{
"title": "我的第二篇博客",
"content": "大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!"
}

然后查询的时候设置 fragment_size

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET /blog_website/blogs/_search
{
"query": {
"match": {
"content": "博客"
}
},
"highlight": {
"pre_tags": ["<tag>"],
"post_tags": ["</tag>"],
"fields": {
"content":{
"type":"plain",
"fragment_size": 20
}
}
}
}

返回值:

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
{
"took": 6,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.56305844,
"hits": [
{
"_index": "blog_website",
"_type": "blogs",
"_id": "2",
"_score": 0.56305844,
"_source": {
"title": "我的第二篇博客",
"content": "大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!"
},
"highlight": {
"content": [
"大家好,这是我写的第二篇<tag>博客</tag>,特别喜欢",
"这个<tag>博客</tag>网站!!!大家好,这是我写",
"的第二篇<tag>博客</tag>,特别喜欢这个<tag>博客</tag>网站!!!大家好",
",这是我写的第二篇<tag>博客</tag>,特别喜欢这个<tag>博客</tag>",
"网站!!!大家好,这是我写的第二篇<tag>博客</tag>"
]
}
}
]
}
}

设置了fragment_size是20,然后在highlight中,就会把content按长度是20的切割成多个

使用场景:有时候field长度太长,但是你的页面不可能全显示出来,可能只需要显示一段内容就好,然后就可以通过设置fragment_size(默认是100)来将field的值进行分割

number_of_fragments

number_of_fragments: 用来指定显示多少个片段

比如上面,一共拆分出5个片段来,可能我们只需要三个,那就设置number_of_fragments为3,就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /blog_website/blogs/_search
{
"query": {
"match": {
"content": "博客"
}
},
"highlight": {
"pre_tags": ["<tag>"],
"post_tags": ["</tag>"],
"fields": {
"content":{
"type":"plain",
"fragment_size": 20,
"number_of_fragments": 3
}
}
}
}

返回值:

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
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.56305844,
"hits": [
{
"_index": "blog_website",
"_type": "blogs",
"_id": "2",
"_score": 0.56305844,
"_source": {
"title": "我的第二篇博客",
"content": "大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!大家好,这是我写的第二篇博客,特别喜欢这个博客网站!!!"
},
"highlight": {
"content": [
"大家好,这是我写的第二篇<tag>博客</tag>,特别喜欢",
"这个<tag>博客</tag>网站!!!大家好,这是我写",
"的第二篇<tag>博客</tag>,特别喜欢这个<tag>博客</tag>网站!!!大家好"
]
}
}
]
}
}

只显示了前3个片段