mapping参数doc_values fielddata enabled index norms coerce
1 前言
Elasticsearch的mapping字段类型非常丰富, 字段类型还有很多参数可设置, 知晓这些参数, 可以优化提高ES存储空间和性能.
在学习mapping的参数配置前, 先大致了解下正排索引和倒排索引.
我水平有限, 可参考大佬的博客Doc Values and Fielddata
2 正排索引
说到正排索引, 我们就想到MySQL, 一般ID为主键, 根据ID可以直接查询到对应文档.
如果根据非主键查数据,在不考虑索引时, MySQL会全表扫描, 找出匹配的数据, 效率低.
正排索引, 他结构比较简单, 根据ID能快速查询到数据.
id | name | sex |
---|---|---|
1 | vissy | 女 |
2 | winter | 男 |
3 | good | 女 |
举例:
查找name包含"king"的数据
正排索引会遍历所以的3条数据, 找出匹配的结果是ID=1和3的文档
根据age排序
正排索引会遍历所以的3条数据, 然后根据age排序
3 倒排索引
倒排索引以词为关键字进行索引, 如下图:第一列是上面表格内容拆分后的词, 第二列是文档ID
- 在真实ES内部,倒排索引第二列还维护词的词频, 位置, 偏移量信息
- 从下表可分析,数据量一旦很大, 这个倒排索引表还是很复杂的, 内容也会很巨大
- 它的好处是, 根据词来查询时, 能直接获取文档ID, 找到文档, 不用全表扫描, 效率很高
- 倒排索引擅长检索, 不擅长做聚合和排序, 所以有了doc_values
- doc_values是列式存储结构, 它擅长聚合和排序
词 | 文档ID |
---|---|
vissy | 1 |
winter | 2 |
good | 3 |
男 | 2 |
女 | 1, 3 |
4 doc_values
为了加快排序、聚合操作,在建立倒排索引的时候,额外增加一个列式存储映射,是一个空间换时间的做法。默认是开启的,对于确定不需要聚合或者排序的字段可以关闭。
- 在ES保持文档,构建倒排索引的同时doc_values就被生成了, doc_values数据太大时, 它存储在电脑磁盘上.
- doc_values是列式存储结构, 它擅长做聚合和排序
- 对于非分词字段, doc_values默认值是true(开启的), 如果确定某字段不参与聚合和排序,可以把该字段的doc_values设为false
- 例如SessionID, 它是keyword类型, 对它聚合或排序毫无意义, 需要把doc_values设为false, 节约磁盘空间
- 分词字段不能用doc_values
实验: 创建index, session_id的doc_values为false
PUT pigg_test_docvalues
{
"mappings":{
"properties":{
"status_code":{
"type":"keyword"
},
"session_id":{
"type":"keyword",
"doc_values":false
}
}
}
}
# 插入下面2个文档
PUT pigg_test_docvalues/_doc/1
{
"status_code": "200",
"session_id": "aaa"
}
PUT pigg_test_docvalues/_doc/2
{
"status_code": "500",
"session_id": "bbb"
}
测试对session_id进行检索
GET pigg_test_docvalues/_search
{
"query": {
"term": {
"session_id": {
"value": "aaa"
}
}
}
}
返回有数据
"hits" : [
{
"_index" : "pigg_test_docvalues",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.6931471,
"_source" : {
"status_code" : "200",
"session_id" : "aaa"
}
}
]
测试对session_id排序
GET pigg_test_docvalues/_search
{
"sort": [
{
"session_id": {
"order": "desc"
}
}
]
}
返回报错
"caused_by" : {
"type" : "illegal_argument_exception",
"reason" : "Can't load fielddata on [session_id] because fielddata is unsupported on fields of type [keyword]. Use doc values instead."
}
测试对session_id聚合
GET pigg_test_docvalues/_search
{
"aggs": {
"terms_by_sessionId": {
"terms": {
"field": "session_id"
}
}
}
}
返回报错
"caused_by" : {
"type" : "illegal_argument_exception",
"reason" : "Can't load fielddata on [session_id] because fielddata is unsupported on fields of type [keyword]. Use doc values instead."
}
5 fielddata
- fielddata默认false, 用在text类型的字段上, fielddata存在内存里
- doc_values是不支持text字符串字段的, doc_values存在磁盘上
- 例如某个text类型字段, 它是分词的, 正常是不能对text字段进行聚合和排序的
- 但是text字段的fielddata设为true后, 就可以对text字段进行聚合和排序
- 与 doc values 不同,fielddata 构建和管理 100% 在内存中,常驻于JVM内存堆
- fielddata是延迟加载的。如果你从来没有聚合一个分析字符串,就不会加载 fielddata 到内存中,是在查询时候构建的
- 文档很多时, fielddata非常占内存, 所以不建议在分词的字段上进行聚合和排序
实验: 插入index
PUT pigg_test_fielddata
{
"mappings": {
"properties": {
"field_one": {
"type": "text"
},
"field_two": {
"type": "text",
"fielddata": true
}
}
}
}
PUT pigg_test_fielddata/_doc/1
{
"field_one": "我不能排序和聚合",
"field_two": "我能排序和聚合"
}
根据fielddata=false的字段排序,会报错
GET pigg_test_fielddata/_search
{
"sort": [
{
"field_one": {
"order": "desc"
}
}
]
}
返回的错误说的很清楚, 建议用keyword字段, 或者设置text字段fielddata=true(很耗内存)
"caused_by" : {
"type" : "illegal_argument_exception",
"reason" : "
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 [field_one] in order to load field data by uninverting the inverted index.
Note that this can use significant memory."
}
根据fielddata=true的字段排序,会返回正确
GET pigg_test_fielddata/_search
{
"sort": [
{
"field_two": {
"order": "desc"
}
}
]
}
返回:
"hits" : [
{
"_index" : "pigg_test_fielddata",
"_type" : "_doc",
"_id" : "1",
"_score" : null,
"_source" : {
"field_one" : "我不能排序和聚合",
"field_two" : "我能排序和聚合"
},
"sort" : [
"能"
]
}
]
6 coerce
coerce: 是否开启自动数据类型转换功能, 默认是true(开启)
例如:
- 字符串"10"自动转数字10
- 浮点数10.0自动转整型10
实验: 创建一个index
field_one默认coerce为true
field_two设置coerce为false
PUT pigg_test_coerce
{
"mappings": {
"properties": {
"field_one": {
"type": "integer"
},
"field_two": {
"type": "integer",
"coerce": false
}
}
}
}
# 执行成功
PUT pigg_test_coerce/_doc/1
{
"field_one": "10"
}
# 执行报错: failed to parse field [field_two] of type [integer] in document
PUT pigg_test_coerce/_doc/2
{
"field_two": "10"
}
7 enabled
- enabled默认值是true(开启)
- enabled只用于mapping中的object字段类型。当设置为false时,其作用是使es不去解析该字段
- 默认情况下,ES会给所有字段进行索引操作, 这样就可以根据该字段检索文档
- 但是当不需要索引某个字段时(例如session信息), 只需要在文档里返回该字段, 可设置enabled=false
- 设置enabled=false的字段可以存任意类型的值, 包括JSON对象
实验如下:
PUT pigg_test_enabled
{
"mappings": {
"properties": {
"name": {
"enabled": false}
}
}
}
插入多种格式的值
PUT pigg_test_enabled/_doc/1
{
"name": "winter"
}
PUT pigg_test_enabled/_doc/2
{
"name": {
"first_name": "wang",
"last_name": "dong"
}
}
GET pigg_test_enabled/_search
返回发现: 不同的值都可以存入
"hits" : [
{
"_index" : "pigg_test_enabled",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "winter"
}
},
{
"_index" : "pigg_test_enabled",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : {
"first_name" : "wang",
"last_name" : "dong"
}
}
}
]
# 查看mapping
GET pigg_test_enabled/_mapping
返回如下: name类型是object, 并不会解析name在其下面添加first_name和last_name子字段
{
"pigg_test_enabled" : {
"mappings" : {
"properties" : {
"name" : {
"type" : "object",
"enabled" : false
}
}
}
}
}
在enable=false的字段上检索文档, 是查询不到数据的
GET pigg_test_enabled/_search
{
"query": {
"term": {
"name": {
"value": "winter"
}
}
}
}
返回没有数据
8 index
- index默认是true
- 当设置为false,表明该字段不能被被检索, 不构建倒排索引,如果查询会报错。但是可以被store。
- 如果对字段进行term、terms 查询,聚合(aggregations)操作,脚本(script)操作以及用来排序(sort), 需要设为true。
- 和上面enabled有区别, index不能用在object类型上, enabled只能用在object类型上
实验: 创建一个索引, 其中words字段index=false
PUT pigg_test_index
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"words": {
"type": "keyword",
"index": false
}
}
}
}
#插入如下数据
PUT pigg_test_index/_doc/1
{
"name": "亚瑟王",
"words": "死亡骑士, 不是死掉的骑士"
}
PUT pigg_test_index/_doc/2
{
"name": "扁鹊",
"words": "命长的是赢家"
}
查询文档, _source是有words的
"hits" : [
{
"_index" : "pigg_test_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "亚瑟王",
"words" : "死亡骑士, 不是死掉的骑士"
}
},
{
"_index" : "pigg_test_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "扁鹊",
"words" : "命长的是赢家"
}
}
]
在index=false的字段上检索文档
GET pigg_test_index/_search
{
"query": {
"term": {
"words": {
"value": "命长的是赢家"
}
}
}
}
该查询会报错:
"caused_by" : {
"type" : "illegal_argument_exception",
"reason" : "Cannot search on field [words] since it is not indexed."
}
最喜欢玩老亚瑟
9 norms
- 不分词的字段,默认 false
- Norms 存储各种用于在查询时计算查询条件的相关性得分的标准化因子。
- 虽然norms 在计算相关性得分时非常有用, 但是同样需要消耗大量内存。
- norms 的配置应该在字段和 索引的设置上保持一致
PUT my_index/_mapping/_doc
{
"properties": {
"title": {
"type": "text",
"norms": false
}
}
}