惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Palo Alto Networks Blog
P
Proofpoint News Feed
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog
Google DeepMind News
Google DeepMind News
N
Netflix TechBlog - Medium
Recorded Future
Recorded Future
M
MIT News - Artificial intelligence
罗磊的独立博客
J
Java Code Geeks
月光博客
月光博客
F
Full Disclosure
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
U
Unit 42
WordPress大学
WordPress大学
A
About on SuperTechFans
C
Cyber Attacks, Cyber Crime and Cyber Security
SecWiki News
SecWiki News
Security Latest
Security Latest
C
Check Point Blog
C
CERT Recently Published Vulnerability Notes
小众软件
小众软件
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
B
Blog RSS Feed
V
Visual Studio Blog
博客园_首页
NISL@THU
NISL@THU
I
Intezer
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
The Register - Security
The Register - Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Latest news
Latest news
Project Zero
Project Zero
博客园 - 叶小钗
C
Cybersecurity and Infrastructure Security Agency CISA
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy International News Feed
博客园 - 【当耐特】
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threat Research - Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
V
Vulnerabilities – Threatpost
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网

Xiaobin's Notes

Mac本地快速部署DeepSeek Electron的原理 如何让大语言模型输出JSON格式 webstorm 的 cpu 占用高 修改Joplin主题样式 ECMAScript 历代版本 新一代包管理器 PNPM React useEffect() Hook Vue 2.x 使用高德地图JS API 2.0加载起点终点路径轨迹 家庭用电插座 MacOS 14.4 引发Java 应用崩溃 重定向广告 Pyenv工具 ElasticSearch集群原理 ElasticSearch集群节点 Elasticsearch Mapping 参数 Elasticsearch元数据 Go语言的向后兼容和toolchain规则 Go 1.21 新增特性
Elasticsearch的数据类型
xbl · 2023-11-12 · via Xiaobin's Notes

本文基于 Elasticsearch 6.6.0

1 核心数据类型

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

(1) 使用示例:

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

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

1
2
3
4
5
6
7


{
"acknowledged": true,
"shards_acknowledged": true,
"index": "website"
}

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

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

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

1.1.1 文本类型 - text

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

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

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

使用示例:

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

1.1.2 关键字类型 - keyword

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

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

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

使用示例:

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

1.2 数字类型 - 8种

数字类型有如下分类:

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

使用注意事项:

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

使用示例:

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

1.3 日期类型 - date

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 添加映射
PUT website
{
"mappings": {
"blog": {
"properties": {
"pub_date": {"type": "date"} // 日期类型
}
}
}
}

// 添加数据
PUT website/blog/11
{ "pub_date": "2018-10-10" }

PUT website/blog/12
{ "pub_date": "2018-10-10T12:00:00Z" } // Solr中默认使用的日期格式

PUT website/blog/13
{ "pub_date": "1589584930103" } // 时间的毫秒值

(2) 多种日期格式:

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

使用示例:

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

1.4 布尔类型 - boolean

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

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

1.5 二进制型 - binary

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

(1) doc_values: 该字段是否需要存储到磁盘上, 方便以后用来排序、聚合或脚本查询. 接受truefalse(默认);
(2) store: 该字段的值是否要和_source分开存储、检索, 意思是除了_source中, 是否要单独再存储一份. 接受truefalse(默认).

使用示例:

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

注意: Base64编码的二进制值不能嵌入换行符\n, 逗号(0x2c)等符号.

1.6 范围类型 - range

range类型支持以下几种:

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

(1) 添加映射:

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

(2) 添加数据:

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

(3) 查询数据:

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

查询结果:

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
29
30
31
32
33
34
{
"took": 26,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1.0,
"hits": [
{
"_index": "company",
"_type": "department",
"_id": "1",
"_score": 1.0,
"_source": {
"expected_number": {
"gte": 10,
"lte": 20
},
"time_frame": {
"gte": "2018-10-01 12:00:00",
"lte": "2018-11-01"
},
"ip_whitelist" : "192.168.0.0/16"
}
}
]
}
}

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
2
3
4
5
6
7
8
9
PUT employee/developer/1
{
"name": "ma_shoufeng",
"address": {
"region": "China",
"location": {"province": "GuangDong", "city": "GuangZhou"}
}
}

(2) 存储方式:

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

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

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

2.3 嵌套类型 - nested

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

2.3.1 对象数组是如何存储的

① 添加数据:

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

② 内部存储结构:

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

③ 存储分析:

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

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

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

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

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

① 创建映射:

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

② 添加数据:

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

③ 检索数据:

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

3 地理数据类型

3.1 地理点类型 - geo point

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

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

(1) 添加映射:

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

(2) 存储地理位置:

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

// 方式二: "纬度, 经度"的字符串参数
PUT employee/developer/2
{
"text": "小蛮腰-字符串地理点参数",
"location": "23.11, 113.33" // 纬度, 经度
}

// 方式三: ["经度, 纬度"] 数组地理点参数
PUT employee/developer/3
{
"text": "小蛮腰-数组参数",
"location": [ 113.33, 23.11 ] // 经度, 纬度
}

(3) 查询示例:

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

3.2 地理形状类型 - geo_shape

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

4 专门数据类型

4.1 IP类型

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

(1) 添加映射:

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

(2) 添加数据:

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

(3) 查询数据:

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

4.2 计数数据类型 - token_count

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

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

(1) 添加映射:

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

(2) 添加数据:

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

(3) 查询数据:

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

参考资料

Elasticsearch 6.6 官方文档 - Field datatypes