ElasticSearch Mapping 设置详解以及dynamic mapping、自定义mapping

概念

Mapping 映射,描述了文档字段的属性以及每个字段的数据类型,比如 string, integer 或 date —以及Lucene是如何索引和存储这些字段的,这就是mapping 映射的功能。
这样说可能有些偏概念,我们可以这样来理解,对于mysql数据库来说,每一个表都有一个 schemal 定义,mapping 就是类似 数据库的 schemal,它来描述 索引文档的字段信息。

  • mapping 类似数据库中的 schemal 定义
    - 定义索引文档中的字段的名称
    - 定义索引文档中字段的类型,比如 string, integer 或 date
    - 字段,倒排索引的配置,比如配置 Analyzed 倒排索引分词规则,是否进行分词等
  • mapping 会把 JSON 文档映射成 Lucene 需要的扁平格式
    - Lucene 没有文档、映射的概念,Lucene解析一个文档为一组简单的字段键值对,类似分词的概念,比如一个字符串可以通过分析过程转化为多个值。Lucene 不关心这些值是字符串、数字或日期—​所有的值都被当做 不透明字节 ,这些是不利用户理解的,所以 ElasticSearch 通过 Mapping 来将问那个映射成为Lucene 需要的扁平格式。
  • 一个 mapping 属于一个索引的 type,每个type 都有一份 mapping 定义,在 7 中默认只有一个 type,所以不需要考虑一个索引下的多个type的mapping定义
# 查看一个索引的mapping
GET movies/_mapping
{
  "movies" : {
    "mappings" : {
      "properties" : {
        "genre" : {  # 字段名字
          "type" : "text", # 字段类型
          "analyzer": "whitespace" # 倒排索引分词器
        },
        "id" : {
          "type" : "text",    
        },
        "title" : {
          "type" : "text",
        },
        "year" : {
          "type" : "long"
        }
      }
    }
  }
}

上边就是一个mapping实例,大致样子就是这样,可以看到,定义了字段的名字、类型、倒排索引分析器等信息

ElasticSearch 的数据类型

  • 简单类型
    - Text / Keyword 字符串文本类型
    - Date 日期类型
    - Integer long / Float dubbo 数字类型
    - Boolean 布尔值类型
    - IPV4 / IPV6 ip地址类型
  • 复杂类型
    - 对象 / 嵌套对象
  • 特殊类型
    - geo_point $ geo_shap / percolator 地理位置信息
    ElasticSearch 中有数组的概念,但是数组不是一个数据类型,而且一个 ElasticSearch 数据类型的集合。
Text 与 keyword的区别
  • 简单单词,例如 “Apple” 这种的,他就是一个单词,不需要再去分词,或者 1 这种的,可以使用 keyword 或者其他的简单数据类型
  • 全文本,类似 “hello world elastic” 这种的,是一个短语,就需要建立倒排索引来统计词项,这种的可以使用 text 这种全文本类型,搭配分词器使用。
  • keyword 不会去分词,支持精确查找,text 会去分词,支持部分搜索

动态映射

当 Elasticsearch 遇到文档 mapping 中以前所没有定义过的字段时,它会自动确定字段的数据类型并把新的字段添加到 mapping 中,这叫做动态映射。
这样的机制,一般场景还能满足,如果有特殊场景,可能会导致 一些字段不能正确映射,至少与你预期的不一致,这个时候可以选择关闭动态映射,手动添加映射关系,默认动态映射是开启的。

dynamic = true 动态添加新的字段—​缺省
		  false 忽略新的字段
		  strict 如果遇到新字段抛出异常

dynamic mapping 有如下特性

  • 在写入文档时,如果索引不存在,会自动创建索引并且自动映射
  • dynamic mapping 使得我们无需自己去定义 mapping 的类型,ElasticSearch 会自动根据文档信息去推算出字段的类型。
  • 推算特殊时候会失败,比如地理信息,会推算成 字符串文本

自动推算的类型识别

JSON 类型Elastic 类型
字符串text
布尔值boolean
浮点数float
整数long (对,不是integer)
对象Object
数组由第一个非空数字决定类型
空值 null忽略

我们来测试一下自动类型推断

#写入文档,查看 Mapping
PUT mapping_test/_doc/1
{
  "firstName":"Chan",
  "lastName": "Jackie",
  "loginDate":"2018-07-24T10:29:48.103Z",
  "bat": null,
  "age": 11
}

