ES 12 - 配置使用Elasticsearch的動態映射(dynamic mapping)

来源:https://www.cnblogs.com/shoufeng/archive/2019/04/04/10655797.html
-Advertisement-
Play Games

什麼是Elasticsearch的動態映射? 它有什麼作用和優點? 如何自定義使用動態模板? 本篇文章介紹這些內容. ...


目錄

1 動態映射(dynamic mapping)

1.1 什麼是動態映射

動態映射時Elasticsearch的一個重要特性: 不需要提前創建iindex、定義mapping信息和type類型, 你可以 直接向ES中插入文檔數據時, ES會根據每個新field可能的數據類型, 自動為其配置type等mapping信息, 這個過程就是動態映射(dynamic mapping).

Elasticsearch動態映射的示例:

欄位內容(field) 映射的欄位類型(type)
true | false boolean
1234 long
123.4 float
2018-10-10 date
"hello world" text

說明: 動態映射雖然方便, 可並不直觀, 為了個性化自定義相關設置, 可以在添加文檔之前, 先創建index和type, 並配置type對應的mapping, 以取代動態映射.
mapping的配置可參考博文: ES 11 - 配置Elasticsearch的映射(mapping).

1.2 體驗動態映射

(1) 插入如下數據:

如果已有website索引, 先刪除再執行下麵的插入操作: DELETE website.

PUT website/blog/1
{
    "blog_id": 10001,
    "author_id": 5520,
    "post_date": "2018-01-01",
      "title": "my first blog",
      "content": "my first blog in the website"
}

PUT website/blog/2
{
    "blog_id": 10002,
    "author_id": 5520,
    "post_date": "2018-01-02",
    "title": "my second blog",
    "content": "my second blog in the website"
}

PUT website/blog/3
{
    "blog_id": 10003,
    "author_id": 5520,
    "post_date": "2018-01-03",
    "title": "my third blog",
    "content": "my third blog in the website"
}

(2) 進行如下檢索測試:

註意這裡結果數是3的情況.

GET website/blog/_search?q=2018                 // 1條結果, 5.6之前的版本是3條結果
GET website/blog/_search?q=2018-01-01           // 1條結果, 5.6之前的版本是3條結果
GET website/blog/_search?q=post_date:2018       // 1條結果
GET website/blog/_search?q=post_date:2018-01-01 // 1條結果

(3) 查看ES自動建立的mapping:

GET website/_mapping

// 結果如下: 
{
  "website" : {                  // index是website
    "mappings" : {
      "blog" : {                 // type是blog
        "properties" : {
          "author_id" : {
            "type" : "long"
          },
          "blog_id" : {
            "type" : "long"
          },
          "content" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "post_date" : {
            "type" : "date"        // 發佈日期"2018-01-01"被自動識別為date類型
          },
          "title" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          }
        }
      }
    }
  }
}

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

如果使用的是較早的版本, 以5.6.x為例, [1.2]節中搜索結果會不一致, 這是因為:

ES自動建立mapping時, 為不同的field映射了不同的數據類型, 而不同數據類型在分詞、搜索等行為上也是不同的.

官方文檔指出, 從6.0+版本開始, _all欄位的設置已經禁止使用, 建議我們使用copy_to實現相似的功能.—— 也就是說, 如果_all欄位被關閉, 就不會出現搜索結果不一致的情況.

(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類型, 所以將進行精確匹配.

而date類型的欄位索引的內容有其預設的固定格式. post_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.x版本中做的一個優化, 搜索post_date:01等是不會出現結果的, 搜索2018會出現第一條結果.

2 開啟dynamic mapping策略

2.1 約束策略

策略 功能說明
true 開啟 —— 遇到陌生欄位時, 進行動態映射
false 關閉 —— 忽略遇到的陌生欄位
strict 遇到陌生欄位時, 作報錯處理

2.2 策略示例

(1) 使用不同的約束策略:

PUT user
{
  "mappings": {
      "blog_user": {
          "dynamic": "strict",          // 嚴格控制策略
          "properties": {
              "name": { "type": "text" },
              "address": {
                  "type": "object",
                  "dynamic": "true"     // 開啟動態映射策略
              }
          }
      }
  }
}

(2) 插入數據演示:

// 插入數據時多添加一個欄位
PUT user/blog_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 [blog_user] is not allowed"
      }
    ],
    "type": "strict_dynamic_mapping_exception",
    "reason": "mapping set to strict, dynamic introduction of [content] within [blog_user] is not allowed"
  },
  "status": 400
}

添加符合約束的數據, 操作就能成功:

PUT user/blog_user/1
{
    "name": "shou feng",
    "address": {
        "province": "guangdong",
        "city": "guangzhou"
    }
}

(3) 查看映射信息:

GET user/_mapping

