Try   HackMD

Elasticsearch QueryString 查詢語法筆記

最近開始想把 LOG 儲存在 Elasticsearch 裡,但這樣做需要有個方便查詢的 UI 介面,對我而言 Kibana 功能過於複雜,Postman 查詢又比較麻煩。後來發現了 Elasticvue 這個工具,選擇它的原因是它支援多種瀏覽器擴充套件及桌面應用程式版本。

Elasticvue 的查詢介面主要基於 query_string 語法,這是 Elasticsearch 中基於 Lucene 查詢語法的擴展版本。對熟悉 SQL 的使用者來說,query_string 比其他 DSL 語法更容易上手,因此我整理了一些常用的語法方便查閱。

可從 Elasticvue 官網 查看各個瀏覽器擴充套件,或是桌面應用程式的安裝檔案或連結。

基本語法

基本 API 結構

{
  "query": {
    "query_string": {
      "query": "your query string here",     // 必要參數:查詢字串(使用 "*" 可搜尋所有文件)
      "default_field": "content",            // 選用參數:預設搜尋欄位,未指定則搜尋全部欄位
      "default_operator": "OR"               // 選用參數:預設運算符,預設值為 OR
      // 其他可選參數
    }
  },
  "size": 10,                                // 選用參數:回傳結果數量,預設為 10
  "from": 0,                                 // 選用參數:起始位置,預設為 0
  "sort": []                                 // 選用參數:結果排序
}

未指定欄位時,QueryString 會在所有可搜尋欄位中進行搜尋。

查詢語法

1. 基本搜尋

簡單關鍵字搜尋:

apple

多個詞彙(預設使用 OR 連接):

apple banana

精確片語搜尋(使用雙引號):

"red apple"

2. 布林運算符

AND 運算符(兩個詞都必須存在):

apple AND banana

OR 運算符(至少有一個詞必須存在):

apple OR banana

NOT 運算符(排除包含某詞的文件):

apple NOT banana

加號(必須包含此詞):

+apple banana

減號(必須排除此詞):

apple -banana

3. 欄位指定查詢

針對特定欄位搜尋:

title:apple

針對多個欄位的查詢:

title:apple AND content:banana

多值查詢(OR 條件):

user_id:(1234 OR 5678)

欄位存在性查詢:

_exists_:email        // 查詢 email 欄位存在的文件,可以理解成不為 null
NOT _exists_:phone    // 查詢 phone 欄位不存在的文件,可以理解成為 null

欄位指定優先順序:查詢字串中明確指定欄位 > fields 參數 > default_field 參數。

4. 範圍查詢與比較運算符

範圍查詢:

price:[10 TO 20]    // 閉區間,包含 10 和 20
price:{10 TO 20}    // 開區間,不包含 10 和 20
price:[10 TO *]     // 大於等於 10
price:[* TO 20]     // 小於等於 20

比較運算符:

price:>10           // 大於 10
price:>=10          // 大於等於 10
price:<20           // 小於 20
price:<=20          // 小於等於 20

這兩種寫法在功能上通常等價,可依情境選擇使用。

5. 萬用字元搜尋

萬用字元搜尋:

te?t      // 問號代表一個字元
test*     // 星號代表零個或多個字元

重要參數

1. 欄位相關參數

default_field vs fields:

  • default_field: 指定預設搜尋的單一欄位。
  • fields: 指定多個搜尋欄位及其權重。
// 使用 default_field
{
  "query_string": {
    "query": "apple",
    "default_field": "content"
  }
}

// 使用 fields
{
  "query_string": {
    "query": "apple",
    "fields": ["title^2", "content", "tags"]
  }
}

2. analyze_wildcard

控制是否對萬用字元表達式進行分析處理:

  • analyze_wildcard: false(預設):萬用字元表達式不經過分析器處理。
  • analyze_wildcard: true:萬用字元表達式先經過分析器處理,可實現大小寫不敏感搜尋。
{
  "query_string": {
    "query": "Te*",
    "analyze_wildcard": true,
    "analyzer": "standard"
  }
}

3. analyzer

指定如何處理和分析查詢字串:

{
  "query_string": {
    "query": "The Quick Brown Fox",
    "analyzer": "standard"
  }
}

analyzer 在 text 與 keyword 類型欄位上的差異:

  • text 欄位:分析器會分詞並通常轉換為小寫。
  • keyword 欄位:通常保留原始格式,需要特殊處理才能實現大小寫不敏感。

4. auto_generate_synonyms_phrase_query

控制同義詞處理方式:

  • true(預設):自動為同義詞生成片語查詢,保持詞序和相鄰性。
  • false:只生成普通同義詞查詢,不考慮詞序。

例如,若設定 "ny" 與 "new york" 為同義詞:

{
  "query_string": {
    "query": "ny restaurants",
    "auto_generate_synonyms_phrase_query": true
  }
}
  • true:會匹配 "ny restaurants" 或 "new york restaurants"("new york" 作為整體片語)。
  • false:會匹配 "ny restaurants" 或 "new restaurants" 或 "york restaurants"。

5. 權重控制:boost 與欄位加權

