Elasticsearch系列---初識搜索

概要

本篇主要介紹搜索的報文結構含義、搜索超時時間的處理過程,提及了一下多索引搜索和輕量搜索,最後將精確搜索與全文搜索做了簡單的對比。

空搜索

搜索API最簡單的形式是不指定索引和類型的空搜索,它將返回集羣下所有索引的所有文檔(默認顯示10條):

GET /_search

響應的結果示例(有篩選,只取了一條document作爲示例):

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 1,
    "hits": [
      {
        "_index": "music",
        "_type": "children",
        "_id": "2",
        "_score": 1,
        "_source": {
          "name": "wake me, shark me",
          "content": "don't let me sleep too late, gonna get up brightly early in the morning",
          "language": "english",
          "length": "55",
          "likes": 9
        }
      }
    ]
  }
}

針對響應報文的字段,我們做一些簡單解釋:

  • took:整個搜索請求花費了多少毫秒。
  • time_out:查詢是否超時。
  • _shards:查詢中參與分片的總數,其中成功的分片數量,失敗的分片數量,以及跳過的分片數量。正常情況下不會有失敗的分片數量,如果發生了災難級別的故障,超過了容錯的最大node數量,可能會同時丟失shard和replica,此時會報告這些分片是失敗的,但還是會繼續返回剩餘可用分片的查詢結果。
  • hits:包含total表示匹配到的文檔總數,max_score值是所有匹配文檔中_score的最大值。
  • hits.hits:數組內包含匹配的文檔的完整信息,默認查詢前10條數據,並且按_score降序排序。

timeout機制

默認不使用timeout參數,如果某些場景下,低響應比搜索完整結果更重要,可以指定timeout爲10ms或1s,在指定的超時時間內,Elasticsearch會把已經成功搜索到的文檔返回。
注意timeout不是停止執行查詢,它只是告訴Coordinate Node返回到指定時間爲止收集到的結果,並且關閉連接,在ES後臺,其他node正在進行的查詢並不會中斷,只是結果沒人要了。

舉個例子:某電商平臺商品SKU品類300萬條,輸入某個關鍵字查詢,有2000條記錄匹配,但是要查15秒鐘,一個搜索要等15秒纔出結果,顯得太不專業了,產品有SLA要求,必須1秒內出結果,最快的解決方案是查詢使用參數timeout=1s,前端分頁顯示默認只展示20條,1秒內的查詢結果要填滿這20條還是比較容易的。

設置timeout的查詢過程

多索引搜索

一個搜索請求,可以同時寫多個索引名稱,這叫做multi-index搜索模式。

/_search:所有索引,所有type下的所有數據都搜索出來
/index1,index2/_search:同時搜索兩個index下的數據
/1,2/_search:按照通配符去匹配多個索引

單一索引下搜索時,ES會轉發請求到索引的每個分片中,shard或replica均可,然後收集結果返回。多索引時,原理相同,只是涉及的分片更多。另外搜索一個索引有5個分片和搜索5個索引各有一個分片,性能是等價的。

順帶我們看一下搜索原理示意圖:

搜索原理示意圖

輕量搜索

有兩種形式的搜索API,一種是query string search,查詢條件和排序規則寫在request URI裏,也叫輕量搜索;另一種是query DSL,查詢條件等信息用JSON格式寫在request body裏。

輕量搜索的示例:

單個字段搜索,"q="後面接的是查詢條件"field:text",field是字段名,text是搜索的關鍵詞,有三種前綴修飾符:

GET /music/children/_search?q=content:friend
GET /music/children/_search?q=+content:friend
GET /music/children/_search?q=-content:friend
  • "+"號前綴表示必須與查詢條件匹配。
  • "-"號前綴表示一定不與查詢條件匹配。
  • 默認沒寫前綴表示條件可選

匹配的條件越多,文檔就越相關。

如果多個字段搜索,多個條件之間要有空格:

GET /music/children/_search?q=-content:friend +name:wake

_all元數據的原理
如果"q="後面沒寫field,直接跟的是搜索關鍵詞,表示搜索指定索引下的所有字段,如下:

GET /music/children/_search?q=friend

只要music索引下的document,任何一個字段包含friend,就能搜索出來。那_all是怎麼來的?

_all是Elasticsearch中的元數據,在建立索引的時候,新增一個document裏面包含了多個field,此時,es會自動將多個field的值,全部用字符串的方式串聯起來,變成一個長的字符串,作爲_all field的值,同時建立索引。後面如果在搜索的時候,沒有對某個field指定搜索,就默認搜索_all field。

找個document示例:

"name": "wake me, shark me",
"content": "don't let me sleep too late, gonna get up brightly early in the morning",
"language": "english",
"length": "55",
"likes": 9

"wake me, shark me don't let me sleep too late, gonna get up brightly early in the morning english 55 9",作爲這一條document的_all field的值,同時進行分詞後建立對應的倒排索引

注意事項

輕量搜索在開發階段會拿這些命令來做一些簡單的查詢,實際生產中用得比較少,語法複雜容易錯,並且可閱讀性低,遇到重量級查詢,還有可能會把ES集羣拖垮。

精確搜索與全文搜索

Elasticsearch的數據類型可以分成兩類:精確值和全文。

  • 精確值(exact value)
    精確值如日期、ID,數值類型,有些文本類型也可以表示精確值,如郵箱、常用縮寫等等。精確值的一個特點是必須完全相同、大小寫敏感,很容易查詢,hello與Hello是不相等的,日期爲2019-11-20的字段值,輸入2019是搜索不到的。

  • 全文(full text)
    全文數據就微妙得多,拿英文來說,各種詞根變化、大小寫轉換、同義詞、縮寫,漢字方面各種分詞、詞庫、網絡詞等,都希望匹配程度能高一些,能夠理解我們的意圖,舉幾個中文例子:
  • 南京市長江大橋,有一些分詞器得到的結果:南京/市長/江大橋,完全不是我們想的結果,我們希望是:南京/南京市/長江/大橋/長江大橋。
  • 長春市長春街長春藥店,分詞分得不對,搞成這樣:長春/市長/春/街/長/春藥/店,結果就很尷尬了。

全文搜索方面,最基本的步驟是先分詞,再索引,然後搜索時進行匹配,英文相對好辦,中文方面有相像不到的難點要去克服。

小結

本篇介紹搜索的基礎知識,闡述搜索結果的含義,多索引搜索和輕量搜索的基本使用,最後對比了一下精確搜索與全文搜索,以及著名的中文分詞大坑,謝謝。

專注Java高併發、分佈式架構,更多技術乾貨分享與心得,請關注公衆號:Java架構社區
Java架構社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章