1. 程式人生 > 程式設計 >Elasticsearch入門(3)-mapping

Elasticsearch入門(3)-mapping

前言

掘友們好久不見,在之前的文章中,我們瞭解到了elasticsearch的查詢相關操作方法和一些原理,本章節將帶來elasticsearch的mapping詳細配置和用法,主要分為

  1. dynamic mapping機制
  2. 顯示mapping和相關引數
  3. 多欄位特性及mapping中自定義analyzer

Dynamic mapping

mapping

  • mapping類似於資料庫中的schema的定義,作用如下
    • 定義索引中的欄位的名稱
    • 定義欄位的資料型別,例如字串,數字,布林
    • 欄位,倒排索引的相關配置(Analyzed or Not Analyzed,Analyzer)
  • Mapping會把JSON檔案對映成Lucene所需要的扁平格式
  • 一個Mapping屬於一個索引的Type
    • 每個檔案都屬於一個Type
    • 一個Type有一個Mapping定義
    • 7.0開始,不需要在Mapping定義中指定Type資訊

1. 是什麼

  • 在寫入檔案時候,如果索引不存在,會自動建立索引
  • Dynamic Mapping的機制,使得我們無需手動定義Mappings.Elasticsearch會根據檔案資訊,推算出欄位的型別
  • 會遇到推算的不對的情況,例如地理位置資訊
  • 當型別設定不對時,會導致一些功能無法正常執行,例如Range查詢
# 檢視Mapping,get ${indexname}/_mappings
GET movies/_mappings
複製程式碼

2. 型別的自動識別

JSON型別 Elasticsearch
字串 匹配成日期格式,設定成Date
配置數字設定為float或long,該選項預設關閉
設定為text,並且增加keyword子欄位
布林值 boolean
浮點數 float
整數 long
物件 Object
陣列 由第一個非空數值的型別所決定
空值 忽略

demo

# dynamic mapping 推斷欄位的型別
PUT mapping_test/_doc/1
{
  "uid":"123","isVip":false,"isAdmin":"true","age":19,"height":"183"
}

# 檢視Mapping檔案,檢視mapping推算
GET mapping_test/_mapping
複製程式碼

檢視結果如圖,我們可以發現es對輸入的json進行了相應的型別轉換

dynamic mapping

3. 更改Mapping的欄位型別

  • 兩種情況下能夠修改
    • 新增加欄位
      • Dynamic 設定為true時,一旦有新增欄位的檔案寫入,Mapping也同時被更新
      • Dynamic設為false,當有新的檔案加入,並且新的檔案包含新的欄位,Mapping不會被更新,意味著新增欄位的資料無法被索引,但是資訊會出現在_source中
      • Dynamic設定為Strict,檔案寫入失敗
    • 對已有欄位,一旦已有資料寫入,就不再支援修改欄位定義
      • es基於Lucene實現的倒排索引,一旦生成後,就不允許修改
      • 如果希望改變欄位型別,必須Reindex API,重建索引
  • 原因
    • 如果修改了欄位的資料型別,會導致已被索引的屬於無法被搜尋
    • 對於新增欄位,不存在該影響(新增欄位時建立新欄位索引)

4. 控制Dynamic mappings

dynamic設定對應功能

“true" "false" "strict"
檔案可索引 ×
欄位可索引 × ×
Mapping被更新 × ×
  • 當dynamic被設定為false時候,存在新增欄位的資料寫入,該資料可以被索引,但是新增欄位被丟棄
  • 當設定為Strict模式時候,資料寫入直接出錯

4.1 true

檔案可索引,欄位可索引,mapping被更新

# 預設mapping支援dynamic,寫入的檔案中加入新的欄位
PUT dynamic_mapping_test/_doc/1
{
  "newFileld":"someValue" 
}
# 搜尋
POST dynamic_mapping_test/_search
{
  "query": {
    "match": {
      "newFileld": "someValue"
    }
  }
}
GET dynamic_mapping_test/_mapping
複製程式碼

true mapping

4.2 false

檔案可索引,欄位不可索引,mapping不更新

# 修改dynamic false
PUT dynamic_mapping_test/_mapping
{
  "dynamic":"false"
}

# 新增 anotherField
PUT dynamic_mapping_test/_doc/2
{
  "anotherField":"anotherValue"
}

# 新增的欄位不可以被搜尋,因為dynamic已經被設定為false
POST dynamic_mapping_test/_search
{
  "query": {
    "match": {
      "anotherField": "anotherValue"
    }
  }
}
複製程式碼

false mapping

# mapping檔案查詢
GET dynamic_mapping_test/_mapping
複製程式碼

mapping檔案

4.3 strict

檔案不可索引,欄位不可索引,mapping不更新

# 修改為strict
PUT dynamic_mapping_test/_mapping
{
  "dynamic":"strict"
}

# 寫入資料,http code 400
PUT dynamic_mapping_test/_doc/3
{
  "lastField":"lastValue"
}
複製程式碼

strict

顯示mapping和引數介紹

1. 如何顯示定義

