前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Elasticsearch Mapping

Elasticsearch Mapping

作者头像
程序猿杜小头
发布2022-12-01 21:31:35
7780
发布2022-12-01 21:31:35
举报
文章被收录于专栏:程序猿杜小头程序猿杜小头

Elasticsearch Mapping

Elasticsearch Mapping用于定义文档。比如:文档所拥有的字段、文档中每个字段的数据类型、哪些字段需要进行索引等。本文将先后从mapping typemapping parametermapping fieldmapping explosion这四个维度展开。

1 Mapping Type

Elasticsearch Mapping有两种类型,分别是Dynamic Mapping和Explicit Mapping。

1.1 Dynamic Mapping

Dynamic Mapping,即动态映射。动态映射使得我们在索引文档时甚至不需要新增一个空的索引,更无需配置显式映射,其自动将文档中新字段插入到索引的mapping中。另外,动态映射默认为text类型字段生成一个keyword类型的字段。动态映射的核心逻辑:

  • 新字段自动检测
  • 新字段自动插入

假设现有一my-index-000001索引,其mapping如下:

代码语言:javascript
复制
{
    "my-index-000001": {
        "mappings": {
            "properties": {
                "content": {
                    "type": "text"
                },
                "date": {
                    "type": "date",
                    "store": true
                },
                "title": {
                    "type": "text",
                    "store": true
                }
            }
        }
    }
}

然后,我们新增一个包含author新字段的文档:

代码语言:javascript
复制
PUT /my-index-000001/_doc/1
{
    "content": "i am optimus prime",
    "title": "transformers",
    "date": "2021-01-19",
    "author": "optimus prime"
}

最后,验证my-index-000001索引的mapping中是否已包含author字段:

代码语言:javascript
复制
{
    "my-index-000001": {
        "mappings": {
            "properties": {
                "author": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "content": {
                    "type": "text"
                },
                "date": {
                    "type": "date",
                    "store": true
                },
                "title": {
                    "type": "text",
                    "store": true
                }
            }
        }
    }
}

1.2 Explicit Mapping

Explicit Mapping,即显式映射。显式映射允许我们更加精细化地定义文档,比如:哪些字段是全文搜索字段、哪些字段是数值型、日期数据类型的格式、自定义动态映射的规则等。

2 Mapping Parameter

2.1 type

type参数用于声明字段的数据类型。

2.2 analyzer

Only text fields support the analyzer mapping parameter.

在index和search场景中,analyzer参数用于指定针对text类型字段进行文本分析时所使用的分析器。如果试图针对同一text类型字段在index和search场景使用不同的分析器,那么你需要使用search_analyzer来单独声明search场景所使用的分析器。

代码语言:javascript
复制
{
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "my_index_analyzer",
                "search_analyzer": "my_search_analyzer"
            }
        }
    }
}

2.3 boost

  1. The boost is applied only for term queries.
  2. Index time boost is deprecated. Instead, the field mapping boost is applied at query time.

boost,即权重提升,默认值为1。常见地,我们可以为特定字段设定权重提升值,其值越大,那么该字段对最后相关度得分的提升越明显。

2.3.1 权重提升设定方式一
代码语言:javascript
复制
PUT /my-index-000001
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "boost": 2 
      },
      "content": {
        "type": "text"
      }
    }
  }
}

GET /my-index-000001/_search
{
  "query": {
    "match": {
      "title": {
        "query": "quick brown fox"
      }
    }
  }
}
2.3.2 权重提升设定方式二
代码语言:javascript
复制
GET /my-index-000001/_search
{
  "query": {
    "match": {
      "title": {
        "query": "quick brown fox",
        "boost": 2
      }
    }
  }
}

2.4 dynamic

dynamic参数用于控制是否启用动态映射特性,其值如下:

描述

true

默认值,新字段会自动添加到mapping中

runtime

新字段作为运行时字段被添加到mapping中

false

新字段不会添加到mapping中,这些字段既无法被索引也无法被搜索

strict

如果检测到新字段,那么会抛出异常,进而导致文档写入失败

2.5 doc_values

doc values是一种在索引文档时构建于磁盘的数据结构,doc values存储的值与_source字段相同,只不过是以面向列的方式存储,这对于排序和聚合而言更为有效。几乎所有字段类型都支持doc_values参数,但text和annotated_text类型字段除外。

默认情况下,在所有支持doc values的字段中,doc_values值均为true。如果你确定不需要对字段进行排序或聚合操作,也不需要通过script访问字段值,则可以将doc_values置为false,从而以节省磁盘空间。

2.6 enabled

