Elasticseach原理

简介

ElasticSearch(以下简称ES)是一个基于Lucene构建的开源(open-source),分布式(distributed),RESTful,实时(real-time)的搜索与分析(analytics)引擎。它可以让你在浏览数据时具备非常快的速度和优秀的可扩展性。它用于全文索引、结构化数据索引、数据分析以及三者的结合。它可以运行在你的笔记本上,或者扩展至数百台的服务器节点上来处理PB级的数据。

与关系型数据库的名词对照

Relational DB => Databases => Tables => Rows => Columns
Elasticsearch => Index => Types => Documents => Fields

面向文档

ES面向文档,这就意味着你可以存储完整的对象或者文档。ES不仅存储它们,并且对它们的每一个文档的内容做了索引以便可以查询到它们。在ES中,你是对文档进行的建索引、查询、排序、过滤,而不是对关系型数据的一行数据。这就是ES处理数据的一个最基本的不同点,这也是ES为什么能处理全文索引的关键。

精确索引和全文索引

在ES中的数据可以分为两类:精确值(exact values)以及全文(full text)。 精确值:例如日期类型date,若date其有两个值:2014-09-15与2014,那么这两个值不相等。又例如字符串类型foo与Foo不相等。 全文:通常是人类语言写的文本,例如一段tweet信息、email的内容等。

精确值很容易被索引:一个值要么相等要么不等。 索引全文值就需要很多功夫。例如我们不仅要想:这个文档符合我们的查询吗?还要想:这个文档有多符合我们的查询?换句话说就是:这个文档跟我们的查询关联大吗?我们很少精确的去匹配整个全文,我们最想要的是去匹配全文文本的内部信息。除此,我们还希望搜索能够理解我们的意图:例如

如果你搜索UK,我们需要包含United Kingdom的文本也会被匹配。 如果你搜索jump,那么包含jumped,jumps,jumping,更甚者leap的文本会被匹配。

为了更方便的进行全文索引,ES首先要先分析文本,然后使用分析过的文本去创建倒序索引。

倒序索引与文本分析

ES使用倒序索引来加速全文索引。一个倒序索引由两部分组成:在文档中出现的所有不同的词;对每个词,它所出现的文档的列表。 例如:如果我们有两个文档,每一个文档有一个content字段,包含的内容如下:

1.The quick brown fox jumped over the lazy dog
2.Quick brown foxes leap over lazy dogs in summer

要创建一个倒序索引,首先要将content分割成单独的词(称为terms or tokens),创建一个所有terms的列表,然后罗列每一个term出现的文档。此过程称为tokenization。如下图:
这里写图片描述
现在,如果我们想要搜索 quick brown,我们仅仅只需要找每一个term出现的文档即可。如下图:
这里写图片描述
每一个文档都匹配到了,但是第一个比第二个要匹配的多。如果我们使用一个简单的相似性算法仅仅只计算匹配的数量,那么我们可以称第一个文档要比第二个匹配的好(与我们的查询更有关联)。

但是现在的倒序索引有一些问题:

Quick与quick是两个不同的term,但是搜索的用户会认为它们应该是一样的term才是合理的。
fox和foxes,dog和dogs是一样的词根,应该列为同一个term。 jumped和leap虽然词根不一样,但是意义却相同。

如果改善了上面的问题,那么倒序索引应该如下图:
这里写图片描述

设计原理

这里写图片描述
如果我们启动了一个节点,没有索引没有数据,那么看起来就像上图一样。 一个节点Node指一个运行着的ES实例,一个集群由一个或多个使用着同样名字(cluster.name)的节点组成,分享数据和负载。 当Node从集群中添加或删除时,集群会重组自己,使数据平摊的更均匀。

集群中需要有一台master节点。master的作用是掌管集群的管理工作: 例如创建和删除索引。 从集群中添加或删除一台节点。 master节点无需掌管文档级的变更和索引。这也意味着在只有一台master的情况下,随着负载的增加master不会成为瓶颈。 所有的节点都可能变成master。

作为user,我们可以与任何一个节点通信,包括master。每一个节点都知道每一个文档的位置并且可以将user的请求路由到文档所在的节点,并且这个节点负责接收它路由到的node or nodes的响应,并且将数据组织起来返回给用户。这些对用户都是透明的。

创建一个索引—index,shard,cluster

将数据添加到ES的前提是,我们需要一个索引(名词):index——一个存储与这个索引相对应数据的地方。实际上,index仅仅只是一个命名空间来指向一个或多个实际的物理分片(shard)。

一个分片(shard)是一个比较低层的工作单元来处理这个索引(index)的所有数据的一个切片(slice)。一个shard实际上是一个Lucene实例,在它的能力范围内拥有完整的搜索功能(在处理它自己拥有的数据时有所有的功能)。我们所有文档的索引indexed(动词)和存储工作都是在shard上,但这是透明的,我们不需要直接和shard通信,而是和我们创建的index(名词)通信。

shards是ES将数据分布式在你的集群的关键。想象下shards是数据的容器,文档存储在shards里,而shards被分配在集群的每一个节点Node里。当你的集群规模增长和降低时,ES会自动的在Nodes间迁移shards以保持集群的负载均衡。

一个分片(shard)是一个比较低层的工作单元来处理这个索引(index)的所有数据的一个切片(slice)。一个shard实际上是一个Lucene实例,在它的能力范围内拥有完整的搜索功能(在处理它自己拥有的数据时有所有的功能)。我们所有文档的索引indexed(动词)和存储工作都是在shard上,但这是透明的,我们不需要直接和shard通信,而是和我们创建的index(名词)通信。

shards是ES将数据分布式存储在你的集群的关键。想象下shards是数据的容器,文档存储在shards里,
而shards被分配在集群的每一个节点里。当你的集群规模增长和降低时,ES会自动的在Nodes间迁移shards以保持集群的负载均衡。

shard可分为primary shard和replica shard。 在一个index里的每一个文档都属于一个单独的primary shard,所以primary shard的数量决定了最大存储容量(对应于一个index)。

注意:shard是归属与index的,而不是cluster的。

replica shard是primary shard的拷贝。replica有两个作用:
1.冗余备份 2.提供读请求服务,例如搜索或读取文档

primary shard的数量在索引创建时确定后不能修改,replica可以在任何时候修改。

例: 见Figure2,在2.1的集群上创建一个index,拥有3个primary shards以及1个replica shards。
这里写图片描述
由于只有一台Node,而Primary shard的Replicas与其在同一台节点上毫无意义,所以集群没有初始化replicas,这时添加另外一台Node。见Figure3,每一个primary shard初始化了一个replica。

这里写图片描述

水平扩容

当我们继续添加一台节点时,Node1和Node2中的各取一个shard移动到了Node3.见Figure4
这里写图片描述
这样,我们每一台Node上只有两个shard。这就意味着每一台Node的硬件资源(CPU,RAM,I/O)将会被更少的shards共享,提高了每一个shard的性能。在这个案例中,6个shards最多可使用6台Node,这样每个shard就可以使用100%的node硬件资源。

Shards文档路由

当你对一个文档建立索引时,它仅存储在一个primary shard上。
ES是怎么知道一个文档应该属于哪个shard?当你创建一个新的文档时,ES是怎么知道应该把它存储至shard1还是shard2? 这个过程不能随机无规律的,因为以后我们还要将它取出来。它的路由算法是:

shard = hash(routing) % numberofprimary_shards

routing的值可以是文档的id,也可以是用户自己设置的一个值。hash将会根据routing算出一个数值然后%primaryshards的数量。这也是为什么primary_shards在index创建时就不能修改的原因。

Primary/Replica Shards的交互

假如我们有Figure8的集群。我们可以向这个集群的任何一台NODE发送请求,每一个NODE都有能力处理请求。每一个NODE都知道每一个文档所在的位置所以可以直接将请求路由过去。下面的例子,我们将所有的请求都发送到NODE1。
这里写图片描述
注:最好的实践方式是轮询所有的NODE来发送请求,以达到请求负载均衡。

写操作

创建、索引、删除文档都是写操作,这些操作必须在primary shard完全成功后才能拷贝至其对应的replicas上,如下图。

这里写图片描述

步骤:

1.客户端向Node1发送写操作的请求。
2.Node1使用文档的_id来决定这个文档属于shard0,然后将请求路由至NODE3,P0所在的位置。
3.Node3在P0上执行了请求。如果请求成功,则将请求并行的路由至NODE1 NODE2的R0上。当所有的replicas报告成功后,NODE3向请求的node(NODE1)发送成功报告,NODE1再报告至Client。
当客户端收到执行成功后,操作已经在Primary shard和所有的replica shards上执行成功了。

读操作

一个文档可以在primary shard和所有的replica shard上读取。
这里写图片描述

步骤:

1.客户端发送Get请求到NODE1。
2.NODE1使用文档的_id决定文档属于shard 0.shard 0的所有拷贝存在于所有3个节点上。这次,它将请求路由至NODE2。
3.NODE2将文档返回给NODE1,NODE1将文档返回给客户端。 对于读请求,请求节点(NODE1)将在每次请求到来时都选择一个不同的replica。
shard来达到负载均衡。使用轮询策略轮询所有的replica shards。

更新操作

更新操作,结合了以上的两个操作:读、写
这里写图片描述

1.客户端发送更新操作请求至NODE1
2.NODE1将请求路由至NODE3,Primary shard所在的位置
3.NODE3从P0读取文档,改变source字段的JSON内容,然后试图重新对修改后的数据在P0做索引。如果此时这个文档已经被其他的进程修改了,那么它将重新执行3步骤,这个过程如果超过了retryon_conflict设置的次数,就放弃。
4.如果NODE3成功更新了文档,它将并行的将新版本的文档同步到NODE1和NODE2的replica shards重新建立索引。一旦所有的replica
shards报告成功,NODE3向被请求的节点(NODE1)返回成功,然后NODE1向客户端返回成功。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值