ElasticSearch简单应用

创建一个索引

创建一个名为customer的索引,然后再次列出所有索引:

PUT /customer?pretty

GET /_cat/indices?v

第一条命令使用PUT动词创建名为“ customer”的索引。我们只需pretty在调用末尾追加内容,以告诉它漂亮地打印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        

                                 

第二个命令的结果告诉我们,我们现在有1个名为customer的索引,它具有5个主分片和1个副本(默认值),并且其中包含0个文档。现在customer索引带有标记为黄色的健康状况。默认情况下,Elasticsearch为此索引创建了一个副本。由于目前我们只有一个节点在运行,因此直到另一节点加入群集的稍后时间,才能分配一个副本(以实现高可用性)。一旦将该副本分配到第二个节点,此索引的运行状况将变为绿色。

 

 

索引和查询文件

现在在customer索引中添加一些内容。我们将一个简单的客户文档编入客户索引,其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为1,这是我们在索引时指定的。重要的是要注意,Elasticsearch不需要先显式创建索引,然后才能将文档建立索引。

现在,让我们检索刚刚索引的文档:

GET /customer/_doc/1?pretty

响应:

{

  "_index" : "customer",

  "_type" : "_doc",

  "_id" : "1",

  "_version" : 1,

  "found" : true,

  "_source" : { "name": "John Doe" }

}

found字段为true,我们找到了具有请求的ID 1的文档,另一个字段_source,该字段返回上一步中索引的完整JSON文档。

 

删除索引

现在,删除刚刚创建的索引:

DELETE /customer?pretty

 

 

修改数据

Elasticsearch提供近乎实时的数据处理和搜索功能。默认情况下,从索引/更新/删除数据到显示在搜索结果中的时间可能会有一秒钟的延迟(刷新间隔)。这是与其他平台(例如SQL)的重要区别,在其他平台上,数据在事务完成后可用。

 

索引/更新文件

前面我们已经看到了如何为单个文档建立索引。让我们再次调用该命令:


PUT /customer/_doc/1?pretty

{

  "name": "John Doe"

}

同样,上面的代码会将指定文档的ID索引到客户索引中,其ID为1。如果我们再对另一个(或相同)文档执行上述命令,Elasticsearch将更新(即重新索引)一个新文档。现有的ID为1的1:


PUT /customer/_doc/1?pretty

{

  "name": "John Doe"

}

上面将ID为1的文档的名称从“ John Doe”更改为“ Jane Doe”。另一方面,如果我们使用其他ID,则将为新文档建立索引,而索引中已经存在的现有文档保持不变。

PUT /customer/_doc/2?pretty

{

  "name": "Jane Doe"

}

上面的代码索引了ID为2的新文档。

 

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

 

此示例显示如何在没有显式ID的情况下索引文档:

POST /customer/_doc?pretty

{

  "name": "Jane Doe"

}

在上述情况下,由于未指定ID ,因此我们使用动词POST代替PUT。

 

更新文件

除了能够索引和替换文档之外,我们还可以更新文档。注意,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指的是当前源文档。

 

 

删除文件

删除文档非常简单。此示例显示了如何删除ID为2的先前客户:

DELETE /customer/_doc/2?pretty

注意,删除整个索引比使用Delete By Query API删除所有文档要有效得多。

 

 

批量处理

除了能够索引,更新和删除单个文档外,Elasticsearch还提供了使用_bulkAPI批量执行上述任何操作的功能。此功能可以以尽可能少的网络往返来尽可能快地执行多项操作。

