天天看點

ES7學習筆記(十二)高亮 和 搜尋建議

ES當中大部分的内容都已經學習完了,今天呢算是對前面内容的查漏補缺,把ES中非常實用的功能整理一下,在以後的項目開發中,這些功能肯定是對你的項目加分的,我們來看看吧。

高亮

高亮在搜尋功能中是十分重要的,我們希望搜尋的内容在搜尋結果中重點突出,讓使用者聚焦在搜尋的内容上。我們看看在ES當中是怎麼實作高亮的,我們還用之前的索引

ik_index

,前面的章節,我們搜尋過

香蕉好吃

,但是傳回的結果中并沒有高亮,那麼想要在搜尋結果中,對

香蕉好吃

高亮該怎麼辦呢?我們看看,

POST /ik_index/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "desc": "香蕉好吃"
        }
      }
    }
  },
  "highlight": {
    "fields": {
      "desc": {}
    }
  }
}           

我們重點看一下請求體中的

highlight

部分,這部分就是對傳回結果高亮的設定,

fields

字段中,指定哪些字段需要高亮,我們指定了

desc

字段,執行一下,看看結果吧。

{
    "took": 73,
    "timed_out": false,
    "_shards": { "total": 1,"successful": 1,"skipped": 0,"failed": 0},
    "hits": {
        "total": {
            "value": 5,
            "relation": "eq"
        },
        "max_score": 1.3948275,
        "hits": [
            {
            "_index": "ik_index",
            "_type": "_doc",
            "_id": "2",
            "_score": 1.3948275,
            "_source": {
                "id": 1,
                "title": "香蕉",
                "desc": "香蕉真好吃"
                },
            "highlight": {
                "desc": [
                        "<em>香蕉</em>真<em>好吃</em>"
                    ]
                }
            }
        ……           

我們看到在傳回的結果中,增加了

highlight

highlight

裡有我們指定的高亮字段

desc

,它的值是

<em>香蕉</em>真<em>好吃</em>

,其中“香蕉”和“好吃”字段在

<em>

标簽中,前端的小夥伴就可以針對這個

<em>

标簽寫樣式了。我們再看看程式當中怎麼設定高亮,繼續使用上一節中的搜尋的程式,

public void searchIndex() throws IOException {
        SearchRequest searchRequest = new SearchRequest("ik_index");
        SearchSourceBuilder ssb = new SearchSourceBuilder();
        QueryBuilder qb = new MatchQueryBuilder("desc","香蕉好吃");
        ssb.query(qb);
        
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("desc");

        ssb.highlighter(highlightBuilder);

        searchRequest.source(ssb);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            String record = hit.getSourceAsString();
            HighlightField highlightField = hit.getHighlightFields().get("desc");

            for (Text fragment : highlightField.getFragments()) {
                System.out.println(fragment.string());
            }
        }
    }           

我們重點關注一下

HighlightBuilder

,我們在發送請求前,建立

HighlightBuilder

,并指定高亮字段為

desc

。搜尋結束後,我們取結果,從

hit

當中取出高亮字段

desc

,然後列印出

fragment

,運作一下,看看結果吧,

<em>香蕉</em>真<em>好吃</em>
<em>香蕉</em>真<em>好吃</em>
橘子真<em>好吃</em>
桃子真<em>好吃</em>
蘋果真<em>好吃</em>           

完全符合預期,“香蕉好吃”被分詞後,在搜尋結果中都增加了

<em>

标簽,我們可不可以自定義高亮标簽呢?當然是可以的,我們稍微改一下程式就可以了,

HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("desc");

highlightBuilder.preTags("<b>");
highlightBuilder.postTags("</b>");

ssb.highlighter(highlightBuilder);
           

HighlightBuilder

中,使用

preTags

添加起始标簽,指定為

<b>

,用

postTags

添加閉合标簽,指定為

</b>

,再運作一下,看看結果,

<b>香蕉</b>真<b>好吃</b>
<b>香蕉</b>真<b>好吃</b>
橘子真<b>好吃</b>
桃子真<b>好吃</b>
蘋果真<b>好吃</b>           

結果完全正确,用

<b>

替換了

<em>

,是不是很靈活。接下來我們再看看搜尋建議。

搜尋建議

“搜尋建議”這個功能也是相當實用的,當我們在搜尋框中輸入某個字時,與這個字的相關搜尋内容就會羅列在下面,我們選擇其中一個搜尋就可以了,省去了敲其他字的時間。我們看看ES中是怎麼實作“搜尋建議”的。

如果要在ES中使用“搜尋建議”功能,是需要特殊設定的,要設定一個類型為

completion

的字段,由于之前的索引中已經有了資料,再添加字段是會報錯的,索引我們建立一個索引,

PUT /my_suggester
{
    "settings":{
        "analysis":{
            "analyzer":{
                "default":{
                    "type":"ik_max_word"
                }
            }
        }
    },
    "mappings":{
        "dynamic_date_formats": [
             "MM/dd/yyyy",
             "yyyy/MM/dd HH:mm:ss",
             "yyyy-MM-dd",
             "yyyy-MM-dd HH:mm:ss"
         ],
        "properties":{
            "suggest":{
                "type":"completion"
            }
        }
    }
}           

這已經成了我們建立索引的一個标配了,指定分詞器為ik中文分詞,動态字段的時間映射格式,以及搜尋建議字段,注意

suggest

字段的類型為

completion

。我們再添加字段的時候,就要為

suggest

字段添加值了,如下:

POST /my_suggester/_doc
{
    "title":"天氣",
    "desc":"今天天氣不錯",
    "suggest": {
       "input": "天氣"
    }
}

POST /my_suggester/_doc
{
    "title":"天空",
    "desc":"藍藍的天空,白白的雲",
    "suggest": {
       "input": "天空"
    }
}           

我們向索引中添加了兩條資料,大家需要額外注意的是

suggest

字段的指派方法,要使用

input

,我們看一下資料,

ES7學習筆記(十二)高亮 和 搜尋建議

suggest

字段并沒有像其他字段那樣展示出來,說明它和其他字段是不一樣的。現在我們如果隻輸入一個“天”字,看看搜尋建議能不能給出提示,如下:

POST /my_suggester/_search
{
  "suggest": {
    "s-test": {
      "prefix": "天",
      "completion": {
        "field": "suggest"
      }
    }
  }
}           

在請求體中,

suggest

就是“搜尋建議”的辨別,

s-test

是自定義的一個名稱,

prefix

是字首,也就是我們輸入的“天”字,

completion

指定搜尋建議的字段,我們看看查詢的結果,

……
"suggest": {
    "s-test": [
        {
            "text": "天",
            "offset": 0,
            "length": 1,
            "options": [{
                "text": "天氣",
                "_index": "my_suggester",
                "_type": "_doc",
                "_id": "QtgAWnIBOZNtuLQtJgpt",
                "_score": 1,
                "_source": { "title": "天氣","desc": "今天天氣不錯","suggest": { "input": "天氣"}}
            }
            ,
            {
                "text": "天空",
                "_index": "my_suggester",
                "_type": "_doc",
                "_id": "T9gAWnIBOZNtuLQtWQoX",
                "_score": 1,
                "_source": { "title": "天空","desc": "藍藍的天空,白白的雲","suggest": { "input": "天空"}}
            }
        ]
        }
    ]
}           

s-test.options

裡,包含了兩條記錄,

text

字段就是我們寫的建議字段,後面

_source

裡還包含對應的資料,下面我們再看看程式裡怎麼使用“搜尋建議”,

public void searchSuggest(String prefix) throws IOException {
    SearchRequest searchRequest = new SearchRequest("my_suggester");
    SearchSourceBuilder ssb = new SearchSourceBuilder();

    CompletionSuggestionBuilder suggest = SuggestBuilders
        .completionSuggestion("suggest")
        .prefix(prefix);

    SuggestBuilder suggestBuilder = new SuggestBuilder();
    suggestBuilder.addSuggestion("s-test",suggest);

    ssb.suggest(suggestBuilder);

    searchRequest.source(ssb);
    SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

    CompletionSuggestion suggestion = response.getSuggest().getSuggestion("s-test");
    for (CompletionSuggestion.Entry.Option option : suggestion.getOptions()) {
        System.out.println(option.getText().string());
    }

}

@Test
public void searchSuggest() throws IOException {
    eService.searchSuggest("天");
}           

我們建立了

CompletionSuggestionBuilder

,通過方法

completionSuggestion

指定“搜尋建議”字段

suggest

,并且指定字首為方法傳入的

prefix

,我們在測試的時候傳入"天"字。然後,我們自定義“搜尋建議”的名字為

s-test

,傳入前面構造好的

suggest

發送請求後,在響應中擷取前面自定義的

s-test

,然後循環

options

,取出

text

字段,這就是搜尋建議的字段,我們運作一下,看看結果,

天氣
天空           

完全符合預期,這樣使用者在搜尋的時候,就會給出提示資訊了。

好了,今天這兩個ES的知識點就全部OK了~ 大家有問題在評論區留言。

繼續閱讀