柴少鹏的官方网站 技术在分享中进步,水平在学习中升华

Elasticsearch详细记录(六)

#还是翻译官网,可忽略......

一、入门

1.1 基本概念

Elasticsearch有一些核心概念。 从一开始就理解这些概念将极大地帮助缓解学习过程。

Near Realtime (NRT)

Elasticsearch是一个接近实时的搜索平台。 这意味着从索引文档的时间到可搜索的时间都有一个小的延迟(通常是一秒)。

Cluster

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

      确保不要在不同的环境中重复使用相同的群集名称,否则可能会导致节点加入错误的群集。 例如,您可以使用logging-dev,logging-stage和logging-prod来开发,分段和生产集群。

      请注意,有一个只有一个节点的集群是完全正确的。 此外,您也可能拥有多个独立的群集,每个群集都有自己的唯一群集名称。

Node

      节点是作为集群一部分的单个服务器,存储数据并参与集群的索引和搜索功能。就像一个集群一样,一个节点由一个名字来标识,默认情况下它是一个在启动时分配给节点的随机通用唯一标识符(UUID)。如果您不需要默认值,您可以定义任何您想要的节点名称。此名称对于管理目的非常重要,您需要确定网络中的哪些服务器对应于Elasticsearch群集中的哪些节点。

      可以将节点配置为按集群名称加入特定的集群。默认情况下,每个节点都设置为加入一个名为elasticsearch的集群,这意味着如果启动网络中的许多节点,并假设它们可以互相发现,它们将自动形成并加入一个名为elasticsearch的集群。

       在单个群集中,您可以拥有任意数量的节点。而且,如果网络中没有其他Elasticsearch节点正在运行,则默认情况下启动单个节点会形成一个名为elasticsearch的新单节点群集。

Index

       索引是具有相似特征的文档的集合。 例如,您可以拥有客户数据的索引,产品目录的另一个索引以及订单数据的另一个索引。 索引由名称标识(必须全部为小写),该名称用于在对索引文档进行索引,搜索,更新和删除操作时引用索引。在单个群集中,可以根据需要定义多个索引。

Type

     在6.0.0中弃用。

     一种类型曾经是您的索引的逻辑类别/分区,以允许您在同一个索引中存储不同类型的文档,例如一种类型的用户,另一种类型的博客文章。 在索引中不再可能创建多个类型,并且在后面的版本中将删除整个类型的概念。 

Document

       文档是可被索引的基本信息单元。 例如,您可以为单个客户提供文档,为单个产品提供另一个文档,为单个订单提供另一个文档。 这个文档是用JSON(JavaScript Object Notation)表示的,它是一个无处不在的互联网数据交换格式。

       在索引/类型中,您可以根据需要存储多个文档。 请注意,尽管文档实际上驻留在索引中,但实际上文档必须被索引/分配给索引内的类型。

Shards & Replicas(碎片和副本)

       索引可能潜在地存储大量数据,这些数据可能会超出单个节点的硬件限制。 例如,占用1TB磁盘空间的十亿份文档的单个索引可能不适合单个节点的磁盘,或者可能太慢而无法单独为来自单个节点的搜索请求提供服务。

       为了解决这个问题,Elasticsearch提供了将索引细分成多个碎片的能力。 当你创建一个索引时,你可以简单地定义你想要的碎片数量。 每个碎片本身都是一个功能齐全且独立的“索引”,可以在集群中的任何节点上进行托管。

       分拆是重要的两个主要原因:

它允许您水平分割/缩放您的内容量
它允许您跨越分片(可能在多个节点上)分发和并行化操作,从而提高性能/吞吐量

       分片如何分布的机制以及文档如何聚合回搜索请求完全由Elasticsearch管理,对用户来说是透明的。

       在任何时候都可能出现故障的网络/云环境中,非常有用并强烈建议有一个故障切换机制,以防碎片/节点以某种方式脱机或因任何原因而消失。 为此,Elasticsearch允许您将索引分片的一个或多个副本分成所谓的副本分片或副本。

复制很重要,主要有两个原因:

它在碎片/节点失败的情况下提供高可用性。 由于这个原因,重要的是要注意副本分片永远不会被分配在与从中复制的原始/主分片相同的节点上。
它允许您扩展您的搜索量/吞吐量,因为搜索可以在所有副本上并行执行。

      总而言之,每个索引可以分成多个碎片。 索引也可以被复制为零(意味着没有复制品)或更多次。 一旦被复制,每个索引将具有主要碎片(从中复制的原始碎片)和副本碎片(主要碎片的副本)。 在创建索引时,可以为每个索引定义分片和副本的数量。 创建索引之后,您可以随时更改动态副本的数量,但不能随意更改碎片的数量。

      默认情况下,Elasticsearch中的每个索引都分配了5个主分片和1个副本,这意味着如果您的集群中至少有两个节点,则索引将包含5个主分片和另外5个副本分片(1个完整副本) 每个索引10个碎片。

