一、Elasticsearch概述
ElasticSearch是一个分布式的可扩展的实时搜索和分析引擎,是一个建立在全文搜索引擎apache lucene基础上的搜索引擎。
1.特点
1.分布式的实时文件存储,并将每一个字段都编入索引,使其都可以被搜索。
2.实时分析的分布式搜索引擎
3.可以扩展到上百台服务器,可以处理PB级别的结构化数据和分结构化数据。
- 优点
1.分词搜索、全文搜索,不会再对数据库中的数据进行一条一条地扫描。而是通过直接搜索节点进行搜所数据。
2.自己维护冗余数据,不会由于某台节点宕机而丢失数据。
3.强大的搜索功能,聚合分析的功能。
4.结合kibana进行建立图表,更好地展示科学化数据,便于数据分析
2.结构
- Cluster集群
es可以作为一个独立的但搜索服务器,不过为了处理大数据集,实现高性能、高可用性,es是可以运行在集群服务器上的。 - Shard分片
当处理大量的数据文档的时候,由于磁盘的处理能力和内存限制以及无法快速响应用户的数据请求,这种情况写一台节点服务器是远远不够的,这样准备多态服务器,并把数据分成多个较小的数据分片,并把这些数据分切放置在不同的服务器上,当用户查询数据的时候,当查询的索引在不同的服务器上的分片上的时候,es会把查询语句,发送到每个切片上,并将查询到的结果聚集到一起,这个结果对于用户来说是透明的。
注意:一台服务器默认是5个分片,5个分片会进行投票将主片进行选举出来,来决定哪个分片是Master。
- repliaction副本:
为了提高数据的查询吞吐量和数据的高可用,可以使用副本的分片策略,副本是一个数据分片的精准复制,每个分配都有0到多个副本,es集群中有很多相同的分片。其中之一有主分片从分片之分,主分片往往和次分片不在同一个节点服务器之上,
当主分片处于丢失状态或者不可用状态时,用户可以将从分片的的状态提升为主分片。
3.Elasticsearch实现Master的选举
1.elasticsearch的选主是通过ZenDicovery模块负责的, 主要包含ping(节点之间是通过rpc来发现彼此)和unicast(单播模块主要包含一个主机列表需要以那些节点ping通)。
2.对所有可以成为master(node.master:true)的节点的masterid进行字典序排序,每次将每个节点所知道的其他节点进行排序,然后选出最0个节点,暂且当它是主节点。
3.如果某个节点的投票数量达到一定的值(可以成为master节点数n/2+1)并且该节点自己也选举自己,那这个节点就是master,否则车后鞥新选举一致到满足上述条件。
二、ES的核心概念
1.Elasticsearch核心概念:
- 1.集群cluster:
包含一个或多个具有相同cluster.name的节点,
1),集群内各个节点之间协同合作,共享数据,共同分担工作负荷。
2)由于节点是从属集群的,集群会自我重组来均匀地分发数据。
3)Cluster name是很重要的,因为每个节点都是数据集群的一部分, 当该节点的cluster name被设置为相同的名称时,该节点会自动加入集群。
4)集群通过选举产生一个master主节点,他将负责管理集群范畴的变更, 包括创建索引、删除所有、向集群汇总添加节点,选出节点。 master节点无需参与文档层面的变更和搜索,这就意味着仅有一个节点不随流量的增长而成为瓶颈, 任何一个节点都可以成为master节点。
5)作为用户,我们可以访问包括 master 节点在内的集群中的任一节点。 每个节点都知道各个文档的位置,并能够将我们的请求直接转发到拥有我们想要的数据的节点。 无论我们访问的是哪个节点,它都会控制从拥有数据的节点收集响应的过程, 并返回给客户端最终的结果。这一切都是由 Elasticsearch 透明管理的。 - 2.节点Node
一个节点是一个逻辑上独立的服务,可以储存数据,并参与集群的索引和搜索功能, 一个节点也有唯一的名字,集群通过节点名称来管理和通信 - 3.索引index:
索引与数据库相当,索引只是一个逻辑命名空间,它指向一个或多个分片shards), 内部通过apache lucene实现索引中数据的读写 - 4.文档类型type:
es中的type相当于数据库中的一个表table,它在es中必须要设置它的类型。 - 5.document文档:
相当于数据库中的一个row。 - 6.Mapping:
相当于数据库中的schema,用来约束字段的类型,不过 Elasticsearch 的 mapping 可以自动根据数据创建 - 分片(shard) :
是工作单元(worker unit) 底层的一员,用来分配集群中的数据,它只负责保存索引中所有数据的一小片。
分片是一个独立的Lucene实例,并且它自身也是一个完整的搜索引擎。
文档存储并且被索引在分片中,但是我们的程序并不会直接与它们通信。取而代之,它们直接与索引进行通信的, 把分片想象成一个数据的容器。数据被存储在分片中,然后分片又被分配在集群的节点上。
当你的集群扩展或者缩小时,elasticsearch 会自动的在节点之间迁移分配分片,以便集群保持均衡
分片分为主分片(primary shard) 以及从分片(replica shard) 两种。
在你的索引中,每一个文档都属于一个主分片 ,从分片只是主分片的一个副本,它用于提供数据的冗余副本,
在硬件故障时提供数据保护,同时服务于搜索和检索这种只读请求索引中的主分片的数量在索引创建后就固定下来了,
但是从分片的数量可以随时改变。一个索引默认设置了5个主分片,每个主分片有一个从分片对应ES模块结构 - 补充:
1.若es集群中有两个节点,并使用了默认的分片配置,es自动把这5个主分片分配到2个节点上, 而他们分别对应的副本在完全不同的节点上。3.索引number_of_shards参数只对向前索引有效而不是对整个集群生效, 对每个索引来讲,该参数定义了当前索引的主分片数(而不是集群中的所有的主分片数) - 性能扩容:就像上面说的primary
就像上面说的primary shard?在创建的时候就已经固定了,不可以再修改。
也就是说如果我在创建的时候设置了primary?shard是3(6个shard,3 primary,3 replica), 最多扩容到6台机器,每个shard可以占用单台服务器的所有资源,性能最好。 那如果我们的超出了上面所说的扩容极限了怎么办呢?primary shard不是不能修改么?
是的,primary?shard?在创建后是不能修改的,但是replica shard可以添加啊,
我们可以创建9个shard(3primary,6 replica),将服务器扩容到9台机器,吞吐量会大大增加,是3台服务器的三倍,当然为了提高容错率也可以在此基础上在每台服务器上部署多个shard(primary和replica不能在同一台服务器上)
三、理解倒排索引
1.理解倒排索引
ES使用倒排索引的结构进行全文快速搜索,一个倒排索引由文档中所有不重复的列表构成,对于每一个单词,有一个包含他的文档列表。本小节主要以京东互联网医院医院信息为例介绍倒排索引的存储方式及数据存储标准化规则。
如下表所示,假设文档集合中包含5个文档,左边对应文档编号,右边文档内容,我们的任务就是对这个文档集合建立倒排索引。
文档编号 文档内容
1 {“hospitalName”:”北京大学第三附属医院”}
2 {“hospitalName”:”北京协和医院”}
3 {“hospitalName”:”解放军总医院第一附属医院”}
4 {“hospitalName”:”Peking University Third Hospital”}
5 {“hospitalName”:”Peking Union Medical College Hospital”}
- (1)首先利用中、英文分词器从所有文档中提取不重复的单词,每一个单词对应有一个ID和含有这个单词的文档ID,这样可以很清晰的看出单词及对应的文档,如下表所示。
单词ID 单词 文档id
1 医院 1、2、3
2 北京 1、2
3 北京大学 1
4 第三 1
5 附属 1、3
6 协和 2
7 解放军 3
8 第一 3
9 总 3
- (2)索引系统还可以记录除此之外的很多信息,下图还记录了单词频率信息(TF),即单词在每个文档中出现的次数。这个信息是用户为词条信息在搜索时,计算查询和文档相似程度(相关度分数)是一个很重要的计算因子。
单词ID 单词 文档Id:出现次数
1 医院 (1:1)、(2:1)、(3:2)
2 北京 (1:1)、(2:1)
3 北京大学 (1:1)
4 第三 (1:1)
5 附属 (1:1)、(3:1)
6 协和 (2:1)
7 解放军 (3:1)
8 第一 (3:1)
9 总 (3:1)
- (3)还可以记录单词在文档中出现的位置
例如:(1,<8>,1)代表“医院”这个单词在ID为1、位置为8的文档中的出现了1次。
单词ID 单词 文档id,<位置>,出现次数
1 医院 (1,<8>,1)、(2<5>1)、(3<5,11>2)
… … …
显然,利用倒排索引,我们可以很快定位到文档,从而提高用户对词条的检索速度。
2.标准化规则(normalization)
为解决词条检索时词条命中率问题,ES在建立倒排索引时运用标准化规则即针对存储的索引词条进行一些相关预处理再作为索引进行存储。
为了便于理解,此部分利用英文文档解释倒排索引的标准化规则。
例如:通常情况下,在搜索“Third”、“Hospital”这两个单词时候,文档4两个单词都出现了,计数为2;文档5只有“Hospital”这个单词出现了,计数为1,所以文档4命中率高,排名靠前。
Term Doc_4 Doc_5
Third 1 0
Hospital 1 1
Peking 1 1
Total 3 2
但是这样搜索就会存在下列问题:
(1)”Third”与”third” 用户认为是相同单词,但是首字母小写可能搜不到内容。
(2)“hospitals”与”hospital”有相同的词根,如果存储了”hospitals”,那么”hospital”可能检索不到 。
(3)“piking”与”beijing”为相同意思的词,”beijing”可能检索不到。
基于以上问题,ES在建立倒排索引时,会对拆分的各个单词进行相应处理,以提升后面搜索的时候能够搜索到相关联的文档的概率,这就是标准化规则转换,主要包括:时态的转换、单复数的转换、同义词的转换、大小写的转换
最终文档在es中的可能存储结构就变为
Term Doc_4 Doc5 Term Doc_4 Doc_5 Attention
Peking 1 1 peking 1 1 同义词互转
beijing 1 1 beijing 1 1
University 1 1 university 1 1 同义词互转
College 1 1 college 1 1
Third 1 0 third 1 0 大小写转换
Hospital 1 1 hospital 1 1 大小写转换
Union 0 1 union ; 0 1 大小写转换
Medical 0 1 medical 0 1 大小写转换
有了标准化规则,搜索是不区分大小写,不区分同义词,不区分单复数,这样就可以大大提升用户对词条搜索的命中率。
3.相关度分数的计算
当利用ES进行查询时,查询结果都会返回一个对应词条的相关度分数(score)。相关度分数的计算基于TF/IDF算法(Term Frequence&Inverse Doucument Frequency),翻译大意为:词条在文档中出现的频率及在倒排索引中出现的频率。
1.Term Frequence:我们查询的词条在文本中出现多少次,出现次数越多,相关度越高。
TF(t in f)=
例如:前面所列医院信息文档中,“医院”,“北京大学”这两个单词,在第1文档中都出现了,但是第2和第3个文档只出现了“医院”,所以第1个相关度分数高。
2.Inverse Doucument Frequency:查询词条在所有文本中出现的次数,出现次数越高,相关度越低。
例如:“医院”在3个文档中出现4次,而“北京大学”出现1次,所以“医院”这个单词的相关度越低。
3.Field-length(字段长度规约):字段的长度越长,相关度越低
例如:“北京大学第三附属医院”长度大于“北京协和医院”,那么在检索“医院”这个单词时,第二个文档中分数要大于第一个文档的分数。
总结:ES相关度分数计算结果直接影响搜索排名顺序,对用户检索命中率有极大的影响
4.自定义相关度分数计算
实际搜索过程中,会出现一种情况,当用户群体对某个文档的搜索次数越多,我们认为这个文档的关注度高,那么这个文档排名理应适当靠前,但是当前的计算方法无法完成这个需求。此时我们可以做到自定义一个function_score函数,自己将某个field的值,跟es内置算出来的分数进行运算,然后由自己指定的field来进行分数的增强
注:new_score代表新分数;_score代表旧分数;factor代表权重;number_of_votes代表搜索次数
ES分布式架构以及维护机制
ES集群通过自定义的一些机制来保证集群条件下的扩展性,效率及事务性等特性。本小节主要从ES分片和副本机制、扩容机制、数据路由机制、增删改查机制、写一致性原理和Quorum机制这几个方面来介绍ES分布式架构。为便于理解需先解释一些相关专业用语。
(1)分片机制(shard):ES决定特定的数据存到特定的分片中去。
(2)分片副本:主分片的备份。
(3)集群发现机制:新加入的es进程会作为一个节点(node)会自动发现集群并加入进去。
(4)分片负载均衡:例如现在有10个shard,集群中3个node,ES会均衡分配shard,保证node负载均衡。
(5)数据路由:某条数据最终根据什么路径进行存储。
(6)ES透明隐藏特性:ES针对集群的操作对用户进行隐藏,用户面对的只是数据而不是相关的机器
1.分片和副本机制
ES利用分片机制将用户数据分节点存储,保证存储效率以及数据安全性。重要性不言而喻。在介绍ES分片机制之前,首先需要说明ES主节点(master)主要职责。ES集群主节点主要进行与集群操作相关内容,比如删除或者创建索引,跟踪哪些节点是集群的一部分,决定分片(shard)的分配情况,因为稳定的节点对集群健康非常重要。
ES分片机制主要基于以下规则进行。
(1)ES根据将一个索引下的数据根据数据大小以及分片个数分布式存储,所有主分片共同组成一个索引。
假设一个索引大小为3T,每个分片存储为1T,每个分片有一个副本则单节点下分片存储机制如图所示,其中每个文档只能存在于一个分片下,3个分片共同组成一个索引。
(2)副本和主分片上的数据是同步的,承担集群数据的容错功能。
(3)主分片的个数一旦确认不可改变(原因请阅数据路由小节),但是副本的数量是可以随意改变的。
(4)某个分片与他的副本不在同一个节点上,但是与其他副本可以在一个节点上。
总结:ES分片以及副本机制在保证数据存储效率以及数据安全性方面提供了有力的支持,也是ES能够快速检索数据的架构基础。
2.扩容机制
在介绍ES扩容机制之前,需要先需要介绍ES的【集群发现机制】:新加入的es进程作为一个节点(node)会自动发现集群并加入进去。集群发现机制为ES扩容提供了后续操作的先决条件。
(1)水平扩容:增加服务器个数。
自平衡机制(rebalance): ES在增加减少节点时对shard进行自动均衡,如下图当ES集群server2有两个分片,当集群中再加入一个节点server4,server2会自动将一个分片迁移到server4中。
水平扩容极限:当每个节点上只存在一个shard,则不可再进行扩容。
容错性能:当某台服务器发送宕机,ES集群能够正常数据的存取。
例:如下图所示,若集群有3个节点,6个shard,则按照ES的shard 分配机制3个节点分别存【主分片1,主分片2】,【主分片3,副本1】,【副本3,副本1】,若其中1个节点宕机,其他两台能够照常提供服务。
集群中接受服务器宕机台数越多,说明容错性越好。事例中,只能接受1台服务器宕机。可以看出,增加副本个数可以提高集群容错性能。
(2)垂直扩容:在服务器台数不变情况下,单个服务器容量扩大。
总结:扩容机制首先可提高集群吞吐量,其次也可以提高机器的容错性能。
3.数据路由机制
一个索引由多个分片构成,当添加(删除、修改)一个文档时,ES就需要决定这个文档存储在哪个分片上,这个过程就成为数据路由(routing)。
路由算法:shard=hash(routing)%number_of_primary_shards
解释:对文档路由值取hash后对ES集群中主分片数取余数。
例:一个索引,3个主分片
(1)当每次增删改查时,都有一个routing,默认是文档ID值。
(2)对这个routing进行哈希函数计算。
(3)计算出的值再跟主分片个数取余数。文档就在对应的shard上。
总结:由路由算法快速定位数据位置,并兼有负载均衡的作用。同时可理解若主分片个数发生改变,我们就不能正确计算出的对应分片位置,造成查询故障,这就是分片数不可变的原因。
4.数据增删改查机制
ES针对数据进行不同操作所用的策略略有不同,本小节分为数据操作(增删改)与数据查询两部分进行详述。
(1)增删改:
当用户发送请求进行增删改时,并不是首先发送到master节点,而是任何节点都有可能接收到请求(节点对等原则),如果数据在请求的节点上,那么直接返回,如果数据不在节点上,那么请求转发到相应节点,再返回数据。接受用户请求的节点被称为协调节点,负责根据路由算法将数据转发至相应节点,最终处理请求的节点负责将信息的正删改,并同步到对应的副本上。
(3)查询操作
与正删改操作不同,查询不需要进行数据操作,所以在转发的时候运用轮询算法,将请求依次发送到数据对应的对主、副分片,从而减小查询对单个节点的压力。
总结:ES增删改查策略给我们查询和修改数据提供了一条最简化的路径,同时保证了ES集群的负载均衡,保证了搜索的稳定和效率。
5.写一致性原理和quorum机制
本小节主要介绍用户操作ES集群进行数据的增删改操作时,集群会针对不同的操作类型(ES条件),做出不同的响应(执行操作或者不执行操作)。主要分为通过指定参数和quorum算法两种机制进行指定。
(1)consistency参数指定
任何一个增删改操作都可以跟上一个参数consistency,可以给该参数指定值
例如:PUT /myindex/mytype/myid?consistency=one
one:只要有一个主分片是活跃的就可以执行。
all:所有主分片和副本都是活跃的才可以执行。
(3)quorum(ES默认机制):大部分分片是活跃的才可以执行。
算法:int((primary+number_of_replica)/2)+1
例如:集群中有3个主分片,每个分片有1个副本,那么计算公式为int((3+1)/2)+1=3及至少有3个分片是活跃的才能进行增删改操作。
ES的API
- 1.条件查询
term查询:主要是精确匹配单个或者多条词条
QueryBuilder builder = QueryBuilders.termQuery("hospitalName","协和");
QueryBuilder builder = QueryBuilders.termQuery("hospitalName","北京","协和")
- 2.match匹配查询
匹配短语查询要求是查询字符串中的terms必须出现在document中,要么terms一次按照输入顺序一次出现在结果中,在默认情况下,查询输入的terms必须在搜索字符串紧挨着出现,否则会插叙拿不到,不过我们可已制定slop参数,来控制输入的terms之间有多少个单词仍然能够搜索到。
QueryBuilder builder=QueryBuilders.matchQuery("hospitalName","协和");
QueryBuilder builder=QueryBuilders.MultiMatchQuery("hospitalName","协和")
现将match匹配规则总结如下:
词条(含搜索顺序) 是否匹配
“北京”,“协和” 匹配doc_1
“协和”,“北京” 匹配doc_1
“北京”,“协和”,“附属” 匹配doc_1
“北京”,“附属”,“协和” 无匹配
- 3.range查询
主要是对字段进行过滤或者筛选,可以是数字或者字符串类型
QueryBuilder builder = QuilderBuilers.rangQuery("paseDate").from("2019-5-1").to("2019-5-20").format("yyyy-MM-dd");
- 4.prefix匹配查询
主要是匹配字段的前缀
QueryBuilder builder = QueryBuilders.prefixQuery("hospitalName","北京协和");
- 5.wildcard模糊查询
?号匹配单个单词
*号匹配多个单词
QueryBuilder builder = QueryBuilders.wildcardQuery("hospitalName","北京协和")
- 6.fuzzy查询,分词模糊查询
主要是通过添加fuzziness属性来进行模糊查询,例:能够匹配hospitalName为Medical前或后加一个字母的term的文档Fuzziness的含义是检索的term 前后增加或减少n个单词的匹配查询。
QueryBuilder builder=QueryBuilders.fuzzyQuery("hospitalName","Medica").fuzziness(Fuzziness.ONE);
- 7.聚合查询
聚合查询主要用于针对文档某一指标进行相关统计,主要涉及客户端AggregationBuilders类进行处理。本小节结合互联网医院医生表展示聚合查询的用法,需要注意的是聚合查询需先指定查询结果对应的字段。
文档ID 文档内容
1 {“name”:”赵大保”,”age”:28}
2 {“name”:”孟小飞”,”age”:26}
3 {“name”:”苏小玲”,”age”:18}
(1)获取最大值。
AggregationBuilder agg= AggregationBuilders.max("aggMax").field("age");
结果:{”aggMax”:28}
(2)获取最小值:
AggregationBuilder agg = AggregationBuilders.min("aggMin").field("age");
结果:{”aggMin”:18}
(3)获取平均值:
AggregationBuilder agg = AggregationBuilders.avg("aggAvg").field("age");
结果:{”aggAvg”:24}
(4)求和:
AggregationBuilder agg = AggregationBuilders.sum("aggSum").field("age");
结果:{"aggSum":72}