一 什么是highlight

Highlight就是我们所谓的高亮,即允许对一个或者对个字段在搜索结果中高亮显示。比如字体加粗或者字体呈现和其他文本普通颜色等。

为了执行高亮显示,该字段必须有实际的内容,并且这个字段必须存储,即在mapping中store设为true,不能只存在于内存中,否则系统会自动加载_source字段并匹配相关的列。

 

二 三种高亮类型

ES提供了三种高亮类型,Lucene的plain highlighter,以及fast vector highlighter(fvh)以及posting highlighter.

2.1 Plain Highlighter

Plain Hightlighter是默认的高亮选择,由使用Lucene Hightlighter实现的。它主要是试图反应查询匹配逻辑。

如果你想高亮很多字段,而且带有复杂的查询,那么这个highlight不是很快的。为了准确地反映查询逻辑,它创建了一个很小的内存索引。

并通过Lucene的查询执行计划来重新运行原始的查询条件,从而获得对当前文档的低级匹配信息,每个字段和每个需要高亮显示的文档都会重复这个过程,所以是有性能隐患的。所以需要你换一个hightlight类型

POST /ecommerce/music/_search
{
   "query":{
       "match":{"desc":"雅马哈 "}
    },
   "highlight": {
       "fields": {
           "desc":{}
        }
    }
}

2.2 Fast Vector Highlighter

如果我们在mapping中对字段指定了term_vector参数,且参数值是with_positions_offsets,那么fast vector highlighter 将会替代plain highlighter成为默认的highlight类型。

它的主要特点:

# 快,特别是对于大字段来说比较快(>1M)
# 要求在mapping中设置term_vector=with_positions_offsets
# 可以分配不同的权重来匹配不同的位置
# 我们可以设定一些属性,boundary_chars,boundary_max_scan
fragment_offset
boundary_chars:分割字符,比如有些字符包含.,!?等特殊符号,我们可以指定是否遇到他们进行分割
boundary_max_scan:表示最多扫描多少个字符
fragment_offset:从什么地方开始进行fragment
phrase_limit: 可以阻止对很多短语进行分词从而吃掉很多内存,默认是256. 只有前256个phrase才会被考虑
 
PUT /blogs
{
 "mappings": {
   "news": {
     "properties": {
       "title": {
         "type": "text",
         "analyzer": "ik_max_word"
        },
       "content": {
         "type": "text",
         "analyzer": "ik_max_word",
         "term_vector" : "with_positions_offsets"
        }
      }
    }
  }
}

 

 

2.3 Posting Highlighter

如果我们在mapping里index_options设置成offsets,这个posting hightlighter将会代替plain highlighter

它有哪些特点呢?

# 比起plain highlight性能更快一点,因为它不需要重新分析文档:尤其是对大文件对性能的提高更为明显

# 占用更少的磁盘空间

# 把高亮显示和句子分开,方便阅读

# 使用BM25算法,使搜索的时候像是整篇文档

首先你在mapping需要预先定义:

PUT /website
{
   "mappings": {
       "article":{
           "properties": {
               "title":{
                   "type":"text"
               },
               "content":{
                   "type":"text",
                   "index_options": "offsets"
               }
            }
        }
    }
}
然后添加一条数据:
PUT /website/article/1
{
   "title":"Posting Highlighter",
   "content":"Note that the postings highlighter is meant toperform simple query terms highlighting, regardless of their positions."
}
 
高亮查询
POST /website/article/_search
{
   "query":{
       "match":{"content":"Highlighter"}
    },
   "highlight": {
       "fields": {
            "content":{}
        }
    }
}

ES版 正显 es正显和qs区别_ElasticSearch

请注意:postinghighlighter只是做一个简单的查询,而不会管它的位置,这也就是说也短语查询结合的时候,它会高亮显示所有term,而不管它是否查询匹配的一部分

POST /website/article/_search
{
   "query": {
       "match_phrase": {
          "content": {
              "query": "perform terms",
              "slop":3
           }
        }
    }, 
   "highlight": {
       "fields": {
           "content":{}
        }
    }
}

还有,postinghighlighter不支持很复杂的查询,比如match_phrase_prefix,返回结果不会高亮

 

所以我们需要从实际情况去考虑,一般情况下,用plain highlight也就足够了,不需要做其他额外的设置;如果对高亮的性能要求很高,可以尝试启用posting highlight;如果field的值特别大,超过了1M,那么可以用fastvector highlight

 

三 控制参数

3.1设置高亮html标签,默认是<em>标签

我们可以使用pre_tags属性和post_tags属性自定义高亮显示html标签,去替代默认的em标签

PUT /blogs
{
 "mappings": {
   "news": {
     "properties": {
       "title": {
         "type": "text",
         "analyzer": "ik_max_word"
        },
       "content": {
         "type": "text",
         "analyzer": "ik_max_word",
         "term_vector" : "with_positions_offsets"
        }
      }
    }
  }
}
PUT /blogs/news/1
{
   "title":"资本催熟的!流行!,或是共享经济大潮里的#流星#",
   "content":"迷你.KTV一开始就绑着/共享娱乐/的名号,和自助健身屋、自助咖啡厅、共享单车"
}
POST /blogs/news/_search
{
   "query": {
       "match":{"content":"迷你"}
    },
    "highlight": {
       "pre_tags": ["<h1>"],
       "post_tags": ["</h1>"],
       "fields": {
           "content":{}
        }
     }
}

3.2 强制使用某种highlight

当前你可能已经在mapping中设置了index_options选项为offsets或者设置了term_vector为with_positions_offsets,那么他们默认的高亮就不是plain highlight,如果我们就希望使用plain highlight,那么我们可以使用type参数来指定。他有三种可以选择的类型:plain,posting,fvh.

POST /blogs/news/_search
{
   "query": {
       "match":{"content":"迷你"}
    },
    "highlight": {
       "fields": {
           "content":{
               "type":"plain"
            }
        }
     }
}

 

3.3高亮片段fragment的设置

fragment_size: 某字段的值,长度是1万,但是我们一般不会在页面展示这么长,可能只是展示一部分。设置要显示出来的fragment文本判断的长度,默认是100

 

number_of_fragments:高亮的文本片段有多个,你希望展示几个

no_match_size: 可能没有高亮的文本片段,这个参数可以设置从该字段的开始制定长度为多少,然后作为默认的显示

POST /blogs/news/_search
{
   "query": {
       "match":{"content":"自助"}
    },
    "highlight": {
       "fields": {
           "content":{
               "fragment_size" : 2,
               "number_of_fragments" : 1,
               "no_match_size": 2
            }
        }
     }
}

四 全局设置

我们可以进行全局的设置高亮属性,然后fields字段可以重写这些全局设置

GET /_search
{
   "query" : {
       "match": { "user": "kimchy" }
    },
   "highlight" : {
       "number_of_fragments" : 3,
       "fragment_size" : 150,
       "fields" : {
           "_all" : { "pre_tags" : ["<em>"],"post_tags" : ["</em>"] },
           "bio.title" : { "number_of_fragments" : 0 },
           "bio.author" : { "number_of_fragments" : 0 },
           "bio.content" : { "number_of_fragments" : 5,"order" : "score" }
        }
    }
}