Elasticsearch尝试索引所有字段,但有时你只想存储该字段而不索引该字段,即无需对该字段进行搜索或者聚合操作,那么你就可以将enabled值置为false。enabled参数仅适用于mapping中的顶级字段且数据类型必须为object。若enabled值为true,那么Elasticsearch会跳过对其内容进行解析,但依然会存储该字段。默认值为true。

代码语言:javascript
复制
PUT /my-index-000001
{
    "mappings": {
        "properties": {
            "user_id": {
                "type": "keyword"
            },
            "last_updated": {
                "type": "date"
            },
            "session_data": {
                "type": "object",
                "enabled": false
            }
        }
    }
}

PUT /my-index-000001/_doc/session_1
{
    "user_id": "kimchy",
    "session_data": {
        "arbitrary_object": {
            "some_array": [
                "foo",
                "bar",
                {
                    "baz": 2
                }
            ]
        }
    },
    "last_updated": "2015-12-06T18:20:22"
}

GET /my-index-000001/_doc/session_1
{
    "_index": "my-index-000001",
    "_type": "_doc",
    "_id": "session_1",
    "_version": 1,
    "_seq_no": 0,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "user_id": "kimchy",
        "session_data": {
            "arbitrary_object": {
                "some_array": [
                    "foo",
                    "bar",
                    {
                        "baz": 2
                    }
                ]
            }
        },
        "last_updated": "2015-12-06T18:20:22"
    }
}

2.7 copy_to

copy_to参数可以将多个字段的值复制到多个字段中,然后可以将其作为单个字段进行查询;如果相关字段值是通过copy_to参数填充的,那么这些字段并不会在_source字段中出现。如果你经常搜索多个字段,则可以通过使用copy_to参数来搜索更少的字段,从而来提高搜索速度。

代码语言:javascript
复制
PUT /my-index-000001
{
    "mappings": {
        "properties": {
            "first_name": {
                "type": "text",
                "copy_to": "full_name"
            },
            "last_name": {
                "type": "text",
                "copy_to": "full_name"
            },
            "full_name": {
                "type": "text"
            }
        }
    }
}

PUT /my-index-000001/_doc/1
{
    "first_name": "John",
    "last_name": "Smith"
}

GET /my-index-000001/_search
{
    "query": {
        "match": {
            "full_name": {
                "query": "John Smith",
                "operator": "and"
            }
        }
    }
}
{
    "took": 128,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 0.5753642,
        "hits": [
            {
                "_index": "my-index-000001",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.5753642,
                "_source": {
                    "first_name": "John",
                    "last_name": "Smith"
                }
            }
        ]
    }
}

2.8 fields

针对同一字段,你可能既想对其进行全文检索,又想将其作为排序或者聚合字段;亦或对同一字段采用不同的分词器等。

