Elasticsearch建立索引和對映結構詳解
前言
這篇文章詳細介紹瞭如何建立索引和某個型別的對映。
下文中[address]指代elasticsearch伺服器訪問地址(http://localhost:9200)。
1 建立索引
1.1 簡單建立語句
curl -XPUT [address]/blog
1.2 帶引數的建立語句
curl -XPUT [address]/blog/ -d '{
"settings":{
"number_of_shards":1, //設定分片數量
"number_of_replicas":2, //設定副本數量
//自定義索引預設分析器
"index":{
"analysis":{
"analyzer":{
"default":{
"tokenizer":"standard", //分詞器
"filter":[ //過濾器
"asciifolding",
"lowercase",
"ourEnglishFilter"
]
}
},
"filter":{
"ourEnglishFilter":{
"type":"kstem"
}
}
}
}
}
}'
2 建立對映(扁平結構)
2.1 簡單建立語句
curl -XPUT [address]/blog/_mapping/article?pretty -d '{
"properties":{
"id":{"type":"long"},
"name":{"type":"string"},
"published":{"type":"date"}
}
}'
2.2 帶引數的建立語句
curl -XPUT [address]/blog/_mapping/article?pretty -d '{
"dynamic":"false", //關閉自動新增欄位,關閉後索引資料中如果有多餘欄位不會修改mapping,預設true
"_id":{"index":"not_analyzed","store":"no"}, //設定文件識別符號可以被索引,預設不能被索引。可以設定為"_id":{"path":"book_id"},這樣將使用欄位book_id作為識別符號
"_all":{"enabled":"false"}, //禁用_all欄位,_all欄位包含了索引中所有其他欄位的所有資料,便於搜尋。預設啟用
"_source":{"enabled":"false"}, //禁用_source欄位,_source欄位在生成索引過程中儲存傳送到elasticsearch的原始json文件。elasticsearch部分功能依賴此欄位(如區域性更新功能),因此建議開啟。預設啟用
"_index":{"enabled":"true"}, //啟用_index欄位,index欄位返回文件所在的索引名稱。預設關閉。
"_timestamp":{"enabled":"true","index":"not_analyzed","store":"true","format":"YYYY-mm-dd"}, //啟用時間戳並設定。時間戳記錄文件索引時間,使用區域性文件更新功能時,時間戳也會被更新。預設未經分析編入索引但不儲存。
"_ttl":{"enabled":"true","default":"30d"}, //定義文件的生命週期,週期結束後文檔會自動刪除。
"_routing":{"required":"true","path":"name"} //指定將name欄位作為路由,且每個文件必須指定name欄位。
"properties":{
"id":{
"type":"long",
//公共屬性
"store":"yes",
//數值特有屬性
"precision_step":"0" //指定為該欄位生成的詞條數,值越低,產生的詞條數越多,查詢會更快,但索引會更大。預設4
},
"name":{
"type":"string",
//公共屬性
"store":"yes",
"index":"not_analyzed", //analyzed:編入索引供搜尋、no:不編入索引、not_analyzed(string專有):不經分析編入索引
"boost":"1", //文件中該欄位的重要性,值越大表示越重要,預設1
"null_value":"jim", //當索引文件的此欄位為空時填充的預設值,預設忽略該欄位
"include_in_all":"xxx" //此屬性是否包含在_all欄位中,預設為包含
//字串特有屬性
"analyzer":"xxx", //定義用於索引和搜尋的分析器名稱,預設為全域性定義的分析器名稱。可以開箱即用的分析器:standard,simple,whitespace,stop,keyword,pattern,language,snowball
"index_analyzer":"xxx", //定義用於建立索引的分析器名稱
"search_analyzer":"xxx", //定義用於搜尋時分析該欄位的分析器名稱
"ignore_above":"xxx" //定義欄位中字元的最大值,欄位的長度高於指定值時,分析器會將其忽略
},
"published":{
"type":"date",
//公共屬性
"store":"yes",
//日期特有屬性
"precision_step":"0", //指定為該欄位生成的詞條數,值越低,產生的詞條數越多,查詢會更快,但索引會更大。預設4
"format":"YYYY-mm-dd" //指定日期格式,預設為dateOptionalTime
}
}
}'
3 建立對映(非扁平結構)
在第二章我們講解了建立對映的語句。所建立的是簡單的扁平結構對映。這一章我們看看如何建立非扁平結構對映。
3.1 樹形結構
樹形結構的作用是為索引層級路徑提供便利。例如一家汽車店中可能會有如下路徑:/cars/passenger/sport、/cars/passenger/camper、/cars/delivery_truck,我們想在搜尋cars的時候返回三條記錄,搜尋cars/passenger的時候返回前兩條記錄,可以這樣建立對映:
curl -XPUT [address]/path -d '{
"settings":{
//定義一個路徑分析器
"index":{
"analysis":{
"analyzer":{
"path_analyzer":{"tokenizer":"path_hierarchy"}
}
}
}
},
"mappings":{
"category":{
"properties":{
"category":{
"type":"string",
"fields":{
//定義多欄位物件,使用category.path進行查詢時將啟用路徑分析匹配指定路徑下的所有文件,使用category.name進行查詢時將精確匹配指定路徑的文件,略過結構更深的文件。
"name":{"type":"string","index":"not_analyzed"},
"path":{"type":"string","analyzer":"path_analyzer","store":true}
}
}
}
}
}
}'
3.2 物件
先執行curl –XPUT [address]/extend_mapping,建立extend_mapping索引
建立一個帶有物件屬性author的型別book:
curl –XPUT [address]/extend_mapping/_mapping/book –d ‘{
"properties":{
"title":{"type":"string","index":"not_analyzed"},
"author":{
"type":"object",
"properties":{
"firstName":{"type":"string","index":"not_analyzed"},
"lastName":{"type":"string","index":"not_analyzed"}
}
}
}
}’
3.3 巢狀物件
巢狀物件允許我們連線一個主文件和多個附屬文件,下面通過一個例子來說明巢狀物件的應用場景。
現在我們有一個服裝店,需要設計一個數據結構來儲存服裝店裡的服裝資訊。例如現在有一種名字為”cloth”的服裝,這件服裝現有兩件存貨,一件XXL的紅色和一件XL的黑色,請設計一個數據結構來儲存該服裝資訊。
我們可能會把資料結構設計成這樣:
{
“name”:”cloth”,
“variation”:[
{“size”:”XXL”,”color”:”red”},
{“size”:”XL”,”color”:”black”}
]
}
直觀的來看,這個資料結構是能夠表現我們所描述的服裝資訊的,我們依據這個結構建立以下對映(傳送rest請求語句略):
{
"properties":{
"name":{"type":"string","index":"not_analyzed"},
"variation":{
"properties":{
"size":{"type":"string","index":"not_analyzed"},
"color":{"type":"string","index":"not_analyzed"}
}
}
}
}
建立對映後索引以下資料:
{
"name": "cloth",
"variation": [
{
"size": "XXL",
"color": "red"
},
{
"size": "XL",
"color": "black"
}
]
}
下面我們查詢一下我們的服裝資訊庫,看看是否有尺寸為XXL,顏色為black的服裝:
{
"filter": {
"and": [
{
"term": {
"variation.size": "XXL"
}
},
{
"term": {
"variation.color": "black"
}
}
]
}
}
出乎意料的是,該查詢返回了結果:
{
......(此處資訊略去)
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "extend_mapping",
"_type": "unnested_cloth",
"_id": "AVACnlA-8eAUpvGq_eZa",
"_score": 1,
"_source": {
"name": "cloth",
"variation": [
{
"size": "XXL",
"color": "red"
},
{
"size": "XL",
"color": "black"
}
]
}
}
]
}
}
這與我們的預期不符,我們只有XXL紅色和XL黑色兩件服裝,並沒有所查詢的XXL黑色服裝。
這是因為按照我們之前定義的對映結構,尺寸資訊(“size”:”XXL”,”size”:”XL”)和顏色資訊(“color”:”red”,”color”:”black”)都存在同一個文件中,ES無法將XXL和red、XL和black繫結在一起,因此在查詢時造成了混淆。
解決的方法就是使用巢狀物件,將variation物件的型別指定為巢狀:
重新建立以下對映:
{
"properties":{
"name":{"type":"string","index":"not_analyzed"},
"variation":{
“type”:”nested”,
"properties":{
"size":{"type":"string","index":"not_analyzed"},
"color":{"type":"string","index":"not_analyzed"}
}
}
}
}
索引之前的測試資料:
{
"name": "cloth",
"variation": [
{
"size": "XXL",
"color": "red"
},
{
"size": "XL",
"color": "black"
}
]
}
現在我們通過”type”:”nested”將variation物件指定為巢狀物件,需要注意的是,如果我們對新對映執行類似之前的查詢,將無任何文件返回。因為對於巢狀對映,必須要使用專用的查詢語法,如下:
{
"filter": {
"nested": {
"path": "variation",
"filter": {
"and": [
{
"term": {
"variation.size": "XXL"
}
},
{
"term": {
"variation.color": "black"
}
}
]
}
}
}
}
這次的查詢如我們的預期,沒有返回結果。這是因為使用巢狀結構後,當我們索引測試資料時,事實上ES生成了3個文件,一個cloth的主文件,和兩個variation物件的附屬文件,這樣就分離儲存了兩件服裝存貨,避免了尺寸和顏色的混淆。