1. 程式人生 > >小白學ES 12 - 什麼是Elasticsearch的動態對映 + 如何自定義動態對映

小白學ES 12 - 什麼是Elasticsearch的動態對映 + 如何自定義動態對映

文章目錄

1 動態對映(dynamic mapping)

1.1 什麼是動態對映

沒有提前定義欄位和資料型別間的對映關係, 而是直接向ES中插入資料, 此時ES將根據每個field可能對應的資料型別, 自動為其配置type及其對應的mapping, 這個過程就是動態對映(dynamic mapping).

示例:

true or false		-->	boolean
233			-->	long
123.45			-->	double
2018-10-10		-->	date
"hello world"		-->	string/text

可以配置自定義對映, 供ES在動態對映時使用.

  • 動態對映雖然方便, 可並不直觀, 為了個性化自定義相關設定, 可以在新增文件之前, 先建立index和type, 並配置type對應的mapping, 以取代動態對映.

1.2 體驗動態對映

  • 插入如下資料:

    PUT website/blog/1
    {
        "post_date": "2018-01-01",
    	"title": "my first blog",
    	"content": "my first blog in the website",
    	"author_id": 5520
    }
    
    PUT website/blog/2
    {
        "post_date":
    "2018-01-02", "title": "my second blog", "content": "my second blog in the website", "author_id": 5520 } PUT website/blog/3 { "post_date": "2018-01-03", "title": "my third blog", "content": "my third blog in the website", "author_id": 5520 }
  • 進行如下檢索測試:

    GET website/blog/_search?q=2018				// 3條結果
    GET website/blog/_search?q=2018-01-01			// 3條結果
    GET website/blog/_search?q=post_date:2018-01-01		// 1條結果
    GET website/blog/_search?q=post_date:2018		// 1條結果
    
  • 檢視ES自動建立的mapping:

    GET website/_mapping/blog
    
    // 結果如下: 
    {
      "website": {
        "mappings": {
          "blog": {
            "properties": {
              "author_id": {
                "type": "long"
              },
              "content": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              },
              "post_date": {
                "type": "date"			// post_date為date型別
              },
              "title": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              }
            }
          }
        }
      }
    }
    

1.3 搜尋結果不一致的原因分析

上節中搜索結果不一致, 是因為ES自動建立mapping時, 為不同的field映射了不同的資料型別.

—— 不同資料型別在分詞、搜尋等行為上也是不同的.

(1) GET website/blog/_search?q=2018

ES預設將每個文件的所有field的值抽取到一個名為_all的元欄位中, 如id=1的文件的_all的值為:

2018-01-01 my first blog my first blog in the website 5520
  • _all欄位的倒排索引結果如下:

    說明: _all欄位將所有的值作為字串索引, 所以日期被索引為年、月、日三個值.

    doc1 doc2 Doc3
    2018 * * *
    01 * * *
    02 *
    03 *

此項搜尋中, ES是從_all欄位中檢索, 3個文件中都有 2018 , 所以結果數是3.

(2) GET website/blog/?q=2018-01-01

同(1), ES也是從_all欄位中檢索, 結果數同樣是3.

(3) GET website/blog/_search?q=post_date:2018-01-01

此檢索指定了檢索條件, ES將從post_date欄位中檢索, 而post_date被對映為date型別, 所以將進行精確匹配.

  • post_date欄位的倒排索引結果如下:

    注意: date型別的欄位索引的內容有其預設的固定格式, 如下:

    doc1 doc2 doc3
    2018-01-01 00:00:00 UTC *
    2018-01-02 00:00:00 UTC *
    2018-01-03 00:00:00 UTC *

可以看出, 滿足條件的只有1個結果, 即doc1.

(4) GET /_search?q=post_date:2018

這是ES 5.2版本中做的一個優化, 搜尋01/02等是不會出現結果的, 搜尋2018會出現第一條結果.

2 開啟dynamic mapping策略

2.1 約束策略

(1) true: 開啟 —— 遇到陌生欄位時, 進行動態對映;
(2) false: 關閉 —— 遇到陌生欄位時, 忽略之;
(3) strict: 遇到陌生欄位時, 報錯處理.

