一開始使用 Elasticsearch 時,簡單的透過一個 HTTP POST 或 PUT 就能將一個 JSON 文件 indexing 進入 Elasticsearch,然後就可以直接透過 _search API endpoint 來進行搜尋,如此的簡單,不像一般 Database 要先定義好 table schema,這背後到底是怎麼運作的?
Dynamic Template的設定,來強化我們設計 Mapping 時的技巧。這個功能是 Elasticsearch 之所以能宣稱他是 schema-less,也就是不用預先定義好資料的 schema 就能直接將文件 indexing 進入 Elasticsearch 的幕後機制,他的做法就是:
當一份被 indexing 進入 Elasticsearch 的文件,若是有一個欄位,沒有在 mapping 中被定義時,Elasticsearch 會自動的判斷他的資料型態,並且依照預設或指定的規則,來產生這個新欄位的 mapping 設定。
Dynamic Mapping 的運作主要依照以下兩種機制及其相關的設定:
以下我們分別就這兩個部份來說明。
當一個 JSON 文件 indexing 進入 Elasticsearch 時,Dynamic field mapping 會依照 JSON 欄位原本的資料型態,來分別執行判定的規則:
| JSON 的資料型態 | 判定成為的 Elasticsearch 資料型態 | 
|---|---|
| null | 不會產生這個欄位 | 
| trueorfalse | boolean | 
| 浮點數 | float | 
| 整數 | long | 
| 物件 | object | 
| 陣列 | 依照陣列內的資料型態決定 | 
| 字串 | 1. 判定這個字串是否為日期格式。2. 判定這個字串是否為 double或是long的格式。3. 若都非以上的格式,會直接指派text型態,並搭配keyword的 sub-field。 | 
其中日期格式預設的規則為:
[ "strict_date_optional_time","yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]
strict_date_optional_time 支援的是一般廣泛被使用在 JSON 中表示日期時間的 ISO8601 格式。
也可以在宣告 mapping 時自行定義日期格式的規則:
PUT my-index-000001
{
  "mappings": {
    "dynamic_date_formats": ["MM/dd/yyyy"]
  }
}
我們可以在 mapping 宣告時,直接指定 dynamic template 的規則,從官方的文件可以看到宣告的格式如下:

其中 match conditions 代表的定義為:
match_mapping_type: Elasticsearch 根據 JSON 文件的欄位資料內容,所判斷出來的資料型態是什麼。 例如: boolean, date, double, long, object, string.match 和 unmatch: 欄位的名稱,可以支援萬用字元 *。例如: *_text, long_*.match_pattern: 一樣是針對欄位的名稱進行比對,不過是以 full Java regular expression 的比對方式。path_match 和 path_unmatch: 類似 match 與 unmatch 是針對欄位的名字,不過多包含整體的路徑,例如: name.*, *.middle。string 的欄位指定成 text加上包含 keyword sub-field 的型態,如果這個 index 的應用場景是 log,而 log 的格式有先定義好,大部份的字串欄位都不用被搜尋,只有特定的字串欄位會是 text 的話,可將預設的字串欄位指定成 keyword。PUT my-index-000001
{
  "mappings": {
    "dynamic_templates": [
      {
        "strings_as_keywords": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "keyword"
          }
        }
      }
    ]
  }
}
text,不需要使用到 Aggregation, Sorting 或是 Script 的操作 ,因此不必保留 keyword 的 sub-field,即可明確指定為 text。PUT my-index-000001
{
  "mappings": {
    "dynamic_templates": [
      {
        "strings_as_text": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "text"
          }
        }
      }
    ]
  }
}
指定好團隊寫入特定 Index 的命名規則,可以簡化設定與錯誤發生的機會,例如:
_datetime 結尾。_count 結尾。long_, double_, int_。這樣即可以較單純的設定來滿足日後欄位擴充的管理。
PUT my-index-000001
{
  "mappings": {
    "dynamic_templates": [
      {
        "long_field": {
          "match":   "long_*",
          "mapping": {
            "type": "long"
          }
        }
      },
      {
        "double_field": {
          "match":   "double_*",
          "mapping": {
            "type": "double"
          }
        }
      }
    ]
  }
}
Dynamic Template,特別是修改原先的 Dynamic Template時,否則會發生 Runtime Error,也就是 indexing 才會發現有錯。PUT /my_index
{
    "mappings": {
        "dynamic": "strict"
    }
}
dynamic可以設定為:
true: 執行 dynamic mapping。false: 不執行 dynamic mapping,並在 indexing 時忽略沒有被宣告的欄位。strict: 不執行 dynamic mapping,並在 indexing 時遇到沒有宣告的欄位會直接拋出 exception。PUT my-index-000001
{
  "mappings": {
    "date_detection": false,
    "numeric_detection": true
  }
}
其中數值的部份指的是在字串內容中是否要嘗試判斷是否為數值,預設是關閉的
查看最新 Elasticsearch 或是 Elastic Stack 教育訓練資訊: https://training.onedoggo.com
歡迎追蹤我的 FB 粉絲頁: 喬叔 - Elastic Stack 技術交流
不論是技術分享的文章、公開線上分享、或是實體課程資訊,都會在粉絲頁通知大家哦!
此系列文章已整理成書
喬叔帶你上手 Elastic Stack:Elasticsearch 的最佳實踐與最佳化技巧
書中包含許多的修正、補充,也依照 Elastic 新版本的異動做出不少修改。
有興趣的讀書歡迎支持! 天瓏書局連結