Elasticsearch学习笔记(8)

Elasticsearch 字段类型

核心类型

字符串类型

  • string : 这是一个已经过期的字符串类型。在 ES 5 之前用这个来描述字符串,现在已经被 text 和 keyword 替代了。
  • text : 如果一个字段是要被全文检索的,比如说文章内容,那么可以使用 text。用了 text 之后,字段内容会被分析,在生成倒排索引之前,字符串会被分词器分成一个个的词项,text 类型的字段不用于排序,很少用于聚合。这种字符串也被称之为 analyzed 字段。
  • keyword : 这种类型适用于结构化的字段,例如标签、手机号码等等,这种类型的字段可以用作过滤、排序、聚合等。这种字符串也称之为 not-analyzed 字段。

数字类型

类型取值范围
long-2^63 到 -2^63-1
integer-2^31 到 -2^31-1
short-2^15 到 -2^15-1
byte-2^7 到 -2^7-1
double64 位的双精度 IEEE754 浮点类型
float32 位的双精度 IEEE754 浮点类型
half_float16 位的双精度 IEEE754 浮点类型
scaled_float缩放类型的浮点类型
  • 在满足需求的情况下,优先使用范围小的字段。字段长度越短,索引和搜索的效率越高。

  • 浮点数,优先考虑使用 scaled_float 。

    scaled_float 举例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    PUT product
    {
    "mappings": {
    "properties": {
    "name":{
    "type": "text"
    },
    "price":{
    "type": "scaled_float",
    "scaling_factor": 100
    }
    }
    }
    }

    如上代码,比如我们商品价格精确到分,那么一个88.88元的商品在ES底层存储的为8888,但是由于缩放因子为100,ES给我们提供的所有API返回的为88.88,在底层,long类型比float类型更易压缩存储。

日期类型(date)

由于JSON中没有日期类型,所以ES中的日期类型形式就比较多样。

  • 2021-06-09 或者 2021-06-09 11:00:00
  • 一个从1970.1.1 零点 到现在的一个秒数或者毫秒数。

ES 内部将时间转为 UTC ,然后将时间按照 millseconds-since-the-epoch 的长整型来存储。

自定义日期类型:

1
2
3
4
5
6
7
8
9
10
PUT product
{
"mappings": {
"properties": {
"date":{
"type": "date"
}
}
}
}

这个能够解析的时间类型比较多。

1
2
3
4
5
6
7
8
9
10
11
12
PUT product/_doc/1
{
"date":"2021-06-09"
}
PUT product/_doc/2
{
"date":"2021-06-09T11:00:00Z"
}
PUT product/_doc/3
{
"date":"1623208124"
}

上面三个文档中的日期都可以被解析,内部存储的是毫秒计时的长整型数。

布尔类型(boolean)

JSON 中的 “ture”,“false”,true,false。

二进制类型(binary)

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

范围类型

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

定义的时候,指定范围类型即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT product
{
"mappings": {
"properties": {
"name":{
"type": "text"
},
"pirce":{
"type": "float_range"
}
}
}
}

插入文档时,需要指定文档的界限。

1
2
3
4
5
6
7
8
PUT product/_doc/1
{
"name":"apple",
"pirce":{
"gt":9,
"lt":19.9
}
}

指定范围时,可以使用gt、gte、lt、lte。

复合类型

数组类型

ES 中没有专门的数组类型。默认情况下,任何字段都可以有一个或多个值。需要注意的是,数组中的元素必须是同一种类型。

添加数组时,数组中的第一个元素就决定了整个数组类型。

对象类型(object)

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

1
2
3
4
5
6
7
PUT product/_doc/2
{
"name":"apple",
"ext":{
"adderss":"China"
}
}

嵌套类型(nested)

nested 是object 中的一个特例。

如果只使用 object 类型,假如有如下文档:

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT product/_doc/3
{
"users":[
{
"first_name":"Zhang",
"last_name":"San"
},
{
"first_name":"Li",
"last_name":"Si"
}
]
}

由于Luncene 没有内部对象的概念,所以 ES 会将对象层次扁平化,将一个对象转为字段名和值构成的简单列表。即上面的文档最终存储形式如下:

