Elasticsearch Reference [7.2]中文文档(四)

注意:此文档为自译,由于个人能力有限,只作为个人学习文档分享。原文档请访问elastic.co     

从本章开始,文档会包含了一些基本的操作实例,其中分为CURL请求和REST API调用。若有需求请在官方文档上方操作。有疑惑的地方欢迎留言评论。

浏览你的数据

样本数据集

现在我们已经了解了基础知识,让我们尝试更真实的数据集。 我准备了一份关于客户银行账户信息的虚构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"
}

For the curious 这些数据都是使用www.json-generator.com/生成的。所以请忽略这些数据的值和含义,因为他们都是随机生成的。

加载一个样本数据集

你可以下载一个样本数据集,解压到我们的当前目录,然后加载我们的集群中,如下

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

curl 'localhost:9200/_cat/indices?v'

响应结果:忽略。

表示我们仅是成功的批量索引1000个文档到我们的银行索引(再账户类型之下)

查询API

我们现在可以做一些简单的查询了。查询的方式有两种,一是通过使用REST request URI来发送查询的数据。另一种通过REST request body来发送数据。请求体方法能让你在一个更可读的JSON格式中更好的展示和定义一个搜索。我们会试着使用一个请求URI的方法,但是再其余的实例中,我们将专注于使用请求体方法。

REST API可以从_search端点访问,下面是一个返回bank索引中所有文档的例子

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

首先我们分析一下搜索请求。我们在bank索引下搜索(使用了_search端点) ;q=*参数指示了Elasticsearch去整个索引的文档中匹配对应参数;sort=account_number:asc 参数指示了以升序的方式对每个文档中的account_number进行排序,再是pretty让elasticsearch返回一组漂亮的JSON结果。

响应结果:

再响应中,我们可以看见下面这些部分

以下是使用替代请求体方法的完全相同的搜索

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

这里的不同之处在于,我们不是在URI中传递q = *,而是向_search API提供JSON样式的查询请求体。 我们将在下一节讨论这个JSON查询。

最重要的是你要明白你一次性的获得了你的查询结果,Elasticsearch 已经完全的获取了结果并且和服务器端不再保持任何连接or open cursors into your results. 这与SQL等许多其他平台形成鲜明对比,其中您最初可能会预先获得查询结果的部分子集,然后如果要获取(或翻页)其余部分,则必须不断返回服务器 the rest of the results using some kind of stateful server-side cursor.

原文:It is important to understand that once you get your search results back, Elasticsearch is completely done with the request and does not maintain any kind of server-side resources or open cursors into your results. This is in stark contrast to many other platforms such as SQL wherein you may initially get a partial subset of your query results up-front and then you have to continuously go back to the server if you want to fetch (or page through) the rest of the results using some kind of stateful server-side cursor.

介绍查询语言

elasticsearch 提供一个 JSON-style domain-specific语言来用于执行查询,简称为Query DSL。Query DSL非常的全面,最初可能令人生畏,但是实际学习它的方式就是从一些基础的例子开始。

回到上一个例子,我们执行了这个查询:

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

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

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

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

注意如果size没有被指定,一般默认为10。这个例子执行了match_all,返回了从10到19的文档,from参数(从0开始)指定从哪个文档索引开始,size参数指定从from参数开始返回的文档数。 在实现搜索结果的分页时,此功能非常有用。 请注意,如果未指定from,则默认为0。

此示例执行match_all并按帐户余额降序对结果进行排序,并返回前10个(默认大小)文档。GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": { "balance": { "order": "desc" } }
}

执行查询

现在我们拥有一些基础的查询参数,让我们深入研究Query DSL.首先我们观察返回的文档字段。默认情况下,搜索的其中一部分会返回一个完整的JSON文档。这部分被称之为源数据(_source字段在搜索结果的hits中)。如果我们不希望返回整个源文档,我们可以请求返回源中的几个字段。
GET /bank/_search
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}