作为快速示例,以下调用在一个批量操作中为两个文档(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"}}

注意,对于删除操作,在其后没有相应的源文档,因为删除仅需要删除文档的ID。

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

 

搜索API

现在让我们从一些简单的搜索开始。有运行检索两种基本方式:一种是通过发送搜索参数REST请求URI和其他通过发送他们REST请求主体。request body方法使用更具可读性的JSON格式定义搜索。可从_search端点访问用于搜索的REST API 。

本示例返回bank索引中的所有单据:

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

我们在bank索引中搜索,并且该q=*参数指示Elasticsearch匹配索引中的所有文档。该sort=account_number:asc参数指示使用account_number每个文档的字段以升序对结果进行排序。pretty同样,该参数只是告诉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" : "_doc",

      "_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" : "_doc",

      "_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字段是一个数值,是文档与我们指定的搜索查询匹配程度的相对度量。分数越高,文档越相关,分数越低,文档越不相关。但是查询并不总是需要产生分数,尤其是当查询仅用于“过滤”文档集时。Elasticsearch会检测到这些情况并自动优化查询执行,以免计算出无用的分数。

这是上面使用替代请求正文方法的完全相同的搜索:

GET /bank/_search

{

  "query": { "match_all": {} },

  "sort": [

    { "account_number": "asc" }

  ]

}

此处的区别在于,我们没有传递q=*URI,而是使用_search API提供的JSON样式的查询请求主体

重要的是要了解,一旦返回搜索结果,Elasticsearch将完全完成请求,并且不会维护任何类型的服务器端资源或在结果中打开游标。

 

 

查询语言

Elasticsearch提供了一种JSON-style domain-specific语言,您可以用来执行查询。这称为查询DSL。查询语言非常全面。

回到上一个示例,我们执行了以下查询:

GET /bank/_search

{

  "query": { "match_all": {} }

}

该query部分告诉我们查询定义是什么,而该match_all部分只是我们要运行的查询的类型。该match_all查询是搜索指定索引中的所有文档。

除了query参数外,我们还可以传递其他参数来影响搜索结果。在上面部分的示例中,我们传入 sort,在这里我们传入size:

GET /bank/_search

{

  "query": { "match_all": {} },

  "size": 1

}

 

注意,如果size未指定,则默认为10。

本示例执行match_all并返回文档10至19:

GET /bank/_search

{

  "query": { "match_all": {} },

  "from": 10,

  "size": 10

}

该from参数(从0开始)指定从和启动哪些文档索引size参数指定如何许多文件,返回从参数开始的。实现分页搜索结果时,此功能很有用。请注意,如果from未指定,则默认为0。

本示例执行a match_all并按帐户余额的降序对结果进行排序,并返回前10个(默认大小)的文档。

GET /bank/_search

{

  "query": { "match_all": {} },

  "sort": { "balance": { "order": "desc" } }

}

 

搜索

默认情况下,完整的JSON文档将作为所有搜索的一部分返回。这称为源文档(_source搜索结果中的字段)。如果我们不希望返回整个源文档,则可以从源中仅请求返回几个字段。

此示例说明了如何从搜索中返回两个字段account_number和balance(在中_source):

GET /bank/_search

{

  "query": { "match_all": {} },

  "_source": ["account_number", "balance"]

}

请注意,上面的示例只是简化了该_source字段。它仍然只会返回一个名为_source的字段,但只有account_number和balance也包括在内。在概念上与SQL SELECT FROM字段列表有些相似。

 

matchquery查询,可以将其视为基本的字段搜索查询(即针对特定字段或一组字段进行的搜索)。

本示例返回编号为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_phrase)的变体,它返回地址中包含短语“mill lane”的所有帐户,“mill lane”不分词:

GET /bank/_search

{

  "query": { "match_phrase": { "address": "mill lane" } }

}

bool查询。该bool查询允许我们使用boolean逻辑将较小的查询组合为较大的查询。

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

GET /bank/_search

{

  "query": {

    "bool": {

      "must": [

        { "match": { "address": "mill" } },

        { "match": { "address": "lane" } }

      ]

    }

  }

}

在上面的示例中,must子句指定了所有文档进行匹配,返回结果为真的查询。

相反,此示例组成两个match查询,并返回地址中包含“ mill”或“ lane”的所有帐户:

GET /bank/_search

