ES入门:查询和聚合

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

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

测试工具

从索引文档开始

插入

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

请求体为 JSON 格式,包含一个字段 name 和其值 DLBoy。

Elasticsearch 支持多种请求方法来对索引进行操作,其中包括 GET、POST、PUT、DELETE 等等。

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

javascript 复制代码
PUT /customer/_doc/1
{
  "name": "DLBoy"
}

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

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

查询

批量索引文档

下载测试数据

数据的格式如下:

批量插入数据

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

执行

javascript 复制代码
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数据。

查看状态

javascript 复制代码
curl "localhost:9200/_cat/indices?v=true" | grep bank

查询数据

查询所有

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

javascript 复制代码
GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ]
}

解释

这是一个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两个字段

javascript 复制代码
GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ],
  "from": 10,
  "size": 10
}

指定字段查询

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

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

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

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

查询段落匹配

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

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

多条件查询:

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

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

Query or Filter

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

那么filterquery子句有啥区别呢?

查询条件

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

javascript 复制代码
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之间。

只包含filter的查询:

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

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

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

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

聚合查询

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

简单聚合

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

javascript 复制代码
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,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作对于分析文档集的统计信息非常有用。

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):

javascript 复制代码
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,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作对于分析文档集的统计信息非常有用,包括平均值、总和、最小值、最大值等。

这是执行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,进行排序

javascript 复制代码
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,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作有助于找到平均账户余额最高的州。

相关推荐
鸡c1 小时前
IM项目-----ElasticSearch
大数据·elasticsearch·搜索引擎
Java 第一深情1 小时前
Flink数据源的读写介入体系
大数据·flink
天冬忘忧2 小时前
Kafka 消费者全面解析:原理、消费者 API 与Offset 位移
大数据·kafka
jlting1952 小时前
《智慧教育实时数据分析推荐项目》详细分析
大数据·redis·sql·kafka·database
青云交3 小时前
大数据新视界 -- Hive 数据仓库:架构深度剖析与核心组件详解(上)(1 / 30)
大数据
EasyNVR3 小时前
NVR管理平台EasyNVR多品牌NVR管理工具的流媒体视频融合与汇聚管理方案
大数据·网络·安全·音视频·监控·视频监控
java1234_小锋3 小时前
在Elasticsearch中,是怎么根据一个词找到对应的倒排索引的?
大数据·elasticsearch·搜索引擎
油头少年_w4 小时前
Hadoop进阶原理(HDFS、MR、YARN的原理)
大数据·hadoop·分布式
大数据编程之光5 小时前
基于 Flink 的车辆超速监测与数据存储的小实战
大数据·flink·linq
Mephisto.java8 小时前
【大数据学习 | Spark-Core】广播变量和累加器
大数据·学习·spark