ElasticSearch基本概念及索引过程

ElasticSearch概述

Elasticsearch是一个近实时分布式搜索引擎,其底层基于开源全文搜索库Lucene;Elasticsearch对Lucene进行封装,对外提供REST API 的操作接口。基于 ES,可以快速的搭建全文搜索引擎;除了搜索功能,ES还可以对数据进行分析:如日志分析、指标分析,同时还提供了机器学习功能。Elasticsearch有一个完整的生态圈(ELK),形成了从数据采集(logstash,filebeat)、数据存储(Elasticsearch)、数据可视化(kibana)的闭环。

ES属于面向文档(Document Oriented)的,这意味着它可以存储整个对象或者文档数据(Document),然而,它不仅仅是存储,还有索引(index)每一个文档的内容使之可以被搜索,可以对文档进行索引,搜索,排序,过滤,分词,高亮显示。ES比传统关系型数据库查询更加迅速。

ES中每一个运行的实例都被称为一个节点(node),实例即可在同一个机器上运行也可以在不同的机器上运行。一个ES集群是由一个或者多个ES节点组成的集合,这个集群里有一个节点叫主节点(master),节点可以存储数据,参与索引数据等的独立服务。而且ES是去中心化的,所以主节点是动态选举出来的,不存在单点故障

ES的特性:

  • 速度快、易扩展、弹性、灵活、操作简单、多语言客户端、X-Pack、hadoop/spark强强联手、开箱即用。
  • 分布式:横向扩展非常灵活
  • 全文检索:基于lucene的强大的全文检索能力;
  • 近实时搜索和分析:数据进入ES,可达到近实时搜索,还可进行聚合分析
  • 高可用:容错机制,自动发现新的或失败的节点,重组和重新平衡数据
  • 模式自由:ES的动态mapping机制可以自动检测数据的结构和类型,创建索引并使数据可搜索。
  • RESTful API:JSON + HTTP

ElasticSearch基本概念

集群

集群由一个或多个节点组成,对外提供服务,索引和搜索功能。在所有的节点中,一个集群有一个唯一的名称默认为“elasticsearch”,此名称很重要,因为每个节点只能是集群的一部分,当该节点被设置为相同的集群名称时,就会自动加入集群。当需要多个集群的时候,要确保每个集群的名称不能重复,否则,节点可能会加入错误的集群。

当集群中有节点停止或丢失时不会影响集群服务或造成数据丢失;同时当访问量或数据量增加时可用采用横向扩展的方式增加节点,将请求或数据分散到集群的各个节点上。

节点

一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的。

一个节点是一个ElasticSearch的实例,本质上是一个Java进程。ES根据功能不同分为不同的节点类型,在生产环境中,建议根据数据量,写入及查询吞吐量,选择合适的部署方式,最好将节点设置为单一角色。

节点类型 节点作用 节点配置参数 默认值
Master Node 管理节点,进行创建、删除索引等操作,决定分片被分配到哪个节点,负责索引创建删除,维护并更新集群状态。 node.master true  
Data Node 数据节点,处理与数据相关的操作,如索引的CRUD、搜索和聚合,数据节点的操作属于I/O、内存和CPU密集型操作。 node.data true 
Ingest Node 提取节点,具有数据预处理的能力,可拦截Index或Bulk Api的请求,可对数据进行转换,并重新返回Index或Bulk Api,默认配置下,所有节点都是Ingest Node。 node.ingest true 
Coordinating Node 协调节点,负责接受客户端的请求,并将请求分发到合适的节点,并将各节点返回的数据汇聚到一起。每个节点都默认是Coordinating Node。 设置master、data、ingest全为false
Maching Learning Node 机器学习节点,用于运行作业和处理机器学习API请求。 node.ml true,需要enable x-pack

索引

一个索引就是一个拥有几份相似特征的文档的集合。比如说,你可以有一个客户数据的索引,一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。

类型

类型是文档的逻辑容器,类似于数据库中的表,类型在 Elasticsearch中表示一类相似的文档,每个类型中字段的定义称为映射。ES7.x已经将类型移除,7.x中一个索引只能有一个类型,默认为_doc。

文档

文档是存储在ES中的一个JSON字符串,相当于数据库中表的一行,ES是一个非结构化的数据库,每一个文档可以有不同的字段,并且有一个唯一的标识符。

字段

类似关系型数据库的某一列,这是ES数据存储的最小单位。

