一架梯子,一头程序猿,仰望星空!

Elasticsearch 数据类型和映射


映射(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类型说明
idinteger订单id,整数
shop_idinteger店铺Id, 整数
user_idinteger用户id, 整数
order_nokeyword订单编号,字符串类型,精确值
create_atdate订单创建时间,日期类型
phonekeyword电话号码,字符串类型,精确值
addresstext用户地址,字符串类型,需要模糊搜索

创建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对象嵌套。