Elasticsearch Bài học 35: Aggregations là gì? Tư duy Group By trong Elasticsearch
Trong bất kỳ dự án Backend nào, sau khi hoàn thiện các API phục vụ end-user (người dùng cuối), bạn sẽ lập tức đối mặt với yêu cầu từ team Operation (Vận hành) và Data Analytics: "Hãy vẽ cho tôi biểu đồ số lượng giao dịch soát vé AFC theo từng giờ", hoặc "Thống kê tổng doanh thu theo từng thương hiệu mỹ phẩm trong tháng qua".
Nếu bạn gọi lệnh SELECT brand, SUM(price) FROM products GROUP BY brand trên một bảng MySQL có 50 triệu dòng, query đó có thể chạy mất vài phút, gây lock ổ cứng và làm sập các API khác.
Trong Elasticsearch, bài toán này được giải quyết trọn vẹn trong vài chục mili-giây bằng một cơ chế gọi là Aggregations (Thống kê và Tổng hợp).
1. Bí mật tốc độ: Rời bỏ Inverted Index, tiến về Doc Values
Tại sao Elasticsearch có thể GROUP BY hàng chục triệu bản ghi nhanh như chớp?
Câu trả lời nằm ở Bài 17. Aggregations KHÔNG sử dụng Inverted Index (Chỉ mục đảo ngược). Inverted Index rất giỏi việc trả lời "Từ khóa này nằm ở đâu?", nhưng nó cực kỳ tệ trong việc trả lời "Document A có giá trị price là bao nhiêu?".
Khi chạy Aggregations, Elasticsearch truy xuất vào một cấu trúc dữ liệu khác tên là Doc Values. Đây là kiến trúc lưu trữ dạng cột (Columnar Store) nằm trên ổ cứng, được nén cực kỳ tối ưu, cho phép CPU quét qua hàng triệu con số một cách liên tục mà không gặp hiện tượng tràn RAM.
Quy luật sinh tử: Bạn chỉ có thể chạy Aggregations trên các trường kiểu
keyword,numeric(số học),date(ngày tháng), hoặcboolean. Tuyệt đối không thể chạy Aggregations trên trường kiểutext(vì nó bị băm nát bởi Analyzer và mặc định không có Doc Values).
2. Cú pháp cơ bản và Bí kíp size: 0
Một request Aggregations (thường được viết tắt là aggs) có cấu trúc song song với khối query tìm kiếm.
JSON
GET products/_search
{
"size": 0,
"query": {
"match": {
"category": "Chăm sóc da mặt"
}
},
"aggs": {
"my_first_aggregation": {
"terms": {
"field": "brand.raw"
}
}
}
}
Chi tiết thiết kế:
-
Phễu lọc (
query): Elasticsearch không ngốc đến mức đi thống kê trên toàn bộ Database. Nó sẽ chạy khốiquerytrước để lấy ra tập kết quả (ví dụ: chỉ lấy đồ Chăm sóc da mặt), sau đó mới đẩy tập kết quả này vào cỗ máyaggsđể đếm. -
Tuyệt chiêu
"size": 0: Khi bạn vẽ Dashboard báo cáo, bạn chỉ quan tâm đến số liệu thống kê, chứ không quan tâm đến nội dung JSON của từng cái áo hay chai sữa rửa mặt. Setsize: 0ép Elasticsearch không trả về mảnghitsgốc, giúp tiết kiệm 99% băng thông mạng (Network I/O) cho API Backend của bạn. -
Tên tự đặt (
my_first_aggregation): Đây là key do bạn tự định nghĩa, nó sẽ hiển thị y hệt trong JSON Response để code Golang/PHP của bạn dễ dàng parse (trích xuất) kết quả.
3. Ba trụ cột quyền lực của Aggregations
Khác với SQL nơi GROUP BY và các hàm SUM/AVG bị trộn lẫn trong một dòng lệnh, Elasticsearch chia rạch ròi thế giới thống kê làm 3 họ (Family) riêng biệt:
A. Metric Aggregations (Tính toán con số)
Đóng vai trò giống hệt các hàm toán học trong SQL.
-
Nhiệm vụ: Tính toán các giá trị đơn lẻ từ các Document.
-
Các loại phổ biến:
min(Nhỏ nhất),max(Lớn nhất),avg(Trung bình),sum(Tổng),cardinality(Đếm số lượng phần tử duy nhất - tương đươngCOUNT(DISTINCT)).
B. Bucket Aggregations (Chia giỏ dữ liệu)
Đóng vai trò chính của mệnh đề GROUP BY trong SQL.
-
Nhiệm vụ: Phân loại Document thành nhiều "cái giỏ" (Buckets) dựa trên các tiêu chí nhất định.
-
Các loại phổ biến:
-
terms: Chia giỏ theo từng giá trị chính xác (Ví dụ: Giỏ Cetaphil, Giỏ L'Oreal). -
range: Chia giỏ theo khoảng (Ví dụ: Giỏ từ 0-100k, Giỏ 100k-500k). -
date_histogram: Chia giỏ theo trục thời gian (Ví dụ: Doanh thu theo từng ngày, từng giờ).
-
C. Pipeline Aggregations (Thống kê của Thống kê)
Đây là thứ biến Elasticsearch thành một hệ thống BI (Business Intelligence) thực thụ.
-
Nhiệm vụ: Nhận đầu vào không phải là Document, mà là kết quả của một Aggregation khác đã chạy xong.
-
Ứng dụng: Tính toán đường Trung bình trượt (Moving Average), tính Đạo hàm (Derivative) để đo tốc độ tăng trưởng doanh thu so với tháng trước, hoặc tìm ra "Cái giỏ có doanh thu cao nhất" (
max_bucket).
4. Tư duy "Mẹ bồng con" (Nesting)
Sự ảo diệu lớn nhất của JSON so với SQL là khả năng lồng ghép vô hạn.
Trong SQL, bạn viết GROUP BY category, brand tạo ra một bảng kết quả phẳng.
Trong Elasticsearch, bạn có thể tạo một Bucket cấp 1 (Chia giỏ theo Category). Ngay bên trong định nghĩa của giỏ Category, bạn khai báo tiếp một khối aggs con để tạo Bucket cấp 2 (Chia nhỏ theo Brand). Và bên trong giỏ Brand, bạn gọi một Metric (Tính tổng tiền).
JSON
"aggs": {
"nhom_theo_danh_muc": {
"terms": { "field": "category.raw" },
"aggs": {
"nhom_theo_thuong_hieu": {
"terms": { "field": "brand.raw" },
"aggs": {
"tong_doanh_thu": {
"sum": { "field": "price" }
}
}
}
}
}
}
Kết quả trả về sẽ là một cây JSON phân cấp rõ ràng, cực kỳ thuận tiện cho Frontend vẽ biểu đồ đa tầng (Treemap hoặc Sunburst Chart) mà code Backend không cần phải xào nấu gì thêm.
All rights reserved