ES3:ElasticSearch 索引

这是ElasticSearch系列的第三篇:

第一篇:ES1:Windows下安装ElasticSearch

第二篇:ES2:ElasticSearch 集群配置

第三篇:ES3:ElasticSearch 索引

ElasticSearch是文档型数据库,索引(Index)定义了文档的逻辑存储和字段类型,每个索引可以包含多个文档类型,文档类型是文档的集合,文档以索引定义的逻辑存储模型,比如,指定分片和副本的数量,配置刷新频率,分配分析器等,存储在索引中的海量文档分布式存储在ElasticSearch集群中。

ElasticSearch是基于Lucene框架的全文搜索引擎,将所有文档的信息写入到倒排索引(Inverted Index)的数据结构中,倒排索引建立的是索引中词和文档之间的映射关系,在倒排索引中,数据是面向词(Term)而不是面向文档的。

ElasticSearch的对象模型,跟关系型数据库模型相比:

  • 索引(Index):相当于数据库,用于定义文档类型的存储;在同一个索引中,同一个字段只能定义一个数据类型;
  • 文档类型(Type):相当于关系表,用于描述文档中的各个字段的定义;不同的文档类型,能够存储不同的字段,服务于不同的查询请求;
  • 文档(Document):相当于关系表的数据行,存储数据的载体,包含一个或多个存有数据的字段; 字段(Field):文档的一个Key/Value对;
  • 词(Term):表示文本中的一个单词;
  • 标记(Token):表示在字段中出现的词,由该词的文本、偏移量(开始和结束)以及类型组成;

索引是由段(Segment)组成的,段不是实时更新的,这意味着,在建立索引时,一个段写入磁盘后,就不再被更新。被删除文档的信息存储在一个单独的文件中,在搜索数据时,ElasticSearch首先从段中查询,再从查询结果中过滤被删除的文档,这意味着,段中存储未被删除文档”的密度降低。多个段可以通过段合并(Segment Merge)操作把”已删除的文档将从段中物理删除,将未删除的文档合并成一个新段,新段中没有已删除文档”,因此,段合并操作能够提高索引的查找速度,但段合并是IO密集型的,需要消耗大量的IO操作。

一,创建索引

在创建索引之前,首先了解RESTful API的调用风格,在管理和使用ElasticSearch服务时,常用的HTTP动词有下面五个:

  • GET 请求:获取服务器中的对象 相当于SQL的Select命令
  • GET /blogs:列出所有博客
POST 请求:在服务器上更新对象
  • 相当于SQL的Update命令
  • POST /blogs/ID:更新指定的博客
PUT 请求:在服务器上创建对象
  • 相当于SQL的Create命令
  • PUT /blogs/ID:新建一个博客  
DELETE 请求:删除服务器中的对象
  • 相当于SQL的Delete命令
  • DELETE /blogs/ID:删除指定的博客
HEAD 请求:仅仅用于获取对象的基础信息

1,禁用自动创建索引

推荐设置:在全局配置文件 elasticsearch.yml 中,禁用自动创建索引:

action.auto_create_index:false

2,手动创建索引

创建索引的语法是:PUT http://host:port/index_name/  + index_configuration

其中,index_name是创建的索引的名字,indiex_configuration是向ElasticSearch服务器传递的请求负载的主体,数据格式json,用于定义索引的配置信息:映射节(mappings)和配置节(settings)。

在创建索引时,需要精心设计索引的映射节(mappings)和配置节(settings),本例创建blog索引和articles文档类型,创建索引的语法是:

PUT http://localhost:9200/blog/

下文详细介绍ElasticSearch索引的配置信息

二,索引映射节(mappings)

1,索引结构

索引是由文档类型构成的,在mappings字段中定义索引的文档类型,示例代码中为blog索引定义了三个文档类型:articles,followers和comments

{  
   "mappings":{  
      "articles":{ },
      "followers":{ },
      "comments":{ }
   }
}

2,文档属性

文档属性定义了文档类型的共用属性,适用于文档的所有字段:

  • numeric_detection属性:检查文本的值,以确定该文本是否为数字类型,默认值为false;
  • dynamic_date_formats属性:该属性定义可以识别的日期格式列表;
  • dynamic属性:默认值为true,允许向文档类型中加入字段,推荐设置为false,关闭ElasticSearch自动类型检测,同时关闭自动添加字段;文档类型的所有字段必须显式定义,在properties字段中未定义的字段都将会ElasticSearch忽略。
{  
   "mappings":{  
      "articles":{  
         "numeric_detection":false,
         "dynamic":false,
         "dynamic_date_formats":["yyyy-MM-dd hh:mm:ss", "yyyy-MM-dd" ],
         "properties":{  
            "id":{},
            "title":{},
            "author":{},
            "content":{},
            "postedat":{}
         }
      }
   }
}

三,文档的字段属性

1,字段的数据类型

字段的数据类型由字段的属性type指定,ElasticSearch支持的基础数据类型主要有:

  • 字符串类型:string;
  • 数值类型:字节(byte)、2字节(short)、4字节(integer)、8字节(long)、float、double;
  • 布尔类型:boolean,值是true或false;
  • 时间/日期类型:date,用于存储日期和时间;
  • 二进制类型:binary;
  • IP地址类型:ip,以字符串形式存储IPv4地址;
  • 特殊数据类型:token_count,用于存储索引的字数信息

