Filter Context and Query Context
Đây là một trong những khái niệm quan trọng nhất để tối ưu hiệu năng Elasticsearch. Nếu bạn thấy một câu query chạy chậm, khả năng cao là do đang lạm dụng Query Context cho những điều kiện lẽ ra phải nằm trong Filter Context.
Dưới đây là sự khác biệt cốt lõi dưới góc độ của một Backend Engineer:
1. Bản chất: "How well?" vs. "Yes or No?"
Feature
Query Context
Filter Context
Câu hỏi
"Tài liệu này khớp với câu truy vấn tốt đến mức nào?"
"Tài liệu này có khớp hay không?"
Logic
Fuzzy / Scoring (Tính điểm)
Binary (Đúng / Sai)
Output
Trả về kết quả kèm theo điểm số _score (Relevance).
Trả về kết quả, _score được bỏ qua (thường là 0 hoặc hằng số).
Cache
Không Cache kết quả (vì điểm số thay đổi tùy ngữ cảnh).
Có Cache (Node Query Cache - LRU).
Use Case
Tìm kiếm Full-text (match, multi_match).
Lọc dữ liệu chính xác (term, range, ids, exists).
2. Deep Dive: Tại sao Filter lại nhanh hơn? (Bitsets & Caching)
Đây là phần "ăn tiền" về mặt kỹ thuật:
A. Cơ chế của Filter Context
Khi bạn thực hiện một Filter (ví dụ: status = "active"), Elasticsearch không so sánh từng dòng text. Thay vào đó, nó làm việc với Bitsets (mảng các bit 0 và 1).
Bitset Creation: Nó tạo một chuỗi bit đại diện cho toàn bộ index. Nếu Document 1, 3 khớp
status="active", bitset sẽ là[1, 0, 1, 0, ...].Bitwise Operations: Nếu bạn có nhiều filter (
status="active"ANDage > 25), ES chỉ đơn giản thực hiện phépANDgiữa hai chuỗi bit. CPU xử lý việc này cực nhanh (chỉ mất vài nano-seconds).Caching (Node Query Cache): Quan trọng nhất, chuỗi bit này được lưu vào RAM. Lần sau nếu có query nào (kể cả query khác) dùng lại điều kiện
status="active", ES sẽ lấy bitset từ Cache ra dùng ngay lập tức mà không cần truy cập ổ cứng.
B. Cơ chế của Query Context
Khi bạn dùng Query (ví dụ: match: "backend engineer"):
ES phải tìm các document chứa từ khóa.
Với mỗi document tìm được, nó phải chạy thuật toán BM25 (hoặc TF/IDF) để tính toán độ tương đồng (relevance score).
Công thức BM25 tốn CPU: Nó cần tính tần suất từ trong doc, độ dài doc, tần suất từ trong toàn bộ index...
Kết quả phải được sắp xếp (sort) theo điểm số
_scorecao xuống thấp trước khi trả về.
-> Kết luận: Query Context tốn CPU để tính toán điểm số và không thể cache kết quả vì điểm số phụ thuộc vào sự kết hợp của các từ khóa cụ thể.
3. Ví dụ thực tế (Bad vs. Good)
Giả sử bạn muốn tìm: "Các bài viết về 'Golang' được đăng năm 2024 có trạng thái là 'published'".
❌ Cách viết sai (Tất cả dồn vào Query Context)
Cách này ép ES phải tính điểm relevance cho cả năm 2024 và trạng thái published (điều này vô nghĩa vì năm thì chỉ có đúng/sai chứ không có "năm này đúng hơn năm kia").
JSON
✅ Cách viết chuẩn (Phân tách rõ ràng)
Chỉ tính điểm cho từ khóa "Golang". Các điều kiện lọc chính xác (năm, trạng thái) đẩy vào filter.
JSON
4. Quy tắc vàng (Rule of Thumb)
Khi viết Query DSL, hãy luôn tự hỏi:
"Tôi có quan tâm đến thứ tự xuất hiện của kết quả dựa trên điều kiện này không?"
CÓ (VD: Tìm từ khóa trong tiêu đề) -> Dùng
must(Query Context).KHÔNG (VD: Lọc theo Category, UserID, Date, Status, Price) -> Dùng
filter(Filter Context).
Last updated