Tới đây, chắc hẳn các bạn đã đọc hầu hết các bài trong chuỗi bài viết về Elasticsearch. Chúng ta đã cùng nhau tìm hiểu từ những khái niệm sơ khai nhất đến cách xây dựng một index, cách thêm dữ liệu vào đó hay làm sao để có thể tìm kiếm dữ liệu một cách chính xác và hiệu quả. Và để kết thúc cho chuỗi bài viết này, chúng ta sẽ cùng nhau tìm hiểu một tính năng rất là hay mà công cụ này cung cấp, đó chính là aggregation.

>>> Xem thêm bài viết trong chuỗi bài hướng dẫn tìm hiểu ngôn ngữ lập trình Elasticsearch:

1. Aggregations trong Elasticsearch là gì?

Một truy vấn aggregation trong Elasticsearch hay còn gọi là truy vấn tính toán sẽ tổng hợp lại dữ liệu của chúng ta dưới dạng các metrics, các thông số thống kê hoặc các dữ liệu được phân tích khác.

Aggregations được chia làm ba loại:

  • Metric: tính toán các metrics như là sum (tổng) hoặc average (tính trung bình) từ giá trị của các field
  • Bucket: gom các document lại vào thành các bucket dựa trên giá trị của các field, dải dữ liệu hoặc các thông tin khác
  • Pipeline: lấy đầu vào từ các aggregation khác để thực thi thay vì sử dụng các document hoặc trường dữ liệu

2. Thực hiện aggregation

Chúng ta có thể chạy một aggregation như một phần của một quy trình search bằng cách cung cấp cho body của API search một biến aggs.

Một số loại aggregation phổ biến:

  • terms: là một bucket aggregation, nó cho phép chúng ta có thể lấy được value source từ nhiều bucket, các bucket sẽ được build một cách linh hoạt tùy vào các giá trị duy nhất được liệt kê trong field mà truy vấn sử dụng
GET index-01/_search
{
  "aggs": {
    "ages": {
      "terms": {
        "field": "age",
        "size": 10
      }
    }
  }
}

Khi đó chúng ta sẽ thu được kết quả từ truy vấn này như sau:

{
  ...
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [<hits>]
  },
  "aggregations": {
    "ages": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 20,
          "doc_count": 2
        },
        {
          "key": 18,
          "doc_count": 1
        },
        {
          "key": 19,
          "doc_count": 1
        }
      ]
    }
  }
}

Thuộc tính aggregations sẽ bao gồm các thông tin tính toán, nó sẽ trả về các thông tin aggregation chúng ta request khi tìm kiếm. Trong đó:

Doc_count_error_upper_bound:số lượng lỗi dựa trên từng term được đếm trong aggregation

sum_other_doc_count: trả về số lượng các document chưa được bao gồm trong response của lần này

buckets: danh sách các bucket

  • avg: là một metrics aggregation, có thực hiện tính toán giá trị trung bình của các trường có dạng số được trích xuất ra từ các document. Các giá trị này có thể được trích xuất ra từ một giá trị số cụ thể hoặc từ một trường histogram trong các document.

Giả sử, trong index index-01, chúng ta muốn tính trung bình chung số tuổi của các bản ghi có trong index, ta có thể sử dụng avg như sau:

GET index-01/_search
{
  "aggs": {
    "ages_avg": {
      "avg": {
        "field": "age"
      }
    }
  }, 
  "size": 0
}

Tương ứng từ đó, Elasticsearch sẽ trả chúng ta kết quả như sau:

{
  ...
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "ages_avg": {
      "value": 19.25
    }
  }
}

Khi đọc kết quả tìm kiếm, chúng ta cần chú ý trường value tương ứng với aggregation đã định nghĩa ở trên, đây chính là kết quả trung bình đã được tính toán.

  • range: là một bucket aggregation, nó cho phép người dùng có thể định nghĩa một set các dải dữ liệu, mỗi dải sẽ tương ứng với một bucket. Trong suốt quá trình này, các giá trị được trích xuất ra từ từng document sẽ được so sánh lại với từng bucket và các điểm liên quan của nó. Các giá trị aggregation sẽ bao gồm cả các đầu mút là from và to
GET index-01/_search
{
  "aggs": {
    "ages_range": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 16,
            "to": 19
          }
        ]
      }
    }
  },
  "size": 0
}

Truy vấn sẽ trả lại kết quả là

{
 ...
 "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "ages_range": {
      "buckets": [
        {
          "key": "16.0-19.0",
          "from": 16,
          "to": 19,
          "doc_count": 1
        }
      ]
    }
  }
}

Chúng ta sẽ focus vào buckets ở trong kết quả trả về. Tại đây, ta có thể thấy được key tìm kiếm là giá trị dải mà ta tìm kiếm, hai đầu mút from và to cũng như là giá trị doc_count là số document thuộc vào range mà ta tìm kiếm.

3. Tùy chỉnh một aggregation theo ý mình

3.1. Thay đổi scope của một truy vấn

Ở đây, chúng ta có thể sử dụng biến query trong API search để giới hạn số document mà một aggregation có thể được chạy.

GET index-01/_search
{
  "query": {
    "match": {
      "name": "John"
    }
  }, 
  "aggs": {
    "ages_avg": {
      "avg": {
        "field": "age"
      }
    }
  }, 
  "size": 0
}

>>> Xem thêm bài viết:

Bài 1: Giới thiệu về Elastic Search

Bài 2: Hướng dẫn cài đặt ElasticSearch + Kibana

Bài 3: Tạo index, tạo mapping, CRUD trong Elasticsearch

3.2. Chỉ nhận về kết quả tính toán

Mặc định, một truy vấn aggregation sẽ bao gồm cả kết quả tính toán và kết quả tìm kiếm (để trong trường hits). Nếu bạn muốn nhận về duy nhất chỉ kết quả tính toán, hãy đặt size bằng 0 trong truy vấn tìm kiếm.

GET index-01/_search
{
  "aggs": {
    "ages_range": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 16,
            "to": 19
          }
        ]
      }
    }
  },
  "size": 0
}

3.3. Chạy nhiều aggregations

Việc định nghĩa nhiều aggregation trong cùng một request là điều hoàn toàn có thể thực hiện được, dưới đây là một ví dụ:

GET index-01/_search
{
  "aggs": {
    "ages_range": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 16,
            "to": 19
          }
        ]
      }
    },
    "ages_avg": {
      "avg": {
        "field": "age"
      }
    }
  },
  "size": 0
}

3.4. Sub aggregations

Với các bucket aggregations, chúng ta có thể thực hiện các sub aggregation dạng bucket hoặc metrics trong các truy vấn đó. Không có một giới hạn cụ thể nào về độ sâu giới hạn hay bất kỳ sub nested-aggregations nào cả.

GET index-01/_search
{
  "aggs": {
    "ages_range": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 16,
            "to": 19
          }
        ]
      },
      "aggs": {
        "ages_avg": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
  },
  "size": 0
}

Kết

Aggregation trong Elasticsearch là một tính năng quan trọng cho việc phân tích và tóm tắt dữ liệu từ các tập hợp lớn. Đây là một công cụ mạnh mẽ giúp phân tích và trích xuất thông tin thống kê từ các dữ liệu đa dạng được lưu trữ trong Elasticsearch. Qua bài viết này, mong rằng các bạn sẽ có thêm nhiều kiến thức để áp dụng phép toán cực kỳ hữu ích này vào công việc của mình nhé.


Stringee Communication APIs là giải pháp cung cấp các tính năng giao tiếp như gọi thoại, gọi video, tin nhắn chat, SMS hay tổng đài CSKH cho phép tích hợp trực tiếp vào ứng dụng/website của doanh nghiệp nhanh chóng. Nhờ đó giúp tiết kiệm đến 80% thời gian và chi phí cho doanh nghiệp bởi thông thường nếu tự phát triển các tính năng này có thể mất từ 1 - 3 năm.

Bộ API giao tiếp của Stringee hiện đang được tin dùng bởi các doanh nghiệp ở mọi quy mô, lĩnh vực ngành nghề như TPBank, VOVBacsi24, VNDirect, Shinhan Finance, Ahamove, Logivan, Homedy,  Adavigo, bTaskee…

Quý bạn đọc quan tâm xin mời đăng ký NHẬN TƯ VẤN TẠI ĐÂY: