这里讲的 ElasticSearch 中的映射(schema mapping),是定义存储和索引的文档类型和字段的过程。这里记住映射是一个动态过程。索引中的每一个文档都有一个类型,每种类型都有他自己的映射。映射起到定义文档字段的数据类型的功能,这一功能其实是通过配置来定义字段类型和该类型关联的元数据的关系来实现的。

映射类型

每个索引都有一个或多个映射类型,他的作用是在一个索引中将数据划分为不同的逻辑组。每个映射类型都由元字段和字段组成。

1. 元字段

元字段的作用是用来表示如何处理文档的元数据。常见的元字段有 _index,_type,_id,_source。 每个文档都有与之关联的元数据,元字段是保证系统正常运转的内置字段。

2. 字段(或属性)

字段(或属性)的作用是标识数据的类型。每个映射类型都包含与类型相关的字段或者属性列表。这里注意如果是在同一个索引中的不同映射类型的相同字段都具有相同的数据类型,意思是指在同一索引范围中,只要映射字段相同,那么他就具有相同的映射类型。

字段数据类型

ElasticSearch 中的字段数据类型包括基本的字符串,日期,长整型 long,双精度 double,布尔型 boolean,类似 JSON 的对象,IP,地理点和地理形状(以后会对不同的类型做详细解释)。ElasticSearch 可以显式或者动态的设置映射,ElasticSearch 的映射可以不事先定义,依靠动态映射,依靠新的索引文档,新的类型和字段名可以自动添加。而新的类型映射又可以添加到顶级映射类型或者映射类型内部的对象和嵌入字段。

映射类型在一个索引中是唯一的。也就是在同一个索引的不同类型中,相同的映射名称一样,那么他们就具有相同的类型。

1. 核心数据类型

  • 字符串数据类型

字符串数据类型可以分为全文本和关键词,同一字段又可以同时设置全文本和关键字。全文本非常适合基于文本的相关性搜索。

全文本的字符串数据类型可以分词,在索引执行之前通过分词器将文本转化为单词表,这个操作就是 ElasticSearch 能在全文本中搜索单词的原理。这里注意全文本的字符串数据类型不用于排序且很少用于聚合。

关键词的字符串数据类型通常用来过滤,排序和聚合。并且不参与分词。

  • 数字
  • 日期类型:注意 json 没有日期类型,所以只能是字符串,代表时间毫秒数的长整型,或者整型。可以使用双竖线做多日期格式匹配。
  • boolean 类型
  • base64 编码的二进制值。不以默认方式存储且不能被搜索。

2. 复杂数据类型

  • 数组

ElasticSearch 没有特定的数组类型,但是每个字段默认可以包含一个或者多个相同数据类型的值。

  • 对象类型

这里指的对象类型采用的是 json 的天然分层特性。json 文档内部可以包含对象。

  • 嵌套数据类型

3. 地理数据类型

这里的地理数据类型说的是经纬度。从经纬度扩展一下几个方面:

  • 查找一定地理范围内的数据
  • 聚合距离中心点一定距离的文档
  • 按照距离中心点的远近进行排序
  • 整合地理数据到文档的相关性评分中

地理数据类型又分为:

  • 地理点
  • 地理形状

3. 专门数据类型

  • IP
  • 单词计数器:token_count

映射参数

用于字段映射的参数。ElasticSearch 中有大量的映射参数,这些参数的默认值都是最合适普遍场景的,但是如果想精通调优,需要理解这些映射参数。下面这些是选取的几个典型映射参数。

1.analyzer

字符串在索引和查询时,都是被分析为一个个索引词。通过合理的配置索引器可以大大提高在索引查询时的效率。

2.boost

对字段进行加权。默认值为 1,如果设置了值则是所设置值的倍数。这里注意在数据索引时最好不要加权。因为除非重新索引所有文档,不然加权值不会变。

3.coerce

强制类型转换。如果值为 false,在索引到不匹配类型的文档时就会丢弃

4.facat

facat 代表多字段,ElasticSearch 允许你在一个字段上设定两种类型。假如你想在同一个字段上进行两种分析,一种用于搜索,一种用于排序。或一个经过特定语言分析器来分析,而另一个只经过空白字符分析。那么可以使用多字段功能。该功能可以允许用户只定义一个字段类型就同时赋予该字段两种类型的类型。如下所示:

