映射(mapping)这个概念, 类似数据库中的表结构定义 (schema) ,描述了文档包含哪些字段 、每个字段的数据类型是什么。
1.ES数据基础类型
下面是ES支持的数据类型:
- 字符串
- 主要包括: text和keyword两种类型,keyword代表精确值不会参与分词,text类型的字符串会参与分词处理。
- 数值
- 包括: long, integer, short, byte, double, float
- 布尔值
- boolean
- 时间
- date
- 数组
- 数组类型不需要专门定义,只要插入的字段值是json数组就行。
- GEO类型
- 主要涉及地理信息检索、多边形区域的表达,后面GEO相关的章节单独讲解
提示:text类型,支持全文搜索,因为text涉及分词,所以可以配置使用什么分词器,尤其涉及中文分词,这些涉及全文搜索的内容,请参考后面的全文搜索章节。
2.精确值 & 全文类型
精确值通常指的就是数值类型、时间、布尔值、字符串的keyword类型,这些不可分割的数据类型,精确值搜索效率比较高,精确值匹配类似MYSQL中根据字段搜索,例如:拿一个手机号去搜索数据,对于每一个文档的手机号字段,要么相等,要么不等,不会做别的计算。
全文类型,指的就是text类型,会涉及分词处理,存储到ES中的数据不是原始数据,是一个个关键词。
例如:我们有一个title字段,数据类型是text, 我们插入"上海复旦大学"这个字符串,经过分词处理,可能变成:"上海"、"复旦大学"、"大学" 这些关键词,然后根据这些关键词建倒排索引。
提示:实际项目中,如果不需要模糊搜索的字符类型,可以选择keyword类型,例如:手机号、email、微信的openid等等,如果选text类型,可能会出现搜出一大堆相似的数据,而且不是精确的数据。
全文搜索后面的章节单独介绍。
2.自动映射 (dynamic mapping)
前面的章节我们没有预先定义文档的映射(数据类型),也可以插入数据,因为ES默认会自动检测我们插入的数据的类型,相当于自动定义文档类型(mapping)。
自动映射的缺点就是会出现ES映射的数据类型,不是我们想要的类型,例如:手机号,我们希望是一个精确值,使用keyword类型,ES映射成为了text类型,这就不符合业务预期了。
提示:实际项目中,我们通常会预先定义好ES的映射规则,也就是类似MYSQL一样,提前定义好表结构。
3.自定义文档的数据类型
语法:
PUT /{索引名字}
{
"mappings": { // 表示定义映射规则
"properties": { // 定义属性,也就是字段类型
"字段名1": { "type": "字段类型" },
"字段名2": { "type": "字段类型" }
...(提示:最后一行末尾不要加逗号)...
}
}
}
例子:
创建一个订单索引,索引名字order
订单索引结构如下表:
字段名 | ES类型 | 说明 |
id | integer | 订单id,整数 |
shop_id | integer | 店铺Id, 整数 |
user_id | integer | 用户id, 整数 |
order_no | keyword | 订单编号,字符串类型,精确值 |
create_at | date | 订单创建时间,日期类型 |
phone | keyword | 电话号码,字符串类型,精确值 |
address | text | 用户地址,字符串类型,需要模糊搜索 |
创建ES索引:
PUT /order
{
"mappings": {
"properties": {
"id": { "type": "integer" },
"shop_id": { "type": "integer" },
"user_id": { "type": "integer" },
"order_no": { "type": "keyword" },
"create_at": { "type": "date", "format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"},
"phone": { "type": "keyword" },
"address": { "type": "text" }
}
}
}
4.查询索引的映射规则
如果想知道索引的映射规则(索引结构)是怎么样的,可以通过下面语法查询。
语法:
GET /索引名/_mapping
{
}
例子:
查询上面的订单索引的映射规则
GET /order/_mapping
{
}
输出:
{
"order" : {
"mappings" : {
"properties" : {
"address" : {
"type" : "text"
},
"create_at" : {
"type" : "date",
"format" : "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"id" : {
"type" : "integer"
},
"order_no" : {
"type" : "keyword"
},
"phone" : {
"type" : "keyword"
},
"shop_id" : {
"type" : "integer"
},
"user_id" : {
"type" : "integer"
}
}
}
}
}
5.JSON嵌套类型定义
例如下面json,我们如何在ES中定义。
{
"order_no" : "20200313120000123123",
"shop_id" : 12,
"user" : {
"id" : 100,
"nickname" : "dacui",
}
}
这里user属性是一个Object类型,json类型本身支持这种通过对象无线嵌套的结构。
ES的映射也支持Object类型,嵌套json的定义如下:
PUT /order_v2
{
"mappings": {
"properties": { // 第一层json属性定义
"order_no": { "type": "keyword" },
"shop_id": { "type": "integer" },
"user": { // user属性是Object类型,可以单独定义属性类型
"properties" : { // 第二层user对象的属性定义
"id": { "type": "integer" },
"nickname": { "type": "text" }
}
}
}
}
}
通过上面例子,如果属性是Object类型只要使用properties单独定义即可支持多层Json对象嵌套。