2.8.1 场景一
代码语言:javascript
复制
PUT /my-index-000001
{
    "mappings": {
        "properties": {
            "city": {
                "type": "text",
                "fields": {
                    "raw": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}
2.8.2 场景二
代码语言:javascript
复制
PUT /my-index-000001
{
    "mappings": {
        "properties": {
            "text": {
                "type": "text",
                "fields": {
                    "english": {
                        "type": "text",
                        "analyzer": "english"
                    }
                }
            }
        }
    }
}

2.9 format

format参数用于将特定格式的字符串日期解析为毫秒值。

2.10 ignore_above

Strings longer than the ignore_above setting will not be indexed, But the whole string will still be present in the _source field.

如果某字段所包含的字符长度大于ignore_above值,那么该字段将不会被索引,但整个字段值依然会完好无损地出现在_source字段中。

2.11 index

index参数用于控制是否对相关字段进行索引,默认值为true。

2.12 normalizer

normalizer是简化版的analyzer,其仅包含character filtertoken filter,既然没有tokenizer分词器模块,那么normalizer只能生成一个分词。

2.13 null_value

null_value参数主要用于将null替换为指定内容,因为一旦字段值为null,那么就无法索引从而也就无法进行搜索。具体如下:

代码语言:javascript
复制
PUT /my-index-000001
{
    "mappings": {
        "properties": {
            "status_code": {
                "type": "keyword",
                "null_value": "NULL"
            }
        }
    }
}

PUT /my-index-000001/_doc/1
{
    "status_code": null
}

GET /my-index-000001/_search
{
    "query": {
        "term": {
            "status_code": "NULL"
        }
    }
}
{
    "took": 66,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 0.2876821,
        "hits": [
            {
                "_index": "my-index-000001",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.2876821,
                "_source": {
                    "status_code": null
                }
            }
        ]
    }
}

2.14 position_increment_gap

当索引多值字段时,Elasticsearch会在该字段各个值之间添加一个间隙,间隙值的大小,取决于position_increment_gap参数值,其默认值为100。接下来,我们通过短语匹配来加深对该参数的理解。

代码语言:javascript
复制
PUT /my-index-000001/_doc/1
{
  "names": [ "John Abraham", "Lincoln Smith"]
}

GET /my-index-000001/_search
{
    "query": {
        "match_phrase": {
            "names": {
                "query": "Abraham Lincoln"
            }
        }
    }
}
{
    "took": 0,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 0,
            "relation": "eq"
        },
        "max_score": null,
        "hits": []
    }
}

很明显,并没有搜索到文档,这是为什么呢?这时就需要分词器登场了。

代码语言:javascript
复制
GET /_analyze
{
    "tokenizer": "standard",
    "text": [ "John Abraham", "Lincoln Smith"]
}
{
    "tokens": [
        {
            "token": "John",
            "start_offset": 0,
            "end_offset": 4,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "Abraham",
            "start_offset": 5,
            "end_offset": 12,
            "type": "<ALPHANUM>",
            "position": 1
        },
        {
            "token": "Lincoln",
            "start_offset": 13,
            "end_offset": 20,
            "type": "<ALPHANUM>",
            "position": 102
        },
        {
            "token": "Smith",
            "start_offset": 21,
            "end_offset": 26,
            "type": "<ALPHANUM>",
            "position": 103
        }
    ]
}

分析上述分词结果后,我们可以察觉到position_increment_gap参数的默认值的确为100,因为第二个文本中第一个分词Lincoln的position为102,其计算公式如下:

代码语言:javascript
复制
final position = original position + position_increment_gap

为了得到正确的搜索结果,我们可以通过使用slop参数为短语匹配引入一定程度的灵活性,slop指分词的最大移动次数。

代码语言:javascript
复制
GET /my-index-000001/_search
{
    "query": {
        "match_phrase": {
            "names": {
                "query": "Abraham Lincoln",
                "slop": 100
            }
        }
    }
}
{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 0.010358453,
        "hits": [
            {
                "_index": "my-index-000001",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.010358453,
                "_source": {
                    "names": [
                        "John Abraham",
                        "Lincoln Smith"
                    ]
                }
            }
        ]
    }
}

短语匹配在slop参数的加持下的确灵活很多:

代码语言:javascript
复制
GET /my-index-000001/_search
{
    "query": {
        "match_phrase": {
            "names": {
                "query": "Lincoln Abraham",
                "slop": 102
            }
        }
    }
}
{
    "took": 0,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 0.010158896,
        "hits": [
            {
                "_index": "my-index-000001",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.010158896,
                "_source": {
                    "names": [
                        "John Abraham",
                        "Lincoln Smith"
                    ]
                }
            }
        ]
    }
}

2.15 similarity

similarity参数用于指定相关度得分的算法模型,其值如下:

描述

BM25

即Okapi_BM25算法,默认值

classic

即TF/IDF算法,Elasticsearch 7.0.0后该算法已经废弃

boolean

2.16 store

It’s also possible to store an individual field’s values by using the store mapping option. You can use the stored_fields parameter to include these stored values in the search response.

默认情况下,Elasticsearch对字段值进行索引以使其可搜索,但并不存储它们。这意味着可以查询该字段,但是无法检索原始字段值。通常这无关紧要,因为该字段值已经是_source字段的一部分,默认情况下,_source字段是已存储的。store参数默认值为false,那么什么时候建议将其显式置为true呢?假设文档中有三个字段,分别是:title、date和content,其中content字段内容很长,可能你仅仅想获取title和date字段值,那么这时你就需要将其显式置为true,具体如下:

代码语言:javascript
复制
PUT /my-index-000001
{
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "store": true
            },
            "date": {
                "type": "date",
                "store": true
            },
            "content": {
                "type": "text"
            }
        }
    }
}

PUT /my-index-000001/_doc/1
{
    "title": "Some short title",
    "date": "2015-01-01",
    "content": "A very long content field..."
}

GET /my-index-000001/_search
{
    "stored_fields": [
        "title",
        "date"
    ]
}
{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "my-index-000001",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0,
                "fields": {
                    "date": [
                        "2015-01-01T00:00:00.000Z"
                    ],
                    "title": [
                        "Some short title"
                    ]
                }
            }
        ]
    }
}

3 Mapping Field

通俗的说,文档是一系列字段的集合。本章节从字段类型字段数据类型两个维度进行展开。

3.1 Field Type

3.1.1 Metadata Field

元字段

描述

_id

文档唯一标识

_source

_source字段包含索引文档时传入的原生JSON;_source字段本身不会被索引,但会被存储

_type

文档映射类型

_index

标识文档所属索引

_routing

文档路由标识,默认文档ID

_doc_count

