ES入门:查询和聚合

举报
不惑 发表于 2024/10/29 09:16:37 2024/10/29
【摘要】 安装完ElasticSearch 和 Kibana后我们开始学习 为了方便测试,使用kibana的dev tool来进行学习测试

—theme: theme-blue —

安装完ElasticSearch 和 Kibana后我们开始学习

为了方便测试,使用kibana的dev tool来进行学习测试:

测试工具

image.png

从索引文档开始

插入

向 Elasticsearch 索引 customer 的 _doc 类型的文档 id 为 1 的文档发送 PUT 请求的例子。

请求体为 JSON 格式,包含一个字段 name 和其值 DLBoy。
Elasticsearch 支持多种请求方法来对索引进行操作,其中包括 GET、POST、PUT、DELETE 等等。

在这个例子中,我们使用的 PUT 方法将更新或创建一个新的文档:

PUT /customer/_doc/1
{
  "name": "DLBoy"
}

/customer/_doc/1,其中customer是索引的名称,\_doc通常是文档类型(在Elasticsearch 7.x及更高版本中,文档类型通常被忽略),而1是文档的唯一标识ID。

使用 PUT 方法提交文档时,如果指定的 id 已经存在,则该文档将被更新;如果不存在则该文档将被创建。在 POST 方法中,不需要提供 id 参数, Elasticsearch 会生成一个唯一的 id 。

image.png

查询

image.png

批量索引文档

下载测试数据

数据的格式如下:

image.png

批量插入数据

  • 将accounts.json拷贝至指定目录,我这里放在/opt/下面
    image.png

执行

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

解释

  • curl: 这是一个命令行工具,用于发起HTTP请求。
  • -H "Content-Type: application/json": 这是HTTP请求头,指定请求的内容类型为JSON。
  • -XPOST: 这指示curl执行HTTP POST请求。
  • "localhost:9200/bank/_bulk?pretty&refresh": 这是目标Elasticsearch服务器的URL,它指定了索引名称"bank",并在URL中使用"_bulk"来指示批量导入操作。pretty参数是可选的,用于格式化响应以使其更易阅读,refresh参数用于在导入完成后刷新索引,以使新数据立即可用。
  • --data-binary "@/opt/accounts.json": 这是HTTP请求的数据部分,它指定了要导入的数据文件的路径,这里是"/opt/accounts.json"。@符号表示要上传文件的路径。这个文件包含了要批量导入的JSON数据。

查看状态

curl "localhost:9200/_cat/indices?v=true" | grep bank

查询数据

查询所有

match_all表示查询所有的数据,sort即按照什么字段排序

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

image.png

解释

这是一个Elasticsearch批量导入数据的响应示例。响应包含了以下信息:

  • "took" : 1: 表示处理请求所花费的时间,以毫秒为单位。
  • "timed_out" : false: 表示请求没有超时。
  • "_shards": 提供了与索引分片相关的信息,包括总分片数、成功的分片数、跳过的分片数和失败的分片数。
  • "total": 表示索引总共包含了1个分片。在分布式环境下,索引通常被分成多个分片以提高性能和可伸缩性。这里的值为1,表示索引可能是单一分片的。
  • "successful": 表示成功完成的分片数。在这里,所有的分片操作都成功,所以值为1。
  • "skipped": 表示跳过的分片数。在这个响应中,没有分片被跳过,所以值为0。
  • "failed": 表示失败的分片数。在这个响应中,没有分片失败,所以值为0。
  • "hits": 这是一个包含有关查询匹配文档的信息的部分。
  • "total": 提供了匹配查询条件的总文档数,这里是1000个文档。这是符合查询条件的文档总数。
  • "relation": 表示与总文档数的关系,这里是"eq",表示匹配文档的数量等于总文档数。其他可能的关系包括"gte"(大于或等于)、“lte”(小于或等于)等,根据查询条件的具体情况而定。
  • "hits": 这是一个文档数组,包含了查询匹配的文档。每个文档都包括了以下信息:
  • “_index”: 文档所属的索引名称,这里是"bank"。
  • “_type”: 文档的类型,通常在Elasticsearch 7.x及更高版本中使用"_doc"。
  • “_id”: 文档的唯一标识ID。
  • “_score” - 文档的相关性得分(使用match_all时不适用)
  • “_source”: 包含文档的实际数据。在这个示例中,包含了账户信息,如账号号码、余额、姓名、年龄、性别、地址等。
  • “sort” - 文档的排序位置(不按相关性得分排序时)

