Elasticsearch Bài học 37: Bucket Aggregations - Phân nhóm theo Terms, Range, Date Histogram
Trong Bài 36, chúng ta đã dùng Metric Aggregations để trả lời câu hỏi "Tổng doanh thu là bao nhiêu?". Nhưng con số tổng đó chưa đủ để ra quyết định kinh doanh. Sếp sẽ muốn biết: "Tổng doanh thu đó đến từ những Thương hiệu nào? Phân bố theo các Mức giá ra sao? Và biến động theo Từng ngày như thế nào?"
Đó là lúc chúng ta phải dùng Bucket Aggregations (Chia giỏ dữ liệu). Nhiệm vụ của nó là nhóm các Document có chung đặc điểm vào các "giỏ" (buckets) khác nhau.
Dưới đây là 3 loại Bucket mạnh mẽ nhất mà mọi Backend Engineer phải nằm lòng.
1. Terms Aggregation: Chia giỏ theo giá trị chính xác
Đây là tính năng được dùng nhiều nhất, tương đương với mệnh đề GROUP BY column_name trong SQL. Nó cực kỳ hữu ích để vẽ biểu đồ tròn (Pie Chart) hoặc hiển thị danh sách bộ lọc ở sidebar (như "Thương hiệu (15)", "Màu sắc (8)").
Ví dụ: Thống kê số lượng sản phẩm theo từng Thương hiệu.
JSON
GET products/_search
{
"size": 0,
"aggs": {
"nhom_theo_thuong_hieu": {
"terms": {
"field": "brand.raw",
"size": 10 // Chỉ lấy Top 10 thương hiệu có nhiều sản phẩm nhất
}
}
}
}
Luật sinh tử: Bắt buộc phải chạy terms trên trường kiểu keyword (như brand.raw). Nếu bạn chạy trên trường text, Elasticsearch sẽ nổ lỗi tưng bừng.
Thảm họa "Sai số" của Terms Aggregation: Khi bạn chạy terms trên một hệ thống phân tán, Elasticsearch thực chất chỉ lấy Top N (ví dụ Top 10) từ từng Shard, gom về Coordinating Node rồi cộng lại. Nếu một thương hiệu có số lượng rất ít nằm rải rác ở các Shard, nó có thể bị rớt khỏi Top 10 cục bộ và biến mất hoàn toàn khỏi kết quả cuối cùng. Do đó, con số doc_count trả về đôi khi chỉ là ước lượng. Để tăng độ chính xác, bạn có thể tăng tham số shard_size lên (đánh đổi bằng việc ngốn thêm RAM).
2. Range Aggregation: Chia giỏ theo khoảng tự định nghĩa
Rất nhiều lúc, bạn không thể nhóm theo từng giá trị chính xác (ví dụ giá tiền: 150k, 151k, 152k... sẽ tạo ra hàng vạn cái giỏ vô nghĩa). Bạn muốn nhóm thành các "khoảng" (Ranges) để khách hàng lọc: Dưới 200k, 200k - 500k, Trên 500k.
JSON
GET products/_search
{
"size": 0,
"aggs": {
"phan_khuc_gia": {
"range": {
"field": "price",
"ranges": [
{ "to": 200000 }, // Dưới 200k
{ "from": 200000, "to": 500000 }, // Từ 200k đến < 500k
{ "from": 500000 } // Từ 500k trở lên
]
}
}
}
}
Kết quả trả về sẽ chia chính xác thành 3 Bucket tương ứng với 3 khoảng bạn vừa định nghĩa, kèm theo doc_count của từng khoảng.
3. Date Histogram: Chia giỏ theo trục thời gian
Đây là vũ khí hạng nặng để vẽ biểu đồ đường (Line Chart) hoặc biểu đồ cột (Bar Chart) dạng Time-series (Chuỗi thời gian). Ví dụ: Vẽ biểu đồ số lượng giao dịch AFC theo từng giờ, hoặc số lượng đơn hàng theo từng tháng.
Khác với range (bạn phải tự định nghĩa từng khoảng), date_histogram tự động chia đều trục thời gian dựa trên một "chu kỳ" (interval) cố định.
JSON
GET afc_logs/_search
{
"size": 0,
"aggs": {
"giao_dich_theo_ngay": {
"date_histogram": {
"field": "created_at",
"calendar_interval": "1d", // Chia rổ theo từng ngày (1d). Có thể dùng 1h (giờ), 1M (tháng)
"format": "yyyy-MM-dd", // Format lại key trả về cho đẹp
"extended_bounds": { // Ép hiển thị cả những ngày không có giao dịch (doc_count = 0)
"min": "2026-10-01",
"max": "2026-10-31"
}
}
}
}
}
Bí kíp extended_bounds: Mặc định, nếu ngày 15/10 không có ai mua hàng, Elasticsearch sẽ "nhảy cóc" từ ngày 14 sang ngày 16. Trên biểu đồ Line Chart, điều này sẽ tạo ra một đường gãy cực kỳ xấu xí (hoặc sai lệch trục X). Tham số extended_bounds (kết hợp với min_doc_count: 0) ép hệ thống phải trả về giỏ ngày 15/10 với giá trị 0, giúp biểu đồ của Frontend mượt mà và chuẩn xác.
Tóm lại, Bucket Aggregations chính là "bộ khung" của mọi báo cáo BI. Bằng cách lồng ghép (Nesting) các Bucket này với nhau (Ví dụ: Nhóm theo Tháng, trong mỗi Tháng lại nhóm theo Thương hiệu), chúng ta có thể tạo ra những ma trận dữ liệu cực kỳ sâu.
Tuy nhiên, nếu sếp yêu cầu: "Cho tôi biết tháng nào có tỷ lệ tăng trưởng doanh thu so với tháng trước cao nhất?", thì Bucket và Metric thông thường đều "bó tay", vì chúng không thể nhìn thấy dữ liệu của nhau. Lúc này, chúng ta phải viện đến Pipeline Aggregations.
All rights reserved