映射

mapping映射, 就像数据库中的 schema ,定义索引中字段的名称、字段的数据类型(如 string, integer 或 date),设置字段倒排索引的相关配置。当索引文档遇到未定义的字段,会使用dynamic mapping 来确定字段的数据类型,并自动把新增加的字段添加到类型映射。在实际生产中一般或禁用dynamic mapping,避免过多的字段导致cluster state占用过多,同时禁止自动创建索引的功能,创建索引时必须提供Mapping信息或者通过Index Template创建。

分片

一个分片是一个运行的Lucene的实例,是一个包含倒排索引的文件目录。一个ES索引由一个或多个主分片以及零个或多个副本分片组成,主分片数在索引创建时指定,后续不允许修改;副本分片主要用于解决数据高可用的问题,是主分片的拷贝,一定程度上提高服务的可读性。分片的设定:生产环境中主分片数的设定,需要提前做好容量规划,因为主分片的数量是不可修改的。如果分片数设置过小,则无法通过增加节点实现水平扩展,单个分片的数据量太大,导致数据重新分片耗时;如果分片数设置过大,则会影响搜索结果的相关性打分,浪费资源,同时影响性能。

备份

拷贝一个分片就完成了分片的备份,备份的好处:当主分片失败或者挂掉, 备份就可以代替分片进行操作, 进而提高了es的可用性, 备份的分片还可以进行搜索操作, 以分摊搜索的压力。ES在创建索引时, 默认创建5个分片, 一份备份, 可以修改, 分片的数量只能在创建索引的时候指定, 索引创建后就不能修改分片的数量了, 而备份是可以动态修改的。

数据库与ES对比图

注:在ES6.0.0及更高的版本中,创建的索引只能包含一个映射类型。在6.0.0以下的版本中创建的一个索引映射多个类型的索引在6.0.0版本中继续发挥作用,但是将在7.0.0中完全删除。

ES索引的全流程

1、客户端发送索引请求

客户端向ES节点发送索引请求,以RestClient客户端发起请求为例,ES提供了Java High Level REST Client,可以通过RestClient发送请求:

RestClient restClient = RestClient.builder(
            new HttpHost("127.0.0.1", 9200, "http"),
            new HttpHost("127.0.0.2", 9200, "http")
           ).build();

其中127.0.0.1,127.0.0.2是ES节点地址,充当coordinate node节点的角色,接收客户端请求,如果设置有专用coorinate node,则应该将接受客户端请求的节点设置为该专用节点,负责请求的接受和转发。在RestClient中使用round-robin轮询算法,进行发送节点的选取。

2、参数检查

对请求中的参数进行检查,检查参数是否合法,不合法的参数直接返回失败给客户端。

3、数据预处理

如果请求指定了pipeline参数,则对数据进行预处理,数据预处理的节点为Ingest Node,如果接受请求的节点不具备数据处理能力,则转发给其他能处理的节点。在Ingest Node上有定义好的处理数据的Pipeline,Pipeline中有一组定义好的Processor,每个Processor分别具有不同的处理功能,ES提供了一些内置的Processor,如:split、join、set 、script等1,同时也支持通过插件的方式,实现自定义的Processor。数据经过Pipeline处理完毕后继续进行下一步操作。

4、判断索引是否存在

判断索引是否存在。如果索引不存在,则判断是否能够自动创建,可以通过action.auto_create_index设置能否自动创建索引;如果节点支持Dynamic Mapping,写入文档时,如果字段尚未在mapping中定义,则会根据索引文档信息推算字段的类型,但并不能完全推算正确。

配置:

  • Dynamic:true时,文档有新增字段的时候,索引的mapping也会同步更新。
  • Dynamic:false时,索引的mapping不会被更新,新增字段无法被索引到。
  • Dynamic:strict时,索引有新增字段时,将会报错。

5、创建索引

创建索引请求被发送到Master节点,由Master节点负责进行索引的创建,索引创建成功后,Master节点会更新集群状态clusterstate,更新完毕后将索引创建的情况返回给Coordinate节点,收到Master节点返回后,进入下一流程。

6、请求预处理

(1)获取集群状态信息,判断集群是否正常;

(2)从集群状态中获取对应索引的元信息,从元信息中获取索引的mapping、version等信息,从请求中解析routing、id信息,如果请求没有指定文档的id,则会生成一个UUID作为文档的id。

7、路由计算