这个响应示例表明批量导入操作成功,共导入了1000个文档,并提供了匹配的文档详细信息。这些信息可用于后续的搜索和分析操作。


分页查询

from和size两个字段

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

image.png

指定字段查询

如果要在字段中搜索特定字词,可以使用match

查询address 字段中包含 mill 或者 lane的数据;

GET /bank/_search
{
  "query": {
    "match": {
      "address": "Holmes Lane"
    }
  }
}
  • "query": 查询请求的主体,指示Elasticsearch执行查询操作。
  • "match": 查询类型,表示执行一个文本匹配查询。
  • "address": 要匹配的字段名称,这里是"address"字段。
  • "Holmes Lane": 要匹配的文本内容,这里是"Holmes Lane"。查询将在"address"字段中查找包含"Holmes Lane"的文本。
    image.png

由于ES底层是按照分词索引的,所以上述查询结果是address 字段中包含 Holmes 或者 Lane 的数据

查询段落匹配

查询的条件是 address字段中包含 “Holmes Lane”,则可以使用match_phrase

GET /bank/_search
{
  "query": {
    "match_phrase": {
      "address": "Holmes Lane"
    }
  }
}
  • "query": 查询请求的主体,指示Elasticsearch执行查询操作。
  • "match_phrase": 查询类型,表示执行一个短语匹配查询。
  • "address": 要匹配的字段名称,这里是"address"字段。
  • "Holmes Lane": 要匹配的短语,这里是"Holmes Lane"。查询将在"address"字段中查找包含完整短语"Holmes Lane"的文本。
    image.png

多条件查询:

如果要构造更复杂的查询,可以使用bool查询来组合多个查询条件。

GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}
  • "query": 查询请求的主体,指示Elasticsearch执行查询操作。
  • "bool": 查询类型,表示执行一个布尔查询,它可以包含多个条件。
  • "must": 这是一个数组,包含了必须匹配的条件。在这里,我们要求文档的"age"字段必须匹配值"40"。
  • "must_not": 这也是一个数组,包含了不能匹配的条件。在这里,我们要求文档的"state"字段不能匹配值"ID"。

image.png

Query or Filter

must,should,must_notfilter 都是bool查询的子句。

那么filterquery子句有啥区别呢?

查询条件

bool查询的子句中同时具备query,must 和 filter

GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "state": "ND"
          }
        }
      ],
      "filter": [
        {
          "term": {
            "age": "40"
          }
        },
        {
          "range": {
            "balance": {
              "gte": 20000,
              "lte": 30000
            }
          }
        }
      ]
    }
  }
}

Elasticsearch查询的示例,使用HTTP GET请求来搜索名为"bank"的索引中的文档。这个查询是一个复杂的布尔查询,包含了多个子查询条件,同时指定了必须匹配的条件和过滤条件。以下是这个查询的各个部分的解释:

  • HTTP方法:GET,表示发起一个查询请求。
  • 路径:/bank/_search,这是指定要搜索的索引名称为"bank",并且执行搜索操作。
  • 请求正文:这是一个包含查询条件的JSON请求体,用于定义查询的细节。在这个示例中,查询条件如下:
  • "query": 查询请求的主体,指示Elasticsearch执行查询操作。
  • "bool": 查询类型,表示执行一个布尔查询,它可以包含多个条件。
  • "must": 这是一个数组,包含了必须匹配的条件。在这里,我们要求文档的"state"字段必须匹配值"ND",即北达科他州。
  • "filter": 这是一个数组,包含了过滤条件,这些条件用于排除文档。在这里,有两个过滤条件:
  • "term": 这是一个精确匹配查询条件,要求文档的"age"字段必须精确匹配值"40"。
  • "range": 这是一个范围查询条件,要求文档的"balance"字段的值必须在20000到30000之间(包括20000和30000)。

