作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
1、映射
1.1、动态映射
底层会自动的根据存入的数据判断数据类型,这种自动分析就叫动态映射。
创建一个索引:
PUT book/_doc/1
{
"name": "三国演义",
"author": "罗贯中",
"price": 20,
"publishDate": "2020-01-01"
}
查看动态映射:
GET /book/_mapping
返回:
{
"book" : {
"mappings" : {
"properties" : {
"author" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"price" : {
"type" : "long"
},
"publishDate" : {
"type" : "date"
}
}
}
}
}
text:字符串,存储需要分词的。
keyword:字符串,存储不需要分词的。
动态映射还有一个日期检测的问题。可以看到 publishDate 的数据类型会被推断是日期类型。如果这个时候再存一本书,publishDate 不是日期,而是其他数据类型,那么存储一定会报错;如果是要存字符串类型,我们存数字类型,都一样可以,因为字符串跟数字可以转换,但是日期类型不能转换。
要解决这个问题,可以使用静态映射,即在索引定义时,将 publishDate 指定为 text 类型。也可以关闭日期检测:
PUT blog
{
"mappings": {
"date_detection": false
}
}
默认情况下,文档中如果新增了字段,mappings 中也会自动新增进来。有的时候,如果希望新增字段时,能够抛出异常来提醒开发者,这个可以通过 mappings 中 dynamic属性来配置。但是这么设置,其实也就是变成静态映射了。
1.2、静态映射
如果希望新增字段时,能够抛出异常来提醒开发者,这个可以通过 mappings 中 dynamic属性来配置。
dynamic 属性有三种取值:
- true:默认即此。自动添加新字段。
- false:忽略新字段。
- strict:严格模式,发现新字段会抛出异常。
PUT blog
{
"mappings": {
"dynamic": "strict",
"properties": {
"title": {
"type": "text"
},
"age": {
"type": "long"
}
}
}
}
静态映射的意思就是在定义索引时,就把索引中的所有字段类型,统统提前定义枚举好,那么以后往索引中加数据和字段时,就只能按照规定好的加。
PUT /user
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"phone": {
"type": "keyword"
},
"age": {
"type": "integer"
}
}
}
}
1.3、类型推断
JSON中的数据 | 自动推断出来的数据类型 |
---|---|
null | 没有字段被添加 |
true/false | boolean |
浮点数字 | float |
数字 | long |
JSON对象 | object |
数组 | 数组中的第一个非空值决定 |
string | text/keyword/date/double/long都有可能 |
2、核心类型
2.1、字符串类型
- string :这是一个已经过期的字符串类型。在 es5 之前,用这个来描述字符串,现在的话,它已经被 text 和 keyword替代了。
- text :如果一个字段是要被全文检索的,比如说博客内容、新闻内容、产品描述,那么可以使用text。用了 text
之后,字段内容会被分析,在生成倒排索引之前,字符串会被分词器分成一个个词项。text类型的字段不用于排序,很少用于聚合。这种字符串也被称为 analyzed 字段。 - keyword :这种类型适用于结构化的字段,例如标签、email地址、手机号码等等,这种类型的字段可以用作过滤、排序、聚合等。这种字符串也称之为 not-analyzed 字段。
2.2、数字类型
类型 | 取值范围 |
---|---|
long | -2^63到2^63-1 |
integer | -2^31到2^31-1 |
short | -2^15到2^15-1 |
byte | -2^7到2^7-1 |
double | 64位的双精度IEEE754浮点类型 |
float | 32位的双精度IEEE754浮点类型 |
half_float | 16位的双精度IEEE754浮点类型 |
scaled_float | 缩放类型的浮点类型 |
- 在满足需求的情况下,优先使用范围小的字段。字段长度越短,索引和搜索的效率越高。
- 浮点数,优先考虑使用 scaled_float。
scaled_float 举例:
PUT /product
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"price": {
"type": "scaled_float",
"scaling_factor": 100
}
}
}
}
2.3、日期类型
由于 JSON 中没有日期类型,所以 es 中的日期类型形式就比较多样:
- 2020-11-11 或者 2020-11-11 11:11:11
- 一个从 1970.1.1 零点到现在的一个秒数或者毫秒数。
es 内部将时间转为 UTC,然后将时间按照 millseconds-since-the-epoch 的长整型来存储。
自定义日期类型:
PUT /product
{
"mappings": {
"properties": {
"date": {
"type": "date"
}
}
}
}
这个能够解析出来的时间格式比较多:
PUT /product/_doc/1
{
"date": "2020-11-11"
}
PUT /product/_doc/2
{
"date": "2020-11-11T11:11:11Z"
}
PUT /product/_doc/3
{
"date": "1604672099958"
}
上面三个文档中的日期都可以被解析,内部存储的是毫秒计时的长整型数。
2.4、布尔类型(boolean)
JSON 中的 “true”、“false”、true、false 都可以。
2.5、二进制类型(binary)
二进制接受的是 base64 编码的字符串,默认不存储,也不可以搜索。
PUT /img
{
"mappings": {
"properties": {
"icon": {
"type": "binary"
}
}
}
}
2.6、范围类型
integer_range | 一个带符号的32位整数范围,最小值为,最大值为。 |
---|---|
integer_range | 一个带符号的32位整数范围,最小值为,最大值为。 |
float_range | 一系列单精度32位IEEE754浮点值。 |
long_range | 一系列带符号的64位整数,最小值为-2的63次方,最大值为2的63次方-1。 |
double_range | 一系列双精度64位IEEE754浮点值。 |
date_range | 自系 EPOCH 以来经过的一系列日期值,表示为无符号的64位整数毫秒。 |
ip_range | 支持IPv4或IPv6(或混合)地址的一系列ip值。 |
定义的时候,指定范围类型即可:
PUT range_index
{
"mappings": {
"properties": {
"expected_attendees": {
"type": "integer_range"
},
"time_frame": {
"type": "date_range",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
新增一个文档:
PUT range_index/_doc/1?refresh
{
"expected_attendees" : {
"gte" : 10,
"lte" : 20
},
"time_frame" : {
"gte" : "2015-10-31 12:00:00",
"lte" : "2015-11-01"
}
}
在上面的文档中,我们输入了两个 range 的数据,它们分别对应我们之前在 mapping 中定义的 integer_range 及 date_range。
下面我们可以使用一个 term query 来查询 integer_range 字段 expected_attendees:
GET range_index/_search
{
"query": {
"term": {
"expected_attendees": {
"value": "10"
}
}
}
}
返回:
{
"took" : 6,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "range_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"expected_attendees" : {
"gte" : 10,
"lte" : 20
},
"time_frame" : {
"gte" : "2015-10-31 12:00:00",
"lte" : "2015-11-01"
}
}
}
]
}
}
因为 10 刚好是在我们之前的文档定义的 10-20 区间。为了验证我们的搜索是否有效,我们可以做另外的一个搜索:
GET range_index/_search
{
"query": {
"term": {
"expected_attendees": {