#查看 Mapping文件
GET mapping_test/_mapping
结果:{
  "mapping_test" : {
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "firstName" : {
          "type" : "text",
        },
        "lastName" : {
          "type" : "text",
        },
        "loginDate" : {
          "type" : "date"
        }
      }
    }
  }
}

我们可以看到结果, age 被计算成了 long, loginDate被计算成了 date,bat 则被忽略掉了

dynamic 值的配置

dynamic配置不同时,新增字段的状态是不一样的

  • dynamic 为 true
    - 有新字段加入,mappin也会自动更新
  • dynamic 为 false
    - 有新字段加入,mapping不会被更新,但是新字段会被加入到 _source 元数据中,不过不能被索引查询
  • dynamic 为 strict
    - 写入直接失败
  • 已有的字段,是不支持修改 mapping的,无论 dynamic 配置是什么,这是 Lucene的 特性,倒排索引一旦生成,不支持修改 (除非重建索引 Reindex API)
修改 dynamic API

修改 dynamic 之前,这条索引必须已经存在,否则会异常

#修改dynamic false
PUT dynamic_mapping_test/_mapping
{
  "dynamic": false
}
dynamic 为 false 的测试

我们设置 dynamic为 false并且新增一个字段 anotherField

#修改为dynamic false
PUT dynamic_mapping_test/_mapping
{
  "dynamic": false
}