注:每个Elasticsearch分片是一个Lucene索引。 您可以在单个Lucene索引中拥有最大数量的文档。 从LUCENE-5843(https://issues.apache.org/jira/browse/LUCENE-5843)开始,限制是2,147,483,519(= Integer.MAX_VALUE - 128)文件。 可以使用_cat/shards (https://www.elastic.co/guide/en/elasticsearch/reference/6.0/cat-shards.html)API监视分片大小。   

博文来自:www.51niux.com

1.2 探索集群

The REST API:

      Elasticsearch提供了一个非常全面和强大的REST API,可以使用它来与群集进行交互。 可以用API完成的几件事情如下:

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

集群健康

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

     为了检查集群健康状况,我们将使用_cat API。 可以在Kibana的控制台中运行下面的命令,点击“VIEW IN CONSOLE”或点击下面的“COPY AS CURL”链接并粘贴到终端。

GET /_cat/health?v

  结果是:

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默认使用单播网络发现来查找同一台计算机上的其他节点,所以可能会意外启动计算机上的多个节点并使其 全部加入一个集群。 在这种情况下,您可能会在上述响应中看到多个节点。

      我们也可以得到我们集群中的节点列表,如下所示:

GET /_cat/nodes?v

结果是:

ip        heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1           10           5   5    4.46                        mdi      *      PB2SGZY

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

列出所有指标:

现在我们来看看我们的指数:

GET /_cat/indices?v

结果是:

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

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

创建一个索引:

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

PUT /customer?pretty
GET /_cat/indices?v

#第一个命令使用PUT动词创建名为“customer”的索引。 我们只是简单地追加到调用结束,告诉它漂亮地打印JSON响应(如果有的话)。结果是:

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默认为这个索引创建了一个副本。由于此刻我们只有一个节点正在运行,因此,在另一个节点加入集群的较晚时间点之前,尚无法分配一个副本(以获得高可用性)。 一旦该副本被分配到第二个节点上,该索引的健康状态将变成绿色。

索引和查询文档

现在让我们把东西放入我们的客户索引。 我们会将一个简单的客户文档编入客户索引,ID为1,如下所示:

PUT /customer/doc/1?pretty
{
  "name": "John Doe"
}

结果是:

{
  "_index" : "customer",
  "_type" : "doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

从上面我们可以看到客户索引里面成功创建了一个新的客户文档。 该文件也有一个我们在索引时间指定的内部ID。

请注意,Elasticsearch不需要您先指定文档,然后再明确地创建一个索引。 在前面的例子中,Elasticsearch将自动创建客户索引,如果事先不存在的话。现在我们来检索我们刚编入索引的那个文档:

GET /customer/doc/1?pretty

结果是:

{
  "_index" : "customer",
  "_type" : "doc",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : { "name": "John Doe" }
}

#没有什么比这里发现的字段,发现,我们发现一个文件与所要求的ID 1和另一个field, _source,它返回从上一步索引完整的JSON文档。

删除索引

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

DELETE /customer?pretty
GET /_cat/indices?v

结果是:

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

这意味着索引已经成功删除了,现在我们回到我们在集群中没有任何东西的地方。在我们继续之前,让我们再仔细看看迄今为止学到的一些API命令:

PUT /customer
PUT /customer/doc/1
{
  "name": "John Doe"
}
GET /customer/doc/1
DELETE /customer

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

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

#这种REST访问模式在所有的API命令中都非常普遍,如果你能简单地记住它,你将在掌握Elasticsearch方面有一个良好的开端。

1.3 修改数据

      Elasticsearch几乎实时提供数据操作和搜索功能。 默认情况下,从索引/更新/删除数据开始,直到搜索结果中显示的时间为止,您可以预期会有一秒的延迟(刷新间隔)。 这是与SQL等其他平台的重要区别,其中数据在交易完成后立即可用。

索引/替换文档

我们以前看过我们如何索引一个文档。 让我们再次回忆起那个命令:

PUT /customer/doc/1?pretty
{
  "name": "John Doe"
}

再次,上面将索引指定的文件到客户索引,ID为1.如果我们然后用不同的(或相同的)文件再次执行上述命令,Elasticsearch将取代(即重新索引) 现有的ID为1:

PUT /customer/doc/1?pretty
{
  "name": "Jane Doe"
}

以上将ID号为1的文档的名称从“John Doe”改为“Jane Doe”。 另一方面,如果我们使用不同的ID,则新文档将被索引,并且索引中已经存在的文档将保持不变。

PUT /customer/doc/2?pretty
{
  "name": "Jane Doe"
}

#以上索引ID为2的新文档。

索引时,ID部分是可选的。 如果未指定,Elasticsearch将生成一个随机ID,然后用它来索引文档。 Elasticsearch生成的实际ID(或者我们前面例子中明确指定的)会作为索引API调用的一部分返回。

下面这个例子展示了如何索引没有显式ID的文档:

POST /customer/doc?pretty
{
  "name": "Jane Doe"
}

#请注意,在上述情况下,我们使用POST动词而不是PUT,因为我们没有指定一个ID。

更新文档

      除了能够索引和替换文档之外,我们还可以更新文档。 请注意,虽然Elasticsearch实际上并没有在原地进行更新。 无论何时我们进行更新,Elasticsearch都会删除旧文档,然后索引一个新文档,一次性应用更新。

      此示例显示如何通过将名称字段更改为“Jane Doe”来更新以前的文档(ID为1):

POST /customer/doc/1/_update?pretty
{
  "doc": { "name": "Jane Doe" }
}

这个例子展示了如何通过改变名称字段为“Jane Doe”来更新我们以前的文档(ID为1),同时给它添加一个年龄字段:

POST /customer/doc/1/_update?pretty
{
  "doc": { "name": "Jane Doe", "age": 20 }
}

更新也可以通过使用简单的脚本来执行。 此示例使用脚本将年龄增加5:

POST /customer/doc/1/_update?pretty
{
  "script" : "ctx._source.age += 5"
}

#在上面的例子中,ctx._source引用了即将被更新的当前源文档。Elasticsearch提供了在给定查询条件(如SQL UPDATE-WHERE语句)的情况下更新多个文档的能力。 请参阅docs-by-query API(https://www.elastic.co/guide/en/elasticsearch/reference/6.0/docs-update-by-query.html)。

删除文档

删除文件相当简单。 此示例显示如何删除我们以前的客户,其ID为2:

DELETE /customer/doc/2?pretty

请参阅_delete_by_query API(https://www.elastic.co/guide/en/elasticsearch/reference/6.0/docs-delete-by-query.html)以删除与特定查询匹配的所有文档。 值得注意的是,删除整个索引而不是使用Delete By Query API删除所有文档会更有效率。

批处理

     除了能够索引,更新和删除单个文档外,Elasticsearch还提供了使用_bulk API批量执行上述任何操作的功能。 这个功能很重要,因为它提供了一个非常有效的机制,尽可能快地完成多个操作,尽可能少的网络往返。

     作为一个简单的例子,下面的调用在一个批量操作中索引两个文档(ID 1 - John Doe和ID 2 - Jane Doe):

POST /customer/doc/_bulk?pretty
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }

      本示例更新第一个文档(ID为1),然后在一个批量操作中删除第二个文档(ID为2):

POST /customer/doc/_bulk?pretty
{"update":{"_id":"1"}}
{"doc": { "name": "John Doe becomes Jane Doe" } }
{"delete":{"_id":"2"}}

#请注意,对于删除操作,之后没有对应的源文档,因为删除操作只需要删除文档的标识。

批量API不会因其中一个操作失败而失败。 如果一个动作因任何原因失败,它将继续处理其余的动作。 批量API返回时,它将为每个操作提供一个状态(与发送的顺序相同),以便您可以检查特定操作是否失败。

博文来自:www.51niux.com

1.4 探索你的数据

现在我们已经看到了一些基本知识,让我们尝试一下更加真实的数据集。 我准备了一个关于客户银行账户信息的虚构的JSON文档样本。 每个文档都有以下模式:

{
    "account_number": 0,
    "balance": 16623,
    "firstname": "Bradshaw",
    "lastname": "Mckenzie",
    "age": 29,
    "gender": "F",
    "address": "244 Columbus Place",
    "employer": "Euron",
    "email": "bradshawmckenzie@euron.com",
    "city": "Hobucken",
    "state": "CO"
}

#这些数据是使用www.json-generator.com/生成的,所以请忽略数据的实际值和语义,因为这些数据都是随机生成的。

加载示例数据集,可以从这里下载示例数据集(accounts.json)。 将其解压到我们当前的目录,并将其加载到我们的集群中,如下所示:

curl -H "Content-Type: application/json" -XPOST 'localhost:9200/bank/account/_bulk?pretty&refresh' --data-binary "@accounts.json"
curl 'localhost:9200/_cat/indices?v'

下面是结果:

health status index uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   bank  l7sSYV2cQXmu6_4rJWVIww   5   1       1000            0    128.6kb        128.6kb

#这意味着我们只是成功将1000个文件批量索引到银行索引(在帐户类型下)。

搜索API

      有两种运行搜索的基本方法:一种是通过REST请求URI发送搜索参数,另一种是通过REST请求主体发送搜索参数。 请求主体方法允许您更具表现力,并以更易读的JSON格式定义您的搜索。 我们将尝试请求URI方法的一个例子,但在本教程的剩余部分中,我们将专门使用请求主体方法。

      用于搜索的REST API可从_search端点访问。 本示例返回银行索引中的所有文档:

GET /bank/_search?q=*&sort=account_number:asc&pretty

#我们首先解析搜索调用。 我们在银行索引中搜索(_search endpoint),并且q = *参数指示Elasticsearch匹配索引中的所有文档。 sort = account_number:asc参数指示使用每个文档的account_number字段按升序对结果进行排序。 漂亮的参数再次告诉Elasticsearch返回漂亮的JSON结果。下面是部分响应结果:

{
  "took" : 63,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : null,
    "hits" : [ {
      "_index" : "bank",
      "_type" : "account",
      "_id" : "0",
      "sort": [0],
      "_score" : null,
      "_source" : {"account_number":0,"balance":16623,"firstname":"Bradshaw","lastname":"Mckenzie","age":29,"gender":"F","address":"244 Columbus Place","employer":"Euron","email":"bradshawmckenzie@euron.com","city":"Hobucken","state":"CO"}
    }, {
      "_index" : "bank",
      "_type" : "account",
      "_id" : "1",
      "sort": [1],
      "_score" : null,
      "_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}
    }, ...
    ]
  }
}

至于回应,我们看到以下部分:

took    #Elasticsearch花费了几毫秒的时间来执行搜索
timed_out #告诉我们搜索是否超时
_shards   #告诉我们搜索了多少碎片,以及搜索碎片成功/失败的次数
hits  #搜索结果
hits.total #符合我们搜索条件的文档总数
hits.hits   #实际的搜索结果数组(默认为前10个文档)
hits.sort   #结果排序键(按分数排序时缺失)
hits._score和max_score #现在忽略这些字段

以上是使用替代请求主体方法的上述相同的确切搜索:

GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ]
}

