经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Elasticsearch » 查看文章
ES 15 - Elasticsearch中的数据类型 (text、keyword、date、geo等)
来源:cnblogs  作者:马瘦风  时间:2019/4/12 9:01:08  对本文有异议

说在前面: Elasticsearch中每个field都要精确对应一个数据类型.
本文的所有演示, 都是基于Elasticsearch 6.6.10进行的, 不同的版本可能存在API修改不支持的情况, 还请注意.

1 核心数据类型

1.1 字符串类型 - string(不再支持)

(1) 使用示例:

  1. PUT website
  2. {
  3. "mappings": {
  4. "blog": {
  5. "properties": {
  6. "title": {"type": "string"}, // 全文本
  7. "tags": {"type": "string", "index": "not_analyzed"} // 关键字, 不分词
  8. }
  9. }
  10. }
  11. }

(2) ES 5.6.10中的响应信息:

  1. #! Deprecation: The [string] field is deprecated, please use [text] or [keyword] instead on [tags]
  2. #! Deprecation: The [string] field is deprecated, please use [text] or [keyword] instead on [title]
  3. {
  4. "acknowledged": true,
  5. "shards_acknowledged": true,
  6. "index": "website"
  7. }

(3) ES 6.6.10中的响应信息:

  1. {
  2. "error": {
  3. "root_cause": [
  4. {
  5. "type": "mapper_parsing_exception",
  6. "reason": "No handler for type [string] declared on field [title]"
  7. }
  8. ],
  9. "type": "mapper_parsing_exception",
  10. "reason": "Failed to parse mapping [blog]: No handler for type [string] declared on field [title]",
  11. "caused_by": {
  12. "type": "mapper_parsing_exception",
  13. "reason": "No handler for type [string] declared on field [title]"
  14. }
  15. },
  16. "status": 400
  17. }

可知string类型的field已经被移除了, 我们需要用text或keyword类型来代替string.

1.1.1 文本类型 - text

在Elasticsearch 5.4 版本开始, text取代了需要分词的string.

—— 当一个字段需要用于全文搜索(会被分词), 比如产品名称、产品描述信息, 就应该使用text类型.

text的内容会被分词, 可以设置是否需要存储: "index": "true|false".
text类型的字段不能用于排序, 也很少用于聚合.

使用示例:

  1. PUT website
  2. {
  3. "mappings": {
  4. "blog": {
  5. "properties": {
  6. "summary": {"type": "text", "index": "true"}
  7. }
  8. }
  9. }
  10. }

1.1.2 关键字类型 - keyword

在Elasticsearch 5.4 版本开始, keyword取代了不需要分词的string.

—— 当一个字段需要按照精确值进行过滤、排序、聚合等操作时, 就应该使用keyword类型.

keyword的内容不会被分词, 可以设置是否需要存储: "index": "true|false".

使用示例:

  1. PUT website
  2. {
  3. "mappings": {
  4. "blog": {
  5. "properties": {
  6. "tags": {"type": "keyword", "index": "true"}
  7. }
  8. }
  9. }
  10. }

1.2 数字类型 - 8种

数字类型有如下分类:

类型 说明
byte 有符号的8位整数, 范围: [-128 ~ 127]
short 有符号的16位整数, 范围: [-32768 ~ 32767]
integer 有符号的32位整数, 范围: [$-2^{31}$ ~ $2^{31}$-1]
long 有符号的32位整数, 范围: [$-2^{63}$ ~ $2^{63}$-1]
float 32位单精度浮点数
double 64位双精度浮点数
half_float 16位半精度IEEE 754浮点类型
scaled_float 缩放类型的的浮点数, 比如price字段只需精确到分, 57.34缩放因子为100, 存储结果为5734

使用注意事项:

尽可能选择范围小的数据类型, 字段的长度越短, 索引和搜索的效率越高;
优先考虑使用带缩放因子的浮点类型.

使用示例:

  1. PUT shop
  2. {
  3. "mappings": {
  4. "book": {
  5. "properties": {
  6. "name": {"type": "text"},
  7. "quantity": {"type": "integer"}, // integer类型
  8. "price": {
  9. "type": "scaled_float", // scaled_float类型
  10. "scaling_factor": 100
  11. }
  12. }
  13. }
  14. }
  15. }