2.2 策略示例

  • 使用不同的約束策略:

    PUT website
    {
      "mappings": {
          "user": {
              "dynamic": "strict",			// 嚴格控制策略
              "properties": {
                  "name": { "type": "text" },
                  "address": {
                      "type": "object",
                      "dynamic": "true"		// 開啟動態對映策略
                  }
              }
          }
      }
    }
    
  • 插入資料演示:

    // 插入資料時多新增一個欄位
    PUT website/user/1
    {
        "name": "shou feng",
        "content": "this is my blog",		// 多新增的欄位
        "address": {
            "province": "guangdong",		// 多新增的欄位
            "city": "guangzhou"			// 多新增的欄位
        }
    }
    
    // 出錯資訊: 
    {
      "error": {
        "root_cause": [
          {
            "type": "strict_dynamic_mapping_exception",
            // 不允許動態新增field
            "reason": "mapping set to strict, dynamic introduction of [content] within [user] is not allowed"
          }
        ],
        "type": "strict_dynamic_mapping_exception",
        "reason": "mapping set to strict, dynamic introduction of [content] within [user] is not allowed"
      },
      "status": 400
    }
    
    // 新增符合的資料, 操作成功: 
    PUT website/user/1
    {
        "name": "shou feng",
        "address": {
            "province": "guangdong",
            "city": "guangzhou"
        }
    }
    
  • 檢視對映資訊:

    GET website/_mapping/user
    
    // 對映資訊如下: 
    {
      "website": {
        "mappings": {
          "user": {
            "dynamic": "strict",			// 嚴格約束條件
            "properties": {
              "address": {
                "dynamic": "true",			// 開啟動態對映策略
                "properties": {
                  "city": {
                    "type": "text",
                    "fields": {
                      "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                      }
                    }
                  },
                  "province": {
                    "type": "text",
                    "fields": {
                      "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                      }
                    }
                  }
                }
              },
              "name": {
                "type": "text"
              }
            }
          }
        }
      }
    }
    

3 定製dynamic mapping策略

3.1 date_detection - 日期識別策略

ES預設按照一定的格式識別date型別的資料, 如"yyyy-MM-dd". 存在這種情況:

① 第一次新增文件時, 某個field是類似"2018-01-01"的值, 其型別就被動態對映成了date;

② 後期再次新增文件, 該field是類似"hello world"的值, ES就會因為型別不匹配而報錯.

為解決這一問題, 可以手動關閉某個type的date_detection, 如果有需要, 請指定某個field為date型別.

PUT website/_mapping/user
{
    "date_detection": false
}

3.2 自定義動態對映模板 - type層面

  • 在type中定義動態對映模板(dynamic mapping template):

    PUT website
    {
        "mappings": {
            "user": {
                "dynamic_templates": [
                    {
                        "en": {
                            "match": "*_en", 			// 匹配"*_en"的field
                            "match_mapping_type": "string",
                            "mapping": {
                                "type": "text",
                                "analyzer": "english"		// 使用english分詞器
                            }
                        }
                    }
                ]
            }
        }
    }
    
  • 新增資料:

    PUT website/user/1
    {
        "name": "the first register user"
    }
    
    PUT website/user/2
    {
        "name_en": "the second register user"
    }
    
  • 檢索資料:

    // 有結果: "name"沒有匹配到任何動態模板, 預設使用standard分詞器
    GET website/user/_search
    {
        "query": {
            "match": {"name": "the"}
        }
    }
    
    // 無結果: "name_en"匹配到了動態模板, 使用english分詞器, the是停用詞, 被過濾掉了
    GET website/user/_search
    {
        "query": {
            "match": {"name_en": "the"}	
        }
    }
    
  • 注意:

    這裡的match_mapping_type的型別支援 [object, string, long, double, boolean, date, binary], 若使用text將丟擲如下警告資訊:

    Deprecation: match_mapping_type [text] is invalid and will be ignored: 
    No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]
    

3.3 自定義預設對映模板 - index級別

  • 在index中定義預設對映模板(default mapping template):

    PUT website
    {
        "mappings": {
            "_default_": {
                "_all": { "enabled":  false }
            },
            "blog": {
                "_all": { "enabled":  true  }
            }
        }
    }
    
  • 預設對映模板的使用:

    個人理解: 預設對映模板應該是類似於全域性變數的存在, 對當前配置的索引起作用.

    具體使用: 尚未嘗試, 後續接觸到時再補充此部分內容.

版權宣告

作者: ma_shoufeng(馬瘦風)

出處: CSDN 馬瘦風的部落格

您的支援是對博主的極大鼓勵, 感謝您的閱讀.

本文版權歸博主所有, 歡迎轉載, 但未經博主同意必須保留此段宣告, 且在文章頁面明顯位置給出原文連結, 否則博主保留追究相關人員法律責任的權利.