Elasticsearch常用操作:映射篇

[TOC]



其实就是es的字段类型是由es来做自动检测还是由我们自己来指定,因此会分为动态映射和静态映射。

1 动态映射

1.1 映射规则

JSON格式的数据 自动推测的字段类型
null 没有字段被添加
true or false boolean类型
浮点类型数字 float类型
数字 long类型
JSON对象 object类型
数组 由数组中第一个非空值决定
string 有可能是date类型(开启日期检测)、double或long类型、text类型、keyword类型

1.2 日期检测

默认是开启的(es5.4),测试案例如下:

PUT myblog

GET myblog/_mapping

PUT myblog/article/1
{
  "id":1,
  "postdate":"2018-10-27"
}

GET myblog/_mapping
{
  "myblog": {
    "mappings": {
      "article": {
        "properties": {
          "id": {
            "type": "long"
          },
          "postdate": {
            "type": "date"
          }
        }
      }
    }
  }
}

关闭日期检测后,则不会检测为日期,如下:

PUT myblog
{
  "mappings": {
    "article": {
      "date_detection": false
    }
  }
}

GET myblog/_mapping

PUT myblog/article/1
{
  "id":1,
  "postdate":"2018-10-27"
}

GET myblog/_mapping
{
  "myblog": {
    "mappings": {
      "article": {
        "date_detection": false,
        "properties": {
          "id": {
            "type": "long"
          },
          "postdate": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

2 静态映射

2.1 基本案例

PUT myblog
{
  "mappings": {
    "article": {
      "properties": {
        "id":{"type": "long"},
        "title":{"type": "text"},
        "postdate":{"type": "date"}
      }
    }
  }
}

GET myblog/_mapping

PUT myblog/article/1
{
  "id":1,
  "title":"elasticsearch is wonderful!",
  "postdate":"2018-10-27"
}

GET myblog/_mapping
{
  "myblog": {
    "mappings": {
      "article": {
        "properties": {
          "id": {
            "type": "long"
          },
          "postdate": {
            "type": "date"
          },
          "title": {
            "type": "text"
          }
        }
      }
    }
  }
}

2.2 dynamic属性

默认情况下,当添加一份文档时,如果出现新的字段,es也会添加进去,不过这个是可以进行控制的,通过dynamic来进行设置:

dynamic值 说明
true 默认值为true,自动添加字段
false 忽略新的字段
strict 严格模式,发现新的字段抛出异常
PUT myblog
{
  "mappings": {
    "article": {
      "dynamic":"strict",
      "properties": {
        "id":{"type": "long"},
        "title":{"type": "text"},
        "postdate":{"type": "date"}
      }
    }
  }
}

GET myblog/_mapping

PUT myblog/article/1
{
  "id":1,
  "title":"elasticsearch is wonderful!",
  "content":"a long text",
  "postdate":"2018-10-27"
}

{
  "error": {
    "root_cause": [
      {
        "type": "strict_dynamic_mapping_exception",
        "reason": "mapping set to strict, dynamic introduction of [content] within [article] is not allowed"
      }
    ],
    "type": "strict_dynamic_mapping_exception",
    "reason": "mapping set to strict, dynamic introduction of [content] within [article] is not allowed"
  },
  "status": 400
}

3 字段类型

3.1 普通字段类型

一级分类 二级分类 具体类型
核心类型 字符串类型 string、text、keyword
数字类型 long、intger、short、byte、double、float、half_float、scaled_float
日期类型 date
布尔类型 boolean
二进制类型 binary
范围类型 range
复合类型 数组类型 array
对象类型 object
嵌套类型 nested
地理类型 地理坐标 geo_point
地理图形 geo_shape
特殊类型 IP类型 ip
范围类型 completion
令牌计数类型 token_count
附件类型 attachment
抽取类型 percolator

下面只会列出一些在个人工作中常用的,详细的可以参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html

3.1.1 string

ex 5.x之后不支持,但仍可以添加,由text或keyword替代。

3.1.2 text

用于做全文搜索的字段,其字段内容会被分词器分析,在生成倒排索引前,字符串会被分词器分成一个个的词项。

实际应用中,text多用在长文本的字段中,如article的content,显然,这样的字段用于排序和聚合都是没有太大意义的。

3.1.3 keyword

只能通过精确值搜索到,区别于text类型。

其索引的词项都是字段内容本身,因此在实际应用中,会用来比较、排序、聚合等操作。

3.1.4 数字类型

具体注意的细节问题可以考虑官方文档,一般的使用都能满足需求。

3.1.5 date

json中没有日期类型,所以默认情况es的时间的形式可以为:

  • 1."yyyy-MM-dd"或"yyyy-MM-ddTHH:mm:ssZ"

    • 也就是说"yyyy-MM-dd HH:mm:ss"需要写成:"2018-10-22T23:12:22Z"的形式,其实就是加了时区;
  • 2.表示毫秒的timestamp的长整型数
  • 3.表示秒的timestamp的整型数

es内部存储的是毫秒计时的长整型数。

当然上面只是默认情况下的,在设置字段的类型时,我们也可以设置自己定义的时间格式:

PUT myblog
{
  "mappings": {
    "article": {
      "properties": {
        "postdate":{
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss"
        }
      }
    }
  }
}

format也可以指定多个日期格式,使用"||"分隔开:

"format": "yyyy-MM-dd HH:mm:ss||yyyy/MM/dd HH:mm:ss"

之后就可以写入定义的时间格式的数据了:

PUT myblog/article/1
{
  "postdate":"2017-09-23 23:12:22"
}

在我的工作场景中,如果需要存入的为时间,很多时候会先把其处理为毫秒值的timestamp,然后再存入es中,取出显示时再处理为时间字符串。

3.1.6 boolean

设置字段类型为boolean后,可以填入的值为:true、false、"true"、"false"。

3.1.7 binary

binary类型接受base64编码的字符串。

3.1.8 array

es没有专用的数组类型,默认情况下任何字段都可以包含一个或者多个值,但是一个数组中的值必须是同一种类型。动态添加数据时,数组的第一个值的类型决定整个数组的类型(其实也就是这个字段的类型),混合数组是不支持的。数组可以包含null值,空数组[]会被当作missing field对待。另外在文档中使用array类型不需要提前做任何配置,默认支持。

比如添加下面一个数组的字段数据:

DELETE my_index

PUT my_index/my_type/1
{
  "lists":[
    {
      "name":"xpleaf",
      "job":"es"
    }
  ]
}

其实际上该字段的类型就会被动态映射为text:

GET my_index/my_type/_mapping

{
  "my_index": {
    "mappings": {
      "my_type": {
        "properties": {
          "lists": {
            "properties": {
              "job": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              },
              "name": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

直接搜索也是支持的:

GET my_index/my_type/_search
{
  "query": {
    "term": {
      "lists.name": {
        "value": "xpleaf"
      }
    }
  }
}

返回结果:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "lists": [
            {
              "name": "xpleaf",
              "job": "es"
            }
          ]
        }
      }
    ]
  }
}

3.1.9 object

可以直接将一个json对象写入es中,如下:

DELETE my_index

PUT my_index/my_type/1
{
  "object":{
    "name":"xpleaf",
    "job":"es"
  }
}

其实际上该字段的类型就会被动态映射为text:

{
  "my_index": {
    "mappings": {
      "my_type": {
        "properties": {
          "object": {
            "properties": {
              "job": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              },
              "name": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

直接搜索也是可以的:

GET my_index/my_type/_search
{
  "query": {
    "term": {
      "object.name": {
        "value": "xpleaf"
      }
    }
  }
}

返回结果:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "object": {
            "name": "xpleaf",
            "job": "es"
          }
        }
      }
    ]
  }
}

object对象,实际上在es内部会被扁平化处理,如上面的,在es中实际为:

{"object.name":"xpleaf", "object.job":"es"}

3.1.10 nested

nested类型是object类型中的一个特例,可以让对象数组独立索引和查询。Lucene没有内部对象的概念,所以es将对象层次扁平化,转化成字段名字和值构成的简单列表。

虽然是object类型中的一个特例,但是其字段的type是固定的,也就是nested,这是与object的最大不同。

那么为什么要使用nested类型呢,使用object不就可以了吗?这里贴一下官方提供的一个例子来进行说明(https://www.elastic.co/guide/en/elasticsearch/reference/5.6/nested.html):

Arrays of inner object fields do not work the way you may expect. Lucene has no concept of inner objects, so Elasticsearch flattens object hierarchies into a simple list of field names and values. For instance, the following document:

PUT my_index/my_type/1
{
  "group" : "fans",
  "user" : [
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}

would be transformed internally into a document that looks more like this:

{
  "group" :        "fans",
  "user.first" : [ "alice", "john" ],
  "user.last" :  [ "smith", "white" ]
}

The user.first and user.last fields are flattened into multi-value fields, and the association between alice and white is lost. This document would incorrectly match a query for alice AND smith:

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "user.first": "Alice" }},
        { "match": { "user.last":  "Smith" }}
      ]
    }
  }
}

上面是直接使用object而导致的问题,也就是说实际上进行上面的搜索时,该文档是不应该被匹配出来的,但是确匹配出来了。使用nested对象类型就可以保持数组中每个对象的独立性,nested类型将数组中每个对象作为独立隐藏文档来索引,这意味着每个嵌套对象都可以独立被搜索。

If you need to index arrays of objects and to maintain the independence of each object in the array, you should use the nested datatype instead of the object datatype. Internally, nested objects index each object in the array as a separate hidden document, meaning that each nested object can be queried independently of the others, with the nested query:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "user": {
          "type": "nested"
        }
      }
    }
  }
}

