06、ES实战:字段类型Fielddatatypes

本学习笔记基于ElasticSearch 7.10版本,旧版本已经废弃的功能暂时不做笔记,以后有涉及到再做补充。

上一章学习映射的时候,就有接触到一些字段类型。今天来详细说说ElasticSearch中常见的四种字段类型。

一、核心类型

1.1、字符串类型

  • string:在es5.0之前,用这个字段来定义字符串,通过index来定义是否需要被分析或者精准查询。但现在,这两种分别被text和keyword类型替代。
  • text:使用了这个字段,字段内容就会被分词器分析成一个个词条,相当于之前的analyzed属性。text类型的字段hen不用于排序,很少用于聚合。
  • keyword:这种类型适合结构化的字段,用于做精准匹配,例如标签、email 地址、手机号码等等,相当于之前的not-analyzed属性。这种类型的字段可以用作过滤、排序、聚合等。

1.2、数字类型

类型 取值范围
long -263 ~ 263
integer -231 ~ 231
short -215 ~ 215
byte -27 ~ 27
double 64位的双精度 IEEE754 浮点类型
float 32位的双精度 IEEE754 浮点类型
half_float 16位的双精度 IEEE754 浮点类型
scaled_float 缩放类型的浮点类型
  • 在满足需求的情况下,优先使用范围小的字段。字段长度越小,索引和搜索的效率越高。
  • 浮点数,优先考虑使用scaled_float。例如保存一个价格为99.99的商品,当使用了scaled_float类型,定义比例因子scaling_factor为100,在底层保存的数据就是整数9999,可以提高效率。而在运算时,API还是以浮点类型进行运算。
# 比例因子为100
PUT mapping_demo/_mapping
{
   
     
  "properties": {
   
     
    "price": {
   
     
        "type": "scaled_float",
        "scaling_factor": 100
     }
  }
}

1.3、日期类型

JSON中并没有日期类型,所以在es中日期类型可以表现成很多种:

  • 日期格式字符串:“2020-12-28"或"2020/12/28 11:11:11”
  • 毫秒级别的long类型
  • 秒级别的integer类型

不管是什么样的格式,es 内部都会先将时间转为 UTC,然后将时间按照 millseconds-since-the-epoch 来存储成long类型。在查询的时候,再根据字段定义的格式转为字符串输出。
日期类型默认的格式是:strict_date_optional_time||epoch_millis,可以通过format属性来自定义日期格式:

PUT mapping_demo/_mapping
{
   
     
  "properties": {
   
     
    "datetime": {
   
     
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
     }
  }
}

1.4、布尔类型

JSON 中的 “true”、“false”、true、false 都可以存储到布尔类型中。

1.5、二进制类型

二进制接受的是 base64 编码的字符串,默认不存储,也不可搜索。

1.6、范围类型

顾名思义,范围类型字段中存储的内容就是一段范围,例如年龄30-55岁,日期在2020-12-28到2021-01-01之间等。
es中有六种范围类型:

  • integer_range
  • float_range
  • long_range
  • double_range
  • date_range
  • ip_range

定义字段时,指定范围类型即可。在插入文档时,需要指定范围的界限:

PUT mapping_demo/_mapping
{
   
     
  "properties": {
   
     
    "age_range": {
   
     
        "type": "integer_range"
     }
  }
}

# 指定年龄范围,可以使用 gt、gte、lt、lte。
PUT mapping_demo/_doc/3
{
   
     
  "real_name":"大方哥",
  "age_range":{
   
     
    "gt":20,
    "lt":30
  }
}

二、复合类型

2.1、数组类型

es中没有专门的数组类型。默认情况下,任何字段都可以有一个或者多个值。需要注意的是,数组中的元素必须是同一种类型。
添加数组时,数组中的第一个元素决定了整个数组的类型。

2.2、对象类型(object)

由于JSON 本身具有层级关系,所以文档包含内部对象。内部对象中,还可以再包含内部对象。

PUT product/_doc/2
{
   
     
  "date":"2020-11-11T11:11:11Z",
  "ext_info":{
   
     
    "address":"China"
  }
}

2.3、嵌套类型(nested)

nested类型是一种特殊的对象object数据类型specialised version of the object datatype,允许对象数组彼此独立地进行索引和查询。

Lucene中没有内部对象的概念,所以 es 会将对象层次扁平化,将一个对象转为字段名和值构成的简单列表,例如添加以下文档:

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

user会被动态映射为object类型的,其内部转换成类似下面的文档格式:

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

扁平化处理后,用户名之间的关联关系没有,如果我们使用alicewhite查询,就会查询出不存在的用户。

如果您需要索引对象数组并保持数组中每个对象的独立性,请使用nested数据类型,而不是object数据类型。

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

在内部,嵌套对象将数组中的每个对象索引为一个单独的隐藏文档,这意味着每个嵌套对象都可以通过查询独立于其他对象进行nested查询。

使用nested类型的优缺点:

  • 优点:文档存储在一起,读取性能高。
  • 缺点:更新父或者子文档时需要更新更个文档。

参考官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html

三、地理类型

3.1、geo_point

使用场景:

  • 查找某一个范围内的地理位置
  • 通过地理位置或者相对中心点的距离来聚合文档
  • 把距离整合到文档的评分中
  • 通过距离对文档进行排序
# 定义geo_point字段类型
PUT people
{
   
     
  "mappings": {
   
     
    "properties": {
   
     
      "location": {
   
     
        "type": "geo_point"
      }
    }
  }
}

