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
,我們看一下資料,
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了~ 大家有問題在評論區留言。