所以,这个查询的目的是从"bank"索引中查找文档,这些文档同时满足以下条件:位于北达科他州(“state"字段匹配"ND”),年龄为40,账户余额在20000到30000之间。
image.png

只包含filter的查询:

GET /bank/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "age": "40"
          }
        },
        {
          "range": {
            "balance": {
              "gte": 20000,
              "lte": 30000
            }
          }
        }
      ]
    }
  }
}

image.png

在Elasticsearch中,queryfilter都用于定义搜索条件,但它们之间有重要的区别,主要涉及到搜索的目的和结果处理方式。以下是它们的主要区别:

  1. 目的
  • Query(查询):主要用于筛选和排序文档以匹配搜索查询,以便找到相关性最高的文档。查询条件会计算文档的相关性得分,然后对文档进行排序,以使最相关的文档排在前面。
  • Filter(过滤):主要用于筛选文档,不涉及相关性得分或排序。过滤条件用于精确匹配文档,通常用于排除不符合条件的文档。
  1. 计算开销
  • Query(查询):查询条件可能需要较大的计算开销,因为它们计算文档的相关性得分并进行排序。这在某些情况下可能会导致查询变得较慢。
  • Filter(过滤):过滤条件通常具有较小的计算开销,因为它们不涉及相关性得分或排序。这使得过滤条件在性能上更高效。
  1. 结果处理方式
  • Query(查询):查询结果会包括文档的相关性得分,文档按照相关性排序。查询条件用于找到最相关的文档,通常用于全文搜索等情况。
  • Filter(过滤):过滤条件返回文档的精确匹配结果,结果不包括相关性得分。过滤条件用于精确筛选文档,通常用于精确匹配、范围查询、布尔条件等情况。

总之,query主要用于搜索和排序文档,通常在需要考虑相关性的情况下使用,如全文搜索。而filter主要用于筛选文档,通常在需要精确匹配和排除的情况下使用,如范围查询、精确匹配、布尔条件等。根据搜索需求,可以选择使用queryfilter或它们的组合,以达到所需的搜索目标。

聚合查询

我们知道SQL中有group by,在ES中它叫Aggregation,即聚合运算。

简单聚合

比如我们希望计算出account.json的数据中每个州的统计数量, 使用aggs关键字对state字段聚合,被聚合的字段无需对分词统计,所以使用state.keyword对整个字段统计

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}
  • “size”: 这指定了搜索结果的大小,这里是0,表示不返回实际文档结果,只返回聚合结果。
  • “aggs”: 这是用于定义聚合的部分。
  • “group_by_state”: 这是聚合的名称,可以自定义。
  • “terms”: 这是一种聚合类型,表示按照指定字段的值进行分组。在这里,我们希望按照"state.keyword"字段的值进行分组。
  • “field”: 这是要用于分组的字段,这里是"state.keyword",表示按照州的关键字值进行分组。

所以,这个查询的目的是执行一个名为"group_by_state"的聚合,根据文档中的"state.keyword"字段的值进行分组。它将生成一个分组列表,其中包含每个不同州的值,并统计每个州的文档数量。由于"size"设置为0,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作对于分析文档集的统计信息非常有用。
image.png
Elasticsearch聚合操作的响应结果,具体包括了"aggregations"部分解释:

  • “aggregations”: 这是包含聚合结果的部分。
  • “group_by_state”: 这是聚合的名称,与查询中定义的聚合名称一致。
  • “doc_count_error_upper_bound”: 这是文档计数错误的上限,通常为0。它表示文档计数的错误限制,如果值大于0,表示可能存在计数错误。
  • “sum_other_doc_count”: 这是其他文档计数的总和,743表示总共有743个文档分配到了除分桶之外的"其他"类别中。
  • “buckets”: 这是分桶(buckets)的数组,包含了每个分组的信息。
  • 每个"bucket"包括以下信息:
  • “key”: 分组的键,即"state.keyword"字段的值。
  • “doc_count”: 分组中的文档计数,表示每个州拥有的文档数量。

在这个示例中,"group_by_state"聚合对"state.keyword"字段进行了分组,并列出了每个州的文档数量。例如,“TX”(得克萨斯州)有30个文档,“MD”(马里兰州)有28个文档,以此类推。这种聚合操作有助于了解文档集中各个分组的统计信息,通常用于数据分析和可视化。