1.3 日期类型 - date

JSON没有日期数据类型, 所以在ES中, 日期可以是:

  • 包含格式化日期的字符串, "2018-10-01", 或"2018/10/01 12:10:30".
  • 代表时间毫秒数的长整型数字.
  • 代表时间秒数的整数.

如果时区未指定, 日期将被转换为UTC格式, 但存储的却是长整型的毫秒值.
可以自定义日期格式, 若未指定, 则使用默认格式: strict_date_optional_time||epoch_millis

(1) 使用日期格式示例:

  1. // 添加映射
  2. PUT website
  3. {
  4. "mappings": {
  5. "blog": {
  6. "properties": {
  7. "pub_date": {"type": "date"} // 日期类型
  8. }
  9. }
  10. }
  11. }
  12. // 添加数据
  13. PUT website/blog/11
  14. { "pub_date": "2018-10-10" }
  15. PUT website/blog/12
  16. { "pub_date": "2018-10-10T12:00:00Z" } // Solr中默认使用的日期格式
  17. PUT website/blog/13
  18. { "pub_date": "1589584930103" } // 时间的毫秒值

(2) 多种日期格式:

多个格式使用双竖线||分隔, 每个格式都会被依次尝试, 直到找到匹配的.
第一个格式用于将时间毫秒值转换为对应格式的字符串.

使用示例:

  1. // 添加映射
  2. PUT website
  3. {
  4. "mappings": {
  5. "blog": {
  6. "properties": {
  7. "date": {
  8. "type": "date", // 可以接受如下类型的格式
  9. "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
  10. }
  11. }
  12. }
  13. }
  14. }

1.4 布尔类型 - boolean

可以接受表示真、假的字符串或数字:

  • 真值: true, "true", "on", "yes", "1"...
  • 假值: false, "false", "off", "no", "0", ""(空字符串), 0.0, 0

1.5 二进制型 - binary

二进制类型是Base64编码字符串的二进制值, 不以默认的方式存储, 且不能被搜索.

使用示例:

  1. // 添加映射
  2. PUT website
  3. {
  4. "mappings": {
  5. "blog": {
  6. "properties": {
  7. "blob": {"type": "binary"} // 二进制
  8. }
  9. }
  10. }
  11. }
  12. // 添加数据
  13. PUT website/blog/1
  14. {
  15. "title": "Some binary blog",
  16. "blob": "hED903KSrA084fRiD5JLgY=="
  17. }

注意: Base64编码的二进制值不能嵌入换行符\n.

1.6 范围类型 - range

range类型支持以下几种:

类型 范围
integer_range $-2^{31}$ ~ $2^{31}-1$
long_range $-2^{63}$ ~ $2^{63}-1$
float_range 32位单精度浮点型
double_range 64位双精度浮点型
date_range 64位整数, 毫秒计时
ip_range IP值的范围, 支持IPV4和IPV6, 或者这两种同时存在

(1) 添加映射:

  1. PUT company
  2. {
  3. "mappings": {
  4. "department": {
  5. "properties": {
  6. "expected_number": { // 预期员工数
  7. "type": "integer_range"
  8. },
  9. "time_frame": { // 发展时间线
  10. "type": "date_range",
  11. "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
  12. },
  13. "ip_whitelist": { // ip白名单
  14. "type": "ip_range"
  15. }
  16. }
  17. }
  18. }
  19. }

(2) 添加数据:

  1. PUT company/department/1
  2. {
  3. "expected_number" : {
  4. "gte" : 10,
  5. "lte" : 20
  6. },
  7. "time_frame" : {
  8. "gte" : "2018-10-01 12:00:00",
  9. "lte" : "2018-11-01"
  10. },
  11. "ip_whitelist": "192.168.0.0/16"
  12. }

(3) 查询数据:

  1. GET company/department/_search
  2. {
  3. "query": {
  4. "term": {
  5. "expected_number": {
  6. "value": 12
  7. }
  8. }
  9. }
  10. }
  11. GET company/department/_search
  12. {
  13. "query": {
  14. "range": {
  15. "time_frame": {
  16. "gte": "208-08-01",
  17. "lte": "2018-12-01",
  18. "relation": "within"
  19. }
  20. }
  21. }
  22. }