#这里的区别在于,不是在URI中传递q = *,而是将JSON风格的查询请求主体发布到_search API。

#重要的是要明白,一旦你得到你的搜索结果,Elasticsearch完成与请求,并没有维护任何种类的服务器端资源或打开游标到你的结果。 这与许多其他平台(如SQL)形成鲜明对比,其中最初可能会首先获得查询结果的部分子集,然后如果要获取(或翻阅)其余部分,则必须连续返回到服务器的结果使用某种有状态的服务器端游标。

介绍查询语句

     Elasticsearch提供了一种JSON风格的域特定语言,可以用来执行查询。 这被称为查询DSL。 查询语言非常全面,可以乍一看吓人,但实际学习的最好方法是从几个基本的例子开始。回到我们的最后一个例子,我们执行了这个查询:

GET /bank/_search
{
  "query": { "match_all": {} }
}

#解析上述内容,查询部分告诉我们我们的查询定义是什么,match_all部分只是我们想要运行的查询的类型。 match_all查询只是搜索指定索引中的所有文档。

     除查询参数外,我们还可以传递其他参数来影响搜索结果。 在上面的例子中我们通过sort,在这里我们传递的size:

GET /bank/_search
{
  "query": { "match_all": {} },
  "size": 1   #请注意,如果未指定大小,则默认为10。
}