1
2
3
4
{
"users.first_name":["Zhang","Li"],
"users.last_name":["San","Si"],
}

扁平化之后,用户名之间的关系没了。这样会导致如果搜索 Zhang Si 这个人,会搜索到。

此时可以通过nested 类型来解决问题,nested 对象类型可以保持数组中每个对象的独立性。nested 类型 将数组中的每一个对象作为独立隐藏稳定来索引,这样每一个嵌套对象都可以独立被索引。如下结构:

1
2
3
4
5
6
7
8
9
10
{
{
"user.first_name":"Zhang",
"user.last_name":"San"
},
{
"user.first_name":"Li",
"user.last_name":"Si"
}
}

优点

文档存储1在一起,读取性能高。

缺点

更新父或者子文档时需要更新整个文档。

地理类型

使用场景:

  • 查找某一个范围内的地理位置
  • 通过地理位置或者相对中心点的距离来聚合文档
  • 把距离整合到文档的评分中
  • 通过距离对文档进行排序

geo_point

geo_point 就是一个坐标点。定义方式如下:

1
2
3
4
5
6
7
8
9
10
PUT people
{
"mappings": {
"properties": {
"location":{
"type": "geo_point"
}
}
}
}

创建时指定字段类型,存储时有四种方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PUT people/_doc/1
{
"location":{
"lat": 34.27,
"lon": 108.94
}
}

PUT people/_doc/2
{
"location": "34.27,108.94"
}
//geo_hash
PUT people/_doc/3
{
"location": "wqj6yyx"
}


PUT people/_doc/4
{
"location": [108.94,34.27]
}

注意,使用数组描述时,数组中先经度后纬度。

geo_shape

GeoJSON : https://geojson.org/

GeoJsonElasticsearch备注
Pointpoint一个由经纬度描述的点
LineStringlinestring一个任意的线条,由两个以上的点组成
Polygonpolygon一个封闭多边形
MultiPointmultipoint一组不连续的点
MultiLineStringmultilinestring多条不关联的线
MultiPolygonmultipolygon多个多边形
GeometryCollectiongeometrycollection几何对象的集合
circle一个圆形
envelope通过左上角和右下角确定的矩形

指定 geo_shape 的类型:

1
2
3
4
5
6
7
8
9
10
PUT people
{
"mappings": {
"properties": {
"location":{
"type": "geo_shape"
}
}
}
}

添加文档时需要指定具体的类型(点坐标先经度后纬度)。

1
2
3
4
5
6
7
PUT people/_doc/1
{
"location":{
"type":"point",
"coordinates": [108.94,34.27]
}
}

如果是linestring,如下:

1
2
3
4
5
6
7
PUT people/_doc/2
{
"location":{
"type":"linestring",
"coordinates": [[108.94,34.27],[100,33]]
}
}

特殊类型

IP

存储IP地址,类型是IP。

1
2
3
4
5
6
7
8
9
10
PUT blog
{
"mappings": {
"properties": {
"ip_address":{
"type": "ip"
}
}
}
}
1
2
3
4
PUT blog/_doc/1
{
"ip_address":"192.168.1.1"
}

查询如下:

1
2
3
4
5
6
7
8
GET blog/_search
{
"query": {
"term": {
"ip_address": "192.168.0.0/16"
}
}
}

添加 ipv4,ipv6 地址均可以。

token_count

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PUT blog
{
"mappings": {
"properties": {
"title":{
"type": "text",
"fields": {
"length":{
"type":"token_count",
"analyzer":"standard"
}
}
}
}
}
}

相当于新增了 title.length 字段用来统计分词后词项的个数。查询方便。

添加文档:

1
2
3
4
PUT blog/_doc/1
{
"title":"zhang san"
}

可以通过 token_count 去查询。

1
2
3
4
5
6
7
8
GET blog/_search
{
"query": {
"term": {
"title.length": 2
}
}
}

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"took" : 438,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "blog",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"title" : "zhang san"
}
}
]
}
}



-------------文章结束啦 ~\(≧▽≦)/~ 感谢您的阅读-------------

您的支持就是我创作的动力!

欢迎关注我的其它发布渠道