嵌套聚合

ES处理聚合条件的嵌套。

计算每个州的平均结余。涉及到的就是在对state分组的基础上,嵌套计算avg(balance):

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}
  • “size”: 这指定了搜索结果的大小,这里是0,表示不返回实际文档结果,只返回聚合结果。
  • “aggs”: 这是用于定义聚合的部分。
  • “group_by_state”: 这是聚合的名称,用于按州进行分组。
  • “terms”: 这是一种聚合类型,表示按照指定字段的值进行分组,这里是"state.keyword"字段的值。
  • “aggs”: 这是在每个州分组内执行的嵌套聚合。
  • “average_balance”: 这是嵌套聚合的名称,用于计算每个州的平均账户余额。
  • “avg”: 这是嵌套聚合的类型,表示计算平均值。
  • “field”: 这是用于计算平均值的字段,这里是"balance"字段,表示计算每个州的账户余额的平均值。

所以,这个查询的目的是执行一个名为"group_by_state"的聚合,根据文档中的"state.keyword"字段的值进行分组。在每个分组内,还执行了一个名为"average_balance"的嵌套聚合,计算每个州的平均账户余额。由于"size"设置为0,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作对于分析文档集的统计信息非常有用,包括平均值、总和、最小值、最大值等。
image.png

这是执行Elasticsearch聚合操作后的响应结果,具体包括了"aggregations"部分的解释:

  • “aggregations”: 这是包含聚合结果的部分。
  • “group_by_state”: 这是聚合的名称,与查询中定义的聚合名称一致。
  • “doc_count_error_upper_bound”: 这是文档计数错误的上限,通常为0。它表示文档计数的错误限制,如果值大于0,表示可能存在计数错误。
  • “sum_other_doc_count”: 这是其他文档计数的总和,743表示总共有743个文档分配到了除分桶之外的"其他"类别中。
  • “buckets”: 这是分桶(buckets)的数组,包含了每个分组的信息。
  • 每个"bucket"包括以下信息:
  • “key”: 分组的键,即"state.keyword"字段的值,表示各个州的名称。
  • “doc_count”: 分组中的文档计数,表示每个州的文档数量。
  • “average_balance”: 这是嵌套聚合计算的平均账户余额的结果。每个分组都包括一个"average_balance"字段,其中包含了平均值。

在这个示例中,"group_by_state"聚合对"state.keyword"字段进行了分组,列出了每个州的文档数量,并计算了每个州的平均账户余额。例如,“TX”(得克萨斯州)有30个文档,平均账户余额为26073.3,“MD”(马里兰州)有28个文档,平均账户余额为26161.535714285714,以此类推。这种聚合操作非常有助于对文档集进行统计和分析,以获得有关每个分组的信息。

聚合结果排序

通过在aggs中对嵌套聚合的结果进行排序

对嵌套计算出的avg(balance),这里是average_balance,进行排序

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword",
        "order": {
          "average_balance": "desc"
        }
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}
  • “size”: 这指定了搜索结果的大小,这里是0,表示不返回实际文档结果,只返回聚合结果。
  • “aggs”: 这是用于定义聚合的部分。
  • “group_by_state”: 这是聚合的名称,用于按州进行分组。
  • “terms”: 这是一种聚合类型,表示按照指定字段的值进行分组,这里是"state.keyword"字段的值。
  • “order”: 这是一个选项,用于指定排序方式,这里按照嵌套聚合"average_balance"的降序排列。
  • “aggs”: 这是在每个州分组内执行的嵌套聚合。
  • “average_balance”: 这是嵌套聚合的名称,用于计算每个州的平均账户余额。
  • “avg”: 这是嵌套聚合的类型,表示计算平均值。
  • “field”: 这是用于计算平均值的字段,这里是"balance"字段,表示计算每个州的账户余额的平均值。

这个查询的目的是执行一个名为"group_by_state"的聚合,根据文档中的"state.keyword"字段的值进行分组,同时计算每个州的平均账户余额,并按照平均余额的降序排列结果。由于"size"设置为0,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作有助于找到平均账户余额最高的州。
image.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。