下文详细介绍ElasticSearch索引的映射(Mapping)配置,详细信息请参考《Elasticsearch Reference [2.4] » Mapping》。注意,ElasticSearch引擎是大小写敏感的,强制性要求索引名和文档类型小写,对于字段名,ElasticSearch引擎会将首字母小写,建议在配置索引,文档类型和字段名时,都使用小写字母。
二,索引映射节(mappings)
1,索引结构
索引是由文档类型构成的,在mappings字段中定义索引的文档类型,示例代码中为blog索引定义了三个文档类型:articles,followers和comments
{
"mappings":{
"articles":{ },
"followers":{ },
"comments":{ }
}
}
2,文档属性
文档属性定义了文档类型的共用属性,适用于文档的所有字段:
{
"mappings":{
"articles":{ "dynamic":false,
"dynamic_date_formats":["yyyy-MM-dd hh:mm:ss", "yyyy-MM-dd" ],
"properties":{
"id":{},
"title":{},
"author":{},
"content":{},
"postedat":{}
}
}
}
}
三,文档的字段属性
1,字段的数据类型
字段的数据类型由字段的属性type指定,ElasticSearch支持的基础数据类型主要有:
在文档类型的properties属性中,定义字段的type属性,指定字段的数据类型,属性properties 用于定义文档类型的字段属性,或字段对象的属性:
"properties":{
"id":{"type":"long"},
2,字段的公共属性
3,字符串类型常用的其他属性
分析器(analyzer)把analyzed string 字段的值,转换成标记流(Token stream),例如,字符串"The quick Brown Foxes",可能被分解成的标记(Token)是:quick,brown,fox。这些词(term)是该字段的索引值,这使用对索引文本的查找更有效率。字段的属性 analyzer 用于指定在index-time和search-time时,ElasticSearch引擎分解字段值的分析器名称。
4,数值类型的其他属性
5,日期类型的其他属性
6,多字段(fields)
在fields属性中定义一个或多个字段,该字段的值和当前字段值相同,可以设置一个字段用于搜索,一个字段用于排序等。
"properties":
{
"id":{ "type":"long",
"fields":{ "id2":{"type":"long","index":"not_analyzed"} }
},
7,文档值(doc_values)
默认情况下,多数字段都被一起编入索引,用户使用倒排索引(Inverted Index)可以搜索到相应的词(Term),倒排索引支持在唯一的有序词列表中查找特定词,或检查文档中是否包含某个词,但是,对于排序(Sort),聚合和在脚本中访问特定字段的值(Field value),这三个操作需要执行不同的数据访问模式,即单字段数据访问:在文档中查找特定的字段,检查该字段是否包含指定的词。
文档值(doc_values)属性指定将字段的值写入到硬盘上的列式结构,实现了单个字段的数据访问模式,能够高效执行排序和聚合搜索。使用文档值的字段将有专属的字段数据缓存实例,无需像普通字段一样倒排。是存储在硬盘上的数据结构,在文档索引时创建。文档值数据存在硬盘上,在文档索引时创建,存储的数据和字段存储在_source 字段的数据相同,文档值支持所有的字段类型,除了analyzed string 字段之外。
默认情况下,所有的字段都支持文档值,默认是启用的(enabled),如果不需要在单个字段上执行排序或聚合操作,或者从脚本中访问指定字段的值,那么,可以禁用文档值,字段的值将不会存储在硬盘空间中。
"properties": {
"status_code": {
"type": "string",
"index": "not_analyzed"
"doc_values": true
},
"session_id": {
"type": "string",
"index": "not_analyzed",
"doc_values": false
}
}
8,字段数据(Fielddata)
字段数据(Fielddata)是存储在内存中的查询时数据结构,只支持analyzed string字段。该数据结构在字段第一次执行聚合,排序或被脚本访问时创建。创建的过程是:在读取整个倒排索引(Inverted Index)时,ElasticSearch从硬盘上加载倒排索引的每个段(Segment),倒转词(Term)和文档的关系,并将其存储在JVM堆内存中。加载字段数据的过程是非常消耗IO资源的,一旦被加载,就被存储在内存中,直到段的生命周期结束。
对于analyzed string字段,fielddata字段是默认启用的,
"text":{
"type":"string",
"fielddata":{ "loading":"lazy"
}
}
9,存储(store)
存储(store)属性指定是否将字段的原始值写入索引,默认值是no,字段值被分析,能够被搜索,但是,字段的原始值不会存储,这意味着,该字段能够被查询,但是无法获取字段的原始值。默认情况下,该字段的值会被存储到_source字段中,如果想要获取单个或多个字段的值,而不是整个_source字段,可以使用 source filtering 来实现;但是在特定的条件下,只存储一个字段的值是有意义的(make sense),例如,一个article文档包含:title,postdate和content字段,从文档中只获取title和postdate字段,并且使_source 字段包含content字段,必须通过store属性来控制:
"mappings": {
"my_type": {
"properties": {
"title": {
"type": "string",
"store": true
},
"date": {
"type": "date",
"store": true
},
"content": {
"type": "string",
"store": false
}
}
}
}
10,位置增加间隔(position_increment_gap)
对于analyzed string字段,都会考虑把词的位置信息,用于支持位置和短语匹配查询(proximity or phrase queries),例如,有一个字符串字段,该字段中存在多个词“fake”,ElasticSearch引擎会在每个值之间增加一个gap,以防止短语匹配或位置匹配查询出现跨越多个词的异常,这个gap的值就是属性position_increment_gap,默认值是100;
四,元字段
在索引的映射中,元字段(Meta-field)是以下划线开头的字段,部分元字段可以配置,部分元字段不可配置,只能用于返回信息。
1,_all 字段,可以配置
ElasticSearch使用_all字段存储其他字段的数据以便搜索,默认情况下,_all字段是启用的,包含了索引中所有字段的数据,然而这一字段使索引变大,如果不需要,请禁用该字段,或排除某些字段。为了在_all字段中不包括某个特定字段,在字段中设置“include_in_all”属性为false。
禁用_all字段,需要修改映射配置:
{
"articles":{ "_all":{
"enabled":false
}
}
}
2,_source 字段,可以配置
_source字段表示在生成索引的过程中,存储发送到ElasticSearch的原始JSON文档,默认情况下,该字段会被启用,因为索引的局部更新功能依赖该字段。
{
"articles":{
"_source":{
"enabled":true
}
}
}
{
"articles":{
"_source":{
"excludes":["Content","Comments"],
"includes":["author"]
}
}
}
3,_routing 字段,可以配置
路由字段,将一个文档值进行哈希映射,并将该文档路由到指定的分片,路由的公式是:
{
"articles":{
"_routing":{
"required":true
}
}
}
在put 命令中,使用自定义的路由字段,以下示例使用 user1字段作为路由字段更新和查询文档:
PUT my_index/my_type/1?routing=user1
{
"title": "This is a document"
}
GET my_index/my_type/1?routing=user1
4,不可配置的元字段
五,索引配置节(settings)
1,配置索引的分片和副本数量
ElasticSearch索引是有一个或多个分片组成的,每个分片是索引的一个水平分区,包含了文档数据的一部分;每个分片有0,1或多个副本,分片的副本和分片存储相同的数据。
示例代码,为索引创建5个分片,分片没有副本:
"settings":{ "number_of_shards":5, "number_of_replicas":0,
2,配置分析器(analyzer)
在配置结点的analysis属性中配置分析器,参考官方文档了解更多,
分词器(tokenizer)是系统预定义的,常用的分词器是:
过滤器是系统预定义的,常用的过滤器是:
在配置结点中,自定义分析器(analyzer)示例代码:
{
"settings":{
"index":{
"analysis":{
"analyzer":{
"myanalyzer_name":{
"tokenizer":"standard",
"filter":[
"asciifolding",
"lowercase",
"ourEnglishFilter"
]
}
},
"filter":{
"ourEnglishFilter":{
"type":"kstem"
}
}
}
}
}
}
六,删除索引
删除索引的语法是: DELETE http://localhost:9200/blog
七,更新索引
索引的更新分为逐个文档的更新和批量文档更新:
1,单个文档(Individual Document)的更新
单个文档更新的语法是:POST http://localhost:9200/blog/articles/1 +文档对象的JSON数据
POST http://localhost:9200/blog/articles/1
文档对象的JSON数据示例如下:
{
"id":1,
"title":"Elasticsearch index",
"Author":"悦光阴",
"content":"xxxxxxxxxxx",
"postedat":"2017-03-14"
}
2,批量文档的更新(Bluk)
批量文档更新的语法是:POST http://localhost:9200/_bulk + 批量文档对象的JSON数据,在_bulk 端进行批量更新操作。
在传递的请求主体中,每一个请求分为两个JSON数据,第一个JSON数据包含操作说明的描述信息,第二个JSON数据包含文档对象:
{
"index":{
"_index":"blog",
"_type":"ariticles",
"_id":1
}
}
{
"id":1,
"title":"Elasticsearch index",
"Author":"悦光阴",
"content":"xxxxxxxxxxx",
"postedat":"2017-03-14"
}
{
"index":{
"_index":"blog",
"_type":"ariticles",
"_id":2
}
}
{
"id":2,
"title":"Elasticsearch index",
"Author":"悦光阴",
"content":"xxxxxxxxxxx",
"postedat":"2017-03-14"
}
八,搜索索引
在_search端对索引数据进行搜索,ES查询的语法非常复杂,总体来说,ElasticSearch支持聚合查询和简单查询。
1,按照路由搜索
路由可以控制文档和查询转发的目的分片,ElasticSearch计算路由字段的哈希值,对于相同的路由值,将产生相同的哈希值,分配到特定的分片上;如果在查询时,指定路由值,那么只需要搜索单个分片而不是整个索引,就能获取查询结果。
路由字段由文档类型的_routing属性定义,在查询时,使用routing参数来查找特定路由的文档:
GET http://localhost:9200/blog/_search?routing=1235&q=article_id=100
2,聚合和简单查询
请阅读《ElasticSearch查询 第一篇:搜索API》
附:索引的配置文档
{
"settings":{
"number_of_shards":5,
"number_of_replicas":0
},
"mappings":{
"articles":{
"_routing":{
"required":false
},
"_all":{
"enabled":false
},
"_source":{
"enabled":true
},
"dynamic_date_formats":[
"yyyy-MM-dd",
"yyyyMMdd"
],
"dynamic":"false",
"properties":{
"articleid":{
"type":"long",
"store":true,
"index":"not_analyzed",
"doc_values":true,
"ignore_malformed":true,
"include_in_all":true,
"null_value":0,
"precision_step":16
},
"title":{
"type":"string",
"store":true,
"index":"analyzed",
"doc_values":false,
"ignore_above":0,
"include_in_all":true,
"index_options":"positions",
"position_increment_gap":100,
"fields":{
"title":{
"type":"string",
"store":true,
"index":"not_analyzed",
"doc_values":true,
"ignore_above":0,
"include_in_all":false,
"index_options":"docs",
"position_increment_gap":100
}
}
},
"author":{
"type":"string",
"store":true,
"index":"analyzed",
"doc_values":false,
"ignore_above":0,
"include_in_all":true,
"index_options":"positions",
"position_increment_gap":100,
"fields":{
"author":{
"type":"string",
"index":"not_analyzed",
"include_in_all":false,
"doc_values":true
}
}
},
"content":{
"type":"string",
"store":true,
"index":"analyzed",
"doc_values":false,
"ignore_above":0,
"include_in_all":false,
"index_options":"positions",
"position_increment_gap":100
},
"postat":{
"type":"date",
"store":true,
"doc_values":true,
"format":[
"yyyy-MM-dd",
"yyyyMMdd"
],
"index":"not_analyzed",
"ignore_malformed":true,
"include_in_all":true,
"null_value":"2000-01-01",
"precision_step":16
}
}
}
}
}