注意上面的例子只是减少了_source字段。它仍将只返回一个名为_source的字段,但在其中,只包含字段account_number和balance。

如果你了解SQL,上述内容在概念上于SQL SELECT FROM 字段表有些相似。

现在让我们来到查询部分,之前我们已经见过了match_all是用于查询所有文档的。那我们来介绍一下match查询,它被认为是搜索查询的基础字段。(即针对特定字段或字段集进行的搜索)

下面例子返回number为20的account 

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

下面例子返回address中包含mill一词的所有account
GET /bank/_search
{
  "query": { "match": { "address": "mill" } }
}

下面例子返回 address中包含mill或lane的所有account
GET /bank/_search
{
  "query": { "match": { "address": "mill lane" } }
}

下面是match的另一种形式match_phrase 返回address中包含短语“mill lane”的所有account
GET /bank/_search
{
  "query": { "match_phrase": { "address": "mill lane" } }
}
现在让我们介绍一下bool查询。 bool查询允许我们使用布尔逻辑将较小的查询组成更大的查询。下面是两个match匹配查询,返回address中包含“mill”和“lane”的所有帐户:
GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
...}
 在上面的示例中,bool must子句指定必须为true才能将文档视为匹配的所有查询。相反,下面示例组成两个匹配查询并返回地址中包含“mill”或“lane”的所有帐户:
GET /bank/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
...}

在上面的示例中,bool should子句指定了一个查询列表,其中任何一个查询必须为true才能使文档被视为匹配。

下面实例组成两个匹配查询,并返回地址中既不包含“mill”也不包含“lane”的所有帐户
GET /bank/_search
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
...}

在上面的示例中,bool must_not子句指定了一个查询列表,对于文档而言,这些查询都不能为真匹配。我们可以在bool查询中同时组合must,should和must_not子句。 此外,我们可以在任何bool子句中组合bool查询来模仿任何复杂的多级布尔逻辑。

此示例返回任何40岁但未激活ID的人的所有帐户:
GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]

...}

执行过滤/筛选器

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

在通过”过滤/筛选“来处理文档时,查询通常是不需要产生一个分数scores的。elasticsearch会自动优化查询执行,以便避免计算无用的分数。

我们在上一节中介绍到的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中,你可以执行一个搜索并返回一个hits结果,同时也可以在响应中返回一个聚合结果于hits结果区分开来。这是十分强大和有效的因为你可以运行查询和多个聚合,同时获得两个操作的结果,通过使用简洁和简化的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 LIMIT 10;

响应:没有

我们可以看到ID(Idaho)有27个账户,其次是TX(Texas)的27个账户,其次是AL(Alabama)的25个账户,依此类推。请注意,我们将size = 0设置为不显示搜索匹配,因为我们只想在响应中看到聚合结果。

在前一个聚合的基础上,实例计算了平均的账户余额,按照降序排列前10个states。
GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"      },
      "aggs": {
      "average_balance": {
          "avg": {
            "field": "balance"
          }...}

请注意我们是如何将average_balance聚合嵌套在group_by_state中的。这些命令在聚合的嵌套中都是非常普遍。你可以随意的嵌套聚合来提取你需要的pivoted summarizations

在前一个聚合的基础上,我们现在按降序排列平均余额:
GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword",
        "order": {
          "average_balance": "desc"  }},
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
....}

此示例演示了我们如何按照了年龄段进行分组,然后按照性别分组,最后获得每个年龄段,每个性别的平均账户余额。
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"              }
....}


还有许多其他聚合功能,我们在此不再详述。如果你想做进一步的实验,aggregations reference guide是一个很好的起点。

总结

Elasticsearch既简单又复杂。 到目前为止,我们已经了解了它的基础知识,如何查看它,以及如何使用一些REST API来处理它。 希望本教程能让您更好地了解Elasticsearch的内容,更重要的是,启发您进一步尝试其余的强大功能!

-- --
  • 投诉或建议
评论