欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > 重生之我们在ES顶端相遇第5章-常用字段类型

重生之我们在ES顶端相遇第5章-常用字段类型

2024/10/24 5:19:15 来源:https://blog.csdn.net/qq_32880923/article/details/140568297  浏览:    关键词:重生之我们在ES顶端相遇第5章-常用字段类型

思维导图

在这里插入图片描述

前置

在第4章,我们提到了 keyword(一笔带过)。在本章,我们将介绍 ES 的字段类型。全面的带大家了解 ES 各个字段类型的使用场景。

字段类型

ES 支持以下字段类型(仅介绍开发中常用,更多内容请自行阅读 官方文档)。

Keyword
基本介绍

手动设置字段类型为 keyword

PUT /test3
{"mappings": {"properties": {"tags": {"type": "keyword"}}}
}

写入数据

PUT /test3/_doc/1
{"tags": "hello world"
}

keyword 其实就是字符串,输入什么,存储就是什么。

适用场景

keyword 适用于 排序、聚合、term(精确查询) 查询场景中。
例如

GET /test3/_search
{"query": {"term": {"tags": {"value": "hello"}}}
}
查询优化

有 2 个对查询优化重要的点:

  1. 数字类型(int, long)如果不需要使用范围查询,则建议设置为 keyword
  2. term 查询在 keyword 上的搜索速度总是快于数字类型。
Text
基本介绍

与 keyword 相对的则是 text。在第三章,我们介绍了全文搜索 match 的用法。你可能会好奇,为啥默认写入的数据就可以使用全文搜索。因为当输入是无规则字符串时,字段类型就是 text。(别着急,默认的字段类型,一会我们就会详细介绍)

手动设置字段类型为 text

# 先删除索引
DELETE test3PUT /test3
{"mappings": {"properties": {"tags": {"type": "text"}}}
}
适用场景

text 适用场景:全文搜索
text 字段会对输入进行分词。
例如

PUT /test3/_doc/1
{"tags": "hello world"
}

tags 会被分词存储为 hello、world 2个词。
当然,具体被分词为什么,其实跟我们设置的分词器有关(后续讲解,这里先有个概念)。

不适用场景

text 不适用场景:排序、聚合、脚本。
如果你在 text 字段上,进行排序、聚合,或者脚本操作,都会收到以下异常。
Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [name] in order to load field data by uninverting the inverted index. Note that this can use significant memory.

例如:

GET /test3/_search
{"sort": [{"tags": {"order": "desc"}}]
}# 聚合
GET /test3/_search
{"size": 0,"aggs": {"popular_tags": {"terms": {"field": "tags"}}}
}# 脚本操作
GET /test3/_search
{"query": {"script": {"script": "doc['tags'].value == 'hello'"}}
}
illegal_argument_exception 异常解决方式

要解决该异常,有2种方法

  1. 使用多字段类型,即在该字段上面再建一个 keyword 类型(强烈建议)
DELETE test3PUT test3
{"mappings": {"properties": {"tags": {"type": "text","fields": {"keyword": {"type": "keyword"}}}}}
}

排序、聚合时,则使用 tags.keyword。需要全文索引时,依然可以使用 tags 字段。

GET /test3/_search
{"sort": [{"tags.keyword": {"order": "desc"}}]
}
  1. text 字段上启用 fielddata(不建议!不建议!不建议!)
DELETE test3PUT /test3/_mapping
{"properties": {"tags": {"type": "text","fielddata": true}}
}

PS:在 text 字段上启用 fielddata,会消耗非常大的内存!!!

Date

手动指定字段类型为 date

PUT /test3
{"mappings": {"properties": {"ctime": {"type": "date"}}}
}

未指定 format 参数时,默认的值为 strict_date_optional_time||epoch_millis
该默认值接收以下数据

# 秒时间戳
PUT /test3/_doc/1
{"ctime": 1721135125
}
# 毫秒时间戳
PUT /test3/_doc/2
{"ctime": 1721135125000
}
# datetime
PUT /test3/_doc/3
{"ctime":"2024-07-16T12:10:30Z"
}
# date
PUT /test3/_doc/4
{"ctime": "2024-07-15"
}# 对数据排序
GET test3/_search
{"sort": { "ctime": "asc"} 
}
format 参数

