类型映射关系
高版本去掉_doc
了
ignore_above 超过ignore_above的字符串将不会被索引或存储
核心数据类型
- 字符串 - text
- 用于全文索引,该类型的字段将通过分词器进行分词,不可参与聚合
字符串 - keyword
- 不分词,只能搜索该字段的完整的值, 可以聚合
"city": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
- 不分词,只能搜索该字段的完整的值, 可以聚合
数值型 - Numerical
- long:有符号64-bit integer:-2^63 ~ 2^63 - 1
- integer:有符号32-bit integer,-2^31 ~ 2^31 - 1
- short:有符号16-bit integer,-32768 ~ 32767
- byte: 有符号8-bit integer,-128 ~ 127
- double:64-bit IEEE 754 浮点数
- float:32-bit IEEE 754 浮点数
- half_float:16-bit IEEE 754 浮点数
- scaled_float 浮点数的高精度类型
- 布尔 - boolean
- 值:false, “false”, true, “true”
- 日期 - date
- 由于Json没有date类型,所以es通过识别字符串是否符合format定义的格式来判断是否为date类型
- format默认为:
strict_date_optional_time||epoch_millis
format
- 二进制 - binary
- 该类型的字段把值当做经过 base64 编码的字符串,默认不存储,且不可搜索
- 范围类型
- 范围类型表示值是一个范围,而不是一个具体的值
- 譬如 age 的类型是 integer_range,那么值可以是 {“gte” : 10, “lte” : 20};搜索 “term” : {“age”: 15} 可以搜索该值;搜索 “range”: {“age”: {“gte”:11, “lte”: 15}} 也可以搜索到
- range参数 relation 设置匹配模式
- INTERSECTS :默认的匹配模式,只要搜索值与字段值有交集即可匹配到
- WITHIN:字段值需要完全包含在搜索值之内,也就是字段值是搜索值的子集才能匹配
- CONTAINS:与WITHIN相反,只搜索字段值包含搜索值的文档
- integer_range
- float_range
- long_range
- double_range
- date_range:64-bit 无符号整数,时间戳(单位:毫秒)
- ip_range:IPV4 或 IPV6 格式的字符串
# 创建range索引
PUT range_index
{
"mappings": {
"properties": {
"expected_attendees": {
"type": "integer_range"
},
"time_frame": {
"type": "date_range",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
# 插入一个文档
PUT range_index/_doc/1
{
"expected_attendees" : {
"gte" : 10,
"lte" : 20
},
"time_frame" : {
"gte" : "2015-10-31 12:00:00",
"lte" : "2015-11-05"
}
}
# 12在 10~20的范围内,可以搜索到文档1
GET range_index/_search
{
"query" : {
"term" : {
"expected_attendees" : {
"value": 12
}
}
}
}
# within可以搜索到文档
# 可以修改日期,然后分别对比CONTAINS,WITHIN,INTERSECTS的区别
GET range_index/_search
{
"query" : {
"range" : {
"time_frame" : {
"gte" : "2015-11-02",
"lte" : "2015-11-03"
}
}
}
}
复杂数据类型
- 数组类型 Array, 数组中所有的值必须是同一种数据类型, 不支持混合数据类型的数组
- 字符串数组 [ “one”, “two” ]
- 整数数组 [ 1, 2 ]
- 数组的数组 [ 1, [ 2, 3 ]],相当于 [ 1, 2, 3 ]
- Object对象数组 [ { “name”: “Mary”, “age”: 12 }, { “name”: “John”, “age”: 10 }]
- 同一个数组只能存同类型的数据,不能混存,譬如 [ 10, “some string” ] 是错误的
- 数组中的 null 值将被 null_value 属性设置的值代替或者被忽略
- 空数组 [] 被当做 missing field 处理 — 没有值的字段.
- 对象类型 Object
- 对象类型可能有内部对象
- 被索引的形式为:manager.name.first
# tags字符串数组,lists 对象数组
POST my_index/1
{
"message": "some arrays in this document...",
"tags": [ "elasticsearch", "wow" ],
"lists": [
{
"name": "prog_list",
"description": "programming list"
},
{
"name": "cool_list",
"description": "cool stuff list"
}
]
}
# 查看映射
{
"my_index" : {
"mappings" : {
"properties" : {
"lists" : {
"properties" : {
"description" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
},
"message" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"tags" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
嵌套类型Nested
nested 类型是一种对象类型的特殊版本,它允许索引对象数组,独立地索引每个对象
嵌套类型与Object类型的区别
通过例子来说明:
- 插入一个文档,不设置mapping,此时 user 字段被自动识别为对象数组 ```json DELETE /my_index PUT /my_index?pretty
POST /my_index/1 { “group” : “fans”, “user” : [ { “first” : “John”, “last” : “Smith” }, { “first” : “Alice”, “last” : “White” } ] }
POST /my_index/2 { “group” : “fans”, “user” : [ { “first” : “a1”, “last” : “b1” }, { “first” : “Alice”, “last” : “Smith” } ] }
GET /my_index/_mapping
2. 查询 user.first为 Alice,user.last 为 Smith的文档,理想中应该找不到匹配的文档
3. 结果是查到了文档1,为什么呢?
```json
GET /my_index/_search
{
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }}
]
}
}
}
是由于Object对象类型在内部被转化成如下格式的文档:
{ "group" : "fans", "user.first" : [ "alice", "john" ], "user.last" : [ "smith", "white" ] }
user.first 和 user.last 扁平化为多值字段,alice 和 white 的关联关系丢失了。导致这个文档错误地匹配对 alice 和 smith 的查询
- 如果最开始就把user设置为 nested 嵌套对象呢?
DELETE /my_index
PUT /my_index
{
"mappings": {
"properties": {
"user": {
"type": "nested"
}
}
}
}
POST /my_index/1
{
"group": "fans",
"user": [
{
"first": "John",
"last": "Smith"
},
{
"first": "Alice",
"last": "White"
}
]
}
- 再来进行查询,可以发现以下第一个查不到文档,第二个查询到文档1,符合我们预期
```json
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”: {} } } } } } }
8. nested对象将数组中每个对象作为独立隐藏文档来索引,这意味着每个嵌套对象都可以独立被搜索
9. 需要注意的是:
- 使用 [nested 查询](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html)来搜索
- 使用 nested 和 [reverse_nested](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-reverse-nested-aggregation.html) 聚合来分析
- 使用 [nested sorting](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html#nested-sorting) 来排序
- 使用 [nested inner hits](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-inner-hits.html#nested-inner-hits) 来检索和高亮
<a name="Qyw5k"></a>
## Date类型
elasticsearch 数据是以 JSON 格式存储的,而 [JSON](https://www.cnblogs.com/reycg-blog/p/9967865.html#json-%E7%9A%84%E8%AF%AD%E6%B3%95)中是并没有 date 数据类型,因此 Elasticsearch 中虽然有 date 类型,但在展示时却要转化成另外的格式。<br />date 类型在 Elasticsearch 展示的格式有下面几种:
- 将日期时间格式化后的字符串,如 "2015-01-01" 或者 "2015/01/01 12:10:30"
- long 型的整数,意义是 milliseconds-since-the-epoch,翻译一下就是自 1970-01-01 00:00:00 UTC 以来经过的毫秒数。
- int 型的整数,意义是 seconds-since-the-epoch, 是指自 1970-01-01 00:00:00 UTC 以来经过的秒数。
后两种的描述里都包含 UTC ,什么是 UTC 呢?<br />UTC(Universal Time Coordinated) 叫做世界统一时间,中国大陆和 UTC 的时差是 + 8 ,也就是 UTC+8。<br />不论 date 是什么展示格式,在 Elasticsearch 内部存储时都是转换成 UTC,并且把时区也会计算进去,从而得到 milliseconds-since-the-epoch 并作为存储的格式。<br />在查询日期时,会执行下面的过程:
1. 转换成 long 整形格式的范围(range) 查询
1. 得到聚合的结果
1. 将结果中的 date 类型(long 整型数据)根据 date format 字段转换回对应的展示格式
**默认格式**<br />Date 的格式化类型是可以通过 format 来指定的,如果没有指定,就会使用默认的格式:
```java
"strict_date_optional_time||epoch_millis"
表示只要是 ISO datetime parser 可以正常解析的都是 strict_date_optional_time。都有哪些语法呢?
date-opt-time = date-element ['T' [time-element] [offset]]
date-element = std-date-element | ord-date-element | week-date-element
std-date-element = yyyy ['-' MM ['-' dd]]
ord-date-element = yyyy ['-' DDD]
week-date-element = xxxx '-W' ww ['-' e]
time-element = HH [minute-element] | [fraction]
minute-element = ':' mm [second-element] | [fraction]
second-element = ':' ss [fraction]
fraction = ('.' | ',') digit+
其中中括号内的都是可选的,可填可不填。以 std-date_element 举个例子
2018-11-19
2018
2018-11
上面 3 种格式都满足要求。
除了 strict_date_optional_time ,还可以是 epoch_millis 格式,即 epoch 以来的毫秒数。
举个例子
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"date": {
"type": "date"
}
}
}
}
}
PUT my_index/_doc/1
{ "date": "2015-01-01" }
PUT my_index/_doc/2
{ "date": "2015-01-01T12:10:30Z" }
PUT my_index/_doc/3
{ "date": 1420070400001 }
GET my_index/_search
{
"sort": { "date": "asc"}
上面的 PUT 请求中的 date 数据均满足默认的要求。
如何指定多个date格式?
同一个 date 字段可以指定多个 date 格式,只要使用 || 分隔就可以了。在索引,都会对 date 格式挨个进行匹配,直到找到匹配的格式为止。
如果存储时 date 格式为 milliseconds-since-the-epoch ,在查询时会将其转换为指定的第一个 date 格式。
PUT my_index
{
"mappings": {
"doc": {
"properties": {
"date": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
}
PUT /my_index/doc/1
{ "date": "2018-09-24 19:23:45" }
PUT /my_index/doc/2
{ "date": "2018-09-25" }
GET my_index/_search
{
"query": {
"match_all": {}
}
}
地理位置数据类型
- geo_point
- 地理位置,其值可以有如下四中表现形式:
- object对象:”location”: {“lat”: 41.12, “lon”: -71.34}
- 字符串:”location”: “41.12,-71.34”
- geohash:”location”: “drm3btev3e86”
- 数组:”location”: [ -71.34, 41.12 ]
- 查询的时候通过 Geo Bounding Box Query 进行查询
- 地理位置,其值可以有如下四中表现形式:
- geo_shape
# 创建映射
PUT /company-locations
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"location": {
"type": "geo_point"
}
}
}
}
# 字符串形式
PUT /company-locations/_doc/1
{
"name": "NetEase",
"location": "40.715,74.011"
}
# 对象形式
PUT /company-locations/_doc/2
{
"name": "sina",
"location": {
"lat": 40.722,
"lon": 73.989
}
}
# 数组形式
PUT /company-locations/_doc/3
{
"name": "baidu",
"location": [
73.983,
40.719
]
}
注意
- 字符串形式以半角逗号分割,如 “lat,lon”
- 对象形式显式命名为 lat 和 lon
- 数组形式表示为 [lon,lat]
通过地理坐标点过滤
有四种地理坐标点相关的过滤器,可以用来选中或者排除文档
过滤器 | 作用 |
---|---|
geo_bounding_box | 找出落在指定矩形框中的点 |
geo_distance | 找出与指定位置在给定距离内的点, 定义圆心和半径的 |
geo_distance_range | 找出与指定点距离在给定最小距离和最大距离之间的点 |
geo_polygon | 找出落在多边形中的点。这个过滤器使用代价很大。当你觉得自己需要使用它,最好先看看geo-shapes。 |
geo_bounding_box
这是目前为止最有效的地理坐标过滤器了,因为它计算起来非常简单。 你指定一个矩形的顶部 , 底部 , 左边界和右边界,然后过滤器只需判断坐标的经度是否在左右边界之间,纬度是否在上下边界之间
location这些坐标也可以用 bottom_left 和 top_right 来表示
GET /company-locations/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_bounding_box": {
"location": {
"top_left": {
"lat": 40.73,
"lon": 71.12
},
"bottom_right": {
"lat": 40.01,
"lon": 74.1
}
}
}
}
}
}
}
geo_distance
定义圆心和半径的
过滤仅包含与地理位置相距特定距离内的匹配的点。
假设以下映射和索引文档然后可以使用geo_distance过滤器执行以下查询
GET /company-locations/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_distance": {
"distance": "200km",
"location": {
"lat": 40,
"lon": 70
}
}
}
}
}
}
专用数据类型
- 记录IP地址 ip
- 实现自动补全 completion
- 记录分词数 token_count
- 记录字符串hash值 murmur3
- Percolator
# ip类型,存储IP
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"ip_addr": {
"type": "ip"
}
}
}
}
}
PUT my_index/_doc/1
{
"ip_addr": "192.168.1.1"
}
GET my_index/_search
{
"query": {
"term": {
"ip_addr": "192.168.0.0/16"
}
}
}
多字段特性 multi-fields
- 允许对同一个字段采用不同的配置,比如分词,常见例子如对人名实现拼音搜索,只需要在人名中新增一个子字段为 pinyin 即可
- 通过参数 fields 设置
在创建索引,指定analyzer,ES在创建时会先检查是否设置了analyzer字段,如果没定义就用ES预设的
在查询时,指定search_analyzer,ES查询时会先检查是否设置了search_analyzer字段,
如果没有设置,还会去检查创建索引时是否指定了analyzer,还是没有还设置才会去使用ES预设的
- 插入文档时,将text类型的字段做分词然后插入倒排索引,此时就可能用到analyzer指定的分词器
- 在查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索,此时就可能用到search_analyzer指定的分词器
"name": { "type": "text", "fields": [{ "name_english": { "type": "text", "analyzer": "english", "search_anlyzer": "english" "ignore_above": 256 } }] }
搜索可以这样使用"city": { "type": "text", "analyzer": "ik_smart", "search_anlyzer": "ik_smart", "fields": [ { "keyword": { "type": "keyword", "ignore_above": 256 } }, { "k1": { "type": "text", "analyzer": "ik_max_word", "ignore_above": 256 } }, ] }
GET /booktest/_search { "query": { "term": { "description.keyword": "联想手机" } } }