查询结果:

  1. {
  2. "took": 26,
  3. "timed_out": false,
  4. "_shards": {
  5. "total": 5,
  6. "successful": 5,
  7. "skipped": 0,
  8. "failed": 0
  9. },
  10. "hits": {
  11. "total": 1,
  12. "max_score": 1.0,
  13. "hits": [
  14. {
  15. "_index": "company",
  16. "_type": "department",
  17. "_id": "1",
  18. "_score": 1.0,
  19. "_source": {
  20. "expected_number": {
  21. "gte": 10,
  22. "lte": 20
  23. },
  24. "time_frame": {
  25. "gte": "2018-10-01 12:00:00",
  26. "lte": "2018-11-01"
  27. },
  28. "ip_whitelist" : "192.168.0.0/16"
  29. }
  30. }
  31. ]
  32. }
  33. }

2 复杂数据类型

2.1 数组类型 - array

ES中没有专门的数组类型, 直接使用[]定义即可;

数组中所有的值必须是同一种数据类型, 不支持混合数据类型的数组:

① 字符串数组: ["one", "two"];
② 整数数组: [1, 2];
③ 由数组组成的数组: [1, [2, 3]], 等价于[1, 2, 3];
④ 对象数组: [{"name": "Tom", "age": 20}, {"name": "Jerry", "age": 18}].

注意:

  • 动态添加数据时, 数组中第一个值的类型决定整个数组的类型;
  • 不支持混合数组类型, 比如[1, "abc"];
  • 数组可以包含null值, 空数组[]会被当做missing field —— 没有值的字段.

2.2 对象类型 - object

JSON文档是分层的: 文档可以包含内部对象, 内部对象也可以包含内部对象.

(1) 添加示例:

  1. PUT employee/developer/1
  2. {
  3. "name": "ma_shoufeng",
  4. "address": {
  5. "region": "China",
  6. "location": {"province": "GuangDong", "city": "GuangZhou"}
  7. }
  8. }

(2) 存储方式:

  1. {
  2. "name": "ma_shoufeng",
  3. "address.region": "China",
  4. "address.location.province": "GuangDong",
  5. "address.location.city": "GuangZhou"
  6. }

(3) 文档的映射结构类似为:

  1. PUT employee
  2. {
  3. "mappings": {
  4. "developer": {
  5. "properties": {
  6. "name": { "type": "text", "index": "true" },
  7. "address": {
  8. "properties": {
  9. "region": { "type": "keyword", "index": "true" },
  10. "location": {
  11. "properties": {
  12. "province": { "type": "keyword", "index": "true" },
  13. "city": { "type": "keyword", "index": "true" }
  14. }
  15. }
  16. }
  17. }
  18. }
  19. }
  20. }
  21. }

2.3 嵌套类型 - nested

嵌套类型是对象数据类型的一个特例, 可以让array类型的对象被独立索引和搜索.

2.3.1 对象数组是如何存储的

① 添加数据:

  1. PUT game_of_thrones/role/1
  2. {
  3. "group": "stark",
  4. "performer": [
  5. {"first": "John", "last": "Snow"},
  6. {"first": "Sansa", "last": "Stark"}
  7. ]
  8. }

② 内部存储结构:

  1. {
  2. "group": "stark",
  3. "performer.first": [ "john", "sansa" ],
  4. "performer.last": [ "snow", "stark" ]
  5. }

③ 存储分析:

可以看出, user.first和user.last会被平铺为多值字段, 这样一来, John和Snow之间的关联性就丢失了.

在查询时, 可能出现John Stark的结果.

2.3.2 用nested类型解决object类型的不足

如果需要对以最对象进行索引, 且保留数组中每个对象的独立性, 就应该使用嵌套数据类型.

—— 嵌套对象实质是将每个对象分离出来, 作为隐藏文档进行索引.

① 创建映射:

  1. PUT game_of_thrones
  2. {
  3. "mappings": {
  4. "role": {
  5. "properties": {
  6. "performer": {"type": "nested" }
  7. }
  8. }
  9. }
  10. }

② 添加数据:

  1. PUT game_of_thrones/role/1
  2. {
  3. "group" : "stark",
  4. "performer" : [
  5. {"first": "John", "last": "Snow"},
  6. {"first": "Sansa", "last": "Stark"}
  7. ]
  8. }

