Bucket Aggregation 桶聚合 ---------group by (上)

本文深入探讨了Elasticsearch中的各种聚合技术,包括全局聚合、过滤器聚合、多过滤器聚合、匿名过滤器、其他桶聚合、缺省聚合、嵌套聚合等。通过实例展示了如何计算所有文档的平均价格、特定类型产品的平均价格、不同消息类型的数量以及嵌套文档的最低价格。

Global Aggregation

全局聚合,最顶级的聚合,无法嵌入到其他bucket聚合+

example:

POST /sales/_search?size=0
{
    "query" : {
        "match" : { "type" : "t-shirt" }
    },
    "aggs" : {
        "all_products" : {
            "global" : {}, 
            "aggs" : { 
                "avg_price" : { "avg" : { "field" : "price" } }
            }
        },
        "t_shirts": { "avg" : { "field" : "price" } }
    }
}

result:

{
    ...
    "aggregations" : {
        "all_products" : {
            "doc_count" : 7, 
            "avg_price" : {
                "value" : 140.71428571428572 
            }
        },
        "t_shirts": {
            "value" : 128.33333333333334 
        }
    }
}

分析:global 查询了上下文 所有文档的 平均价格。avg_price 是为global 注册的聚合。

javaApi:

    1. 创建聚合请求

AggregationBuilders
    .global("agg")
    .subAggregation(AggregationBuilders.terms("genders").field("gender"));

    2.分析结果

// sr is here your SearchResponse object
Global agg = sr.getAggregations().get("agg");
agg.getDocCount(); // Doc count

Filter Aggregation

定义当前文档集上下文中与指定筛选器匹配的所有文档的单个桶。通常,这将用于将当前聚合上下文缩小到特定的一组文档。

简而言之 ,就是先查,再根据查到的再聚合。

example:

POST /sales/_search?size=0
{
    "aggs" : {
        "t_shirts" : {
            "filter" : { "term": { "type": "t-shirt" } },
            "aggs" : {
                "avg_price" : { "avg" : { "field" : "price" } }
            }
        }
    }
}
{
    ...
    "aggregations" : {
        "t_shirts" : {
            "doc_count" : 3,
            "avg_price" : { "value" : 128.33333333333334 }
        }
    }
}

分析:我们计算了所有t恤类型产品的平均价格。

javaapi:

AggregationBuilders
    .filter("agg", QueryBuilders.termQuery("gender", "male"));

Filters Aggregation

定义一个多桶聚合,其中每个桶与一个过滤器关联。每个bucket将收集与其关联的过滤器匹配的所有文档。

简而言之,先构建多个过滤器,再根据这些过滤器聚合。应用场景,如果你group by 后面的条件不仅仅是字段,而需要将字段中的各个值,重新分类,定义成不同的类型再group by,可以用这个聚合。

example

PUT /logs/message/_bulk?refresh
{ "index" : { "_id" : 1 } }
{ "body" : "warning: page could not be rendered" }
{ "index" : { "_id" : 2 } }
{ "body" : "authentication error" }
{ "index" : { "_id" : 3 } }
{ "body" : "warning: connection timed out" }

GET logs/_search
{
  "size": 0,
  "aggs" : {
    "messages" : {
      "filters" : {
        "filters" : {
          "errors" :   { "match" : { "body" : "error"   }},
          "warnings" : { "match" : { "body" : "warning" }}
        }
      }
    }
  }
}
{
  "took": 9,
  "timed_out": false,
  "_shards": ...,
  "hits": ...,
  "aggregations": {
    "messages": {
      "buckets": {
        "errors": {
          "doc_count": 1
        },
        "warnings": {
          "doc_count": 2
        }
      }
    }
  }
}

javaapi:

      request:

AggregationBuilder aggregation =
    AggregationBuilders
        .filters("agg",
            new FiltersAggregator.KeyedFilter("men", QueryBuilders.termQuery("gender", "male")),
            new FiltersAggregator.KeyedFilter("women", QueryBuilders.termQuery("gender", "female")));

    response:

// sr is here your SearchResponse object
Filters agg = sr.getAggregations().get("agg");

// For each entry
for (Filters.Bucket entry : agg.getBuckets()) {
    String key = entry.getKeyAsString();            // bucket key
    long docCount = entry.getDocCount();            // Doc count
    logger.info("key [{}], doc_count [{}]", key, docCount);
}

 

anonymous filters 匿名 

详情见官方文档,就是filter字段可以用过滤器数组,不需要对过滤器命名

other bucket

可以将other_bucket参数设置为向响应添加一个bucket,该响应将包含与任何给定过滤器不匹配的所有文档。

PUT logs/message/4?refresh
{
  "body": "info: user Bob logged out"
}

