1. 程式人生 > >ElasticSearch教程——字首搜尋、萬用字元搜尋、正則搜尋、推薦搜尋 和 模糊搜尋

ElasticSearch教程——字首搜尋、萬用字元搜尋、正則搜尋、推薦搜尋 和 模糊搜尋

字首搜尋

搜尋包含KDKE字首的articleID

GET /forum/article/_search 
{
  "query": {
    "prefix": {
      "articleID": {
        "value": "KDKE"
      }
    }
  }
}
 
{
  "took": 52,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "forum",
        "_type": "article",
        "_id": "2",
        "_score": 1,
        "_source": {
          "articleID": "KDKE-B-9947-#kL5",
          "userID": 1,
          "hidden": false,
          "postDate": "2017-01-02",
          "tag": [
            "java"
          ],
          "tag_cnt": 1,
          "view_cnt": 50,
          "title": "this is java blog",
          "content": "i think java is the best programming language",
          "sub_title": "learned a lot of course",
          "author_first_name": "Smith",
          "author_last_name": "Williams"
        }
      }
    ]
  }
}

字首搜尋的原理

prefix query不計算relevance score,與prefix filter唯一的區別就是,filter會cache bitset

掃描整個倒排索引,舉例說明

字首越短,要處理的doc越多,效能越差,儘可能用長字首搜尋

字首搜尋,它是怎麼執行的?效能為什麼差呢?

match"articleID": "KDKE-B-9947-#kL5""articleID": "QQPX-R-3956-#aD8""articleID": "XHDK-A-1293-#fJ3"

全文檢索

每個字串都需要被分詞

KDKE          doc1,doc2
KDKE
B
9947
#kL5
QQPX
....

KDKE --> 掃描倒排索引 --> 一旦掃描到KDKE,就可以停了,因為帶KDKE的就1個doc,已經找到了 --> 沒有必要繼續去搜索其他的term了

match效能往往是很高的

不分詞

"articleID": "KDKE-B-9947-#kL5"

"articleID": "QQPX-R-3956-#aD8""articleID": "XHDK-A-1293-#fJ3"

KDKE --> 先掃描到了KDKE-B-9947-#kL5,很棒,找到了一個字首帶KDKE的字串 --> 還是要繼續搜尋的,因為也許還有其他很多的字首帶KDKE的字串 --> 你掃描到了一個字首匹配的term,不能停,必須繼續搜尋 --> 直到掃描完整個的倒排索引,才能結束

因為實際場景中,可能有些場景是全文檢索解決不了的

KDKE-B-9947-#kL5

KD --> match --> 掃描整個倒排索引,能找到嗎

KD --> 只能用prefix

prefix效能很差


萬用字元搜尋
 

跟字首搜尋類似,功能更加強大

5字元-D任意個字元5

5?-*5:萬用字元去表達更加複雜的模糊搜尋的語義
 

GET /forum/article/_search
{
  "query": {
    "wildcard": {
      "articleID": {
        "value": "*Q?PX*8"
      }
    }
  }
}

?:任意字元

*:0個或任意多個字元

效能一樣差,必須掃描整個倒排索引,才ok

正則搜尋

GET forum/article/_search
{
  "query": {
    "regexp": {
      "articleID": "K[A-Z].+"
    }
  }
}

K[A-Z].+

[0-9]:指定範圍內的數字
[a-z]:指定範圍內的字母
.:一個字元
+:前面的正則表示式可以出現一次或多次

wildcard和regexp,與prefix原理一致,都會掃描整個索引,效能很差

主要是給大家介紹一些高階的搜尋語法。在實際應用中,能不用盡量別用。效能太差了。

搜尋推薦
 

搜尋推薦,search as you type,搜尋提示
 

hello w --> 搜尋
 
hello world
hello we
hello win
hello wind
hello dog
hello cat
 
hello w -->
 
hello world
hello we
hello win
hello wind

搜尋推薦的功能
 

百度 --> elas --> elasticsearch --> elasticsearch權威指南

GET forum/article/_search
{
  "query": {
    "match_phrase_prefix": {
      "content": {
        "query": "i elas",
        "slop":5,
        "max_expansions": 1
      }
    }
  }
}

原理跟match_phrase類似,唯一的區別,就是把最後一個term作為字首去搜索

i就是去進行match,搜尋對應的doc
elas,會作為字首,去掃描整個倒排索引,找到所有elas開頭的doc
然後找到所有doc中,即包含i,又包含elas開頭的字元的doc
根據你的slop去計算,看在slop範圍內,能不能讓hello w,正好跟doc中的hello和w開頭的單詞的position相匹配
也可以指定slop,但是隻有最後一個term會作為字首

max_expansions:指定prefix最多匹配多少個term,超過這個數量就不繼續匹配了,限定效能

預設情況下,字首要掃描所有的倒排索引中的term,去查詢w打頭的單詞,但是這樣效能太差。可以用max_expansions限定,w字首最多匹配多少個term,就不再繼續搜尋倒排索引了。

儘量不要用,因為,最後一個字首始終要去掃描大量的索引,效能可能會很差

誤拼寫時的fuzzy模糊搜尋

搜尋的時候,可能輸入的搜尋文字會出現誤拼寫的情況

doc1: hello world
doc2: hello java

搜尋:hallo world

fuzzy搜尋技術 --> 自動將拼寫錯誤的搜尋文字,進行糾正,糾正以後去嘗試匹配索引中的資料
 

POST /my_index/my_type/_bulk
{ "index": { "_id": 1 }}
{ "text": "Surprise me!"}
{ "index": { "_id": 2 }}
{ "text": "That was surprising."}
{ "index": { "_id": 3 }}
{ "text": "I wasn't surprised."}
GET /my_index/my_type/_search 
{
  "query": {
    "fuzzy": {
      "text": {
        "value": "surprize",
        "fuzziness": 2
      }
    }
  }
}

surprize --> 拼寫錯誤 --> surprise --> s -> z

surprize --> surprise -> z -> s,糾正一個字母,就可以匹配上,所以在fuziness指定的2範圍內
surprize --> surprised -> z -> s,末尾加個d,糾正了2次,也可以匹配上,在fuziness指定的2範圍內
surprize --> surprising -> z -> s,去掉e,ing,3次,總共要5次,才可以匹配上,始終糾正不了

fuzzy搜尋以後,會自動嘗試將你的搜尋文字進行糾錯,然後去跟文字進行匹配
fuzziness,你的搜尋文字最多可以糾正幾個字母去跟你的資料進行匹配,預設如果不設定,就是2
 

GET /my_index/my_type/_search 
{
  "query": {
    "match": {
      "text": {
        "query": "SURPIZE ME",
        "fuzziness": "AUTO",
        "operator": "and"
      }
    }
  }
}