PUT my_index/my_type/1
{
  "group" : "fans",
  "user" : [
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}

GET my_index/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},
            { "match": { "user.last":  "Smith" }}
          ]
        }
      }
    }
  }
}

GET my_index/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},
            { "match": { "user.last":  "White" }}
          ]
        }
      },
      "inner_hits": {
        "highlight": {
          "fields": {
            "user.first": {}
          }
        }
      }
    }
  }
}

索引一个包含100个nested字段的文档实际上就是索引101个文档,每个嵌套文档都作为一个独立文档来索引。为了防止过度定义嵌套字段的数量,每个索引可以定义的嵌套字段被限制在50个。

3.1.11 range

range类型及其取值范围如下:

类型 范围
integer_range -2^31~2^31-1
float_range 32-bit IEEE 754
long_range -2^63~2^63-1
double_range 64-bit IEEE 754
date_range 64位整数,毫秒计时

3.2 元字段

元字段就是描述文档本身的字段,其分类及说明如下:

元字段分类 具体属性 作用
文档属性的元字段 _index 文档所属索引
_uid 包含_type_id的复合字段(取值为{type}#{id})
_type 文档的类型
_id 文档的id
源文档的元字段 _source 文档的原始JSON字符串
_size _source字段的大小
_all 包含索引全部字段的超级字段
_field_names 文档中包含非空值的所有字段
路由的元字段 _parent 指定文档间的父子关系
_routing 将文档路由到特定分片的自定义路由值
自定义元字段 _meta 用于自定义元数据

各个字段的详细说明,可以参考:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping-fields.html

4 映射参数

参考:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping-params.html

原文地址:http://blog.51cto.com/xpleaf/2310222

时间: 2024-08-28 20:43:16

Elasticsearch常用操作:映射篇的相关文章

ElasticSearch常用操作:文档篇

[TOC] 1 新建文档 1.1 指定id PUT my_blog/article/1 { "id":1, "title":"elasticsearch", "posttime":"2017-05-01", "content":"elasticsearch is helpfull!" } 返回: { "_index": "my_blog&

ElasticSearch常用操作:查询与聚合篇

[TOC] 0 说明 基于es 5.4和es 5.6,列举的是个人工作中经常用到的查询(只是工作中使用的是Java API),如果需要看完整的,可以参考官方相关文档https://www.elastic.co/guide/en/elasticsearch/reference/5.4/search.html. 1 查询 先使用一个快速入门来引入,然后后面列出的各种查询都是用得比较多的(在我的工作环境是这样),其它没怎么用的这里就不列出了. 1.1 快速入门 1.1.1 查询全部 GET index

elasticsearch常用操作

3.3.1 Preparing a query 准备查询请求 import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.Client; import org.elasticsearch.search.SearchHit; SearchResponse response = client.prepareSearch("library") .addFields("t

Elasticsearch常用操作API

1. 查询所有的索引 [[email protected] cx]# curl '10.0.0.5:9200/_cat/indices?v' health status index    pri rep docs.count docs.deleted store.size pri.store.size  yellow open   customer   5   1          2            0      6.6kb          6.6kb  yellow open   b

WF4常用操作<第二篇>

一.启动工作流 WF4启动工作流有两种方式: WorkflowInvoker.Invoke(); WorkflowApplication.Run(); 区别在于,Invoke能附着在宿主程序上执行. static void Main(string[] args) { //方法1 WorkflowInvoker.Invoke(new Workflow1()); //方法2 WorkflowApplication WorkflowInstance1 = new WorkflowApplication

ElasticSearch入门 第六篇:复合数据类型——数组,对象和嵌套

这是ElasticSearch 2.4 版本系列的第六篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 ElasticSearch入门 第三篇:索引 ElasticSearch入门 第四篇:使用C#添加和更新文档 ElasticSearch入门 第五篇:使用C#查询文档 ElasticSearch入门 第六篇:复合数据类型——数组,对象和嵌套 在ElasticSearch中,使用JSON结构来存储数据,

ElasticSearch入门 第八篇:存储

这是ElasticSearch 2.4 版本系列的第八篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 ElasticSearch入门 第三篇:索引 ElasticSearch入门 第四篇:使用C#添加和更新文档 ElasticSearch入门 第五篇:使用C#查询文档 ElasticSearch入门 第六篇:复合数据类型——数组,对象和嵌套 ElasticSearch入门 第七篇:分析器 Elasti

vim常用操作和使用技巧

vi是linux与unix下的常用文本编辑器,其运行稳定,使用方便,本文将分两部分对其常用操作技巧和配置进行阐述,其中参考了网上的一些文章,对作者表示感谢 PART1 操作技巧 说明: 以下的例子中 xxx 表示在命令模式下输入 xxx 并回车 以下的例子中 :xxx 表示在扩展模式下输入 xxx 并回车 ()中的命令表示相关命令.[]表示命令等同 在编辑模式或可视模式下输入的命令会另外注明. 移动光标 在 vi 中, 移动光标和编辑是两件事, 正因为区分开来, 所以可以很方便的进行光标定 位和

Android Studio常用操作技巧

这段时间一直在用Android Studio做一些Demo的开发,一开始从Eclipse中转向这个开发工具,各种不适应,希望此博文可以一直更新,还有网友可以分享出自己方便更好更快开发的一些技巧. 首先我讲一些经常用到的快捷键吧,网上很多都只说一个大概,很模糊,也不知道什么时候才会用到.我们尽量让这篇博文有作用而不是纯粹的Copy吧! 虽然说Android Studio可以直接一键把所有快捷键设置成Eclipse的快捷键,但是想到你身边的同事,有可能不一定会设置成Eclipse,这样有的时候你如果