每个存储桶中已聚合和已分区的文档数量

3.1.2 Runtime Field

运行时字段特性在Elasticsearch 7.11中依然处于beta版本,因此这里不作介绍。

3.2 Field Data Type

3.2.1 Text

text数据类型适用于存储文本内容。Elasticsearch默认通过标准分析器对这些文本内容进行文本分析,文本分析包含分词预处理、分词和分词后处理三个流程。text数据类型的字段不能用于排序和聚合。另外,对于结构化的文本内容,你应该优先使用keyword作为其数据类型,如:邮箱地址、域名、状态码和标签等。

参数

默认值

analyzer

standard analyzer

boost

1.0

fielddata

false

fields

index

true

position_increment_gap

100

store

每个存储桶中已聚合和已分区的文档数量

search_analyzer

Defaults to the analyzer setting

search_quote_analyzer

Defaults to the analyzer setting

similarity

BM25

3.2.2 Keyword

从场景看,keyword数据类型一般应用于需要排序或者聚合的字段;从存储内容看,keyword数据类型比较适合结构化的文本,如:邮箱地址、域名、标签等;从搜索的角度看,keyword数据类型适合分词级别的精确匹配,而不适用于全文检索。事实上,一旦字段被映射为keyword数据类型,那么Elasticsearch并不会对其进行文本分析,这一点你可以从其参数中得到验证,因为它不像text数据类型有analyzer参数。

参数

默认值

boost

1.0

doc_values

true

fields

ignore_above

2147483647

index

false

null_value

null

store

false

similarity

BM25

normalizer

null

3.2.3 IP

ip数据类型适用于IPv4和IPv6。

参数

默认值

boost

1.0

doc_values

true

index

false

null_value

null

store

false

3.2.4 Numeric

Elasticsearch主要支持以下几种数值型数据类型:

数值型数据类型

取值区间

long

[-2^63, 2^63-1]

integer

[-2^31, 2^31-1]

short

[-32768, 32767]

byte

[-128, 127]

float

单精度32位IEEE 754浮点数

double

双精度64位IEEE 754浮点数

unsigned_long

[0, 2^64-1]


参数

默认值

boost

1.0

doc_values

true

index

false

null_value

null

store

false

3.2.5 Date

在JSON中是没有date数据类型的,所以Elasticsearch中的date可以是以下几种类型:

  • 格式化的字符串日期,如:"2015-01-01" 和 "2015/01/01 12:10:30"
  • 13位整型时间戳
  • 10位整型时间戳

参数

默认值

boost

1.0

doc_values

true

format

strict_date_optional_time

locale

Root Locale

index

false

null_value

null

store

false

3.2.6 Boolean

参数

默认值

boost

1.0

doc_values

true

index

false

null_value

null

store

false

3.2.7 Object

参数

默认值

dynamic

true

enabled

false

properties

4 Mapping Explosion & Mapping Limit Setting

Mapping Explosion,即映射膨胀。在索引中定义太多字段会导致映射膨胀,这可能会导致内存不足错误和难以恢复的情况。为了更好地应对动态映射或显式映射带来的映射膨胀问题,Elasticsearch提供了如下限制参数:

配置项

描述

默认值

index.mapping.total_fields.limit

索引中字段最大数量

1000

index.mapping.depth.limit

索引中字段最大层级数

20

index.mapping.nested_fields.limit

索引中嵌套字段最大数量

50

index.mapping.nested_objects.limit

索引中嵌套JSON对象最大数量

10000

index.mapping.field_name_length.limit

索引中字段最大长度值

Long.MAX_VALUE

代码语言:javascript
复制
PUT /<index-name>/_settings
{
    "settings": {
        "index": {
            "mapping": {
                "total_fields.limit": 100,
                "depth.limit": 10,
                "nested_fields.limit": 20,
                "nested_objects.limit": 100,
                "field_name_length.limit": 200
            }
        }
    }
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-02-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿杜小头 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Elasticsearch Mapping
    • 1 Mapping Type
      • 1.1 Dynamic Mapping
      • 1.2 Explicit Mapping
    • 2 Mapping Parameter
      • 2.1 type
      • 2.2 analyzer
      • 2.3 boost
      • 2.4 dynamic
      • 2.5 doc_values
      • 2.6 enabled
      • 2.7 copy_to
      • 2.8 fields
      • 2.9 format
      • 2.10 ignore_above
      • 2.11 index
      • 2.12 normalizer
      • 2.13 null_value
      • 2.14 position_increment_gap
      • 2.15 similarity
      • 2.16 store
    • 3 Mapping Field
      • 3.1 Field Type
      • 3.2 Field Data Type
    • 4 Mapping Explosion & Mapping Limit Setting
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档