ElasticSearch之高亮顯示
一 什麼是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":{}
}
}
}
請注意: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" }
}
}
}