可以通过5种方式来指定一个地理位置:

# object类型指定经纬度
PUT people/_doc/1
{
   
     
  "text": "Geo-point as an object",
  "location": {
   
     
    "lat": 34.27,
    "lon": 108.94
  }
}
# 字符串形式指定经纬度,中间用逗号,分隔
PUT people/_doc/2
{
   
     
  "text": "Geo-point as a string",
  "location": "34.27,108.94"
}
# 将经纬度转个Geohash后储存
PUT people/_doc/3
{
   
     
  "text": "Geo-point as a geohash",
  "location": "uzbrgzfxuzup"
}
# 使用数组指定经纬度,注意经度在前,纬度在后
PUT people/_doc/4
{
   
     
  "text": "Geo-point as an array",
  "location": [108.94, 34.27]
}
# 使用WKT原点指定经纬度,注意经度在前,纬度在后
PUT people/_doc/5
{
   
     
  "text": "Geo-point as a WKT POINT primitive",
  "location": "POINT (108.94 34.27)" 
}

通过经纬度来指定两左上角top_left和右下角bottom_rigth,来查询范围中的位置:

GET people/_search
{
   
     
  "query": {
   
     
    "geo_bounding_box": {
   
      
      "location": {
   
     
        "top_left": {
   
     
          "lat": 30,
          "lon": 100
        },
        "bottom_right": {
   
     
          "lat": 40,
          "lon": 110
        }
      }
    }
  }
}

geo_point字段参数:

  • ignore_malformed:默认为false,存储格式错误的地理位置将会抛出异常,并且文档也不会写入。true则忽略格式错误的地理位置。
  • ignore_z_value:默认为true,接受并存储第三维z轴坐标,但仅索引经纬度。false则指接受二维经纬度,超过二维的地理坐标将会抛出异常。
  • null_value:接受null值的地理位置,表示该字段被视为丢失。

3.2、geo_shape

在学习geo_shape之前,我们先要了解一下GeoJson

引用自百度百科:
GeoJSON是一种对各种地理数据结构进行编码的格式,基于Javascript对象表示法(JavaScript Object Notation, 简称JSON)的地理空间信息数据交换格式。GeoJSON对象可以表示几何、特征或者特征集合。GeoJSON支持下面几何类型:点、线、面、多点、多线、多面和几何集合。GeoJSON里的特征包含一个几何对象和其他属性,特征集合表示一系列特征。

es将GeoJson几何对象都映射到geo_shape中:

GeoJson geo_shape 描述
Point point 单个由经纬度描述的地理坐标。注意:Elasticsearch仅使用WGS-84坐标
LineString linestring 一个任意的线条,由两个以上点组成
Polygon polygon 一个封闭的多边形,其第一个点和最后一个点必须匹配,由四个以上点组成
MultiPoint multipoint 一组不连续的点
MultiLineString multilinestring 多个不关联的线条
MultiPolygon multipolygon 多个多边形
GeometryCollection geometrycollection 与JSON形状相似的GeoJSON形状, 可以同时存在多种几何对象类型(例如,Point和LineString)。
N/A envelope 通过左上角和右下角两个点来指定一个矩形
N/A circle 由中心点和半径指定的圆
# 定义geo_shape字段类型
PUT people
{
   
     
  "mappings": {
   
     
    "properties": {
   
     
      "location": {
   
     
        "type": "geo_shape"
      }
    }
  }
}

添加地理位置时,需要通过type指定具体的类型:

# point类型
PUT people/_doc/1
{
   
     
  "location":{
   
     
    "type": "point",
    "coordinates": [108.94, 34.27]
  }
}
# linestring类型
PUT people/_doc/2
{
   
     
  "location":{
   
     
    "type": "linestring",
    "coordinates": [[108.94, 34.27], [100, 33]]
  }
}
# polygon类型
POST /people/_doc/3
{
   
     
  "location": {
   
     
    "type": "polygon",
    "coordinates": [
      [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]
    ]
  }
}
...

参考官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html

四、特殊类型

es中的特殊类型有很多种,下面主要介绍两种最常用的

4.1、ip

顾名思义,这个类型用来存储IP地址:

PUT people
{
   
     
  "mappings": {
   
     
    "properties": {
   
     
      "address": {
   
     
        "type": "ip"
      }
    }
  }
}
# 通过IPv4添加
PUT people/_doc/1
{
   
     
  "address":"192.168.1.3"
}
# 查询
GET people/_search
{
   
     
  "query": {
   
     
    "term": {
   
     
      "address": "192.168.0.0/16"
    }
  }
}

4.2、token_count

token_count用于统计字符串分词后的词项个数.

# 增加了length字段,用于统计词项个数
PUT blog
{
   
     
  "mappings": {
   
     
    "properties": {
   
     
      "title": {
   
     
        "type": "text",
        "fields": {
   
     
          "length": {
   
     
            "type": "token_count",
            "analyzer": "standard"
          }
        }
      }
    }
  }
}
# 添加文档
PUT blog/_doc/1
{
   
     
  "title": "zhang san"
}
# 使用token_count进行查询
GET blog/_search
{
   
     
  "query": {
   
     
    "term": {
   
     
      "title.length": 2
    }
  }
}

版权声明:

本文仅记录ElasticSearch学习心得,如有侵权请联系删除。
更多内容请访问原创作者:江南一点雨
*

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: