ElasticSearch中有一个非常重要的特性——动态映射,即索引文档前不需要创建索引、类型等信息,在索引的同时会自动完成索引、类型、映射的创建。
当ES在文档中碰到一个以前没见过的字段时,它会利用动态映射(dynamic mapping)来决定该字段的类型,并自动地对该字段添加映射。
有时这正是需要的行为,但有时不是,需要留意。你或许不知道在以后你的文档中会添加哪些字段,但是你想要它们能够被自动地索引。或许你只是想要忽略它们。或者,尤其当你将ES当做主要的数据存储使用时,大概你会希望这些未知的字段会抛出异常来提醒你注意这一问题。
幸运的是,你可以通过dynamic设置来控制这一行为,它能够接受以下的选项:
true:默认值。动态添加字段false:新检测到的字段将被忽略。这些字段将不会被索引,因此将无法搜索,但仍将出现在返回点击的源字段中。这些字段不会添加到映射中,必须显式添加新字段。strict:如果碰到陌生字段,抛出异常dynamic设置可以适用在根对象上或者object类型的任意字段上。你应该默认地将dynamic设置为strict,但是为某个特定的内部对象启用它:
创建mapping
PUT /my_index{ "mappings": { "dynamic": "strict", "properties": { "title": { "type": "text" }, "address": { "type": "object", "dynamic": "true" } } }插入数据
PUT /my_index/_doc/1{ "title": "my article", "content": "this is my article", "address": { "province": "guangdong", "city": "guangzhou" }}报错,原因为content为新增字段。会抛出异常
{ "error": { "root_cause": [ { "type": "strict_dynamic_mapping_exception", "reason": "mapping set to strict, dynamic introduction of [content] within [_doc] is not allowed" } ], "type": "strict_dynamic_mapping_exception", "reason": "mapping set to strict, dynamic introduction of [content] within [_doc] is not allowed" }, "status": 400}如果你知道你需要动态的添加的新字段,那么你也许会启用动态映射。然而有时动态映射的规则又有些不够灵活。幸运的是,你可以调整某些设置来让动态映射的规则更加适合你的数据。
es会根据传入的值,推断类型,具体如下表所示。
JSON data type | Elasticsearch data type | ES中的数据类型 |
| No field is added. | 不会添加字段 |
|
| boolean |
floating point number |
| double |
integer |
| long |
object |
| object |
array | Depends on the first non- | 依赖于第一个非null得值 |
string | Either a | 如果通过了date检测,则为date 如果通过了numeric检测,则为Number |
默认会按照一定格式识别date,比如yyyy-MM-dd。但是如果某个field先过来一个2017-01-01的值,就会被自动dynamic mapping成date,后面如果再来一个"hello world"之类的值,就会报错。可以手动关闭某个type的date_detection,如果有需要,自己手动指定某个field为date类型。
首先删除上面新建的索引
DELETE my_index然后下面的语句代表的含义为:日期探测为false,表示可添加不是date数据类型的字段,也不会被推断成date类型。address字段里面为true,代表可动态往里面添加新的字段。
PUT /my_index{ "mappings": { "date_detection": false, "properties": { "title": { "type": "text" }, "address": { "type": "object", "dynamic": "true" } } }}测试插入数据。下面的语句代表最外层级新增content、post_date两个字段,address层级新增province、city字段。
PUT /my_index/_doc/1{ "title": "my article", "content": "this is my article", "address": { "province": "guangdong", "city": "guangzhou" }, "post_date": "2019-09-10"}查看映射
GET /my_index/_mapping返回,可以看到字段都成功新增,日期检测(date_detection)为false,所以post_date字段类型不是date类型。
{ "my_index" : { "mappings" : { "date_detection" : false, "properties" : { "address" : { "dynamic" : "true", "properties" : { "city" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "province" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } }, "content" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "post_date" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "title" : { "type" : "text" } } } }}下面为自定义日期格式语法,读者可自行试验。
PUT my_index{ "mappings": { "dynamic_date_formats": ["MM/dd/yyyy"] }}插入数据
PUT my_index/_doc/1{ "create_date": "09/25/2019"}虽然json支持浮点和整数数据类型,但某些应用程序或语言有时可能需要将数字呈现为字符串。通常正确的解决方案是显式地映射这些字段,但是可以启用数字检测(默认情况下禁用)来自动完成这些操作。
首先删除上面新建的索引
DELETE my_index然后开启数字检测
PUT my_index{ "mappings": { "numeric_detection": true }}插入数据
PUT my_index/_doc/1{ "my_float": "1.0", "my_integer": "1"}查看映射
GET my_index/_mapping返回
{ "my_index" : { "mappings" : { "numeric_detection" : true, "properties" : { "my_float" : { "type" : "float" }, "my_integer" : { "type" : "long" } } } }}可以看到两个字段被映射为浮点类型了。
通过dynamic_templates,你可以拥有对新字段的动态映射规则拥有完全的控制。你设置可以根据字段名称或者类型来使用一个不同的映射规则。
每个模板都有一个名字,可以用来描述这个模板做了什么。同时它有一个mapping用来指定具体的映射信息,和至少一个参数(比如match)用来规定对于什么字段需要使用该模板。
首先删除上面新建的索引
DELETE my_index运行下面的语句,代表的含义为:匹配以_en结尾并且是string类型的字段,设置它的type为text,使用english分词。
PUT /my_index{ "mappings": { "dynamic_templates": [ { "en": { "match": "*_en", "match_mapping_type": "string", "mapping": { "type": "text", "analyzer": "english" } } } ] }}插入数据
PUT /my_index/_doc/1{ "title": "this is my first article"}PUT /my_index/_doc/2{ "title_en": "this is my first article"}查看映射
GET my_index/_mapping返回,可以看到title_en字段采用english分词器,说明模板生效了。
{ "my_index" : { "mappings" : { "dynamic_templates" : [ { "en" : { "match" : "*_en", "match_mapping_type" : "string", "mapping" : { "analyzer" : "english", "type" : "text" } } } ], "properties" : { "title" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "title_en" : { "type" : "text", "analyzer" : "english" } } } }}搜索
GET my_index/_search?q=firstGET my_index/_search?q=istitle字段没有匹配到任何的dynamic模板,默认就是standard分词器,不会过滤停用词,is会进入倒排索引,用is来搜索是可以搜索到的
title_en字段匹配到了dynamic模板,就是english分词器,会过滤停用词,is这种停用词就会被过滤掉,用is来搜索就搜索不到了
下面给出了一些大概的写法,读者可根据自身实际需求自定义模板
PUT my_index{ "mappings": { "dynamic_templates": [ { "integers": { "match_mapping_type": "long", "mapping": { "type": "integer" } } }, { "strings": { "match_mapping_type": "string", "mapping": { "type": "text", "fields": { "raw": { "type": "keyword", "ignore_above": 256 } } } } } ] }}模板参数:匹配满足的字段、不匹配满足的字段、匹配的数据类型、路径匹配、路径不匹配。
"match": "long_*","unmatch": "*_text","match_mapping_type": "string","path_match": "name.*","path_unmatch": "*.middle","match_pattern": "regex","match": "^profit_\d+$"默认情况下,elasticsearch将字符串字段映射为带有子关键字(keyword)字段的文本字段。但是,如果只对结构化内容进行索引,而对全文搜索不感兴趣,则可以仅将“字段”映射为“关键字”。但是请注意,这意味着为了搜索这些字段,必须搜索索引所用的完全相同的值。
{ "strings_as_keywords": { "match_mapping_type": "string", "mapping": { "type": "keyword" } } }与前面的示例相反,如果您只关心字符串字段的全文搜索,并且不打算对字符串字段运行聚合、排序或精确搜索,您可以将其仅映射为文本字段(这是es5之前的默认行为)
{ "strings_as_text": { "match_mapping_type": "string", "mapping": { "type": "text" } } }当计算得分的时候,是否需要把字段长度用作参数计算。
尽管计算得分时把字段长度考虑在内可以提高得分的精确性,但这样会消耗大量的磁盘空间(每个文档的每个字段都会消耗一个字节,即使某些文档不包含这个字段)。因此,如果不需要计算字段的得分,你应该禁用该字段的norms。特别是这个字段仅用于聚合或者过滤。
{ "properties": { "title": { "type": "text", "norms": false } }}
本文来自博客园,作者:|旧市拾荒|,转载请注明原文链接:https://www.cnblogs.com/xiaoyh/p/16024245.html