0

Giải mã giới hạn "10.000" kinh điển của Elasticsearch và cách phá vỡ nó với track_total_hits

Chào anh em!

Trong quá trình làm việc với các hệ thống dữ liệu lớn, Elasticsearch (ES) luôn là "vũ khí tối thượng" giúp chúng ta tìm kiếm hàng triệu bản ghi chỉ trong vài mili-giây. Thế nhưng, có một "cú lừa" ngầm định cực kỳ kinh điển mà rất nhiều lập trình viên Backend thường vấp phải khi làm tính năng phân trang (Pagination) hoặc hiển thị tổng số kết quả tìm kiếm: Con số 10.000 ma thuật.

Hôm nay, hãy cùng mổ xẻ xem giới hạn này là gì và tại sao chúng ta đôi khi phải "bật công tắc" để vô hiệu hóa nó nhé!

1. Vấn đề "10.000" mặc định của Elasticsearch là gì?

Khi bạn thực hiện một câu lệnh tìm kiếm (Search Query) trong Elasticsearch, kết quả trả về sẽ bao gồm một trường tên là hits.total, cho bạn biết có tổng cộng bao nhiêu bản ghi khớp với từ khóa hoặc điều kiện tìm kiếm của bạn.

Tuy nhiên, để tối ưu hóa hiệu năng và tiết kiệm bộ nhớ RAM khổng lồ cho hệ thống, Elasticsearch đặt ra một giới hạn (cap) mặc định là 10.000.

  • Nếu kết quả dưới 10.000: Elasticsearch sẽ đếm chính xác từng bản ghi và trả về con số thật cho bạn.
  • Nếu kết quả vượt quá 10.000: (Ví dụ: hệ thống có tới 50.000 đơn hàng thỏa mãn điều kiện lọc), Elasticsearch sẽ không dại gì đi đếm hết 50.000 bản ghi vì sẽ làm tốn tài nguyên CPU và RAM. Nó sẽ dừng đếm ngay lập tức và trả về một con số "tượng trưng" là 10000, kèm theo một cờ cảnh báo (relation: "gte" - lớn hơn hoặc bằng). Lúc này, bạn sẽ hoàn toàn mù tịt không biết thực tế có bao nhiêu kết quả khớp lệnh.

2. track_total_hits => true giải quyết việc gì?

Khi bạn gặp bài toán yêu cầu phải hiển thị chính xác tổng số kết quả (Ví dụ: "Tìm thấy 58.421 sản phẩm phù hợp" thay vì hiển thị một con số cụ thể bị chặn đứng ở 10.000), bạn cần phải can thiệp vào câu lệnh truy vấn.

Đó là lúc thuộc tính track_total_hits xuất hiện. Khi bạn cấu hình track_total_hits => true trong payload gửi lên Elasticsearch, bạn đang trực tiếp ra lệnh cho hệ thống:

"Hãy quên cái giới hạn 10.000 mặc định đi! Hãy đếm chính xác toàn bộ số lượng bản ghi khớp với điều kiện, dù cho nó là 50.000 hay 1.000.000 kết quả đi nữa."

Ngay lập tức, trường hits.total sẽ trả về con số chính xác tuyệt đối thay vì bị chặn lại ở con số 10.000 nữa.

3. Đánh đổi giữa "Chính xác" và "Hiệu năng" (Trade-off)

Biết cách phá vỡ giới hạn là tốt, nhưng với tư cách là một kỹ sư phần mềm, bạn cần phải hiểu cái giá phải trả khi bật track_total_hits => true:

  • Tốn tài nguyên hơn: Khi buộc Elasticsearch phải duyệt qua mọi shard và đếm chính xác số lượng bản ghi lớn, thời gian phản hồi (Latency) của câu lệnh query sẽ tăng lên, đồng thời ngốn nhiều bộ nhớ RAM hơn.

Cân nhắc theo bài toán thực tế:

  • Nếu đó là trang quản trị (Admin Dashboard) nơi người quản lý cần biết chính xác tổng số lượng đơn hàng hoặc người dùng để báo cáo, việc bật track_total_hits => true là hoàn toàn cần thiết.
  • Nếu đó là trang tìm kiếm công khai cho người dùng cuối (E-commerce search), việc hiển thị một con số xấp xỉ (ví dụ: "Hơn 10.000 kết quả") hoàn toàn chấp nhận được và giúp hệ thống giữ được tốc độ phản hồi cực nhanh.

Lời kết

Giới hạn 10.000 của Elasticsearch không phải là một lỗi (bug) mà là một tính năng tối ưu hóa có chủ đích của nhà thiết kế. Hiểu rõ bản chất của nó và biết cách sử dụng linh hoạt cờ track_total_hits sẽ giúp anh em làm chủ được bài toán hiệu năng, cân bằng hoàn hảo giữa trải nghiệm người dùng và tài nguyên hạ tầng hệ thống!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí