ElasticSearch概念
基本概念
索引(Index)
ElasticSearch把数据存放到一个或者多个索引(indices)中。如果用关系型数据库模型对比,索引(index)的地位与数据库实例(database)相当。索引存放和读取的基本单元是文档(Document)。我们也一再强调,ElasticSearch内部用Apache Lucene实现索引中数据的读写。读者应该清楚的是:在ElasticSearch中被视为单独的一个索引(index),在Lucene中可能不止一个。这是因为在分布式体系中,ElasticSearch会用到分片(shards)和备份(replicas)机制将一个索引(index)存储多份。
文档(Document)
在ElasticSearch的世界中,文档(Document)是主要的存在实体(在Lucene中也是如此)。所有的ElasticSearch应用需求到最后都可以统一建模成一个检索模型:检索相关文档。文档(Document)由一个或者多个域(Field)组成,每个域(Field)由一个域名(此域名非彼域名)和一个或者多个值组成(有多个值的值称为多值域(multi-valued))。在ElasticSeach中,每个文档(Document)都可能会有不同的域(Field)集合;也就是说文档(Document)是没有固定的模式和统一的结构。文档(Document)之间保持结构的相似性即可(Lucene中的文档(Document)也秉持着相同的规定)。实际上,ElasticSearch中的文档(Document)就是Lucene中的文档(Document)。从客户端的角度来看,文档(Document)就是一个JSON对象。
参数映射(Mapping)
所有的文档(Document)在存储之前都必须经过分析(analyze)流程。用户可以配置输入文本分解成Token的方式;哪些Token应该被过滤掉;或者其它的处理流程,比如去除HTML标签。此外,ElasticSearch提供的各种特性,比如排序的相关信息。保存上述的配置信息,这就是参数映射(Mapping)在ElasticSearch中扮演的角色。尽管ElasticSearch可以根据域的值自动识别域的类型(field type),在生产应用中,都是需要自己配置这些信息以避免一些问题发生。要保证应用的可控性。
文档类型(Type)
每个文档在ElasticSearch中都必须设定它的类型。文档类型使得同一个索引中在存储结构不同的文档时,只需要依据文档类型就可以找到对应的参数映射(Mapping)信息,方便文档的存取。
节点(Node)
单独一个ElasticSearch服务器实例称为一个节点。对于许多应用场景来说,部署一个单节点的ElasticSearch服务器就足够了。但是考虑到容错性和数据过载,配置多节点的ElasticSearch集群是明智的选择。
集群(Cluster)
集群是多个ElasticSearch节点的集合。这些节点齐心协力应对单个节点无法处理的搜索需求和数据存储需求。集群同时也是应对由于部分机器(节点)运行中断或者升级导致无法提供服务这一问题的利器。ElasticSearch提供的集群各个节点几乎是无缝连接(所谓无缝连接,即集群对外而言是一个整体,增加一个节点或者去掉一个节点对用户而言是透明的)。在ElasticSearch中配置一个集群非常简单,在我们看来,这是在与同类产品中竞争所体现出的最大优势。
分片索引(Shard)
前面已经提到,集群能够存储超出单机容量的信息。为了实现这种需求,ElasticSearch把数据分发到多个存储Lucene索引的物理机上。这些Lucene索引称为分片索引,这个分发的过程称为索引分片(Sharding)。在ElasticSearch集群中,索引分片(Sharding)是自动完成的,而且所有分片索引(Shard)是作为一个整体呈现给用户的。需要注意的是,尽管索引分片这个过程是自动的,但是在应用中需要事先调整好参数。因为集群中分片的数量需要在索引创建前配置好,而且服务器启动后是无法修改的,至少目前无法修改。
索引副本(Replica)
通过索引分片机制(Sharding)可以向ElasticSearch集群中导入超过单机容量的数据,客户端操作任意一个节点即可实现对集群数据的读写操作。当集群负载增长,用户搜索请求阻塞在单个节点上时,通过索引副本(Replica)机制就可以解决这个问题。索引副本(Replica)机制的的思路很简单:为索引分片创建一份新的拷贝,它可以像原来的主分片一样处理用户搜索请求。同时也顺便保证了数据的安全性。即如果主分片数据丢失,ElasticSearch通过索引副本使得数据不丢失。索引副本可以随时添加或者删除,所以用户可以在需要的时候动态调整其数量。
时间之门(Gateway)
在运行的过程中,ElasticSearch会收集集群的状态、索引的参数等信息。这些数据被存储在Gateway中。
ElasticSearch背后的核心理念
ElasticSearch是构建在极少数的几个概念之上的。ElasticSearch的开发团队希望它能够快速上手,可扩展性强。而且这些核心特性体现在ElasticSearch的各个方面。从架构的角度来看,这些主要特性是:
- 开箱即用。安装好ElasticSearch后,所有参数的默认值都自动进行了比较合理的设置,基本不需要额外的调整。包括内置的发现机制(比如Field类型的自动匹配)和自动化参数配置。
- 天生集群。ElasticSearch默认工作在集群模式下。节点都将视为集群的一部分,而且在启动的过程中自动连接到集群中。
- 自动容错。ElasticSearch通过P2P网络进行通信,这种工作方式消除了单点故障。节点自动连接到集群中的其它机器,自动进行数据交换及以节点之间相互监控。索引分片
- 扩展性强。无论是处理能力和数据容量上都可以通过一种简单的方式实现扩展,即增添新的节点。
- 近实时搜索和版本控制。由于ElasticSearch天生支持分布式,所以延迟和不同节点上数据的短暂性不一致无可避免。ElasticSearch通过版本控制(versioning)的机制尽量减少问题的出现。
ElasticSearch的工作原理
启动过程
当ElasticSearch的节点启动后,它会利用多播(multicast)(或者单播,如果用户更改了配置)寻找集群中的其它节点,并与之建立连接。这个过程如下图所示
在集群中,一个节点被选举成主节点(master node)。这个节点负责管理集群的状态,当群集的拓扑结构改变时把索引分片分派到相应的节点上。
需要注意的是,从用户的角度来看,主节点在ElasticSearch中并没有占据着重要的地位,这与其它的系统(比如数据库系统)是不同的。实际上用户并不需要知道哪个节点是主节点;所有的操作需求可以分发到任意的节点,ElasticSearch内部会完成这些让用户感到不明白的工作。在必要的情况下,任何节点都可以并发地把查询子句分发到其它的节点,然后合并各个节点返回的查询结果。最后返回给用户一个完整的数据集。所有的这些工作都不需要经过主节点转发(节点之间通过P2P的方式通信)。
主节点会去读取集群状态信息;在必要的时候,会进行恢复工作。在这个阶段,主节点会去检查哪些分片可用,决定哪些分片作为主分片。处理完成后,集群就会转入到黄色状态。
这意味着集群已经可以处理搜索请求了,但是还没有火力全开(这主要是由于所有的主索引分片(primary shard)都已经分配好了,但是索引副本还没有)。接下来需要做的事情就是找到复制好的分片,并设置成索引副本。当一个分片的副本数量太少时,主节点会决定将缺少的分片放置到哪个节点中,并且依照主分片创建副本。所有工作完成后,集群就会变成绿色的状态(表示所有的主分片的索引副本都已经分配完成)。
探测失效节点
在正常工作时,主节点会监控所有的节点,查看各个节点是否工作正常。如果在指定的时间里面,节点无法访问,该节点就被视为出故障了,接下来错误处理程序就会启动。集群需要重新均衡——由于该节点出现故障,分配到该节点的索引分片丢失。其它节点上相应的分片就会把工作接管过来。换句话说,对于每个丢失的主分片,新的主分片将从剩余的分片副本(Replica)中选举出来。重新安置新的分片和副本的这个过程可以通过配置来满足用户需求。
由于只是展示ElasticSearch的工作原理,我们就以下图三个节点的集群为例。集群中有一个主节点和两个数据节点。主节点向其它的节点发送Ping命令然后等待回应。如果没有得到回应(实际上可能得不到回复的Ping命令个数取决于用户配置),该节点就会被移出集群。
与ElasticSearch进行通信
我们已经探讨了ElasticSearch是如何构建起来的,但是归根到底,最重要的是如何往ElasticSearch中添加数据以及如何查询数据。为了实现上述的需求,ElasticSearch提供了精心设计的API。这些主要的API都是基于REST风格(参看http://en.wikipedia.org/wiki/Pepresentational_state_transfer )。而且这些API非常容易与其它能够处理HTTP请求的系统进行集成。
ElasticSearch认为数据应该伴随在URL中,或者作为请求的主体(request body),以一种JSON格式的文档发送给服务器。如果读者用Java或者其它运行在JVM虚拟机上的语言,应该关注一下Java API,它除了是群集中内置的REST风格API外,功能与URL请求是一样的。
值得一提的是在ElasticSearch内部,节点之间的通信也是用相关的Java API。
索引数据
ElasticSearch提供了4种索引数据的办法。最简单的是使用索引API。通过它可以将文档添加到指定的索引中去。比如,通过curl工具(访问http://curl.haxx.se/ ),我们可以通过如下的命令创建一个新的文档:
1 | curl -XPUT http://localhost:9200/blog/article/1 '{"title": "New |
第2种和第3种办法可以通过bulk API和UDP bulk API批量添加文档。通常的bulk API采用HTTP协议,UDP bulk API采用非连接的数据包协议。UDP协议传输速度会更快,但是可靠性要差一点。最后一种办法就是通过river插件。river运行在ElasticSearch集群的节点上,能够从外部系统中获取数据。
有一点需要注意,索引数据的操作只会发生在主分片(primary shard)上,而不会发生在分片副本(Replica) 上。如果索引数据的请求发送到的节点没有合适的分片或者分片是副本,那么请求会被转发到含有主分片的节点。
数据查询
查询API在ElasticSearch中有着很大的比重。通过使用Query DSL(基于JSON,用来构建复杂查询的语言),我们能够:
- 使用各种类型的查询方式,包括:简单的关键词查询(termquery) 、短语(phrase)、区间(range)、布尔(boolean)、模糊(fuzzy)、跨度(span)、通配符(wildcard)、地理位置(spatial)等其它类型的查询方式。
- 通过组合简单查询构建出复杂的查询。
- 过滤文档,去除不符合标准的文档而且不影响打分排序。
- 查找给定文档的相似文档。
- 查找给定短语的搜索建议和查询短语修正。
- 通过faceting构建动态的导航和数据统计
- 使用prospective search而且找到匹配写定文档的查询语句。(关于prospective search,似乎是一种推送方式。即把用户的查询语句存储到索引中,如果新的文档添加到索引中,就把文档关联到匹配的查询语句中。这种查询适合于新闻、博客等会定时更新的应用场景)
关于数据查询,其核心点在于查询过程不是一个简单、单一的流程。通常这个过程分为两个阶段:查询分发阶段和结果汇总阶段。在查询分发阶段,会从各个分片中查询数据;在结果汇总阶段,会把从各个分片上查询到的结果进行合并、排序等其它处理过程,然后返回给用户。
用户可以通过指定搜索类型来控制查询的分发和汇总过程,目前搜索类型只有6种可选值。在Packt出版的《ElasticSearch Server》一书中,已经讲述了查询范围(query scope)这一知识点.
索引参数设置
前面已经提到ElasticSearch索引参数的自动化配置和文档结构及域类型的自动识别。当然,ElasticSearch也允许用户自行修改默认配置。用户可以自行配置很多参数,比如通过mapping配置索引中的文档结构,设置分片(shard)和副本(replica)的的个数,设置文本分析组件……
集群管理和监控
通过管理和监控部分的API,用户可以更改集群的设置。比如调整节点发现机制(discovery mechanism) 或者更改索引的分片策略。用户可以查看集群状态信息,或者每个节点和索引和统计信息。
ElasticSearch概念