015.Elasticsearch Mapping介绍

1. mapping解析

1.1 mapping是什么

  • mapping,就是index的type的元数据,每个type都有一个自己的mapping,决定了这个type的数据类型,建立倒排索引的行为,还有进行搜索的行为,可以类比关系型数据库,ES给某个index的type设置mapping,就相当于给一张表定义各个字段的名称和数据类型
  • 往一个不存在的index里面插入数据,es会自动建立该index,同时建立type以及对应的mapping
  • mapping中就自动定义了每个field的数据类型
  • es可以进行dynamic mapping,自动建立mapping,包括自动设置数据类型;也可以提前手动创建index和type的mapping,对各个field进行设置,包括数据类型,包括索引行为,包括分词器,等等

1.2 创建mapping

为空index设置mapping,index需要提前创建好

# ES6.x需要在_mapping后指定type,type可以自动创建
curl -X PUT "node01:9200/nba/_mapping/_doc" -H 'Content-Type:application/json' -d'
{
    "properties": {
        "name": {
            "type": "text"
        },
        "team_name": {
            "type": "text"
        },
        "position": {
            "type": "keyword"
        },
        "play_year": {
            "type": "keyword"
        },
        "jerse_no": {
            "type": "keyword"
        }
    }
}
'

# ES7.x
curl -X PUT "node01:9200/nba/_mapping" -H 'Content-Type:application/json' -d'
{
    "properties": {
        "name": {
            "type": "text"
        },
        "team_name": {
            "type": "text"
        },
        "position": {
            "type": "keyword"
        },
        "play_year": {
            "type": "keyword"
        },
        "jerse_no": {
            "type": "keyword"
        }
    }
}
'

创建index的时候设置mapping

# ES6.x
curl -X PUT "node01:9200/index4" -H 'Content-Type:application/json' -d'
{
  "mappings": {
    "test_type": {
      "properties": {
        "id": {
          "type": "text"
        }
      }
    }
  }
}
'
# ES7.x
curl -X PUT "node01:9200/index4" -H 'Content-Type:application/json' -d'
{
  "mappings": {
    "properties": {
      "id": {
      "type": "text"
      }
    }
  }
}
'

1.3 查看mapping

查看某个索引的mapping

# ES6.0需要指定type
curl -X GET "node01:9200/nba/_mapping/_doc"
# ES7.0不需要指定type
curl -X GET "node01:9200/nba/_mapping"

{
    "nba": {
        "mappings": {
            "_doc": {
                "properties": {
                    "jerse_no": {
                        "type": "keyword"
                    },
                    "name": {
                        "type": "text"
                    },
                    "play_year": {
                        "type": "keyword"
                    },
                    "position": {
                        "type": "keyword"
                    },
                    "team_name": {
                        "type": "text"
                    }
                }
            }
        }
    }
}

