介紹完怎麼 一次搜尋多個欄位 之後,不知道有沒有發現 Elasticsearch ( 以下簡稱 ES ) 的全文搜尋有一個不太好的地方呢?
以下面的搜尋為例,當我們搜尋 American Wedding 或是 Wedding American 的時候,出現的搜尋結果是相同的。
// GET /movies/_search
{
"query": {
"multi_match": {
"query": "American Wedding",
"fields": ["title"]
}
}
}
// 或是
{
"query": {
"multi_match": {
"query": "Wedding American",
"fields": ["title"]
}
}
}
至於是為什麼呢?回想一下 Inverted Indices 的內容,就可以知道 ES 是如何去配對的,所以這時候順序對於 ES 來說並不重要。
但是搜尋的體驗應該不止於此,不論是什麼語言,肯定都有上下文的吧?很明顯 Wedding American 不對吧?( 漫才式拍打 )
你可以試試看在 Google 搜尋這兩種單字,出來的結果是不同的,儘管 Wedding American 還是會出現小小的提示在旁邊,但不會作為主要搜尋的結果。
那在 ES 中,我們要怎麼做到這一點呢?答案就是今天的主角,Phrase Search
。
Phrase Search
使用的方式很簡單,下面提供範例:
// GET /movies/_search
{
"query": {
"match_phrase": {
"title": "Wedding American"
}
}
}
結果會如下圖所示,空空如也。
讓我們來解釋一下這是如何做到的。
首先,ES 在儲存 inverted index 的時候,還會順便儲存字詞的位置,以 My name is Robert 來說,My 的位置會 0,name 會是 1,以此類推。
所以 ES 在搜尋的時候就會確保 name 的後面要接 is,而不是 Robert。
這時候問題又來了,這什麼爛搜尋?還要照著當初 index 下去的值去找?使用者怎麼可能會知道這種資訊呢?
所以就有了 slop
的出現來提升搜尋的靈活性,當兩個字詞中間有其他字詞時,我們一樣可以搜尋的到。
以搜尋電影舉例,我們嘗試搜尋 extract
欄位中有關 Gregory Poirier 以及 Jerry O’Connell 的敘述時,直接使用 phrase_match
會找不到。
// GET /movies/_search
{
"query": {
"match_phrase": {
"extract": "Gregory Poirier Jerry O'Connell"
}
}
}
結果如下圖:
但是當我們加入 slop
為 2 時,可以想像成,當配對的字詞中間的詞彙不超過 2 個時,還是會被搜尋到。
所以我們改成:
// GET /movies/_search
{
"query": {
"match_phrase": {
"extract": {
"query": "Gregory Poirier Jerry O'Connell",
"slop": 2
}
}
}
}
就可以找到我們要的結果:
句號和驚嘆號這類的符號不會被算在
slop
的範圍內。
總之,phrase_match
是一個很好用的搜尋,尤其在不熟悉 ES 的時候,使用這樣的搜尋模式可以讓你更直覺一些。
但當然壞處我們也提到了,對於 slop
的設定值是需要拿捏的,當今天使用預設的 0 時,很容易讓使用者搜尋的結果變成無,這在很多電商網站之中並不是一件好事,但要如何拿捏呢?這又是工程師的工作了。