“name”:{“type”:”string”, “property”:{ “facat”:{“type”:”string”,”index”:”not_anayzed"} } }

这样就定义了两个字段,一个叫name,一个叫name.property,ElasticSearch 会把 name 字段中的值复制到 name.property 字段中。

5.copy_to

ElasticSearch 可以使用这个字段来创建自定义的 _all 字段。也就是说可以用多个字段来合成一个字段,把这个合成的字段当做单个字段来查询。

6.doc_valus

倒排索引的列式存储。这种结构很适合聚合,排序,脚本操作。

动态索引

ElasticSearch 可以在事先不设置索引结构的情况下,在文档直接插入到索引中时,系统会根据文档自动进行索引结构的动态映射。这样做极大地简化了索引的操作。

可以根据目的来指定动态映射生成的规则:

  • ElasticSearch 中有个名为 _default_ 的默认映射,这个默认映射相当于创建新映射类型的基础映射。
  • 动态字段映射。
  • 动态模板:也就是根据事先定义好的自定义规则来配置动态添加字段的映射。

默认情况下,在文档中发现新的字段的时候,ElasticSearch 会自动根据一系列简单的规则将新字段添加到类型映射中。这些简单的规则中,有些能解析形如日期的字符串,有些能解析数字。其实 ElasticSearch 底层是通过定义文档的 JSON 来猜测文档结构和数据类型的,比如字符串是被引号包围,布尔值使用特定的字符,数值则是一些数字类型。很明显,这些简单的规则有效而且易于理解。

那么有没有更加灵活的文档类型探测呢?比如被引号包围的数字类型能不能被检测为数值类型呢,答案是肯定的。ELasticsearch 有种机制叫数值自动检测,相关联的设置为numeric_detection,该选项是默认关闭的,可以使用响应的 put 请求来打开该选项。如果该选项打开后,在索引数据时如果被引号包围的数据为数组类型,比如 float 型数据,那么在索引完后,使用 get 方法来请求索引的 _mapping_ 数据,你会发现刚才的数值类型的字段的 type 为 double 了,当然如果索引的数值不是 float,而是 long 类型数据,那么 _mapping 中的类型也会变成 long。

映射是如何 xxx 的

首先找到映射的入口。由于都是从 rest 的接口新增的映射,所以从 rest 包中入手肯定没有错。由于 rest 包中的类不多,查看后知道了映射相关的类在indices包中。因为在映射都是依附在 index 上的,所以放到了indices包下。如下图所示:

新增映射的入口

接下来找到入口,就分析是如何构造映射的。

  • 首先通过 url 中的 index 字段构造一个初始的PutMappingRequest
  • 然后给该PutMappingRequest构造各种 request 中携带的参数
    • type:映射相关元数据
    • source:映射相关元数据
    • update_all_types:是否跨多个类型的映射字段都更新
    • timeout:超时
    • master_timeout:如果在没有发现 master 或者断开与 master 连接情况下的超时值
    • expand_wildcards:索引配置相关,启用的扩展通配符
    • ignore_unavailable:索引配置相关,snapshot,restore 和 index_settings 操作使用此设置。
    • allow_no_indices:索引配置相关,
  • 最后通过NodeClient(实现了 IndicesAdminClient 接口)中的 putMapping 方法,将上一步构造好的 action 传给 ElasticSearch 的 client。

下图显示了实际执行映射操作的地方是NodeClientexecute方法

d

上面提到的PutMappingRequest初始化的参数如下图所示,可看到我们 put 的数据都在 source 中:

然后会从 actions 中找到 putmapping 的 action,action 的类型为TransportAction。而该 action 的实际执行方法execute,该方法是当 transport 操作调用导致产生一个新的关联任务时,实际使用的方法。

我们可以看到该方法使用默认好的 actionName'indices:admin/mapping/put' 和构造好的putMappingRequest注册了一个 task。然后分别在ActionListener中设置了成功和失败的回调方法。

由于我是单节点运行的 ElasticSearch,所以在实际执行任务的类是TransportMasterNodeAction,这个类是需要在主节点上执行的操作的基类。在该类的doStart方法中,通过类TransportPutMappingAction和参数taskreqeust最众到达实际的方法metaDataMappingService.putMapping中,如下图所示;

至此前面的任务调度工作就都做完了,以后就是metaDataMappingService.PutMappingExecutor的工作了。

感谢    赞同    分享    收藏    关注    反对    举报    ...