下面这个例子做一个match_all并返回文档11到20:

GET /bank/_search
{
  "query": { "match_all": {} },
  "from": 10,
  "size": 10
}

#from参数(从0开始)指定从哪个文档索引开始,size参数指定从from参数开始返回多少个文档。 在实现分页搜索结果时,此功能非常有用。 请注意,如果from不指定,则默认为0。

下面这个例子做了一个match_all,以降序的方式对结果进行排序,并返回前10(默认大小)文档。

GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": { "balance": { "order": "desc" } }
}

执行搜索

      现在我们已经看到了一些基本的搜索参数,让我们再深入查询DSL。 我们先来看看返回的文档字段。 默认情况下,完整的JSON文档作为所有搜索的一部分返回。 这被称为源(搜索匹配中的_source字段)。 如果我们不希望整个源文档返回,我们有能力只需要返回源内的几个字段。

      此示例显示如何从搜索中返回两个字段account_number和balance(在_source之内):

GET /bank/_search
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}

#请注意,上面的例子简单地减少了_source字段。 它仍然只会返回一个名为_source的字段,但在其中只包含字段account_number和balance。

#现在我们来看看查询部分。 以前,我们已经看过如何使用match_all查询来匹配所有文档。 现在我们来介绍一个称为匹配查询的新查询,它可以被看作是一个基本的搜索查询(即针对特定字段或字段集合进行的搜索)。此示例返回编号为20的帐户:

GET /bank/_search
{
  "query": { "match": { "account_number": 20 } }
}

此示例返回地址中包含术语“mill”的所有帐户:

GET /bank/_search
{
  "query": { "match": { "address": "mill" } }
}

此示例返回地址中包含“mill”或“lane”的所有帐户:

GET /bank/_search
{
  "query": { "match": { "address": "mill lane" } }
}

这个例子是match(match_短语)的变体,它返回包含在地址中的“mill lane”的所有帐户:

GET /bank/_search
{
  "query": { "match_phrase": { "address": "mill lane" } }
}

bool查询允许我们使用布尔逻辑将更小的查询组合成更大的查询。此示例组成两个匹配查询,并返回地址中包含“mill”和“lane”的所有帐户:

GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

#在上面的例子中,bool must子句指定了一个文档被认为是匹配的所有查询。

#相反,这个例子组成两个匹配查询,并返回地址中包含“mill”或“lane”的所有帐户:

GET /bank/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

#在上面的例子中,bool should子句指定了一个查询列表,其中任何一个查询都必须是真的才能被认为是匹配的文档。

本示例组成两个匹配查询,并返回地址中既不包含“mill”也不包含“lane”的所有帐户:

GET /bank/_search
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

#在上面的例子中,bool must_not子句指定了一个查询列表,其中任何一个查询都不可以被认为是匹配的。

可以在一个bool查询中同时结合must,should和must_not子句。 此外,可以在任何这些bool子句中编写布尔查询来模拟任何复杂的多级布尔逻辑。这个例子返回所有40岁但不住ID(aho)的人的账号:

GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}

执行过滤器

      在前一节中,我们跳过了一个小细节,称为文档score(搜索结果中的_score字段)。分数是一个数字值,它是对文档与我们指定的搜索查询匹配程度的相对度量。分数越高,文档越相关,分数越低,文档的相关性越小。

      但是查询并不总是需要产生分数,特别是当它们仅用于“过滤”文档集时。弹性搜索可以检测到这些情况,并自动优化查询执行,而不是计算无用的分数。

      我们在前一节介绍的bool查询还支持过滤子句,它允许使用查询来限制将被其他子句匹配的文档,而不改变计算得分的方式。 作为一个例子,我们来介绍一下范围查询,它允许我们通过一系列值来过滤文档。 这通常用于数字或日期过滤。

      本示例使用bool查询返回余额在20000和30000之间的所有帐户。 换句话说,我们要查找大于或等于20000且小于等于30000的帐户。