#新增 anotherField
PUT dynamic_mapping_test/_doc/10
{
  "anotherField":"someValue"
}
新增结果
{
  "_index" : "dynamic_mapping_test",
  "_type" : "_doc",
  "_id" : "10",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

结果显示新增字段成功了,我们查看一下索引 mapping 、_source 以及 search一下

#查看mapping
get dynamic_mapping_test/_mapping
{
  "dynamic_mapping_test" : {
    "mappings" : {
      "dynamic" : "false",
      "properties" : {
        "newField" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}
#查询这条数据
get dynamic_mapping_test/_doc/10
{
  "_index" : "dynamic_mapping_test",
  "_type" : "_doc",
  "_id" : "10",
  "_version" : 1,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "anotherField" : "someValue"
  }
}
#该字段不可以被搜索,因为dynamic已经被设置为false
POST dynamic_mapping_test/_search
{
  "query":{
    "match":{
      "anotherField":"someValue"
    }
  }
}
搜索结果:{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ] # hits 为空不能被搜索
  }
}

可以看到,_source中有这个字段,但是mapping中没有这个字段映射,并且不能被搜索

显式设定自定义 mapping

有些时候 dynamic mapping 会出现一些纰漏,所以一般在生产中使用 ElasticSearch 时,dynamic mapping 是关闭的并且使用自定义的设定 mapping 方式来管理索引映射。
显式的设定 mapping Api 其实是很简单的,请求格式如下:

  • 请求方法(PUT) + 索引名字 + mapping的JSON
PUT users
{
    "mappings" : {
      "properties" : {
        "firstName" : {
          "type" : "text"
        },
        "lastName" : {
          "type" : "text"
        },
        "mobile" : {
          "type" : "text",
        }
      }
    }
}

如上就是一个自定义mapping的设置格式,一般在 mapping 下是由一个 properties 属性的,这个是格式。

注意

  • 手动设定mapping的时候,要参考mapping的API设置手册,来保证你的映射字段是最适合的,比如类型,text 是会分词的,keyword 则是精确搜索不会分词,这些需要根据需求去处理
  • mapping 文件很大的,为了减少工作量可以拷贝一个模板过来照着改你的字段

Mapping 字段的一些配置属性

一个 mapping 映射文件,并不是如上只设置一个数据类型便好的,mapping还可以设置很多属性。

控制当前字段是否被索引(创建倒排索引)
  • index 属性控制当前字段是否可以在搜索中被索引搜索,默认为 true, 如果设置为false,则这个字段不能被搜索,因为不会为这个字段去创建倒排索引。比如用户的手机号这种私密信息,不希望被搜索可以设置这个(不能搜索但是不代表这个数据不会出现在_source中)
# 设置索引 mobile 为 index:false
PUT users
{
    "mappings" : {
      "properties" : {
        "firstName" : {
          "type" : "text"
        },
        "mobile" : {
          "type" : "text",
          "index": false  # 设置不允许创建倒排所云
        }
      }
    }
}

# 索引一个文档
PUT users/_doc/1
{
  "firstName":"Ruan",
  "lastName": "Yiming",
  "mobile": "12345678"
}

#根据 mobile 搜索
POST /users/_search
{
  "query": {
    "match": {
      "mobile":"12345678"
    }
  }
}
# 报错 非法参数异常
 "index": "users",
 "caused_by": {
    "type": "illegal_argument_exception",
    "reason": "Cannot search on field [mobile] since it is not indexed."
}
null_value 处理 null 值

ElasticSearch 在处理 null 值得搜索时,是不会去处理的,但是如果我们有需求,就是要对一些null值做搜索,那应该怎么办,这个时候就可以设置 null_value 属性。

  • 需要对 null 值进行搜索
  • 只有keyword 类型支持 null_value
PUT users
{
    "mappings" : {
      "properties" : {
        "firstName" : {
          "type" : "text"
        }
        "mobile" : {
          "type" : "keyword",
          "null_value": "empty"
        }

      }
    }
}

以上就是一个 null_value的配置,这个 empty 是你在搜索时要指定的那个值,相当于是代替 null的一个标识,只要使用 empty ,便是表明你要搜索 null 值。 'empty ’ 可以替代为任何值,比如 ‘ddd’ 都行。

# 一个有 null 值的文档
PUT users/_doc/1
{
  "firstName":"Ruan",
  "lastName": "Yiming",
  "mobile": null
}
# 正常的索引搜索
POST /users/_search
{												"hits" : {
  "query": {											 "total"{}
    "match": {											"max_score" : null,
      "mobile":"null"									"hits" : [ ]
    }												 }
  }
}

# 设置了 null_value 之后的值
GET users/_search                              "hits" : [
{													   {
  "query": {												"_index" : "users",
    "match": {												"_type" : "_doc",
      "mobile":"empty"										"_source" : {
    }															"firstName" : "Ruan",
  }																 "mobile" : null
}																}
														}

正常的结果是没有找到数据,我们再试一下设置了 null_value的字段,通过 empty 去查找,发现找到了mobile 为 null 的值。

copy_to 聚合多个字段的值为一个搜索项

copy_to 有些类似废弃的 _all 属性,它所起的功能是将多个字段的值组合为一个搜索项,然后支持搜索,比如有个文档 ‘one’:‘start’,‘two’:‘end’,然后在这两个值上设置了copy_to 属性,那么最终会合成一个搜索项 ‘start end’.

  • 满足一些特定的搜索需求
  • 将多个字段的值拷贝到目标搜索字段
  • copy_to 的目标字段不会出现在 _source 中
#设置 Copy to
PUT users
{
  "mappings": {
    "properties": {
      "firstName":{
        "type": "text",
        "copy_to": "fullName"
      },
      "lastName":{
        "type": "text",
        "copy_to": "fullName"
      }
    }
  }
}

以上就是一个 copy_to 的使用方法,最终将 firstName 与 lastName合并成了一个 fullName。

#索引一个文档
PUT users/_doc/1
{
  "firstName":"Ruan",
  "lastName": "Yiming"
}
#搜索fulleName 为两个字段的组合值
GET users/_search?q=fullName:(Ruan Yiming)
结果:
"hits" : [
      {
        "_index" : "users",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "firstName" : "Ruan",
          "lastName" : "Yiming"
        }
      }
    ]

最终是可以通过 fullName 将文档搜索出来,但是在 _source 中,并没有 fullName 这个字段,也就是文档中其实并不不存在 fullName,只是建了一个fullName的倒排索引。

fields 多字段属性

多字段属性,可以让同一个 text 文本有多种不同的索引方式,包括使用不同的分词器,ElasticSearch 默认会为text 文本添加一个 keyword 的搜索方式,支持精确查找以及聚合等功能。

  • 增加 keyword 支持精确查找
  • 配置 analyzer 使用不同的语言分词器
# 多字段属性
PUT users
{
    "mappings" : {
      "properties" : {
        "firstName" : {
          "type" : "text",
          "fields": {
            "keyword": { # 配置了一个子字段 keyword 支持精确查找
              "type": "keyword"
            },
            "english": { # 配置了一个子字段 english 支持 英文分词
              "type": "text",
              "analyzer": "english"
            }
          }
        }
      }
    }
}
# 搜索
POST /users/_search
{
  "query": {
    "match": {
      "firstName.english":"Ruan"
    }
  }
}
分词器

是在处理 text 文本这种类型是建立倒排索引所需要的词项处理工具,他会根据不同的规则去处理词项,比如中文分词器,会根据汉语的规则去分词,中文分词器比较好用的是清华大学研制的一款ElasticSearch 分词器。

PUT users
{
    "mappings" : {
      "properties" : {
        "firstName" : {
          "type" : "text",
           "analyzer": "english"
        }
      }
    }
}

如上就是一个多字段的配置,在 firstName 下,我们多了两个子字段,一个支持精确查找,一个支持英文分词,搜索的时候可以 firstName.keyword 或者 firstName.english 来指定使用哪个功能。

mapping parameters 全部的参数设置

参数名描述
analyzer分词器(分析器),配置这个指定倒排索引根据什么去分词,比如:“analyzer”: “ik_max_word”
normalizer用于解析前的标准化配置,比如把所有的字符转化为小写等
boost设置字段的权重,会在搜索时优先考虑这个值 例如:“boost”: 2
coerce是否去自动转化文档字段数据为mapping的映射类型,关闭之后如果添加文档时类型不相符则会报错 例如:“coerce”: false
copy_to将多个字段的值组合成为一个 搜索项,只能被搜索,不会出现在 _source中,例如:“copy_to”: “full_name”
doc_values是否保存字段到磁盘中,关闭后字段数据将不会存储到磁盘中并且不会被索引以及聚合。例如: “doc_values”: false
dynamic对嵌套字段是否开启动态映射功能 例如: “dynamic”: true
enabled与 index 功能类似,只会被存储并不会被搜索。例如:“enabled”: false
fielddatafielddata会占用大量的堆内存,是针对text型的字段查询的一个数据结构,它会将 text 的词项在查询时保存到内存中来做索引,资源消耗很大,不推荐使用,默认不要开启就好了
eager_global_ordinals全局映射器,开启这个会默认在分片中为词项分配一个全局的递增序列号,倒排索引时只需要处理这个序列号便可以不需要加载原本的数据值,这个参数可以优化查询性能。例如:“eager_global_ordinals”: true
format用于格式化日期属性 比如:“format”: “yyyy-MM-dd”
ignore_above超过 ignore_above 的字符串不会被索引存储。对于字符串数组, 如果单个子元素字符串超过了 ignore_above也不会被索引存储。例如:“ignore_above”: 20
ignore_malformedignore_malformed可以无视不规则数据。一般如果数据格式映射不对整个文档会报错,如果ignore_malformed参数设为true,异常会被忽略,出异常的字段不会被索引,其它字段正常索引。“ignore_malformed”: true
index_optionsindex_options 参数控制将哪些信息添加到倒排索引,用于搜索和突出显示目的,这个一般默认就好,是建立倒排索引用的。
index_phrases与 copy_to 的功能类似
index_prefixes设置前缀索引的索引词范围 例如:“index_prefixes”: { “min_chars” : 1, “max_chars” : 10 }
index是否为该字段建立倒排索引,默认为true,设为false,不能被搜索
fields多字段属性,可以让 同一 text 文本有多种不同的索引方式,动态映射默认就是用的这个
normsnorms 在计算相关性得分时很有用, 用于在查询时计算查询条件的相关性得分的标准化因子,但是同样需要消耗大量内存。例如:“norms”: false
null_value指定null值可被搜索
position_increment_gap为了支持短语查询,需要保存可分词字符串自顿啊中分词的位置。当字符串字段索引多个值,一个“虚拟”缺口会被加载各个值之间来防止短语查询跨值匹配,缺口的大小可以使用position_increment_gap配置,默认100. 例如 :“position_increment_gap”: 10
properties一般是一个mapping的跟节点,会将 字段,对象,嵌套对象类型的 子字段成为属性可以直接被搜索。
search_analyzer为搜索单独设置一个分词器。例如:“search_analyzer”: “standard”
similarityElasticsearch 允许你为每个字段配置得分算法或者相似算法。similarity 提供了一个简单的算法来选择不同于默认BM25的相似算法, 例如 TF/IDF.Similarities 大多用于 text 型字段, 但是也可以用于其他类型字段。
store是否被存储
term_vector包含分析过程产生的索引词信息,可以选择要存储那些信息,不建议配置
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值