Elasticsearch 简介

Elasticsearch是一个高度可扩展的开源全文搜索和分析引擎。它允许您快速和近实时地存储,搜索和分析大量数据。它通常用为具有复杂搜索功能和要求的应用程序提供基础引擎/技术支持。

ElasticSearch基于Lucene的搜索服务器,提供RESTful web接口,它是用Java开发的。

基本概念

Elasticsearch有几个核心的基本概念。我们来简单的了解一下:

  • 近实时(NRT),Elasticsearch是一个接近实时的搜索平台。这意味着从索引文档到它可搜索的时间有一个轻微的延迟(通常为1秒)。

  • Cluster,集群是一个或多个节点(服务器)的集合,它们一起保存完整的数据,并在所有节点上提供联合索引和搜索功能。集群由唯一名称标识,默认情况下为“elasticsearch”。此名称很重要,因为如果节点设置为通过其名称加入集群,则节点只能是集群的一部分。

    • 确保您不要在不同的环境中重复使用相同的集群名称,否则您最终可能会加入错误的集群。例如,您可以对开发,暂存和生产集群使用logging-dev,logging-stage和logging-prod。
    • 注意,有一个集群只有一个节点是有效的和完美的。此外,您可能还有多个独立的集群,每个集群都有自己唯一的集群名称。


ElasticSearch

  • Node,节点是作为集群一部分的单个服务器,负责存储数据,并参与集群的索引和搜索功能。和集群一样,一个节点由一个名称标识,默认情况下是一个随机的通用唯一标识符(UUID),在启动时分配给该节点。如果不想使用默认值,可以定义节点名称。此名称对于管理目的很重要,可以说明你希望确定网络中哪些服务器对应于Elasticsearch集群中的哪些节点。
    • 可以通过将节点配置为某个集群名称而加入特定集群。默认情况下,每个节点都设置为加入名为elasticsearch的集群,这意味着如果你在网络上启动多个节点,并且假设它们可以发现彼此,则它们将自动形成并加入名为elasticsearch的单个集群。
    • 在单个集群中,你可以拥有任意数量的节点。此外,如果你的网络上当前没有其他Elasticsearch节点运行,则启动单个节点将默认形成一个名为elasticsearch的新单节点集群。
  • Index,索引是具有某些相似特征的文档的集合。例如,您可以拥有客户数据的索引,产品目录的另一个索引,以及订单数据的另一个索引。索引由名称(必须全部为小写)标识,并且此名称是为了用于在对其中的文档执行索引,搜索,更新和删除操作时引用它。
    • 在单个集群中,你可以根据需要定义任意数量的索引。
  • Type,在索引中,你可以定义一个或多个类型。类型是你的索引的逻辑类别/分区,其语义完全由你来决定。通常,为具有一组公共字段的文档定义类型。例如,假设你运行博客平台并将所有数据存储在一个索引中。在此索引中,你可以为用户数据定义类型,为博客数据定义另一种类型,并为注释数据定义另一种类型。
  • Document,文档是可以索引的信息的基本单位。例如,你可以为单个客户创建一个文档,为单个产品创建另一个文档,为单个订单创建另一个文档。此文档以JSON格式来表示。
    • 在索引/类型中,您可以存储任意数量的文档。请注意,尽管文档物理上驻留在索引中,但实际上文档必须索引或者分配给索引中的类型。
  • Shards & Replicas(分片和复制),索引可以潜在地存储可以超过单个节点的硬件限制的大量数据。例如,占用1TB磁盘空间的10亿个文档的单个索引可能不适合单个节点的磁盘,或者可能太慢,无法单独从单个节点提供搜索请求。
    • 为了解决这个问题,Elasticsearch提供了将索引细分为多个称为分片的功能。创建索引时,可以简单地定义所需的分片数。每个分片本身是一个完全功能和独立的“索引”,可以托管在集群中的任何节点上。
    • 分片是重要的两个主要原因:
      • 它允许水平分割/缩放内容卷。
      • 它允许跨分片(可能在多个节点上)分布和并行化操作,从而提高性能/吞吐量 。分片如何分布以及如何将其文档聚合回搜索请求的机制由Elasticsearch完全管理,并且对用户是透明的。
    • 在可以随时可能发生故障的网络或者云环境中,这是非常有用的,强烈建议具有故障转移机制,以防分片或者节点以某种方式脱机或由于某种原因而消失。为此,Elasticsearch允许将索引的分片的一个或多个副本转换为所谓的分片副本。
    • 复制是重要的两个主要原因:
      • 它在分片或者节点故障的情况下提供高可用性。因此,关键是要注意,复制分片从不分配在与从其复制的原始/主分片相同的节点上。
      • 它允许您扩展搜索量/吞吐量,因为搜索可以并行地在所有副本上执行。
    • 总而言之,每个索引可以拆分成多个分片。索引也可以复制0次(意味着没有副本)或更多次。一旦复制,每个索引将具有主分片(从其复制的原始分片)和副本分片(主分片的副本)。可以在创建索引时为每个索引定义分片和副本的数量。创建索引后,你可以随时动态更改副本的数量,但不能在事后更改数量。
    • 默认情况下,Elasticsearch中的每个索引都会分配5个主分片和1个副本,这意味着如果您的群集中至少有两个节点,那么您的索引将有5个主分片和5个副本分片(1个完整副本)每个索引10个分片。
    • 注意:每个Elasticsearch shard是一个Lucene索引。在一个Lucene索引中可以有最大数量的文档。从LUCENE-5843起,限制为2,147,483,519(= Integer.MAX_VALUE - 128)个文档。可以使用_cat/shards api监视分片大小。