在文档类型的properties属性中,定义字段的type属性,指定字段的数据类型:

"properties":{  
            "id":{"type":"long"},

2,字段的公共属性

  • index_name:该属性定义字段的别名,该别名会存储在索引中;默认值是字段的名称。
  • index:编入索引,该属性共有三个有效值:analyzed、no和not_analyzed: analyzed:表示该字段将会被ES引擎分析,产生token,能够使用全文搜索;
  • not_analyzed:表示该字段不会被分析,使用原始值编入索引;
  • no:无法搜索该字段;
其中analyzed是分析,分解的意思,默认值是analyzed,表示将该字段编入索引,以供搜索。 store:该属性值是boolean,指定是否将字段的原始值写入索引,默认值是no boost:助推,默认值是1,定义了字段在文档中的重要性/权重; copy_to:该属性指定一个字段Field1,字段Field1的值将会被复制到当前字段; include_in_all:该属性指定当前字段是否包括在_all字段中,默认值是ture,所有的字段都会包含_all字段中;如果index=no,那么属性include_in_all无效,这意味着当前字段无法包含在_all字段中。

3,字符串类型常用的其他属性

  • analyzer:该属性定义用于建立索引和搜索的分线器名称,默认值是全局定义的分析器名称
  • index_analyzer:该属性定义用于建立索引的分析器名称;
  • search_analyzer:该属性定义的分析器,用于处理发送到特定字段的查询字符串;
  • index_options:索引选项

分析器(analyzer)属性,可以引用在配置结点(settings)中自定义的分析器

4,数值类型的其他属性

  • precision_step:该属性指定为数值字段每个值生成的term数量,值越低,产生的term数量越高,范围查询越快,索引越大,默认值是4;
  • ignore_malformed:忽略错误格式,默认值是false,不忽略错误格式;

5,日期类型的其他属性

  • format:指定日期的格式,例如:”yyyy-MM-dd hh:mm:ss
  • precision_step:该属性指定为数值字段每个值生成的term数量,值越低,产生的term数量越高,范围查询越快,索引越大,默认值是4;
  • ignore_malformed:忽略错误格式,默认值是false,不忽略错误格式;

6,多字段(fields)

在fields属性中定义一个或多个字段,该字段的值和当前字段值相同,可以设置一个字段用于搜索,一个字段用于排序等。

"properties":
{  
    "id":{  "type":"long",
         "fields":{  "id2":{"type":"long","index":"not_analyzed"} }
      },

7,信息格式(postings_format)

postings_format属性用于为字段指定信息格式:

  • default:使用字段的默认信息格式,提供了实时的对存储字段和词向量的压缩功能
  • pulsing:将高基数字段的信息列表编码为词条矩阵,加快查询速度;
  • direct:在读操作过程中将词条加载到矩阵中,能够提升常用字段的性能,但是内存消耗较大;
  • memory:将所有的数据写入硬盘,并将数据读取到内存中;
  • bloom_default和bloom_pulsing分别是default 和 pulsing的扩展,增加了bloom过滤器;

8,文档值格式(doc_values_format) 

文档值格式(doc_values_format),该属性定义字段的值被写入到具有较高内存效率的列式结构,以便进行高效的排序和聚合搜索。使用文档值的字段将有专属的字段数据缓存实例,无需像普通字段一样倒排。

文档值格式的有效值:

  • default:当未指定文档值格式时,使用默认格式,使用少量内存;
  • disk:将字段数据存储在硬盘中,几乎不需要内存,在执行排序和聚合操作时,性能略有降低;由于字段数据存储在硬盘上,从而节省JVM堆内存空间;
  • memory:将字段数据存储在内存中,在执行排序和聚合操作时,和倒排索引字段的功能不相上下,由于这种数据结构存储在内存中,索引的刷新速度更快;

配置字段的文档值格式:

"properties":{  
     "id":{  
               "type":"int","doc_values_format":"memory"
           },

四,附加字段

1,文档类型字段

_type 字段:用于表示文档类型,默认情况下,文档的类型会编入索引,但不会被分析,也不会被存储

{  
   "articles":{  
      "_type":{  
         "store":"yes"
      },

2,文档标识字段

  • _uid 字段是所有文档的唯一标识符,由该文档的id和文档类型组成;
  • _id 字段是文档的标识,该字段在同一个文档类型中唯一标识一个稳定;
  • path属性,指定从文档中的一个字段中获取标识符,将path设置为”article_id,将该字段的值作为_id字段的值。

配置文档的标识值:

{  
   "articles":{ "_id":{  
         "index":"not_analyzed",
         "store":"no",
         "path":"article_id"
      }
   }
}

3,_all 字段

ElasticSearch使用_all字段存储其他字段的数据以便搜索,默认情况下,_all字段是启用的,包含了索引中所有字段的数据,然而这一字段使索引变大,如果不需要,请禁用该字段,或排除某些字段。为了在_all字段中不包括某个特定字段,在字段中设置”include_in_all属性为false。

禁用_all字段,需要修改映射配置:

{  
   "articles":{  "_all":{  
         "enable":"false"
      }
   }
}

4,_source 字段

_source字段表示在生成索引的过程中,存储发送到ElasticSearch的原始JSON文档,默认情况下,该字段会被启用,因为索引的局部更新功能依赖该字段。

{  
   "articles":{  
      "_source":{  
         "enable":"false"
      }
   }
}

{  
   "articles":{  
      "_source":{  
         "excludes":["Content","Comments"]
      }
   }
}

5,_index 字段

_index 字段用于存储索引的信息,通过该字段,能够返回文档存储在那个索引中,默认情况下,该字段是禁用的。

{  
   "articles":{  
      "_index":{  
         "enable":"true"
      }
   }
}

6,_routing 字段

在路由字段(_routing)中设置一个字段值,使用该值作为路由值。

{  
   "articles":{  
      "_routing":{  
         "required":"true",
         "path":"ariticle_id"
      }
   }
}

五,索引配置节(settings)

1,配置索引的分片和副本数量

ElasticSearch索引是有一个或多个分片组成的,每个分片是索引的一个水平分区,包含了文档数据的一部分;每个分片有0,1或多个副本,分片的副本和分片存储相同的数据。

示例代码,为索引创建5个分片,分片没有副本:

"settings":{
    "number_of_shards":5,
    "number_of_replicas":0,

2,配置分析器(analyzer)

在配置结点的analysis属性中配置分析器,参考官方文档了解更多,

分词器(tokenizer)是系统预定义的,常用的分词器是:

  • standard:默认值,用于大多数欧洲语言的标准分词器
  • simple:基于非字母字符来分词,并将其转化为小写形式
  • whitespace:基于空格来分词
  • stop:除了simple的所有功能,还能基于停用词(stop words)过滤数据;
  • pattern:使用正则表达式分词;
  • snowball:除了standard提供的分词功能之外,还提供词干提取功能;

过滤器是系统预定义的,常用的过滤器是:

  • asciifolding
  • lowercase
  • kstem

在配置结点中,自定义分析器(analyzer)示例代码:

ES3:ElasticSearch 索引ES3:ElasticSearch 索引

{  
   "settings":{  
      "index":{  
         "analysis":{  
            "analyzer":{  
               "myanalyzer_name":{  
                  "tokenizer":"standard",
                  "filter":[  
                     "asciifolding",
                     "lowercase",
                     "ourEnglishFilter"
                  ]
               }
            },
            "filter":{  
               "ourEnglishFilter":{  
                  "type":"kstem"
               }
            }
         }
      }
   }
}
View Code

六,删除索引

删除索引的语法是: 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数据包含文档对象:

ES3:ElasticSearch 索引ES3:ElasticSearch 索引

{  
   "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"
}
View Code

八,搜索索引

在_search端对文档数据进行搜索,索引搜索的语法非常复杂,ElasticSearch支持聚合查询和简单查询

1,按照路由搜索

路由可以控制文档和查询转发的目的分片,ElasticSearch计算路由字段的哈希值,对于相同的路由值,将产生相同的哈希值,分配到特定的分片上;如果在查询时,指定路由值,那么只需要搜索单个分片而不是整个索引,就能获取查询结果。

路由字段由文档类型的_routing属性定义,在查询时,使用routing参数来查找特定路由的文档:

GET http://localhost:9200/blog/_search?routing=1235&q=article_id=100

2,聚合和简单查询

下回分解

附:索引的配置文档

ES3:ElasticSearch 索引ES3:ElasticSearch 索引

{  
   "settings":{  
      "number_of_shards":1,
      "number_of_replicas":0,
      "index":{  
         "analysis":{  
            "analyzer":{  
               "my_analyzer_name":{  
                  "tokenizer":"standard",
                  "filter":[  
                     "asciifolding",
                     "lowercase",
                     "ourEnglishFilter"
                  ]
               }
            },
            "filter":{  
               "ourEnglishFilter":{  
                  "type":"kstem"
               }
            }
         }
      }
   },
   "mappings":{  
      "doc_type_name":{  
         "_routing":{  
            "required":"true",
            "path":"doc_field1"
         },
         "_analyzer":{  
            "path":"doc_field2"
         },
         "_id":{  
            "path":"doc_field3"
         },
         "_type":{  
            "store":"yes"
         },
         "_all":{  
            "enable":"false"
         },
         "_source":{  
            "enable":"false"
         },
         "_idex":{  
            "enable":"true"
         },
         "number_detection":"true",
         "dynamic_date_formats":[  
            "yyyy-MM-dd"
         ],
         "dynamic":"false",
         "properties":{  
            "doc_string_fields":{  
               "type":"string",
               "store":"yes",
               "index":"analyzed",
               "fields":{  
                  "doc_string_field_other_name":{  
                     "type":"string",
                     "index":"no_analyzed"
                  }
               }
            }
         }
      }
   }
}
View Code

参考文档:

RESTful API 设计指南

理解RESTful架构