③ 检索数据:

  1. GET game_of_thrones/_search
  2. {
  3. "query": {
  4. "nested": {
  5. "path": "performer",
  6. "query": {
  7. "bool": {
  8. "must": [
  9. { "match": { "performer.first": "John" }},
  10. { "match": { "performer.last": "Snow" }}
  11. ]
  12. }
  13. },
  14. "inner_hits": {
  15. "highlight": {
  16. "fields": {"performer.first": {}}
  17. }
  18. }
  19. }
  20. }
  21. }

3 地理数据类型

3.1 地理点类型 - geo point

地理点类型用于存储地理位置的经纬度对, 可用于:

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

(1) 添加映射:

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

(2) 存储地理位置:

  1. // 方式一: 纬度 + 经度键值对
  2. PUT employee/developer/1
  3. {
  4. "text": "小蛮腰-键值对地理点参数",
  5. "location": {
  6. "lat": 23.11, "lon": 113.33 // 纬度: latitude, 经度: longitude
  7. }
  8. }
  9. // 方式二: "纬度, 经度"的字符串参数
  10. PUT employee/developer/2
  11. {
  12. "text": "小蛮腰-字符串地理点参数",
  13. "location": "23.11, 113.33" // 纬度, 经度
  14. }
  15. // 方式三: ["经度, 纬度"] 数组地理点参数
  16. PUT employee/developer/3
  17. {
  18. "text": "小蛮腰-数组参数",
  19. "location": [ 113.33, 23.11 ] // 经度, 纬度
  20. }

(3) 查询示例:

  1. GET employee/_search
  2. {
  3. "query": {
  4. "geo_bounding_box": {
  5. "location": {
  6. "top_left": { "lat": 24, "lon": 113 }, // 地理盒子模型的上-左边
  7. "bottom_right": { "lat": 22, "lon": 114 } // 地理盒子模型的下-右边
  8. }
  9. }
  10. }
  11. }

3.2 地理形状类型 - geo_shape

是多边形的复杂形状. 使用较少, 这里省略.

可以参考这篇文章: Elasticsearch地理位置总结


4 专门数据类型

4.1 IP类型

IP类型的字段用于存储IPv4或IPv6的地址, 本质上是一个长整型字段.

(1) 添加映射:

  1. PUT employee
  2. {
  3. "mappings": {
  4. "customer": {
  5. "properties": {
  6. "ip_addr": { "type": "ip" }
  7. }
  8. }
  9. }
  10. }

(2) 添加数据:

  1. PUT employee/customer/1
  2. { "ip_addr": "192.168.1.1" }

(3) 查询数据:

  1. GET employee/customer/_search
  2. {
  3. "query": {
  4. "term": { "ip_addr": "192.168.0.0/16" }
  5. }
  6. }

4.2 计数数据类型 - token_count

token_count类型用于统计字符串中的单词数量.

本质上是一个整数型字段, 接受并分析字符串值, 然后索引字符串中单词的个数.

(1) 添加映射:

  1. PUT employee
  2. {
  3. "mappings": {
  4. "customer": {
  5. "properties": {
  6. "name": {
  7. "type": "text",
  8. "fields": {
  9. "length": {
  10. "type": "token_count",
  11. "analyzer": "standard"
  12. }
  13. }
  14. }
  15. }
  16. }
  17. }
  18. }

(2) 添加数据:

  1. PUT employee/customer/1
  2. { "name": "John Snow" }
  3. PUT employee/customer/2
  4. { "name": "Tyrion Lannister" }

(3) 查询数据:

  1. GET employee/customer/_search
  2. {
  3. "query": {
  4. "term": { "name.length": 2 }
  5. }
  6. }

参考资料

Elasticsearch 6.6 官方文档 - Field datatypes

Elasticsearch 5.4 Mapping详解

版权声明

作者: ma_shoufeng(马瘦风)

出处: 博客园 马瘦风的博客

您的支持是对博主的极大鼓励, 感谢您的阅读.

本文版权归博主所有, 欢迎转载, 但请保留此段声明, 并在文章页面明显位置给出原文链接, 否则博主保留追究相关人员法律责任的权利.

原文链接:http://www.cnblogs.com/shoufeng/p/10692113.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号