Website logo

Robert Chang

技術部落格

Elasticsearch - Full Text Query ( 全文搜尋 )

上一篇文章 中,介紹了 term level 的查詢,其實還有一些比較有趣的查詢,像是查詢某個欄位是否存在的資料、或是使用 prefixwildcard 以及 regular expression 的方式查詢特定字串,但因為使用方式算簡單,也沒什麼特別需要注意的地方,就略過不談。

只是需要注意的是,在查詢某個欄位是否存在時,要想到,什麼樣的資料不會被儲存的搜尋的資料之中。

舉例來說,像是在建立 mapping 時,選擇 keyword 類型的欄位,可以搭配 ignore_above 的參數,當 keyword 的長度超過某個值時,就不會加入到 inverted index 之中,意思就是不會被真正地 index。

還有像是空的 [] 或是 Null 都不會被加入到 inverted index 之中,但 "" 是會的,這是比較有趣的地方。

接著我們就要介紹 Full Text Query ( 全文搜尋 ),主要是拿來搜尋那些沒有結構化的資料,常見的使用場景是部落格的內文、Email 的內容、聊天紀錄等等,也是 Elasticsearch ( 以下簡稱 ES ) 最常做的事情。

Full Text Query

這種搜尋方式和 term level query 的差別就在於它的搜尋字詞會被 Analyzer 給處理過,如果設定的是 Standard Analyzer 那就會被拆解成一個個的 token 並且轉成小寫,接著拿去和 inverted index 做檢查,找到擁有這些字詞的 documents。

忘記 Analyzer 是什麼?可以參考 這裡

直接來看看如何使用,以及和 term level 的查詢到底有什麼不同?

這次使用的是 match 不是 term,告訴 ES 我們要用全文搜尋!

// GET /movies/_search
{
  "query": {
    "match": {
      "title": "beautiful"
    }
  }
}

接著會得到 4 筆電影資料,title 都有包含 beautiful 的單字。

screen shot

如何證明這和 term level 的查詢是不同的呢?

我們把搜尋的單字改成全大寫,因為在 term level 的查詢下,搜尋的字詞並不會被 tokenize,所以就不會匹配的 inverted index 的 key,複習請看 上一篇文章,所以故意用這樣的方式來直接檢測和 term level 的查詢差別:

// GET /movies/_search
{
  "query": {
    "match": {
      "title": "BEAUTIFUL"
    }
  }
}

結果不會有任何的改變,從反方向就可以證明,確實是有經過 tokenize 的過程,才可以對應到正確的 documents。

screen shot

接著搜尋多個單字也是搜尋時常見的做法,我們試試看:

// GET /movies/_search
{
  "query": {
    "match": {
      "title": "beautiful mind"
    }
  }
}

得到的結果會比單純搜尋 beautiful 來得更多,達到 7 筆。

screen shot

為什麼會變多呢?很好理解!搜尋的字詞經過 tokenize 之後,會變成:

["beautiful", "mind"]

接著只要 inverted indices 中有對應到這 2 個 key 的 documents 都會被撈出來。

但這可能會讓你覺得不是你要的搜尋結果,對吧?

我們常常會希望,多加一個字詞,就是希望更精準地匹配到想要的資料,這時候會有這樣的結果是因為 ES 預設的搜尋條件是 OR,也就是找到有 beautiful 或是有 mind 這兩個 key 的 documents。

這時候我們可以接入 operator 的參數來調整:

// GET /movies/_search
{
  "query": {
    "match": {
      "title": {
        "query": "beautiful mind",
        "operator": "and"
      }
    }
  }
}

確實就剩下 1 筆資料了!

screen shot

當然全文搜尋也可以使用在日期或是數字的搜尋上,但我建議是,如果可以知道輸入對應的欄位,就盡量使用 term level 的搜尋方式來搜尋日期或是數字,因為更精準,而且日期或是數字基本上不需要經過 tokenize 這一個步驟。

對了!我說過不要拿 term level 的查詢去操作 text 的資料類型欄位,反之,不要拿 full text 查詢去操作 keyword 的資料類型欄位,因為會被 tokenize 導致對應出來的結果和你想像的不同。

其實真正的重點都圍繞在 Analyzer 以及 Inverted Index,這也是為什麼我會放在搜尋之前的章節介紹,而不是開門見山就討論搜尋怎麼使用,這很容易讓人不理解為什麼。

這兩個概念基本上左右了整個 ES 搜尋的方向,非常重要,一定要想辦法理解!

上一篇文章Elasticsearch - Term Level Query

下一篇文章Elasticsearch - 介紹評分 ( Scoring )