GET /bank/_search
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}

#解析上述内容,bool查询包含一个match_all查询(查询部分)和一个范围查询(过滤器部分)。 我们可以将其他查询替换为查询和过滤器部分。 在上述情况中,范围查询是非常有意义的,因为落入该范围的文档全部匹配“平等”,即没有文档比另一个更相关。

除了match_all,match,bool和range查询之外,还有很多其他查询类型可用,我们不会在这里介绍它们。 由于我们已经对其工作原理有了一个基本的了解,所以将这些知识应用于其他查询类型的学习和实验并不难。

执行聚合

      聚合提供了从数据中分组和提取统计数据的能力。考虑聚合的最简单方法是将其大致等同于SQL GROUP BY和SQL聚合函数。 在Elasticsearch中,您可以执行搜索并返回匹配,同时还可以在一个响应中返回与匹配不同的聚合结果。 这是非常强大和高效的,因为可以运行查询和多个聚合,并一次性获得两个(或两个)操作的结果,从而避免使用简洁和简化的API进行网络往返。

     首先,本示例按状态对所有帐户进行分组,然后返回按降序(也是默认值)排序的前10个(默认)状态:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}

在SQL中,上面的聚合在概念上类似于:

SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC

下面是部分显示:

{
  "took": 29,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped" : 0,
    "failed": 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "group_by_state" : {
      "doc_count_error_upper_bound": 20,
      "sum_other_doc_count": 770,
      "buckets" : [ {
        "key" : "ID",
        "doc_count" : 27
      }, {
        "key" : "TX",
        "doc_count" : 27
      }, {

请注意,我们将size = 0设置为不显示搜索命中,因为我们只想看到响应中的聚合结果。在前面的汇总基础上,本示例按状态计算平均账户余额(再次仅按前几位按降序排列的状态):

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

注意我们如何在group_by_state聚合内嵌套average_balance聚合。这是所有聚合的常见模式。您可以任意地在聚合中嵌套聚合,以从数据中提取所需的pi表决摘要。在前面的集合上建立,现在让我们按降序排列平均余额:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword",
        "order": {
          "average_balance": "desc"
        }
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

下面这个例子演示了我们如何按年龄段(20-29岁,30-39岁和40-49岁)进行分组,然后按性别进行分组,然后最终得到每个性别的年龄段平均账户余额:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 50
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "terms": {
            "field": "gender.keyword"
          },
          "aggs": {
            "average_balance": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}

#更多的聚合功能:https://www.elastic.co/guide/en/elasticsearch/reference/6.0/search-aggregations.html

二、设置Elasticsearch

2.1 Elasticsearch配置

安全配置

      有些设置是敏感的,依靠文件系统权限来保护它们的值是不够的。 对于这个用例,Elasticsearch提供了一个可以用密码保护的keystore,以及一个用来管理keystore中的设置的elasticsearch-keystore工具。

      这里的所有命令都应该以运行Elasticsearch的用户身份运行。只有一些设置被设计为从密钥库中读取。 查看每个设置的文档,看它是否作为密钥库的一部分受支持。所有对密钥库的修改只有在重新启动Elasticsearch之后才会生效。

创建keystore:

bin/elasticsearch-keystore create   #elasticsearch.keystore文件将与elasticsearch.yml一起创建。

列出密钥库中的设置:

bin/elasticsearch-keystore list

添加字符串设置:

bin/elasticsearch-keystore add the.setting.name.to.set   #可以使用add命令添加敏感的字符串设置

该工具将提示输入设置的值。 要通过stdin传递值,请使用--stdin标志:

cat /file/containing/setting/value | bin/elasticsearch-keystore add --stdin the.setting.name.to.set

删除设置:

bin/elasticsearch-keystore remove the.setting.name.to.remove   #要从密钥库中删除设置,请使用remove命令

日志设置

       Elasticsearch使用Log4j 2进行日志记录。 Log4j 2可以使用log4j2.properties文件进行配置。 Elasticsearch公开了三个属性$ ${sys:es.logs.base_path}, ${sys:es.logs.cluster_name}, and ${sys:es.logs.node_name}(如果节点名是通过node.name显式设置的 )可以在配置文件中引用来确定日志文件的位置。 属性$ {sys:es.logs.base_path}将解析为日志目录,$ {sys:es.logs.cluster_name}将解析为集群名称(在默认配置中用作日志文件名的前缀),以及 $ {sys:es.logs.node_name}将解析为节点名称(如果节点名称已明确设置)。

       例如,如果您的日志目录(path.logs)是/var/log/elasticsearch,并且您的集群命名为production,则$ {sys:es.logs.base_path}将解为/var/log/elasticsearch和${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}.log将解析为/var/log/elasticsearch/production.log。

appender.rolling.type = RollingFile 
#配置RollingFile appender
appender.rolling.name = rolling
appender.rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}.log
#日志位置 
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%.-10000m%n
appender.rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}-%i.log.gz
#将日志滚动到/var/log/elasticsearch/production-yyyy-MM-dd-i.log,每次滚动日志都会被压缩,i会增加。 
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy 
#使用基于时间的滚动策略
appender.rolling.policies.time.interval = 1 
#每天滚动日志
appender.rolling.policies.time.modulate = true 
#在日边界上对齐滚动(而不是每24小时滚动一次)
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy 
#使用基于size的滚动策略
appender.rolling.policies.size.size = 256MB 
#在256 MB之后滚动日志
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.fileIndex = nomax
appender.rolling.strategy.action.type = Delete 
#滚动日志时使用删除操作
appender.rolling.strategy.action.basepath = ${sys:es.logs.base_path}
appender.rolling.strategy.action.condition.type = IfFileName 
#只删除匹配文件模式的日志
appender.rolling.strategy.action.condition.glob = ${sys:es.logs.cluster_name}-* 
#模式是只删除主日志
appender.rolling.strategy.action.condition.nested_condition.type = IfAccumulatedFileSize 
#只有当我们累积了太多的压缩日志时才删除
appender.rolling.strategy.action.condition.nested_condition.exceeds = 2GB
#压缩日志上的大小条件是2 GB

#注:Log4j的配置分析会被任何无关的空白混淆; 如果您在本页面上复制并粘贴任何Log4j设置,或者一般输入任何Log4j配置,请务必修剪任何前导和尾随空格。

#请注意,您可以用appender.rolling.filePattern中的.zip替换.gz以压缩使用zip格式的滚动日志。 如果删除.gz扩展名,则日志在滚动时不会被压缩。

如果要在指定的时间段内保留日志文件,则可以使用带有删除操作的滚动策略:

appender.rolling.strategy.type = DefaultRolloverStrategy 
#配置DefaultRolloverStrategy
appender.rolling.strategy.action.type = Delete 
#配置用于处理rollover的删除操作
appender.rolling.strategy.action.basepath = ${sys:es.logs.base_path} 
#Elasticsearch日志的基本路径
appender.rolling.strategy.action.condition.type = IfFileName 
#在处理滚动时应用的条件
appender.rolling.strategy.action.condition.glob = ${sys:es.logs.cluster_name}-* 
#从匹配glob ${sys:es.logs.cluster_name}-*; 的基本路径中删除文件 - *; 这是日志文件滚动到的glob; 只需要删除滚动的Elasticsearch日志,而不是删除弃用和慢日志
appender.rolling.strategy.action.condition.nested_condition.type = IfLastModified 
#嵌套的条件适用于与glob匹配的文件
appender.rolling.strategy.action.condition.nested_condition.age = 7D 
#保留七天的日志

       只要将多个配置文件命名为log4j2.properties并将Elasticsearch config目录作为祖先,就可以加载多个配置文件(在这种情况下,它们将被合并) 这对于公开额外记录器的插件是有用的。 记录器部分包含java包及其相应的日志级别。 appender部分包含日志的目的地。 有关如何自定义日志记录以及所有支持的appender的详细信息可以在Log4j文档中找到(http://logging.apache.org/log4j/2.x/manual/configuration.html)。

配置日志级别:

有四种方法来配置日志记录级别,每种方式都适合使用。

1. 通过命令行:-E <日志层次结构的名称> = <level>(例如,-E logger.org.elasticsearch.transport = trace)。 当您临时调试单个节点上的问题(例如启动问题或开发期间)时,这是最合适的。
2. 通过elasticsearch.yml:<记录层次结构的名称>:<level>(例如,logger.org.elasticsearch.transport:trace)。 当你临时调试一个问题,但不是通过命令行(例如,通过服务)启动Elasticsearch,或者你想要一个更加永久的基础上调整日志级别时,这是最合适的。

3. 通过集群设置:

PUT /_cluster/settings
{
  "transient": {
    "<name of logging hierarchy>": "<level>"
  }
}
#例如:
PUT /_cluster/settings
{
  "transient": {
    "logger.org.elasticsearch.transport": "trace"
  }
}
#当您需要动态调整正在运行的群集上的日志记录级别时,这是最合适的。

4. 通过log4j2.properties:

logger.<unique_identifier>.name = <name of logging hierarchy>
logger.<unique_identifier>.level = <level>
#例如
logger.transport.name = org.elasticsearch.transport
logger.transport.level = trace

#当您需要对记录器进行细粒度的控制时(例如,要将记录器发送到另一个文件或以不同的方式管理记录器,这是非常罕见的用例)。

博文来自:www.51niux.com

2.2 重要的Elasticsearch配置

虽然Elasticsearch只需要很少的配置,但有一些需要手动配置的设置,在投入生产之前一定要进行配置。

path.data and path.logs

       如果使用.zip或.tar.gz安装,则数据和日志目录是$ ES_HOME的子文件夹。 如果这些重要文件夹保留在其默认位置,则在将Elasticsearch升级到新版本时,这些文件夹被删除的风险很高。在生产使用中,几乎可以肯定地要更改数据和日志文件夹的位置:

path:
  logs: /var/log/elasticsearch
  data: /var/data/elasticsearch

path.data设置可以设置为多个路径,在这种情况下,所有路径将用于存储数据(尽管属于单个分片的文件将全部存储在相同的数据路径中):

path:
  data:
    - /mnt/elasticsearch_1
    - /mnt/elasticsearch_2
    - /mnt/elasticsearch_3

cluster.name

      节点只能在与集群中的所有其他节点共享cluster.name时才能加入集群。 默认名称是elasticsearch,但是应该将其更改为描述集群用途的适当名称。

cluster.name: logging-prod

#确保不要在不同的环境中重复使用相同的群集名称,否则可能会导致节点加入错误的群集。

node.name

      默认情况下,Elasticsearch将随机生成的uuid的第一个字符作为节点ID。 请注意,节点ID是持久的,并且在节点重新启动时不会更改,因此默认节点名称也不会更改。值得配置一个更有意义的名字,这个名字在重启节点后也会有持久的优势:

node.name: prod-data-2

node.name也可以设置为服务器的HOSTNAME,如下所示:

node.name: ${HOSTNAME}

bootstrap.memory_lock 

           对于您的节点的健康状况来说,没有任何一个JVM被换出到磁盘上,这一点非常重要。 一种实现方法是将bootstrap.memory_lock设置为true。

          要使此设置生效,需要首先配置其他系统设置。 有关如何正确设置内存锁定的更多详细信息,请参阅启用bootstrap.memory_lock(https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration-memory.html#mlockall)。

network.host

       默认情况下,Elasticsearch只绑定到回送地址 - 例如 127.0.0.1和[:: 1]。 这足以在服务器上运行单个开发节点。实际上,可以从一个节点上的同一$ES_HOME位置启动多个节点。 这可以用于测试Elasticsearch形成群集的能力,但它不是推荐用于生产的配置。

      为了与其他服务器上的节点进行通信并形成群集,您的节点将需要绑定到非环回地址。 虽然有很多的网络设置,通常你只需要配置network.host:

network.host: 192.168.1.10

#network.host设置还可以理解一些特殊的值,如_local_,_site_,_global_和修饰符如:ip4和:ip6,其详细信息可以在network.hostedit的特殊值中找到(https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html#network-interface-values)。

#只要您为network.host提供自定义设置,Elasticsearch就会假定您正在从开发模式转移到生产模式,并将大量系统启动检查从警告升级到异常。 

discovery.zen.ping.unicast.hosts

       没有任何网络配置,Elasticsearch将绑定到可用的环回地址,并将扫描端口9300到9305,尝试连接到运行在同一台服务器上的其他节点。 这提供了自动集群体验,而无需进行任何配置。

      当需要与其他服务器上的节点组成群集时,您必须提供群集中其他节点的种子列表,这些节点可能是活的和可联系的。 这可以指定如下:

discovery.zen.ping.unicast.hosts:
   - 192.168.1.10:9300
   - 192.168.1.11   #如果未指定,端口将默认为transport.profiles.default.port,并回退到transport.tcp.port。
   - seeds.mydomain.com   #解析为多个IP地址的主机名将尝试所有解析的地址。

discovery.zen.minimum_master_nodes

      为防止数据丢失,配置discovery.zen.minimum_master_nodes设置至关重要,以便每个符合主节点的节点都知道为了形成群集而必须可见的主节点的最小数量。

     如果没有这个设置,那么遭受网络故障的集群就有可能将集群分成两个独立的集群 - 分裂的大脑 - 这将导致数据丢失。 在使用minimum_master_nodesedit避免分裂脑中提供了更详细的解释(https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#split-brain)。

    为了避免脑裂,应将此设置设置为符合主数据节点的法定人数:

(master_eligible_nodes / 2) + 1
#换句话说,如果有三个主节点,那么最小主节点应该设置为(3/2)+ 1或2:
discovery.zen.minimum_master_nodes: 2

2.3 重要的系统配置

       理想情况下,Elasticsearch应该在服务器上独立运行,并使用所有可用的资源。 为此,您需要配置您的操作系统,以允许运行Elasticsearch的用户访问比默认允许的资源更多的资源。在投入生产之前,必须解决以下设置:

配置系统设置

#这个就不记录了搭建的时候已经解决了:https://www.elastic.co/guide/en/elasticsearch/reference/current/setting-system-settings.html

通过jvm.options设置JVM堆大小

#官网链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/heap-size.html

禁用swap分区

官网链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration-memory.html

文件描述符

链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/file-descriptors.html

虚拟内存

链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html

线程数:

链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/max-number-of-threads.html

DNS缓存设置:

链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/networkaddress-cache-ttl.html

2.4 引导程序检查

官网链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/bootstrap-checks.html

堆大小检查
文件描述符检查
内存锁定检查
最大线程数
虚拟内存最大尺寸检查
最大文件尺寸检查
最大地图计数检查
客户机JVM检查
使用串行收集器检查
系统调用过滤器检查
OnError和OnOutOfMemoryError检查
早期访问检查
G1GC检查

Stopping Elasticsearch:

通过指定启动时写入PID文件的位置(-p <path>):

$ ./bin/elasticsearch -p /tmp/elasticsearch-pid -d
$ cat /tmp/elasticsearch-pid && echo
15516
$ kill -SIGTERM 15516

停止致命的错误编辑

       在Elasticsearch虚拟机的生命周期中,可能会出现某些致使虚拟机处于可疑状态的致命错误。 这种致命错误包括内存不足错误,虚拟机中的内部错误以及严重的I/O错误。

      当Elasticsearch检测到虚拟机遇到这样的致命错误时,Elasticsearch将尝试记录错误,然后暂停虚拟机。 当Elasticsearch发起这样的关闭时,它不会像上面描述的那样经过有序的关闭。 Elasticsearch进程也将返回一个特殊的状态码,指明错误的性质。

JVM internal error    #128    
Out of memory error    #127    
Stack overflow error    #126    
Unknown virtual machine error    #125    
Serious I/O error    #124    
Unknown fatal error    #1

三、专业术语

analysis:

分析是将全文转换为text的过程。根据使用哪个分析器,这些短语:FOO BAR,Foo-Bar,foo,bar可能全部以foo和bar的形式出现。 这些text是实际存储在索引中的。 FoO:bAR的全文查询(不是词条查询)也将被分析到条件foo,bar,并且将因此匹配存储在索引中的条款。 这是分析过程(在索引时间和搜索时间),允许Elasticsearch执行全文查询。 另请参阅文本和术语。

cluster:

群集由共享相同群集名称的一个或多个节点组成。 每个集群都有一个由集群自动选择的主节点,如果当前主节点发生故障,则可以替换它们。

document:

文档是存储在Elasticsearch中的JSON文档。 它就像一个关系数据库中的表格中的一行。 每个文档都存储在一个索引中,并有一个类型和一个id。 文档是一个JSON对象(在其他语言中也称为散列/散列表/关联数组),其中包含零个或多个字段或键/值对。 索引的原始JSON文档将存储在_source字段中,在获取或搜索文档时默认返回该字段。

id:

文档的标识标识文档。 文档的索引/标识必须是唯一的。 如果没有提供ID,则会自动生成。

field:

文档包含字段或键值对的列表。 该值可以是简单(标量)值(例如字符串,整数,日期),也可以是嵌套结构(如数组或对象)。 字段与关系数据库中的表中的列相似。 每个字段的映射都有一个字段类型(不要与文档类型混淆),它指示可以存储在该字段中的数据的类型,例如整数,字符串,对象。 映射还允许您定义(除其他外)如何分析字段的值。

index:

索引就像关系数据库中的表。 它有一个映射,其中包含一个类型,其中包含索引中的字段。 索引是逻辑名称空间,映射到一个或多个主分片,可以有零个或多个副本分片。

mapping:

映射就像关系数据库中的模式定义。 每个索引都有一个映射,它定义了一个类型,还有一些索引范围的设置。 映射既可以明确定义,也可以在文档编制索引时自动生成。

node:

一个节点是Elasticsearch的一个运行实例,属于一个集群。 为了测试目的,可以在单个服务器上启动多个节点,但通常每个服务器应该有一个节点。 启动时,节点将使用单播来发现具有相同群集名称的现有群集,并尝试加入该群集。

primary shard:

每个文档都存储在一个主分片中。 索引文档时,首先在主分片上索引,然后在主分片的所有副本上索引。 默认情况下,索引有5个主分片。 您可以指定更少或更多的主分片来缩放索引可以处理的文档数量。 创建索引后,您无法更改索引中的主要碎片数量。 

replica shard:

每个主分片可以有零个或多个副本。 副本是主碎片的副本,有两个目的:

增加故障转移:如果主节点失败,可以将副本分片升级为主分片
提高性能:get和搜索请求可以由主或副本碎片处理。 默认情况下,每个主分片都有一个副本,但副本的数量可以在现有索引上动态更改。 副本分片将永远不会在与其主分片相同的节点上启动。

routing:

索引文档时,它将存储在单个主分片上。 该碎片是通过散列路由值来选择的。 默认情况下,路由值是从文档ID派生的,或者如果文档具有指定的父文档,则从父文档的ID派生(以确保子文档和父文档存储在同一个分片上)。 此值可以通过在索引时指定路由值或映射中的路由字段来覆盖。

shard:

碎片是一个单独的Lucene实例。 它是Elasticsearch自动管理的低级“工作”单元。 索引是指向主副本碎片的逻辑名称空间。 除了定义索引应该具有的主分片和副本分片的数量之外,您不需要直接引用分片。 相反,你的代码只能处理一个索引。 Elasticsearch在集群中的所有节点之间分配碎片,在节点故障或增加新节点的情况下,可以自动将碎片从一个节点移动到另一个节点。

source field:

默认情况下,您索引的JSON文档将存储在_source字段中,并将由所有获取和搜索请求返回。 这允许您直接从搜索结果中访问原始对象,而不需要第二步从ID中检索对象。

term:

一个术语是在Elasticsearch中索引的确切值。 术语foo,Foo,FOO不等价。 可以使用术语查询来搜索术语(即精确值)

text:

文本(或全文)是普通的非结构化文本,如本段落。 默认情况下,文本将被分析成条目,这是实际存储在索引中的内容。 文本字段需要在索引时进行分析以便作为全文进行搜索,并且必须在搜索时分析全文查询中的关键字以产生(和搜索)在索引时间生成的相同的术语。 另见术语和分析。

type:

用于表示文档类型的类型,例如 电子邮件,用户或推特。 类型已被弃用,正在被删除。 

作者:忙碌的柴少 分类:ELK 浏览:4437 评论:0
留言列表
发表评论
来宾的头像