PUT docName
{
    “mapping”:{
        # define your mapping here
    }
}
複製程式碼

2. 自定義mapping的建議

  • 可以參考API手冊,純手寫
  • 為了減少輸入的工作量,減少出錯概率,可以依照以下步驟
    • 建立一個臨時的index,寫入一些樣本資料
    • 通過訪問Mapping API獲得該臨時檔案的動態Mapping定義
    • 修改後使用,參考該配置建立自己的索引
    • 刪除臨時索引

3. index

  • Index屬性:控制當前欄位是否被索引,預設為true,如果設定為false,欄位不可被索引
PUT users
{
  "mappings":{
    "properties":{
      "firstName":{
        "type":"text"
      },"lastName":{
        "type":"text"
      },"mobile":{
        "type":"text","index":false
      }
    }
  }
}
複製程式碼

index

4. Index Options

對於倒排索引的建立,es提供了四種配置

  • 四種不同級別的Index Options配置,可以控制倒排索引記錄的內容
    • docs - 記錄doc id
    • freqs - 記錄doc id和term frequencies
    • positions - 記錄doc id / term frequencies / term postion
    • offsets - 記錄 doc id / term frequencies / term position / character offsets
  • Text 型別預設記錄positions,其他預設為docs
  • 記錄內容越多,佔用儲存空間越大

5. null_value

有些時候插入的欄位時null,如果需要對Null值實現搜素,可以在mapping檔案中將“null_value”指定為“NULL”

GET users/_search?q=mobile:NULL

PUT users
{
  "mappings":{
    "properties":{
      "firstName":{
        "type":"text"
      },"lastName":{
        "type":"text"
      },"mobile":{
        "type":"keyword","null_value": "NULL"
      }
    }
  }
}
複製程式碼

空值

注意:

  • 只有Keyword型別支援Null_Value

6. copy_to設定

_all在es7中已被廢棄,如要實現 _all 的功能,可用copy_to所替代

# 這個設定的意思就是說,你在索引一個檔案時候,它如果包含了firstName和lastName,都會把值拷貝到fullName上,當需要查詢的時候,就可以用fullName查詢了
PUT users
{
  "mappings":{
    "properties":{
      "firstName":{
        "type":"text","copy_to": "fullName"
      },"lastName":{
        "type":"text","copy_to": "fullName"
      }
    }
  }
}
複製程式碼

查詢時:GET users/_search?q=fullName:(Jack Ma)

copy to

特點:

  • 能滿足一些特定的搜尋需求
  • copy_to將欄位的數值拷貝到目標欄位,實現類似_all的作用
  • copy_to的目標欄位不出現在_source中

7. 陣列型別

  • Elasticsearch中不提供專門的陣列型別,但是任何欄位,都可以包含多個相同型別別的數值
PUT users/_doc/1
{
    "name":"zhangsan","interests":"reading"
}
PUT users/_doc/2
{
    "name":"lisi","interests":["reading","coding"]
}
複製程式碼

新增資料

檢視mapping檔案,可發現interests型別依然是text

檢視mapping

多欄位特性及Mapping中配置自定義Analyzer

1. 多欄位型別

比如一個預設的text欄位,es都會給它加上keyword欄位型別,但有時候會給特定欄位加上子欄位,指定analyzer

  • 多欄位特性
    • 廠商名字實現精確匹配
      • 增加一個keyword欄位
    • 使用不同的Analyzer
      • 不同語音
      • 拼音欄位的搜尋
      • 支援為搜尋和索引指定不同的analyzer

2. Exact value v.s Full Text

  • Exact value
    • 精確值,包括資料/日期/具體的一個字串(例如“Apple Store")
    • Elasticsearch中的keyword
  • Full Text
    • 全文字,非結構化的文字資料
    • Elasticsearch中的text

Exact value v.s Full Text

如圖,exact value箭頭標註的值,對待這種數值,很多情況下我們要將這種數值作為精確值來看待,不需要對它進行分詞。

但訊息中的message需要對它進行分詞處理,以查到一些關鍵詞

2.1 Exact Values不需要被分詞

在elasticsearch中,exact value不需要做分詞處理

  • Elasticsearch為每一個欄位建立一個倒排索引

    • Exact Value在索引時,不需要做特殊的分詞處理

exact value

3. 自定義分詞

  • 當Elasticsearch自帶的分詞器無法滿足時,可以自定義分詞器,通過自組合不同的元件實現
    • Character Filter
    • Tokenizer
    • Token Filter

3.1 Character Filter

  • 在Tokenizer之前對文字進行處理,例如增加刪除及替換字元,可以配置多個Character Filters,會影響倒排索引Tokenizer的positon和offset資訊

  • 一些自帶的Character Filters

    • HTML strip - 去除html標籤

      #剝除不必要的html標籤
      POST _analyze
      {
        "tokenizer": "keyword","char_filter": ["html_strip"],"text":"<b>hello world</b>"
      }
      複製程式碼
    • Mapping - 字串替換

      # 使用char filter進行替換,將中劃線替換為下劃線
      POST _analyze
      {
        "tokenizer": "standard","char_filter": [
            {
              "type":"mapping","mappings":["- => _"]
            }
          ],"text":"123-456,I-test! test-990 555-789-1114"
      }
      
      # char filter替換表情符號,如把表情替換為單詞
      POST _analyze
      {
        "tokenizer": "standard","mappings":[":) => happy",":( => sad"]
            }
          ],"text": ["I am felling :)","Felling :( today"]
      }
      複製程式碼
    • Pattern replace - 正則匹配替換

      # 正則方式替換,替換http
      GET _analyze
      {
        "tokenizer": "standard","char_filter": [
            {
              "type":"pattern_replace","pattern":"http://(.*)","replacement":"$1"
            }
          ],"text": "http://www.elastic.co"
      }
      複製程式碼

