Elasticsearch系列---定製mapping

概要

本篇接着前一篇內容,繼續介紹mapping信息,重點傾向於自定義mapping、自定義對象以及數組集合類的底層結構。

自定義mapping

上一篇文章介紹的都是Elasticsearch的自動mapping,我們在創建索引時,可以先指定好mapping的信息,還是以music索引爲例:

PUT /music
{
  "mappings": {
    "children": {
      "properties": {
        "content": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "language": {
          "type": "keyword"
        },
        "length": {
          "type": "long"
        },
        "likes": {
          "type": "long"
        },
        "name": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      }
    }
  }
}

共包含name,content,language,length,likes 5個field,這裏我們把language field的type指定爲keyword,這個field無需分詞,精確匹配即可。

修改mapping

我們可以在創建索引時指定mapping信息,也可以爲索引增加新的field時指定mapping信息,但是已經存在的field,我們不能修改其mapping,否則會報錯,例如:
我們爲music索引增加一個author field,並指定其type爲text,analyzer、search_analyzer均爲english

PUT /music/_mapping/children
{
  "properties" : {
    "author" : {
      "type" : "text",
      "index": true, 
      "analyzer": "english",
      "search_analyzer": "english"
    }
  }
}

如果嘗試修改一下已經存在的field,如name字段,則會提示報錯:
請求:

PUT /music/_mapping/children
{
  "properties" : {
    "name" : {
      "type" : "text",
      "index": true, 
      "analyzer": "english",
      "search_analyzer": "english"
    }
  }
}

報錯信息:

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "Mapper for [name] conflicts with existing mapping in other types:\n[mapper [name] has different [analyzer]]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "Mapper for [name] conflicts with existing mapping in other types:\n[mapper [name] has different [analyzer]]"
  },
  "status": 400
}

複雜數據類型底層結構

前面提及的mapping信息,都是針對基礎數據類型的,我們知道Elasticsearch是面向對象的分佈式存儲文檔系統,肯定會遇到各種各樣的自定義對象、集合數組、嵌套對象等數據結構,ES是如何支持、處理這些複雜對象類型的呢?

  1. 數組、集合類

集合在JSON串中與數組等同,均可以認爲是數組類型,在Elasticsearch中對數組沒有特殊的映射需求,建立索引時與text是一樣的,也是分詞處理後得到多個詞條,建立倒排索引。

有一點要注意的是數組內的元素,數據類型要一致,比如都是字符器,都是日期,或都是數值,不能混搭,自動mapping是以第1位元素來決定type的,如果混搭,數組內與第1位元素類型不一致的元素,索引時會報錯。

  1. Null類型
    底層的Lucene不能存儲null值,null類型的不會被索引:
"null_value":               null,
"empty_array":              [],
"array_with_null_value":    [ null ]
  1. 複雜對象
    複雜對象一般有一層或多層嵌套,即對象中的屬性,類型也是對象,有時候還混搭着數組一類的,舉個例子:
{
  "address": {
    "country": "CN",
    "province": "GD",
    "city": "SZ"
  },
  "name": "Herry",
  "age": 28,
  "birth_date": "1992-04-29"
}

人員信息除了姓名年齡外,還有地址信息address,而address屬性本身也是個對象,裏面包含了country、province、city三個屬性,查看它的mapping信息,也是呈嵌套結構(內容有刪除,只保留體現層級的屬性):

{
  "person": {
    "mappings": {
      "info": {
        "properties": {
          "address": {
            "properties": {
              "city": {
                "type": "text"
              },
              "country": {
                "type": "text"
              },
              "province": {
                "type": "text"
              }
            }
          }
        }
      }
    }
  }
}

Elasticsearch在存儲層級結構的數據對象時,會做一些扁平化處理,Luence文檔是一組KV結構的列表,把上述的數據存儲成這樣:

{
  "address.country": "CN",
  "address.province": "GD",
  "address.city": "SZ",
  "name": "Herry",
  "age": 28,
  "birth_date": "1992-04-29"
}

所以最終想要根據address下的country作爲條件進行查詢,應該這麼寫:

GET /person/info/_search
{
  "query": {
    "match": {
      "address.country": "CN"
    }
  }
}
  1. 數組內的複雜對象
    數組內的元素如果是基礎數據類型還好說,只要求數組內所有元素類型一致即可,如果裏面的元素是一個對象,又是如何索引的呢?
    假如一個數組結構是這樣的:
{
    "likes": [
        { "name": "Three Zhang", "datetime": "2019-12-01 08:58:12"},
        { "name": "Four Lee", "datetime": "2019-12-01 09:12:23"},
        { "name": "Five Wang", "datetime": "2019-12-01 09:15:58"}
    ]
}

經過扁平化處理(由列變成行),得到的數據將會是這樣:

{
    "likes.name": ["Three Zhang","Four Lee","Five Wang"],
    "likes.datetime": ["2019-12-01 08:58:12","2019-12-01 09:12:23","2019-12-01 09:15:58"],
}

發現什麼問題沒?這樣處理完了之後,原本對象之間的關聯性就沒有了,數組內只是一堆無序的元素,如果要查詢"Three Zhang在2019-12-01 09:00:00之後有沒有給我點過贊"這樣的組合條件查詢,是會出現一條查詢記錄的,這跟預期的結果不同,顯然是錯了。

留意一下這個問題,數組內的元素是對象類型時,需要聲明爲nested類型,才能得到預期的查詢效果,nested類型在後續會有介紹。

小結

本篇主要對mapping的內容進行一些補充,並簡單描述了各種複雜對象的底層存儲結構,需要注意的是數組內的對象處理,需要聲明爲nested才能得到正確的結果。

專注Java高併發、分佈式架構,更多技術乾貨分享與心得,請關注公衆號:Java架構社區
Java架構社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章