根据请求的routing、id信息计算文档应该被索引到哪个分片,计算公式为:shard_num = hash(_routing) % num_primary_shards。

其中_routing默认值为文档id,num_primary_shards是主分片个数,所以从算法中即可以看出索引的主分片个数一旦指定便无法修改,因为文档利用主分片的个数来进行定位。

当使用自定义_routing或者id时,按照上面的公式计算,数据可能会大量聚集于某些分片,造成数据分布不均衡,所以ES提供了routing_partition_size参数,routing_partition_size越大,数据的分布越均匀。此时分片的计算公式变为:shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards。

定位到分片序号后,还需要定位分片所属的数据节点;从集群状态的内容路由表获取主分片所在的节点,并将请求转发至节点。需要注意的是分片到数据节点的映射关系不是固定的,当检测到数据分布不均匀、新节点加入或者节点宕掉等会进行分片的重新分配。

8、主分片索引分档

当主分片所在节点接受到请求后,节点开始进行本节点的文档写入,文档写入过程:

(1)文档写入时,不会直接写入到磁盘中,而是先将文档写入到Index Buffer内存空间中,到一定的时间,Index Buffer会Refresh把内存中的文档写入Segment中。当文档在Index Buffer中时,是无法被查询到的,这就是ES不是实时搜索,而是近实时搜索的原因

(2)文档写入时,先写入到内存中,当文档落盘之前,节点出现故障重启、宕机等,会造成内存中的数据丢失,所以索引写入的同时会同步向Transaction Log写入操作内容。

(3)每隔固定的时间间隔ES会将Index Buffer中的文档写入到Segment中,这个写入的过程叫做Refresh,Refresh的时间可以通过index.refresh_interval设置,默认情况下为1秒。

(4)写入到Segment中并不代表文档已经落盘,因为Segment写入磁盘的过程相对耗时,Refresh时会先将Segment写入缓存,开放查询,也就是说当文档写入Segment后就可以被查询到。每次refresh的时候都会生成一个新的segment,太多的Segment会占用过多的资源,而且每个搜索请求都会遍历所有的Segment,Segment过多会导致搜索变慢,所以ES会定期合并Segment,减少Segment的个数,并将Segment合并为一个大的Segment;在操作Segment时,会维护一个Commit Point文件,其中记录了所有Segment的信息;同时维护.del文件用于记录所有删除的Segment信息。单个倒排索引文件被称为Segment。多个Segment汇总在一起,就是Lucene的索引,对应的就是ES中的shard。

Lucene倒排索引由单词词典及倒排列表组成:

  • 单词词典:记录所有文档的单词,记录单词到倒排列表的关系,数据量比较大,一般采用B+树,哈希拉链法实现。
  • 倒排列表:记录单词对应的文档集合,由倒排索引项组成。

倒排索引项结构如表所示:文档ID:记录单词所在文档的ID;词频:记录单词在文档中出现的次数;位置:记录单词在文档中的位置;偏移:记录单词的开始位置,结束位置。

(5)每隔一定的时间(默认30分钟),ES会调用Flush操作,Flush操作会调用Refresh将Index Buffer清空;然后调用fsync将缓存中的Segments写入磁盘;随后清空Transaction Log。当Transaction Log空间(默认512M)满后也会触发Flush操作。

9、副本分片索引文档

当主分片完成索引操作后,会循环处理要写的所有副本分片,向副本分片所在的节点发送请求。副本分片执行和主分片一样的文档写入流程,然后返回写入结果给主分片节点。

10、请求返回

主分片收到副本分片的响应后,执行finish()操作,将收到响应信息返回给Coordinate节点,告知Coordinate节点文档写入的情况;coordinate节点收到响应后,将索引执行情况返回给客户端。至此一个文档索引的全过程结束,用户可通过ElasticSearch提供的接口进行数据的查询。

ElasticSearch自诞生以来,使用热度越来越高,功能越来越强大。ES不仅支持分布式、可扩展,还提供了RestFul风格接口,方便应用接入使用;适用于所有的数据类型,具备存储海量数据能力,拥有高性能的近实时检索功能,同时还提供了数据的近实时分析功能;适用于海量数据的近实时检索、分析,在日志、监控数据存储分析,集中式全文搜索方面应用较为广泛。

 

参考:

 

posted @ 2022-02-12 19:25  残城碎梦  阅读(1450)  评论(0编辑  收藏  举报