GET logs/_search
{
  "size": 0,
  "aggs" : {
    "messages" : {
      "filters" : {
        "other_bucket_key": "other_messages",
        "filters" : {
          "errors" :   { "match" : { "body" : "error"   }},
          "warnings" : { "match" : { "body" : "warning" }}
        }
      }
    }
  }
}
{
  "took": 3,
  "timed_out": false,
  "_shards": ...,
  "hits": ...,
  "aggregations": {
    "messages": {
      "buckets": {
        "errors": {
          "doc_count": 1
        },
        "warnings": {
          "doc_count": 2
        },
        "other_messages": {
          "doc_count": 1
        }
      }
    }
  }
}

Missing Aggregation 缺省聚合

一个基于字段数据的单桶聚合,它为当前文档集   中缺少字段值  的所有文档创建一个桶(实际上,缺少字段 或具有已配置的  空值集)。此聚合器通常 与其他字段 数据桶聚合器(例如范围)一起使用,以返回由于缺少字段数据值 而无法放在任何其他桶中  的所有文档的信息。简而言之,就是可以将 为空值的数据 放到一个桶中。

POST /sales/_search?size=0
{
    "aggs" : {
        "products_without_a_price" : {
            "missing" : { "field" : "price" }
        }
    }
}
{
    ...
    "aggregations" : {
        "products_without_a_price" : {
            "doc_count" : 00
        }
    }
}

获得没有价格的产品总数,为0很正常,产品怎么会没价格。

javaapi:

AggregationBuilders.missing("agg").field("gender");

分析结果,同上。

Nested Aggregation 嵌套聚合

一种特殊的单桶聚合,支持聚合嵌套文档。
例如,假设我们有一个产品索引,每个产品都包含分销商列表——每个分销商都有自己的产品价格。映射可以是这样的:

PUT /index
{
  "mappings": {
    "product" : {
        "properties" : {
            "resellers" : { 
                "type" : "nested",
                "properties" : {
                    "name" : { "type" : "text" },
                    "price" : { "type" : "double" }
                }
            }
        }
    }
  }
}
GET /_search
{
    "query" : {
        "match" : { "name" : "led tv" }
    },
    "aggs" : {
        "resellers" : {
            "nested" : {
                "path" : "resellers"
            },
            "aggs" : {
                "min_price" : { "min" : { "field" : "resellers.price" } }
            }
        }
    }
}
{
  ...
  "aggregations": {
    "resellers": {
      "doc_count": 0,
      "min_price": {
        "value": 350
      }
    }
  }
}

正如您在上面看到的,嵌套聚合需要顶层文档中的嵌套文档的路径。然后可以在这些嵌套文档上定义任何类型的聚合。

聚合将返回可以购买产品的最低价格

javaapi:

AggregationBuilders
    .nested("agg", "resellers");

分析结果同上。

预知后事如何,请看下篇。

官方英文文档:文档

在数据库或数据处理系统中,`hashagg-build` 过程通常指的是哈希聚合(Hash Aggregation)执行阶段的一部分,其中系统会构建哈希表以支持后续的聚合操作。在此过程中,为了保证并发操作的安全性与数据一致性,会使用特定类型的锁机制,例如 `HASH` 锁。 `hashagg-build` 过程中使用的 `HASH` 锁属于一种内部锁机制,其主要作用是确保在并发环境下多个线程或进程对哈希表的访问不会导致数据不一致或结构损坏。具体来说,`HASH` 锁可以防止多个并发操作同时修改同一个哈希bucket),从而避免潜在的冲突[^1]。这种锁通常具有粒度较细的特点,意味着它可以在不影响整个哈希表的情况下,仅锁定受影响的特定部分,这样可以减少锁竞争,提高系统的并发性能。 在某些数据库系统中,如 openGauss,`HashAggRunner` 类负责管理哈希聚合的执行流程,其中包括 `HASH` 锁的使用。该类通过协调各个线程对哈希表的访问,确保在 `hashagg-build` 阶段能够高效且安全地完成哈希表的构建。 ### 示例代码:哈希聚合伪代码 ```cpp class HashAggRunner { public: void buildHashTable() { // 使用 HASH 锁确保线程安全 std::lock_guard<std::mutex> lock(hashMutex); // 构建哈希表逻辑 for (auto& row : inputRows) { auto key = extractKey(row); auto& group = hashTable[key]; aggregate(group, row); } } private: std::mutex hashMutex; // HASH 锁 std::unordered_map<KeyType, AggregationState> hashTable; // 哈希表 }; ``` 在上述伪代码中,`std::mutex` 代表了 `HASH` 锁的具体实现,用于保护对 `hashTable` 的并发访问。每当有线程尝试修改哈希表时,它必须先获取锁,从而确保了数据结构的完整性。 ### 总结 `HASH` 锁在 `hashagg-build` 过程中的作用不可忽视,它是确保哈希聚合操作在并发环境中正确执行的关键机制之一。通过合理设计锁的粒度和使用方式,数据库系统能够在保证数据一致性的前提下,最大限度地提升性能和吞吐量。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值