安装

Elasticsearch至少需要Java 8,建议使用Oracle JDK的版本是1.8.0_73。Java安装因平台而异,所以我们不在这里介绍这些细节。Oracle的推荐安装文档可以在Oracle网站上找到。 只需说明,在安装Elasticsearch之前,请首先通过运行(然后根据需要相应地安装/升级)检查您的Java版本:

1
2
$ java -version
$ echo $JAVA_HOME

一旦我们设置好了Java,我们可以下载并运行Elasticsearch。二进制文件可从www.elastic.co/downloads以及过去所有的版本中获得。对于每个版本,你可以在zip、tar、DEB、RPM中进行选择。为了简单起见,让我们使用tar文件。先下载Elasticsearch 5.0.1 tar:

1
$ curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.0.1.tar.gz

然后解压缩如下:

1
$ tar -xvf elasticsearch-5.0.1.tar.gz

然后它将在当前目录中创建一大堆文件和文件夹。然后我们进入bin目录,如下所示:

1
$ cd elasticsearch-5.0.1/bin

现在我们准备好启动我们的节点和单集群:

1
$ ./elasticsearch

如果一切顺利,你应该看到一堆消息,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[2016-09-16T14:17:51,251][INFO][o.e.n.Node] [] initializing ...
[2016-09-16T14:17:51,329][INFO][o.e.e.NodeEnvironment] [6-bjhwl] using [1] data paths, mounts [[/ (/dev/sda1)]], net usable_space [317.7gb], net total_space [453.6gb], spins? [no], types [ext4]
[2016-09-16T14:17:51,330][INFO][o.e.e.NodeEnvironment] [6-bjhwl] heap size [1.9gb], compressed ordinary object pointers [true]
[2016-09-16T14:17:51,333][INFO][o.e.n.Node] [6-bjhwl] node name [6-bjhwl] derived from node ID; set [node.name] to override
[2016-09-16T14:17:51,334][INFO][o.e.n.Node] [6-bjhwl] version[5.0.1], pid[21261], build[f5daa16/2016-09-16T09:12:24.346Z], OS[Linux/4.4.0-36-generic/amd64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_60/25.60-b23]
[2016-09-16T14:17:51,967][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [aggs-matrix-stats]
[2016-09-16T14:17:51,967][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [ingest-common]
[2016-09-16T14:17:51,967][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [lang-expression]
[2016-09-16T14:17:51,967][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [lang-groovy]
[2016-09-16T14:17:51,967][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [lang-mustache]
[2016-09-16T14:17:51,967][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [lang-painless]
[2016-09-16T14:17:51,967][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [percolator]
[2016-09-16T14:17:51,968][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [reindex]
[2016-09-16T14:17:51,968][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [transport-netty3]
[2016-09-16T14:17:51,968][INFO][o.e.p.PluginsService] [6-bjhwl] loaded module [transport-netty4]
[2016-09-16T14:17:51,968][INFO][o.e.p.PluginsService] [6-bjhwl] loaded plugin [mapper-murmur3]
[2016-09-16T14:17:53,521][INFO][o.e.n.Node] [6-bjhwl] initialized
[2016-09-16T14:17:53,521][INFO][o.e.n.Node] [6-bjhwl] starting ...
.......
[2016-09-16T14:17:56,748][INFO][o.e.n.Node] [6-bjhwl] started

没有太多细节,我们可以看到我们的节点命名为“I8hydUG”(你看到的是一个不同的字符集)已经开始并选择本机作为单个集群中的主机。先不管是否符合你的设置意愿,重要的是,我们已经在一个集群中启动了一个节点。

如前所述,我们可以设置集群或节点名称。这可以在启动Elasticsearch时从命令行完成,如下所示:

1
$ ./elasticsearch -Ecluster.name=my_cluster_name -Enode.name=my_node_name

还要注意我们的节点访问的HTTP地址(例如:192.168.8.112)和端口(例如:9200)可用。 默认情况下,Elasticsearch使用端口9200来提供对其REST API的访问。如果有必要也可配置此端口。

浏览你的Cluster

REST API,现在我们已经使我们的节点(和集群)启动并运行,下一步是了解如何与它通信。 幸运的是,ElasticSearch提供了一个非常全面和强大的REST API,可以使用它与集群进行交互。也可以使用API完成的如下事情:

  • 检查群集,节点和索引运行状况,状态和统计信息。
  • 管理集群,节点和索引数据和元数据。
  • 对索引执行CRUD(创建,读取,更新和删除)和搜索操作。
  • 执行高级搜索操作,如分页,排序,过滤,脚本,聚合和其他许多操作。

健康检查

让我们开始一个基本的健康检查,我们可以用来看看我们的集群是如何工作的。我们将使用curl命令来做到这一点,但你可以使用任何允许你进行HTTP/REST调用的工具。让我们假设我们仍然在同一个节点上启动Elasticsearch并打开另一个命令shell窗口。

要检查集群健康,我们将使用_cat API。

1
$ GET /_cat/health?v

而响应是:

1
2
epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1475247709 17:01:49 elasticsearch green 1 1 0 0 0 0 0 0 - 100.0%

我们可以看到,我们的集群名为“elasticsearch”的是一个绿色的状态。

每当我们要求群集健康时,我们或者得到绿色,黄色或红色。绿色意味着一切都是好的(集群是完全功能的),黄色意味着所有数据可用,但一些副本还没有分配(集群是完全功能的),红色意味着一些数据不可用于任何原因。请注意,即使群集是红色的,它仍然有部分功能可用(即它将继续提供来自可用分片的搜索请求),但你可能需要尽快修复它,因为缺少数据了。

从上面的响应,我们可以看到总共1个节点,我们有0个碎片,因为我们还没有数据。请注意,由于我们使用默认集群名称(elasticsearch),并且Elasticsearch默认使用本地网络发现并查找同一台计算机上的其他节点,因此可能会意外启动计算机上的多个节点,所有加入一个集群。在这种情况下,您可能在上述响应中看到超过1个节点。

我们还可以得到我们的集群中的节点列表如下:

1
$ GET /_cat/nodes?

而响应是:

1
2
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role主名称
127.0.0.1 10 5 5 4.46 mdi * I8hydUG

在这里,我们可以看到我们的一个名为“I8hydUG”的节点,它是当前在我们集群中的单个节点。

创建索引

列出所有索引,让我们看一看我们的索引:

1
$ GET /_cat/indices?v
而响应是:
1
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size

这仅仅意味着我们在集群中还没有索引。

现在让我们创建一个名为“customer”的索引,然后再次列出所有索引:

1
2
$ PUT /customer?pretty
$ GET /_cat/indices?v
第一个命令使用PUT命令创建名为“customer”的索引。我们只是简单地追加到调用结束,告诉它pretty输出JSON响应(如果有)。

而响应是:

1
2
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open customer 95SQ4TSUT7mWBT7VNHH67A 5 1 0 0 260b 260b

第二个命令的结果告诉我们,我们现在有一个名为customer的索引,它有5个主分片和1个副本(默认值),它包含0个文档。

您可能还注意到,客户索引有一个标记为黄色的健康。回想起前面的讨论,黄色意味着一些副本没有被分配。发生这种索引的原因是因为Elasticsearch默认情况下为此索引创建一个副本。因为我们目前只有一个节点运行,所以一个副本还不能被分配(为了高可用性),直到另一个节点加入集群的稍后时间点。一旦该副本被分配到第二个节点上,该索引的健康状态将变为绿色。

文档

现在让我们把一些东西放到我们的客户索引中。记住以前为了索引文档,我们必须告诉Elasticsearch它应该去的索引中的类型。

让我们将一个简单的客户文档索引到客户索引“外部”类型,ID为1,如下所示:

1
2
3
4
$ PUT /customer/external/1?pretty
{
"name": "John Doe"
}

而响应是:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"created" : true
}

从上面,我们可以看到在客户索引和外部类型内成功创建了一个新的客户文档。该文档还具有在索引时指定的内部ID为1。

特别要注意,Elasticsearch不需要先显式创建索引,然后才能将文档编入索引。在上一个示例中,Elasticsearch将自动创建客户索引(如果它尚未预先存在)。

让我们现在查询一下我们刚刚建了索引的文档:

1
$ GET /customer/external/1?pretty

响应是:

1
2
3
4
5
6
7
8
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : { "name": "John Doe" }
}

在这里除了一个字段,没有什么其他的,说明我们发现一个文档与请求的ID 1和另一个字段,_source,它返回我们从上一步索引的完整的JSON文档。

删除索引

现在让我们删除我们刚刚创建的索引,然后再次列出所有的索引:

1
2
$ DELETE /customer?pretty
$ GET /_cat/indices?v

响应是:

1
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size

这意味着索引被成功删除,我们现在回到我们的集群中最初的状态。

让我们仔细看看我们迄今为止学到的一些API命令:

1
2
3
4
5
6
7
8
9
10
$ PUT /customer

$ PUT /customer/external/1
{
"name": "John Doe"
}

$ GET /customer/external/1

$ DELETE /customer

如果我们仔细研究上述命令,我们实际上可以看到我们如何在Elasticsearch中访问数据的模式。 这种模式可以总结如下:

1
<REST Verb> /<Index>/<Type>/<ID>

这种REST访问模式遍布所有的API命令,如果你可以简单地记住它,你将有一个良好的开端。

希望你能掌握Elasticsearch,我们的配套免费课: http://www.hubwiz.com/course/55473b0aebfde9b5591bb80a/