概念
Mapping(映射)用来定义文档包含的字段名、字段数据类型以及文档如何存储和索引这些字段的规则
显式映射 & 动态映射
显式映射
显式映射以完全控制字段的存储和索引方式。
显式映射的意义:
- 哪些字符串字段应该作为全文字段(text)处理。
- 哪些字段包含数字、日期或地理位置。
- 日期值的格式。
动态映射
当Elasticsearch在文档中检测到新字段时,会自动确定字段的数据类型,并自动把新字段添加到映射的过程称为动态映射。
ES映射类型
简单数据类型
字符串
text:会分词,不支持聚合
keyword:不会分词,将全部内容作为一个词条,支持聚合、排序
数值
long、integer、short、byte、double、float、half_float、scaled_float
布尔
类型值boolean。接受true、false值,也支持字符串"true"、"false" 或空字符串"",空字符串表示false。在聚合操作时,返回boolean类型使用1和0作为key,使用字符串“true”和“false”作为key_as_string。
二进制
类型值binary。接收一个Base64编码的二进制值。该类型定义的字段不可搜索,且默认不存储。
范围类型
integer_range、float_range、long_range、double_range、date_range
日期
JSON层次结构的类型
数组:[]
对象:{}
"mappings": {
"properties": {
"id":{
"type":"long"
},
"name":{
"properties": {
"firstname":{"type":"keyword"},
"lastname":{"type":"keyword"}
}
}
}
}
nested:直观的说Nested实际上就是Object的数组,但与对象数组实际存储方式又不同,下面有介绍
flattened
join为同一索引中的文档定义父子关系
特定类型
range
ip
version
geo_shape
completion
映射操作API
添加映射
PUT index7/_mapping
{
"properties":{
"name":{
"type":"keyword"
},
"age":{
"type":"integer"
},
"description":{
"type":"text",
"analyzer": "ik_max_word"
}
}
}
查询映射
GET index7/_mapping
添加字段
PUT index7/_mapping
{
"properties":{
"classid":{
"type":"integer"
},
"description":{
"type":"text"
}
}
}
Mapping参数
映射参数(mapping parameters)用于字段类型的映射,每个字段类型有一个或多个映射参数搭配使用。
analyzer
analyzer参数指定一个用于索引text字段时的文本分析的分析器,如果search_analyzer参数没有覆盖,该分析器也用于搜索时的文本分析。
只有text字段支持analyzer参数。
search_analyzer
查询时使用指定的分析器,默认情况下,搜索时将使用参数analyzer定义的分析器,从而保持与索引时一样的分析器
boost
增强匹配权重,默认1.0。通过设置boost参数的值,改变相关性得分的计算,进而可以影响单个字段相比于其他字段在查询时自动提升。如:title的匹配权重大于content匹配权重
PUT my_index_01
{
"mappings": {
"properties": {
"title": {
"type": "text",
"boost": 2
},
"content": {
"type": "text"
}
}
}
}
coerce
默认true。表示尝试清除脏数据值,以符合字段的数据类型,例如,如果字段数据类型为整数类型,那么输入的字符串强制转换为数字,浮点数将被截断。如果coerce参数设置为false,那么遇到脏数据不会进行强制转换,而是直接抛出异常。
通过配置参数index.mapping.coerce,可以进行索引级别的禁用coercion,类型级别的coercion作用优先级大于索引级别
PUT my_index_01
{
"settings": {
"index.mapping.coerce": false
},
"mappings": {
"properties": {
...
}
}
}
copy_to
将多个字段的值复制到组合字段中。然后可以将这个组合字段作为单个字段进行查询。如果经常搜索多个字段,可以通过copy_to参数来搜索更少的字段,进而提高搜索速度,如:first_name和last_name,复制到full_name
PUT my_index_01
{
"mappings": {
"properties": {
"first_name": {
"type": "text",
"copy_to": "full_name"
},
"last_name": {
"type": "text",
"copy_to": "full_name"
},
"full_name": {
"type": "text"
}
}
}
}
dynamic
参数dynamic,可以在文档和对象级别控制动态映射,参数dynamic可以设置为下列三种值:
(1)true:将新的检测到的字段添加到映射中。(默认)
(2)false:忽略新检测到的字段。这些字段将不会被索引,因此不能被搜索,但仍然会出现在返回命中的_source字段中。这些字段将不会添加到映射中,新的字段必须显式添加。
(3)strict:如果检测到新字段,则抛出异常并拒绝索引文档。新字段必须显式地添加到映射中。
fields
fields参数用于提供多字段。使得字段具有多种类型的功能。fields不会修改原始字段_source的值。
PUT my_index_01
{
"mappings": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
PUT my_index_01/_doc/1
{"city":"New York"}
PUT my_index_01/_doc/2
{"city":"York"}
GET my_index_01/_search
{
"query": {
"match": {
"city": "york"
}
},
"sort": {
"city.raw": "asc"
},
"aggs": {
"Cities": {
"terms": {
"field": "city.raw"
}
}
}
}
多字段用于多分析器,示例如下:
PUT my_index_01
{
"mappings": {
"properties": {
"text": { //1
"type": "text",
"fields": {
"english": { //2
"type": "text",
"analyzer": "english"
}
}
}
}
}
}
PUT my_index_01/_doc/1
{ "text": "quick brown fox" }
PUT my_index_01/_doc/2
{ "text": "quick brown foxes" }
GET my_index_01/_search
{
"query": {
"multi_match": {
"query": "quick brown foxes",
"fields": [ //3
"text",
"text.english"
],
"type": "most_fields" //3
}
}
}
注释1:text字段使用standard分析器。
注释2:text.english字段使用english分析器。
注释3:通过text和text.english字段合并得分。
format
通过format参数设置日期格式,参数值需要符合日期格式语法。自定义格式操作如下:
PUT my_index_01
{
"mappings": {
"properties": {
"date": {
"type": "date",
"format": "yyyy-MM-dd"
}
}
}
}
ignore_above
超过长度的字符串内容将不会被索引
properties
类型映射、object字段和nested字段包含的子字段称为属性(properties)。这些属性可以是任何数据类型,包括object和nested。属性可以在通过下列方式添加:
(1)通过在创建索引时显式地定义它们。
(2)通过在使用PUT Mapping API添加或更新映射类型时显式地定义它们。
(3)动态地索引包含新字段的文档。
创建索引时显式地定义示例如下:
PUT my_index_01
{
"mappings": {
"properties": {
"manager": {
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
},
"employees": {
"type": "nested",
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
}
}
}
}
store
单独存储属性值。默认对字段值进行索引以使其可搜索,但不单独存储它们,但是已存储在_source字段中
默认情况下,字段值被索引以使其可搜索,但不会被存储。这意味着可以查询字段,但不能检索原始字段值。通常这并不重要。字段值已经是_source字段的一部分,该字段默认存储。 如果您只想检索单个字段或几个字段的值,而不是整个_source的值,则可以使用source filtering来实现。
在某些情况下,文本的内容可能过大,我们不想将所有文本内容存储在_source字段,但有些字段内容又希望能被查找到,在这种情况下,可以使用store参数。例如,如果有一个有标题的文档,一个日期,和一个非常大的内容字段,我们只想要获取标题和日期内容,但又不想要内容字段,操作示例如下:
PUT my_index_01
{
"mappings": {
"_source": {
"enabled": false
},
"properties": {
"title": {
"type": "text",
"store": true
},
"date": {
"type": "date",
"store": true
},
"content": {
"type": "text"
}
}
}
}
ignore_malformed
index
index_options
index_phrases
index_prefixes
meta
norms
null_value
position_increment_gap
similarity
term_vector
doc_values
eager_global_ordinals
enabled
fielddata
search_quote_analyzer
其他
multi-field
multi_field 多域类型允许你对同一个值以映射的方式定义成多个基本类型 core_types . 这个非常有用,比如,如果你定义一个 string 类型的字段,你需要这个字段的分词一会是 analyzed ,但是有时候又希望该字段是 not_analyzed 类型的,通过使用 multi_field 就可以很方便的解决这个问题. 下面来看个例子:
{
"tweet" : {
"properties" : {
"name" : {
"type" : "multi_field",
"fields" : {
"name" : {"type" : "string", "index" : "analyzed"},
"untouched" : {"type" : "string", "index" : "not_analyzed"}
}
}
}
}
}
上面的例子,显示了我们是如何定义一个名为 name 的字段, 它的数据类型是 string 字符类型, 该字段映射了两次(实际物理上产生了2个索引字段),其中一个是以 name 的名称 定义为 analyzed 分词类型,另外一个定义成了名称为 untouched 的 not_analyzed 类型,即不分词处理.
字段访问
当使用 multi_field mapping定义之后, fields里面的和字段名称和外部的字段名称相同的字段定义会被当做该mult-field的默认字段(因为一个multi类型字段会被拆分成多个字段,所以,会有一个默认值),我们可以通过直接名称 name 或者使用 tweet.name 格式的方式来指定字段.
其它定义的不同名称的字段也可以通过使用特点的导航来指定(即使用“.”符合来分割),如: name.untouched, 或者还带上类型名称 tweet.name.untouched.
Nested和Object List有什么区别?
ES原生支持Object类型,也就是任意字段都可以是个对象,而ES又是所有字段都是多值,也就是都可以是list。那么在ES中Nested和Object List又是什么关系呢?
这就要从Object说起了。Object虽然是个对象,但是实际存储时是在当前文档里打平存储的。如上那个例子,如果只有一个user,那么在真实索引中实际上是下面这样的
{
"user.first" : "John",
"user.last" : "Smith"
}
而如果是个list,那么就成了
{
"user.first" : ["John","Alice"],
"user.last" : ["Smith","White"]
}
因为建索引时打平,因此检索时ES就无法知道到底是John Smith还是John White了。因此引入了Nested结构。
Nested将list里的每个doc单独变成子文档进行存储,因此在查询时就可以知道具体的结构信息了。
Nested因为是单独的子文档存储,因此在使用时,直接用 a.b.c 是无法访问的,需要将其套在nested查询里。除此之外,和其他的查询并无差异。
Nested案例:
PUT /my_index_01
{
"mappings" : {
"properties" : {
"my_object" : {
"type" : "nested"
}
}
}
}
PUT /my_index_01/_doc/1
{
"my_object" : [
{"name": "blue", "count": 10},
{"name": "red", "count": 1},
{"name": "yellow", "count": 20}
]
}
# Nested查询
GET /my_index_01/_search
{
"query": {
"nested" : {
"path" : "my_object",
"query" : {
"bool" : {
"must" : [
{ "match" : {"my_object.name" : "blue"} },
{ "range" : {"my_object.count" : {"gt" : 5}} }
]
}
},
"score_mode" : "avg"
}
}
}
参考:
https://www.jianshu.com/p/6b42a242c704