Elasticsearch的Mapping,定义了索引的结构,类似于关系型数据库的Schema.
Mapping Type:每个索引都拥有唯一的 mapping type,用来决定文档将如何被索引。从7.x开始,不需要在Mapping中指定type信息,默认type为 _doc。mapping type由下面两部分组成
- Meta-fields:元字段用于自定义如何处理文档的相关元数据。 元字段的示例包括文档的_index,_type,_id和_source字段。
- Fields or properties:映射类型包含与文档相关的字段或属性的列表。
Mapping 字段设置流程
Flag: 啥场景下会用到 enable = false ?
字段类型
ES 字段类型主要有:核心类型、复杂类型、地理类型以及特殊类型,具体的数据类型如下图所示:
1、text
text类型的字段用来做全文检索,例如邮件的主题、淘宝京东中商品的描述等。这种字段在被索引存储前先进行分词,存储的是分词后的结果,而不是完整的字段。text字段不适合做排序和聚合。
如果是一些结构化字段,分词后无意义的字段建议使用keyword类型,例如邮箱地址、主机名、商品标签等。
常有参数包含以下:
- index:是否可以被搜索到。默认是true
- fields:Multi-fields允许同一个字符串值同时被不同的方式索引,例如用不同的analyzer使一个field用来排序和聚类,另一个同样的string用来分析和全文检索。如下
-
"IfFullyOpen ": { "type": "text", "fields": { "keyword": { "ignore_above": 256, //超过256个字符的文本,将会被忽略,不被索引 "type": "keyword" } } },
Flag : text 类字段默认不被列存?(是)
2、keyword 类型
keyword:不会被分词,适合简短、结构化字符串,例如主机名、姓名、商品名称等,可以用于过滤、排序、聚合检索,也可以用于精确查询。所以在es中应索引完整的字段,而不是分词后的结果。
3、object类型
mapping中不用特意指定field为object类型,因为这是它的默认类型。json类型天生具有层级的概念,文档内部还可以包含object类型进行嵌套。例如:
1 PUT my_index
2 {
3 "mappings": {
4 "properties": {
5 "region": {
6 "type": "keyword"
7 },
8 "manager": {
9 "properties": {
10 "age": { "type": "integer" },
11 "name": {
12 "properties": {
13 "first": { "type": "text" },
14 "last": { "type": "text" }
15 }
16 }
17 }
18 }
19 }
20 }
21 }
4、nest类型
nest类型是一种特殊的object类型,它允许object可以以数组形式被索引,而且数组中的某一项都可以被独立检索。而且es中没有内部类的概念,而是通过简单的列表来实现nest效果,例如下列结构的文档:
映射参数
- 详细映射参数见: Mapping parameters , 选部分参数进行解释
-
1 "field": { 2 "type": "text", //文本类型 3 4 "index": "false" // 设置成false,字段将不会被索引,倒序存储控制参数 5 6 "analyzer":"ik" //指定分词器 7 8 "boost":1.23 //字段级别的分数加权 9 10 "doc_values":false // 对 not_analyzed 字段,默认都是开启,analyzed字段不能使用,对排序和聚合能提升较大性能,节约内存,如果您确定不需要对字段进行排序或聚合,或者从script访问字段值,则可以禁用doc值以节省磁盘空间: 11 12 "fielddata": {"loading" : "eager" } //Elasticsearch 加载内存 fielddata 的默认行为是 延迟 加载 。 当 Elasticsearch 第一次查询某个字段时,它将会完整加载这个字段所有 Segment 中的倒排索引到内存中,以便于以后的查询能够获取更好的性能。 13 14 "fields":{"keyword": {"type": "keyword","ignore_above": 256}} //可以对一个字段提供多种索引模式,同一个字段的值,一个分词,一个不分词 15 16 "ignore_above":100 //超过100个字符的文本,将会被忽略,不被索引 17 18 "include_in_all":ture //设置是否此字段包含在_all字段中,默认是true,除非index设置成no选项 19 20 "index_options":"docs" //4个可选参数docs(索引文档号) ,freqs(文档号+词频),positions(文档号+词频+位置,通常用来距离查询),offsets(文档号+词频+位置+偏移量,通常被使用在高亮字段)分词字段默认是position,其他的默认是docs 21 22 "norms":{"enable":true,"loading":"lazy"} //分词字段默认配置,不分词字段:默认{"enable":false},存储长度因子和索引时boost,建议对需要参与评分字段使用 ,会额外增加内存消耗量 23 24 "null_value":"NULL" //设置一些缺失字段的初始化值,只有string可以使用,分词字段的null值也会被分词 25 26 "position_increament_gap":0 //影响距离查询或近似查询,可以设置在多值字段的数据上火分词字段上,查询时可指定slop间隔,默认值是100 27 28 "store":false //是否单独设置此字段的是否存储而从_source字段中分离,默认是false,只能搜索,不能获取值 29 30 "search_analyzer":"ik" //设置搜索时的分词器,默认跟ananlyzer是一致的,比如index时用standard+ngram,搜索时用standard用来完成自动提示功能 31 32 "similarity":"BM25" //默认是TF/IDF算法,指定一个字段评分策略,仅仅对字符串型和分词类型有效 33 34 "term_vector":"no"//默认不存储向量信息,支持参数yes(term存储),with_positions(term+位置),with_offsets(term+偏移量),with_positions_offsets(term+位置+偏移量) 对快速高亮fast vector highlighter能提升性能,但开启又会加大索引体积,不适合大数据量用 35 }
小结:
- 与域数据格式及约束相关的参数:normalizer,format,ignore_above,ignore_malformed,coerce
- 与索引相关的参数: index,dynamic,enabled
- 与存储策略相关的参数: store, fielddata,doc_values
- 分析器相关参数: analyzer,search_analyzer
- 其它参数: boost,copy_to,null_value
1、dynamic
是否允许动态的隐式增加字段。对于_source字段中包含一些原先未定义的字段采取的措施,根据dynamic的取值,会进行不同的操作
- true: 默认值,表示新的字段会加入到类型映射中。:
- false:新的字段会被忽略,即不会存入_souce字段中,即不会存储新字段,也无法通过新字段进行查询
- strict:会显示抛出异常,需要新使用put mapping api先显示增加字段映射。
-
1 "mappings":{ 2 "user":{ 3 "dynamic": strict, 4 "properties": { 5 "name": {"type": "text"}, 6 "address": {"type": "object", "dynamic": true} 7 } 8 } 9 }
2、 doc_values
是为了加快排序、聚合操作,在建立倒排索引的时候,额外增加一个列式存储映射,是一个空间换时间的做法。默认是开启的,对于确定不需要聚合或者排序的字段可以关闭。
-
"session_id": { "type": "keyword", "doc_values": false }
文本(text)字段不支持 doc_values,为了实现 text 字段的聚合、排序, 替代的方案:文本(text)字段使用查询时内存中的数据结构,称为fielddata
fielddata是 text 型的字段查询时使用一个内存型数据结构。该数据结构是根据需求第一次建立的,用于聚合、排序或脚本。它是通过从磁盘读取每个段的整个倒排索引、反转术语_文档关系并将结果存储在JVM堆的内存中来构建的。
fielddata会占用大量的堆内存,尤其是在加载的高基数的text型字段。 一旦 fielddata 被加载到堆里,它会一直存在于字段的生命周期中。此外,加载字段数据是一个昂贵的过程,这可能会导致用户体验延迟命中。这就是为什么默认情况下禁用fielddata 的原因
4、copy_to
用于将当前字段拷贝到指定字段:
- _all在7.x版本已经被copy_to所代替
- copy_to将字段数值拷贝到目标字段,实现类似_all的作用
- copy_to的目标字段不出现在_source中
- 在设置mapping的时候加上 store:true
-
1 PUT my_index 2 { 3 "mappings": { 4 "properties": { 5 "first_name": { 6 "type": "text", 7 "copy_to": "full_name" 8 }, 9 "last_name": { 10 "type": "text", 11 "copy_to": "full_name" 12 }, 13 "full_name": { 14 "type": "text", 15 "store": true 16 } 17 } 18 } 19 }
- 查询 : GET my_index/_doc/1?stored_fields=full_name
- 测试实例可参考:https://blog.csdn.net/pony_maggie/article/details/108397409
Flag:
1、啥场景下会用到 enable = false ? 不能被检索、排序、聚合?
2、text 字段要聚合排序可以用 fields ,为什么又有 fielddata、其与docValues ?
Re: 在ElasticSearch中,doc_values和fielddata就是用来给文档建立正排索引的。他俩一个很显著的区别是,前者的工作地盘主要在磁盘,而后者的工作地盘在内存。
-
-
ElasticSearch对于非分词字段,默认doc_value是开启的,如果非常确定某个字段将来不会用来排序或者聚合操作,可以显示地指定关闭doc_value;
-
对于分词字段,如果未将fielddata显示开启,则对于分词字段的排序、聚合操作将会报错。开启fielddata需要慎重,因为开销是昂贵的,还有oom风险。
3、生产环境订单宽表字段太多,换成 object 类型分层会有性能提升吗?此 object 从_source去掉,开启store?
4、为保证数据结构的统一,业务明细表、汇总表禁用动态mapping?
参考资料