{

  "query": {

    "bool": {

      "should": [

        { "match": { "address": "mill" } },

        { "match": { "address": "lane" } }

      ]

    }

  }

}

在上面的示例中,该bool should子句指定了一个查询列表,索引中的文档匹配每一个字句,返回的结果至少一个为真。

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

GET /bank/_search

{

  "query": {

    "bool": {

      "must_not": [

        { "match": { "address": "mill" } },

        { "match": { "address": "lane" } }

      ]

    }

  }

}

在上面的示例中,该bool must_not子句指定了一个查询列表,将文档视为匹配项,返回的结果没有一个为真。

我们可以在查询中同时组合must,should和must_not子句bool。此外,也可以将bool嵌套进bool子句中组成查询,适应任何复杂的多级布尔逻辑。

此示例返回40岁但未使用ID(aho)的任何人的所有帐户:

GET /bank/_search

{

  "query": {

    "bool": {

      "must": [

        { "match": { "age": "40" } }

      ],

      "must_not": [

        { "match": { "state": "ID" } }

      ]

    }

  }

}

 

过滤器

bool查询还支持filter子句,这些子句允许使用查询来限制将由其他子句匹配的文档,而无需更改分数的计算方式。作为示例,让我们介绍一下range查询,它允许我们按一定范围的值过滤文档。通常用于数字或日期过滤。

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

GET /bank/_search

{

  "query": {

    "bool": {

      "must": { "match_all": {} },

      "filter": {

        "range": {

          "balance": {

            "gte": 20000,

            "lte": 30000

          }

        }

      }

    }

  }

}  

bool查询包含一个match_all查询(查询部分)和一个range查询(过滤器部分)。我们可以将任何其他查询替换为查询和过滤器部分。范围查询非常有意义,因为属于该范围的文档都“相等”匹配,即没有文档比另一个文档更相关。

 

 

聚合

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

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

GET /bank/_search

{

  "size": 0,

  "aggs": {    //聚集api函数名字

    "group_by_state": { //自定义的聚集的名字

      "terms": {//分组api函数名字

        "field": "state.keyword"

      }

    }

  }

}

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

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

以及响应(部分显示):

{

  "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

      }, {

        "key" : "AL",

        "doc_count" : 25

      }, {

        "key" : "MD",

        "doc_count" : 25

      }, {

        "key" : "TN",

        "doc_count" : 23

      }, {

        "key" : "MA",

        "doc_count" : 21

      }, {

        "key" : "NC",

        "doc_count" : 21

      }, {

        "key" : "ND",

        "doc_count" : 21

      }, {

        "key" : "ME",

        "doc_count" : 20

      }, {

        "key" : "MO",

        "doc_count" : 20

      } ]

    }

  }

}

我们可以看到ID有27个帐户,其次是TX有27个帐户,其次是AL有25个帐户,依此类推。注意,我们设置size=0为不显示搜索结果,因为我们只想查看响应中的汇总结果。

在上一个汇总的基础上,此示例按州计算平均帐户余额(同样,仅对按计数降序排序的前十个州):

{

  "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

      }, {

        "key" : "AL",

        "doc_count" : 25

      }, {

        "key" : "MD",

        "doc_count" : 25

      }, {

        "key" : "TN",

        "doc_count" : 23

      }, {

        "key" : "MA",

        "doc_count" : 21

      }, {

        "key" : "NC",

        "doc_count" : 21

      }, {

        "key" : "ND",

        "doc_count" : 21

      }, {

        "key" : "ME",

        "doc_count" : 20

      }, {

        "key" : "MO",

        "doc_count" : 20

      } ]

    }

  }

}

注意我们将average_balance聚合嵌套在聚合内部group_by_state。这是所有多重聚合的通用模式。你可以在聚合中任意嵌套聚合,从数据中提取所需的结果汇总。

基于先前的汇总,现在让我们按降序对平均余额进行排序:

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"

              }

            }

          }

        }

      }

    }

  }

}







 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值