Elasticsearch 提供兩種方式來控制搜尋權重:

1. boost 參數:調整整個查詢的權重。

{
  "query_string": {
    "query": "apple iphone",
    "boost": 2.0
  }
}
  • 功能:增加整個查詢的重要性。
  • 主要用途:
    • 在複合查詢結構中調整當前 query_string 查詢相對於其他查詢子句的重要性。
    • 與欄位加權結合使用,同時控制查詢級別和欄位級別的權重。

2. 欄位加權:使用 ^ 語法調整特定欄位的權重。

{
  "query_string": {
    "query": "apple iphone",
    "fields": ["title^3", "description^2", "content"]
  }
}
  • 功能:增加特定欄位的相對重要性。
  • 適用場景:當在多個欄位中搜尋相同關鍵詞,但某些欄位應更重要時。
  • 說明:在上例中,title 欄位的匹配權重是 content 欄位的 3 倍,description 是 2 倍。

兩者結合使用的例子

{
  "query_string": {
    "query": "apple",
    "fields": ["title^3", "description"],
    "boost": 2.0
  }
}

在這個例子中:

  • 欄位加權:控制 title 欄位相對 description 欄位的重要性。
  • boost:控制整個 query_string 查詢的整體權重(在更大的查詢結構中)。

差異

  • boost:控制整個查詢的權重。
  • 欄位加權 ^:控制查詢內不同欄位間的相對權重。

6. 模糊搜尋(fuzziness 與 phrase_slop)

波浪號 ~ 在 QueryString 中有兩種不同用途,取決於它的位置:

1. 模糊搜尋(單詞後的波浪號)

apple~    // 單詞後接波浪號,表示模糊搜尋
apple~2   // 指定模糊度為 2
  • 對應參數:fuzziness
  • 功能:處理單個詞的拼寫錯誤,基於編輯距離。
  • 識別方式:用於單詞後面。

2. 近似搜尋(片語後的波浪號)

"apple banana"~5  // 片語後接波浪號,表示近似搜尋
  • 對應參數:phrase_slop
  • 功能:處理片語中詞的順序和距離。
  • 識別方式:用於引號包圍的片語後面。

在 API 中設定這些參數

{
  "query_string": {
    "query": "apple~2 \"quick fox\"~3",
    "fuzziness": "AUTO",  // 全域設定,會被查詢中的具體值覆蓋
    "phrase_slop": 2      // 全域設定,會被查詢中的具體值覆蓋
  }
}

fuzziness 設定差異

  • "fuzziness": "AUTO":根據詞長自動調整(1-2字元:0錯誤,3-5字元:1錯誤,>5字元:2錯誤)。
  • "fuzziness": 2:固定允許最多2個字元編輯距離。

範例說明

  • apple~1 可匹配 "aple", "appla" 等拼寫錯誤的詞。
  • "quick fox"~3 可匹配 "quick brown fox"(中間有詞)或 "fox is quick"(順序變化)。

優先順序

  • 查詢字串中使用 ~ 設定的值會覆蓋 API 參數中的全域設定。

日期時間查詢

基本日期範圍搜尋:

timestamp:[2023-01-01 TO 2023-01-31]

相對時間搜尋:

timestamp:>now-1d  // 過去24小時

常用相對時間表達式:

  • now-1h:一小時前。
  • now-1w:一週前。
  • now/d:今天開始。
  • now/w:本週開始。
  • now/M:本月開始。

範圍語法vs比較運算符:

// 兩種等價的寫法
timeStamp:[\"2025-01-01T00:00\" TO *]
timeStamp:>=\"2025-01-01T00:00\"

日期時間格式:

  • 標準格式:yyyy-MM-ddTHH:mm:ss.SSSZ
  • 簡化格式:yyyy-MM-dd
  • 注意時區設定,預設為 UTC。

分頁與排序

在查詢中加入分頁參數:

{
  "query": {
    "query_string": {
      "query": "apple"
    }
  },
  "from": 0,   // 起始位置
  "size": 10,  // 每頁數量
  "sort": [
    { "price": "asc" },  // 按價格升序
    "_score"             // 相同價格按相關性排序
  ]
}

實用範例

1. 複雜布林組合查詢

{
  "query": {
    "query_string": {
      "query": "(title:apple OR description:apple) AND (price:[500 TO 1000] OR brand:\"Apple Inc.\")",
      "default_operator": "AND"
    }
  }
}

2. 模糊搜尋與時間範圍組合

{
  "query": {
    "query_string": {
      "query": "phne~ AND date:[now-30d TO now]",
      "fields": ["title", "content"]
    }
  }
}

特殊字元轉義

QueryString 中有許多特殊字元具有特定含義,若要作為普通字元使用,需要使用反斜線 \ 轉義:

\+ \- \= \&\& \|\| \> \< \! \( \) \{ \} \[ \] \^ \" \~ \* \? \: \\ \/

例如:

  • 搜尋包含加號的文件:title:\+1
  • 搜尋包含括號的文件:content:\(sample\)
  • 搜尋包含引號的文件:description:\"quoted text\"
tags: ELK Elasticsearch