// 映射信息如下: 
{
  "user" : {
    "mappings" : {
      "blog_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 - 日期識別策略

對於date類型的數據, Elasticsearch有其預設的識別策略, 比如"yyyy-MM-dd". 存在這種情況:

① 第一次添加文檔時, 某個field是類似"2018-01-01"的值, 其類型就被動態映射成了date;
② 後期再次添加文檔, 該field是類似"hello world"的值, ES就會因為類型不匹配而報錯.

為解決這一問題, 可以手動關閉某個type的date_detection; 如果不需要關閉, 建議手動指定這個field為date類型.

關閉示例如下:

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

3.2 在type中自定義動態映射模板

(1) 在type中定義動態映射模板(dynamic mapping template) —— 把所有的string類型映射成text和keyword類型:

先刪除已有的user索引: DELETE user, 再執行下述命令:

PUT user
{
    "mappings": {
        "blog_user": {
            "dynamic_templates": [
                {
                    "en": {
                        "match": "*_en",           // 匹配"*_en"的field
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "text",        // 把所有的string類型, 映射成text類型
                            "analyzer": "english", // 使用english分詞器
                            "fields": {
                                "raw": {
                                    "type": "keyword",
                                    "ignore_above": 256
                                }
                            }
                        }
                    }
                }
            ]
        }
    }
}

(2) 添加數據:

PUT user/blog_user/1
{
    "name": "the first register user"
}

PUT user/blog_user/2
{
    "name_en": "the second register user"
}

(3) 檢索數據:

// 有結果: "name"沒有匹配到任何動態模板, 預設使用standard分詞器
GET user/_search
{
    "query": {
        "match": {"name": "the"}
    }
}

// 無結果: "name_en"匹配到了動態模板, 使用english分詞器, the是停用詞, 被過濾掉了
GET user/_search
{
    "query": {
        "match": {"name_en": "the"} 
    }
}

說明:

這裡的match_mapping_type的類型支持 [object, string, long, double, boolean, date, binary], 若使用text將拋出如下錯誤信息:

{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "Failed to parse mapping [blog_user]: No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]"
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "Failed to parse mapping [blog_user]: No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]",
    "caused_by": {
      "type": "illegal_argument_exception",
      "reason": "No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]"
    }
  },
  "status": 400
}

在6.0之前的版本, 將拋出如下過期的警告信息:

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中自定義預設映射模板

_default mapping - 預設映射模板是類似於全局變數的存在, 對當前配置的索引起作用.

預設映射模板在Elasticsearch 6.x版本中已經不再支持, 因為6.0版本開始, 每個索引只能有一個類型, 因此預設模板沒有存在的意義了.

下麵的演示過程, 是在6.0之前的版本上的測試.

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

先刪除已有的user索引: DELETE user, 再執行下述命令:

PUT user
{
    "mappings": {
        "_default_": {
            "_all": { "enabled":  false }
        },
        "blog_user": {
            "_all": { "enabled":  true  }
        }
    }
}

(2) 動態映射可以與索引模板(Index Templates)配合使用.

無論是自動創建Index, 還是手動顯示創建Index, 索引模板都可以用來配置新索引的預設mappings(映射), settings(配置項)和aliases(別名). 具體使用方法請參考博客: ES 10 - Elasticsearch的索引別名和索引模板

參考資料

(6.6版)官方文檔 - Dynamic Mapping

版權聲明

作者: ma_shoufeng(馬瘦風)

出處: 博客園 馬瘦風的博客

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

本文版權歸博主所有, 歡迎轉載, 但請保留此段聲明, 併在文章頁面明顯位置給出原文鏈接, 否則博主保留追究相關人員法律責任的權利.


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 樹莓派中QT實現I2C 在QT中實現 I2C 使用的驅動為 wiringPi 庫的引入 代碼實現 widget.h 中 記得引入"wiringPiI2C.h"等 此處,我使用的是讀取感測器adxl345加速度計 widget.cpp 中 首先應該使用在命令行中 來獲取i2c設備文件的地址,比如 ​ ...
  • pssh提供OpenSSH和相關工具的並行版本。包括pssh,pscp,prsync,pnuke和pslurp。該項目包括psshlib,可以在自定義應用程式中使用。pssh是python寫的可以併發在多台機器上批量執行命令的工具,它的用法可以媲美ansible的一些簡單用法,執行起來速度比ansi ...
  • 安裝Aduino開發環境 在官網中下載Arduino開發環境,或者在網盤中下載: 網盤地址: https://pan.baidu.com/s/1OjMhYgKOYW69YC2dEwFgyw: 提取碼:ls15 安裝esp8266庫文件 為了在Arduino的IDE中開發NodeMCU,必須在IDE中 ...
  • 系統記憶體管理簡介 <! TOC "系統記憶體管理簡介" "常見的名詞解釋" "單塊記憶體管理法" "分區管理法" "頁式管理法" "幀與頁" "小結" <! /TOC 系統以 字 為單位,將記憶體劃分為一個個存儲單位,每個存儲單位都有一個地址。指向地址的指針以字的大小為單位移動。目前常見的字單位為32位( ...
  • 電腦sdd+hdd雙硬碟,預設win10裝在了sdd分區,uefi+gpt引導。現在想要在hdd中劃分出一個分區安裝manjaro,併在開機多重引導。 1. 製作安裝盤 先去下載最新的鏡像,最好在國內鏡像站下載,清華開源鏡像。在linux下的話可以直接用dd命令,其中<xxx.iso>為剛纔下好的鏡 ...
  • 語法:sz 文件 比如要下載下麵這個com.zip這個壓縮包 輸入sz com.zip 彈出下載頁面,即可開始下載文件 ...
  • 如果要批量複製大量的數據,用ado.net或者其他orm框架逐條讀取並寫入,有時會耗時太長,滿足不了要求,此時SqlBulkCopy就可以出來大顯身手了,相信許多人瞭解或使用過它。 但實際使用時,還是會遇上些問題,這裡做些記錄,也許能幫你避開一些“坑”。 column mapping 問題 。 在設 ...
  • 存儲過程 就是一組用於完成特定功能的PL/SQL 具名語句塊,該SQL語句集經過編譯後存儲在資料庫系統中。在使用時候,我們只需要通過指定已經定義的存儲過程名字並給出對應的參數來執行 存儲過程的定義語法 create or replace procedure 過程名(參數名 參數模式 參數類型,參數名 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...