3.2 Tokenizer

  • 將原始的文字按照一定的規則,切分為詞(term or token)

  • elasticsearch內建的Tokenizers包括

    • whitespace/standard/uax_url_email/pattern(正則)/keyword(不做處理,直接索引)/path hierarchy(路徑處理)

      # tokenizer按照檔案路徑
      POST _analyze
      {
        "tokenizer": "path_hierarchy","text": "/usr/jackMa/a/b/c/d/e"
      }
      複製程式碼
  • 可以用java開發外掛,實現自己的Tokenizer(期待後續試驗····)

3.3 Token filters

  • 將Tokenizer輸出的單詞(term),進行增加,修改,刪除

  • 自帶的Token Filters

    • Lowercase / stop / synonym(新增近義詞)

      # TOKEN FILTERS
      # whitespace與stop,is去除
      GET _analyze
      {
        "tokenizer": "whitespace","filter": ["stop"],"text": ["The stone is knocked"]
      }
      
      
      # remove 加入lowercase後,小寫處理,然後The被當成stopword刪除
      GET _analyze
      {
        "tokenizer": "whitespace","filter": ["lowercase","stop"],"text": ["The man sitting on the Chair is my classmate!"]
      }
      複製程式碼

3.4 設定一個custom Analyzer

建立索引時,定義custom Analyzer

custom Analyzer

#如何自定義Analyzer

# 先刪除之前建立的
DELETE my_index
# 可以在建立索引的時候指定setting,首先我們定義分詞器,其中的char_filter和tokenizer還有filter中的English_stop都是自定義的
PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer":{
        "type":"custom","char_filter":["emoticons"],"tokenizer":"punctuation","filter":[
          "lowercase","english_stop"
          ]
      }
      },"tokenizer": {
        "punctuation":{
          "type":"pattern","pattern":"[ .,!?]"
        }
      },"char_filter": {
        "emoticons":{
          "type":"mapping","mappings":[
              ":) => _happy_",":( => _sad_"
            ]
        }
      },"filter": {
        "english_stop":{
          "type":"stop","stopwords":"_english_"
        }
      }
    }
  }
}
複製程式碼

針對建立的analyzer進行測試

# 測試自定義的analyzer
POST my_index/_analyze
{
  "analyzer": "my_custom_analyzer","text":"I'm a :) person,and you?"
}
複製程式碼

分詞結果:

analyzer result

3.4.1 方法論

自定義分析器標準格式是:

PUT /my_index
{
    "settings": {
        "analysis": {
            "char_filter": { ... custom character filters ... },//字元過濾器
            "tokenizer": { ... custom tokenizers ... },//分詞器
            "filter": { ... custom token filters ... },//詞單元過濾器
            "analyzer": { ... custom analyzers ... }
        }
    }
}
複製程式碼

例項:

PUT /my_index
{
    "settings": {
        "analysis": {
            "char_filter": {
                "&_to_and": {
                    "type": "mapping","mappings": [ "&=> and "]
            }},"filter": {
                "my_stopwords": {
                    "type": "stop","stopwords": [ "the","a" ]
            }},"analyzer": {
                "my_analyzer": {
                    "type": "custom","char_filter": [ "html_strip","&_to_and" ],"tokenizer": "standard","filter": [ "lowercase","my_stopwords" ]
            }}
}}}

# 比如自定義好的analyzer名字是my_analyzer,在此索引下的某個新增欄位應用此分析器
PUT /my_index/_mapping
{
   "properties":{
        "username":{
             "type":"text","analyzer" : "my_analyzer"
         },"password" : {
          "type" : "text"
        }
    
  }
}
# 插入資料
PUT /my_index/_doc/1
{
  "username":"The quick & brown fox ","password":"The quick & brown fox "


}
# username採用自定義分析器my_analyzer,password採用預設的standard分析器
# 驗證
GET /index_v1/_analyze
{
  "field":"username","text":"The quick & brown fox"
}

GET /index_v1/_analyze
{
  "field":"password","text":"The quick & brown fox"
}
複製程式碼

小結

本篇對elasticsearch的mapping機制進行了大篇幅的介紹和講解,具體的程式碼部分不用宕機硬背,再實際操練時候,結合 Ctrl+/ 的快捷鍵,可以快速檢視官網的檔案,互相結合,理解效率更高。


覺得不錯,請點個贊吧

zan