查看多个索引或者type的mapping

  • ES5.x:一个index可以有多个type

    • 查看一个index的一个type的mapping:curl -X GET "ip:9200/index/_mapping/type"

    • 查看一个index的多个type的mapping:curl -X GET "ip:9200/index/_mapping/type1,type2"

    • 查看一个index的所有type的mapping:curl -X GET "ip:9200/index/_mapping"

    • 查看多个index的多个type的mapping:curl -X GET "ip:9200/index1,index2/_mapping/type1,type2"

      这时会做笛卡尔积,把所有可以查到的index的type的mapping返回

    • 可以使用通配符:

      curl -X GET "ip:9200/index*,test*/_mapping"

      curl -X GET "ip:9200/*1,*2/_mapping/type*"

      使用通配符也会做笛卡尔积,所有满足通配符的index和type,只要可以这个index有这个type就会查出mapping并返回

  • ES6.x:一个index只能有一个type

    • 查看一个index的mapping

      curl -X GET "ip:9200/index/_mapping/type"

      curl -X GET "ip:9200/index/_mapping"

      由于只有一个type,所以这两条查询本质上是一样的

    • 查看多个index的mapping

      curl -X GET "ip:9200/index1,index2/_mapping/type1,type2"

      curl -X GET "ip:9200/test*/_mapping"

      同样,也是做笛卡尔积,只要可以查出来就返回

  • ES7.x:没有type的概念

    • 查看多个index的mapping:

      curl -X GET "ip:9200/index1,index2/_mapping"

      curl -X GET "ip:9200/test*/_mapping"

  • ES6.x测试

    index和type对应关系:

    test_index1/test_type1

    test_index2/test_type2

    curl -X GET "node01:9200/test_index1/_mapping"
    {
      "test_index1":{
          "mappings":{
              "test_type1":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      }
    }
    
    curl -X GET "node01:9200/test_index1/_mapping/test_type1"
    {
      "test_index1":{
          "mappings":{
              "test_type1":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      }
    }
    
    curl -X GET "node01:9200/test_index1,test_index2/_mapping"
    { "test_index2":{
          "mappings":{
              "test_type2":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      },
      "test_index1":{
          "mappings":{
              "test_type1":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      }
    }
    
    curl -X GET "node01:9200/test_index1,test_index2/_mapping/test_type1"
    {
      "test_index1":{
          "mappings":{
              "test_type1":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      }
    }
    
    curl -X GET "node01:9200/test_index1,test_index2/_mapping/test_type2"
    {
      "test_index2":{
          "mappings":{
              "test_type2":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      }
    }
    
    curl -X GET "node01:9200/test_index1,test_index2/_mapping/test_type1,test_type2"
    { "test_index2":{
          "mappings":{
              "test_type2":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      },
      "test_index1":{
          "mappings":{
              "test_type1":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      }
    }
    
    curl -X GET "node01:9200/test_index*,index*/_mapping"
    {
      "index3":{
          "mappings":{}
      },
      "test_index":{
          "mappings":{
              "test_type":{
                  "properties":{
                      "message":{
                          "type":"text",
                          "fields":{
                              "keyword":{
                                  "type":"keyword",
                                  "ignore_above":256
                              }
                          }
                      },
                      "user":{
                          "type":"text",
                          "fields":{
                              "keyword":{
                                  "type":"keyword",
                                  "ignore_above":256
                              }
                          }
                      }
                  }
              }
          }
      },
      "test_index2":{
          "mappings":{
              "test_type2":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      },
      "index2":{
          "mappings":{}
      },
      "index1":{
          "mappings":{
              "_doc":{
                  "properties":{
                      "jerse_no":{
                          "type":"keyword"
                      },
                      "name":{
                          "type":"text"
                      },
                      "play_year":{
                          "type":"keyword"
                      },
                      "position":{
                          "type":"keyword"
                      },
                      "team_name":{
                          "type":"text"
                      }
                  }
              }
          }
      },
      "test_index1":{
          "mappings":{
              "test_type1":{
                  "properties":{
                      "name":{
                          "type":"text"
                      }
                  }
              }
          }
      }
    }
    

查看全部索引的mapping

  • ES5.x/ES6.x

    • 查看所有的index的所有的type的mapping

      curl -X GET "ip:9200/_mapping

    • 查看所有的index的某些type的mapping,没有这个type的index,就不返回它的mapping

      curl -X GET "ip:9200/_all/_mapping/type1,type2

  • ES7.x

    curl -X GET "ip:9200/_mapping"

    curl -X GET "ip:9200/_all/_mapping"

  • ES6.x测试

  curl -X GET node01:9200/_all/_mapping/test_type1,test_type2
{
      "test_index2": {
          "mappings": {
              "test_type2": {
                  "properties": {
                      "name": {
                          "type": "text"
                      }
                  }
              }
          }
      },
      "test_index1": {
          "mappings": {
              "test_type1": {
                  "properties": {
                      "name": {
                          "type": "text"
                      }
                  }
              }
          }
      }
  }
  
  curl -X GET node01:9200/_mapping
  {
      "index1": {
          "mappings": {
              "_doc": {
                  "properties": {
                      "jerse_no": {
                          "type": "keyword"
                      },
                      "name": {
                          "type": "text"
                      },
                      "play_year": {
                          "type": "keyword"
                      },
                      "position": {
                          "type": "keyword"
                      },
                      "team_name": {
                          "type": "text"
                      }
                  }
              }
          }
      },
      "index2": {
          "mappings": {}
      },
      "test_index2": {
          "mappings": {
              "test_type2": {
                  "properties": {
                      "name": {
                          "type": "text"
                      }
                  }
              }
          }
      },
      "test_index": {
          "mappings": {
              "test_type": {
                  "properties": {
                      "message": {
                          "type": "text",
                          "fields": {
                              "keyword": {
                                  "type": "keyword",
                                  "ignore_above": 256
                              }
                          }
                      },
                      "user": {
                          "type": "text",
                          "fields": {
                              "keyword": {
                                  "type": "keyword",
                                  "ignore_above": 256
                              }
                          }
                      }
                  }
              }
          }
      },
      "test2": {
          "mappings": {}
      },
      "nba": {
          "mappings": {
              "_doc": {
                  "properties": {
                      "jerse_no": {
                          "type": "keyword"
                      },
                      "name": {
                          "type": "text"
                      },
                      "play_year": {
                          "type": "keyword"
                      },
                      "position": {
                          "type": "keyword"
                      },
                      "team_name": {
                          "type": "text"
                      }
                  }
              }
          }
      },
      "test_index1": {
          "mappings": {
              "test_type1": {
                  "properties": {
                      "name": {
                          "type": "text"
                      }
                  }
              }
          }
      },
      "test1": {
          "mappings": {}
      },
      "index3": {
          "mappings": {}
      }
  }

1.4 修改mapping

# 只能新增field,不能修改已有field的数据类型
curl -X PUT "node01:9200/test_index1/_mapping/test_type1" -H 'Content-Type:application/json' -d'
{
    "properties": {
        "id": {
            "type": "text"
        }
    }
}
'

# 如果要写上原有的字段,一定要和以前的数据类型一样
curl -X PUT "node01:9200/test_index1/_mapping/test_type1" -H 'Content-Type:application/json' -d'
{
    "properties": {
        "id": {
            "type": "text"
        },
        "name": {
            "type": "text"
        }
    }
}
'

# EX7.x不需要指定type
curl -X PUT "node01:9200/test_index1/_mapping" -H 'Content-Type:application/json' -d'
{
    "properties": {
        "id": {
            "type": "text"
        }
    }
}
'

1.5 mapping其他常用属性总结

PUT index_name
{
  "mappings": {
    "type_name": {
      "_source": {
          "enabled": true
      },
      "_all": {
          "enabled": true
      },
      "dynamic": "strict",
      "date_detection": false,
      "properties": {
          "field_name": {
              "type": "type_name", # 指定field的数据类型
              "analyzer": "analyzer_name", # 指定field的分词器
              "include_in_all": false # 这个field是否包含在_all field中
          }
      }
    }
  }
}
  • _all:是否允许将所有field的值拼接在一起,作为一个_all field,建立索引,这样在没有指定任何field进行搜索时,就是使用_all field在搜索,默认true

  • _source:是否保存原始数据,开启后可以带来以下好处,默认开启:

    (1) ES搜索默认只会返回id,当_source=false时,需要根据返回的id再去查询一次完整的数据,_source=true时,可以直接拿到完整的数据

    (2) ES的更新操作基于_source实现

    (3) 索引的重建必须要有_source

    (4) 可以基于_source自定义返回的field

    (5) 方便于debug

    如果不需要上述好处,可以禁用_source

  • dynamic:自动判断数据类型的策略

    true:如果document的某个field没有提前设置其类型,就自动识别

    false:如果document的某个field没有提前设置其类型,就忽略此field,数据可以插入进去,但在mapping中查不到此field的描述

    strict:如果document的某个field没有提前设置其类型,直接报错

  • date_detection:默认会自动按照一定格式识别date,比如yyyy-MM-dd,这样可能会导致一些问题,比如某个field先插入的值为"2017-01-01",那么这个field会自动识别为date类型,后面再插入一个其他类型,例如字符串"hello world"之类的值,就会报错。可以关闭date_detection,如果有需要,手动指定某个field为date类型就可以避免此类问题。

1.6 mapping模板

# 定制化type级别的mapping模板
# 此模板的意思:
# 假如插入的数据的field的名称中包含"title"这个单词,就将其value设置为text类型,且使用ik_max_word分词器分词
# 其他的field则使用dynamic设置的策略来进行数据类型和分词器的初始化
PUT index_name
{
  "mappings": {
    "type_name": {
      "dynamic_templates": [
        {
          "template_name": {
            "match": "*title*",
            "match_mapping_type": "text",
            "mapping": {
              "type": "text",
              "analyzer": "ik_max_word"
            }
          }
        }
      ] 
    }
  }
}

# 定制化index级别的mapping模板
# 此模板的意思:
# blog这个这个type的_all=true,其他type的_all=false
PUT my_index
{
  "mappings": {
    "_default_": {
      "_all": { "enabled": false}
    },
    "blog": {
      "_all": { "enabled": true}
    }
  }
}

2.ES常用的数据类型

2.1 核心数据类型

  • 字符串

    • text:用于全文检索,该类型的字段将通过分词器进行分词
    • keyword:不分词,只能搜索该字段的完整的值
  • 数值型

    • byte

    • short

    • integer

    • long

    • float

    • half_float

    • scaled_float

    • double

  • 布尔

    • boolean
  • 二进制

    • binary:该类型的字段把值当作经过BASE64编码的字符串,默认不存储且不可搜索
  • 日期

    • date,定义的类型是date,实际需要传入一个字符串或者long值,只要这个字符串满足日期格式,例如"yyyy-MM-dd"或者"yyyy/MM/dd HH:mm:ss",或者这个long值是一个时间戳,就认为是date类型
  • 范围类型

    • integer_range、double_range等数值范围

    • date_range

    • 例如定义age是一个integer_range

      {
          "gte": 20,
          "lte": 40
      }
      

2.2 复杂数据类型

  • Object:对象类型,可以嵌套
  • Array:ES中没有专有的数组类型,使用[]直接定义即可,数组中的元素必须都是同一类型
    • 字符串数组:["hello", "world"]
    • 整数数组:[0, 1]
    • 对象数组:[{"name": "Tom", "age": 12}, {"name": "Jerry", "age": 20}]

3. type底层存储

type,是一个index中用来区分类似的数据的,类似的数据,但是可能有不同的fields,而且有不同的属性来控制索引建立和分词等功能,ES底层的lucene是没有type的概念的,在document中,实际上将type作为一个document的特殊field来存储,即_type,ES通过_type来进行type的过滤和筛选,一个index中的多个type,实际上是放在一起存储的,因此一个index下,type名相同的document,其数据结构和其他设置一定是一样的。

例如以下index:

# 注意:此语句在ES6.x和ES7.x是不能执行的,因为ES6.x只能有一个type,ES7.x移除了type的概念
PUT /my_index
{
  "mappings": {
    "my_type1": {
      "properties": {
        "name": {
          "type": "keyword"
        },
        "age": {
          "type": "long"
        }
      }
    },
    "my_type2": {
      "properties": {
        "name": {
          "type": "keyword"
        },
        "sex": {
          "type": "long"
        }
      }
    }
  }
}

# 插入两条document
PUT /my_index/my_type1/1
{
  "name": "Tom",
  "age": 20
}

PUT /my_index/my_type2/2
{
  "name": "Jerry",
  "sex": 1
}

# 实际的存储为:
{
  "_type": "my_type1"
  "name": "Tom",
  "age": 20,
  "sex": null
}
{
  "_type": "my_type2"
  "name": "Jerry",
  "age": null,
  "sex": 1
}

说明:如果使用ES5.x版本,且在同一个index中使用多个type,那么将类似结构的type放在一个index下,这些type应该有多个field是相同的,假如两个type的field完全不同,却放在一个index下,那么就每条数据都会有很多的空值,会带来严重的性能问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354