我们可以手动指定允许的数据格式。例如

PUT /test3
{"mappings": {"properties": {"ctime": {"type": "date","format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis||epoch_second"}}}
}
存储时间仅为秒时间戳

如果时间为秒时间戳,可以考虑使用 epoch_second

PUT my-index-000001
{"mappings": {"properties": {"ctime": {"type":   "date","format": "strict_date_optional_time||epoch_second"}}}
}PUT /test3/_doc/1
{"ctime": 1721135125
}# 以下查询,时间会被格式化
GET test3/_search
{"fields": [ {"field": "ctime"}]
}
数字类型

在复习一下,如果不需要范围查询,建议使用 keyword 存储(后续在进阶篇会讲原理)。

scaled_float

ES 除了支持常见的数字类型。如:long、integer、short、byte、double、float
还针对浮点数,有一个优化的类型 scaled_float
如果我们能够得知我们的浮点数最多有多少个小数点。使用该类型,在空间存储上会比浮点数更好。

PUT /test3
{"mappings": {"properties": {"sf": {"type": "scaled_float","scaling_factor": 100}}}
}

上面的意思为:存储时,* 100。即,将浮点数变为整数。

Boolean
PUT /test3
{"mappings": {"properties": {"enable": {"type": "boolean"}}}
}
  • false, “false”, “” (empty string) 均被认为是 false
  • true, “true” 均被认为是 true
POST /test3/_doc
{"enable": false
}
POST /test3/_doc
{"enable": "false"
}
POST /test3/_doc
{"enable": ""
}
POST /test3/_doc
{"enable": true
}
POST /test3/_doc
{"enable": "true"
}GET /test3/_search
{"query": {"term": {"enable": {"value": false}}}
}
Object

写入一个 manager 对象

PUT test3/_doc/1
{ "region": "US","manager": { "age":     30,"name": { "first": "John","last":  "Smith"}}
}

在 ES 内部,该文档被索引为一个简单的键值对列表,大致如下

{"region":             "US","manager.age":        30,"manager.name.first": "John","manager.name.last":  "Smith"
}

例如,我们可以查询 manager.age=30 的文档

GET /test3/_search
{"query": {"term": {"manager.age": {"value": 30}}}
}

上述文档的显式映射如下

PUT /test3
{"mappings": {"properties": { "region": {"type": "keyword"},"manager": { "properties": {"age":  { "type": "integer" },"name": { "properties": {"first": { "type": "text" },"last":  { "type": "text" }}}}}}}
}
Array
  1. 不支持混合数据类型的数组
POST /test3/_doc
{"arr": ["12", 12, false]
}
  1. 无法查询数组中的每个对象
PUT test3/_doc/1
{"group" : "fans","user" : [ {"first" : "John","last" :  "Smith"},{"first" : "Alice","last" :  "White"}]
}# 查询 user.first=Alice & user.last=White。你可能会使用以下写法,但实际上并不能正确工作GET test3/_search
{"query": {"bool": {"must": [{ "match": { "user.first": "Alice" }},{ "match": { "user.last":  "Smith" }}]}}
}

如果你的索引结构是这么设计的,并且有这样的需求,可能需要考虑下如何做优化了。例如,将表铺平。

PS:虽然 nested 嵌套类型可以解决该问题,但开发中会尽可能的把数据结构铺平,从而避免使用 nested 嵌套类型。这里不对 nested 过多介绍,因为开发中真的很不推荐使用。

  1. 开发中仅推荐基本数据类型数组,不推荐对象数组,如果你有第2 点描述的查询需求
PUT test3
{"mappings": {"properties": {"arr": {"type": "keyword"}}}
}PUT test3/_doc/1
{"arr": ["1", "2", "3"]
}GET test3/_search
{"query": {"term": {"arr": {"value": "1"}}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com