Dynamic Mapping
什么是Dynamic Mapping
在写入文档时候,如果所有不存在,会自动创建索引。
Dynamic Mapping的机制,使得我们无需手动自定义Mappings。Elasticsearch会自动根据文档信息,推算出自动的类型。
但是有时候回推算不正确,例如地理位置信息,当类型如果不对时,会导致一些功能无法正常运行,例如Range查询。
类型的自动识别
JSON类型 | Elasticsearch类型 |
---|---|
字符串 | 1.匹配日期格式,设置成Date 2.配置数字设置为float/long,配置默认关闭 3.设置为Text,并且增加keyword子自动 |
布尔值 | boolean |
浮点数 | float |
整数 | long |
对象 | object |
数组 | 由第一个非空数值的类型所决定 |
空值 | 忽略 |
查询Mapping
kibana执行以下:
get movies/_mappings
返回结果:
{
"movies" : {
"mappings" : {
"properties" : {
"@version" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"genre" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"id" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"year" : {
"type" : "long"
}
}
}
}
}
更改Mapping字段类型
有两种情况:
情况 | |
---|---|
新增字段 | 1.Dynamic设为true,一旦有新增字段的文档写入,Mapping也同时更新 2.Dynamic设置为false,Mapping不会被更新,新增字段的数据无法被索引,但是信息会出现在_source中 3.Dynamic设置成Strict,文档写入失败 |
已有字段 | 一旦已经有数据写入,就不再支持修改字段定义,Lucene实现的倒排序索引,一旦生成后,就不允许修改 |
原因:
- 如果修改了字段的数据类型,会导致已被索引的属于无法被搜索
- 但是如果是新增的字段,就不会有这样的影响
Dynamic 使用
- true:遇到陌生字段 进行dynamic mapping
- false:遇到陌生字段,忽略
- strict:遇到陌生字段,报错
put mapping_test
{
"mappings":{
"dynamic":"strict",
"properties":{
"title":{
"type":"text"
},
"address":{
"type":"object",
"dynamic":"true"
},
"year":{
"type":"long"
}
}
}
}
查询mapping
get mapping_test/_mappings
返回结果:
{
"mapping_test" : {
"mappings" : {
"dynamic" : "strict",
"properties" : {
"address" : {
"type" : "object",
"dynamic" : "true"
},
"title" : {
"type" : "text"
},
"year" : {
"type" : "long"
}
}
}
}
}
数据类型
Elasticsearch支持多种数据类型,这些数据类型可以分为两类:核心数据类型和复杂数据类型。
字符串(String)
字符串(String):字符串是最常用的数据类型,可以用于存储文本信息。Elasticsearch提供了两种特殊的字符串类型:text和keyword。
- text:text类型的字符串主要用于全文搜索,它会使用分词器对字符串进行分词,然后将分词后的词项存储在索引中。这使得text类型的字符串可以进行模糊匹配、短语搜索等高级搜索功能。然而,由于进行了分词,text类型的字符串不能直接用于排序和聚合操作。
- keyword:keyword类型的字符串主要用于精确匹配,它不会使用分词器对字符串进行分词,而是直接将原始字符串存储在索引中。这使得keyword类型的字符串可以直接用于排序和聚合操作。然而,由于没有进行分词,keyword类型的字符串不能进行模糊匹配和短语搜索等高级搜索功能。
建立mappings例子:
PUT /my_index
{
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "standard"
},
"email": {
"type": "keyword"
}
}
}
}
整数(Integer)
整数(Integer):整数类型用于存储整数值,如年龄、分数等。Elasticsearch支持的有符号整数类型包括:
- byte:8位有符号整数,范围是-128到127。
- short:16位有符号整数,范围是-32768到32767。
- integer:32位有符号整数,范围是-2147483648到2147483647。
- long:64位有符号整数,范围是-9223372036854775808到9223372036854775807。
建立mappings例子:
PUT /my_index
{
"mappings": {
"properties": {
"age": {
"type": "integer"
}
}
}
}
浮点数(Floating point)
浮点数(Floating point):浮点数类型用于存储小数值,如价格、重量等。Elasticsearch支持的浮点数类型包括:
- float:32位浮点数,精度较低,适合存储较大的数值范围。
- double:64位浮点数,精度较高,适合存储较小的数值范围。
建立mappings例子:
PUT /my_index
{
"mappings": {
"properties": {
"price": {
"type": "double"
}
}
}
}
日期(Date)
日期(Date):日期类型用于存储日期和时间信息。Elasticsearch支持多种日期格式,包括ISO 8601格式和其他自定义格式。日期类型还可以存储时间戳,表示从1970年1月1日00:00:00 UTC到当前时间的毫秒数。
建立mappings例子:
PUT /my_index
{
"mappings": {
"properties": {
"birthday": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
}
}
}
}
# 写入数据
POST /my_index/_doc/1
{
"date": "2023-04-05T14:12:12Z"
}
POST /my_index/_doc/2
{
"date": 1649168857000
}
date
字段指定了两个格式:
strict_date_optional_time
:这是一个内置的格式,它支持类似2023-04-05T14:12:12Z
的 ISO 8601 兼容日期。epoch_millis
:代表从 Unix epoch (1970年1月1日 UTC) 开始的毫秒数,例如1649168857000
。
查询日期
对日期字段进行查询时,你也可以使用多种格式来指定日期值。
GET /my_index/_search
{
"query": {
"range": {
"date": {
"gte": "2023-04-05T00:00:00Z",
"lte": "now"
}
}
}
}
在上面的查询中,我们使用 range
查询来寻找日期在 2023-04-05T00:00:00Z
到当前时间之间的文档。
自定义日期格式
可以指定自定义的日期格式,使用 Java 的 SimpleDateFormat
风格的日期格式:
PUT /my_custom_index
{
"mappings": {
"properties": {
"custom_date": {
"type": "date",
"format": "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd"
}
}
}
}
POST /my_custom_index/_doc/1
{
"custom_date": "2023/04/05 14:12:12"
}
POST /my_custom_index/_doc/2
{
"custom_date": "2023/04/05"
}
这个自定义格式接受两种日期格式:完整的日期时间和只有日期的字符串。当然,Elasticsearch 还支持其他更多的内置格式和自定义格式,你可以根据你的需求来指定。
布尔值(Boolean)
布尔值(Boolean):布尔值类型用于存储真/假值,如是否可用、是否已读等。
建立mappings例子:
PUT /my_index
{
"mappings": {
"properties": {
"is_active": {
"type": "boolean"
}
}
}
}
二进制(Binary)
二进制(Binary):二进制类型用于存储二进制数据,如图片、音频、视频等。
建立mappings例子:
PUT /my_index
{
"mappings": {
"properties": {
"photo": {
"type": "binary"
}
}
}
}
嵌套对象
在Elasticsearch中,嵌套对象是一种复杂的数据类型,它允许你将一个对象嵌入到另一个对象中。这种数据类型非常适合用于表示具有层次结构的关系数据,例如订单中的商品,或者用户中的地址。
object和nested类型的区别:
- Object类型:Object类型用于存储嵌套的对象或文档。当您查询一个object字段时,Elasticsearch会将整个嵌套对象作为一个整体进行处理。这意味着,如果您想要查询嵌套对象内部的某个字段,您需要将整个嵌套对象都包含在查询中。此外,object类型不支持对嵌套对象内部的多个实例进行独立的查询。
- Nested类型:Nested类型是object类型的特殊版本,它允许对象数组以一种可以相互独立查询的方式进行索引。在Nested内部,每个对象索引其实是一个单独的隐藏文档,这意味着每个嵌套对象都可以独立于其他对象进行查询。这使得Nested类型在处理复杂的查询场景时更加灵活和强大。
总的来说,object类型更适合处理简单的嵌套文档,而nested类型更适合处理复杂的嵌套文档和查询场景。
假设我们有一个订单(Order)对象,每个订单包含一个客户(Customer)对象和一个商品(Product)对象的列表。我们可以这样定义映射:
PUT /orders
{
"mappings": {
"properties": {
"customer": {
"type": "object"
},
"products": {
"type": "nested"
}
}
}
}
# 向索引中插入一个文档
POST /orders/_doc
{
"customer": {
"name": "John Doe",
"email": "john.doe@example.com"
},
"products": [
{
"name": "Product A",
"price": 100
},
{
"name": "Product B",
"price": 200
}
]
}
# 查询所有包含"Product A"的订单
GET /orders/_search
{
"query": {
"nested": {
"path": "products",
"query": {
"match": {
"products.name": "Product A"
}
}
}
}
}
"customer"字段是一个普通对象,而"products"字段是一个嵌套对象。这意味着"products"字段中的每个元素都可以单独进行查询和过滤。
地理空间
在Elasticsearch中,地理空间搜索是一种基于地理位置的搜索功能,它可以让你根据文档的位置信息进行搜索。Elasticsearch支持多种地理空间数据类型,包括地理坐标(geo_point)和多边形(geo_shape)。
建立mappings例子:
PUT /users
{
"mappings": {
"properties": {
"location": {
"type": "geo_point"
}
}
}
}
# 插入一个文档
POST /users/_doc
{
"name": "John Doe",
"location": {
"lat": 40.7128,
"lon": -74.0060
}
}
# 查询距离某个地点一定范围内的所有用户
GET /users/_search
{
"query": {
"geo_distance": {
"distance": "100km",
"location": {
"lat": 40.7128,
"lon": -74.0060
}
}
}
}