Elasticsearch Bài học 26: Bool Query - Xương sống của mọi câu query phức tạp (Must, Should, Must_not, Filter)
Trong thực tế làm backend cho các hệ thống như Hasaki hay kiểm soát luồng giao dịch, người dùng hiếm khi chỉ tìm kiếm với một điều kiện duy nhất. Họ sẽ đưa ra những yêu cầu kiểu: "Tìm tất cả sữa rửa mặt trị mụn, giá dưới 300k, thuộc hãng Cetaphil hoặc La Roche-Posay, nhưng tuyệt đối không lấy hàng sắp hết hạn".
Để giải quyết bài toán đa điều kiện này, Elasticsearch cung cấp Bool Query. Nó đóng vai trò là "chiếc hộp chứa" (Compound query), cho phép bạn nhét nhiều truy vấn lá (Leaf queries) vào bên trong và kết nối chúng bằng logic Toán học (Boolean Logic).
1. Cấu trúc tứ trụ của Bool Query
Bool Query được xây dựng dựa trên 4 mệnh đề cốt lõi. Mỗi mệnh đề nhận vào một mảng (array) các câu query con.
A. must (BẮT BUỘC CÓ - AND)
-
Logic: Tất cả các điều kiện nằm trong mảng
mustđều bắt buộc phải thỏa mãn (Giống hệt toán tửANDtrong SQL). -
Điểm số (Scoring): Các truy vấn trong
mustĐÓNG GÓP vào điểm Relevance Score. Càng khớp nhiều, điểm càng cao. -
Ví dụ: Sản phẩm phải chứa chữ "sữa rửa mặt".
B. filter (BẮT BUỘC CÓ - Nhưng KHÔNG TÍNH ĐIỂM)
-
Logic: Tương tự như
must, các điều kiện trongfilterbắt buộc phải thỏa mãn. -
Điểm số: KHÔNG đóng góp vào Relevance Score.
-
Sức mạnh vô địch: Vì không phải tính điểm phức tạp, kết quả của
filterđược Elasticsearch Cache (lưu vào bộ nhớ đệm) tự động. Nó chạy cực kỳ nhanh. -
Quy tắc ngầm: Nếu bạn đang lọc theo
keyword(Hãng, Mã SKU), hoặc số học (Giá tiền, Ngày tháng), HÃY LUÔN ĐẶT NÓ VÀOfilter, tuyệt đối không để ởmust.
C. should (NÊN CÓ - OR)
-
Logic: Đóng vai trò như toán tử
OR. -
Tương tác với Must/Filter: Nếu trong khối
boolCÓ chứamusthoặcfilter, thìshouldchỉ đóng vai trò "tăng điểm thưởng". Tức là Document không thỏa mãnshouldvẫn được trả về, nhưng nếu thỏa mãn thì nó sẽ được cộng thêm điểm để leo lên Top 1. -
Tương tác khi đứng một mình: Nếu trong khối
boolKHÔNG CÓmusthayfilter, thì Document bắt buộc phải thỏa mãn ít nhất 1 điều kiện trongshouldmới được trả về. (Có thể tinh chỉnh bằng tham sốminimum_should_match).
D. must_not (TUYỆT ĐỐI KHÔNG - NOT)
-
Logic: Các điều kiện trong này tuyệt đối không được xuất hiện (Giống
NOTtrong SQL). -
Điểm số: Nó được chạy trong Filter context, nghĩa là hoàn toàn không dính dáng đến tính toán điểm số (Scoring) và cũng được Cache cực nhanh.
2. Thực hành: Lắp ráp câu query E-commerce hoàn chỉnh
Bây giờ, hãy chuyển ngữ yêu cầu ở đầu bài toán thành một câu Query DSL chuẩn mực:
JSON
GET products/_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "sữa rửa mặt trị mụn" } }
],
"filter": [
{ "range": { "price": { "lt": 300000 } } },
{ "terms": { "brand.raw": ["Cetaphil", "La Roche-Posay"] } }
],
"should": [
{ "term": { "is_best_seller": true } } // Nếu là Best seller thì cộng thêm điểm
],
"must_not": [
{ "term": { "tags": "sắp hết hạn" } }
]
}
}
}
Cách Elasticsearch thực thi câu query này:
-
Bước 1 (Bộ lọc siêu tốc): Elasticsearch nhìn vào
filtervàmust_nottrước. Nó dùng cơ chế Inverted Index và Caching để loại bỏ hàng triệu Document sai hãng, sai giá, hoặc sắp hết hạn. Lúc này tập kết quả chỉ còn lại vài nghìn Document. -
Bước 2 (Chấm điểm): Nó lấy vài nghìn Document đó đưa qua khối
must. Nó chạy thuật toán tính điểm TF/IDF để xem sản phẩm nào khớp chữ "sữa rửa mặt trị mụn" nhiều nhất. -
Bước 3 (Thưởng điểm): Nó nhìn vào khối
should. Trong những sản phẩm đã lọt qua Bước 2, món nào có cờis_best_seller = truesẽ được cộng thêm một lượng điểm kha khá. -
Bước 4 (Trả kết quả): Sắp xếp danh sách theo điểm số từ cao xuống thấp và trả về Top 10 cho API của bạn.
3. Cạm bẫy thiết kế: Lồng ghép bool vô hạn
Vì bản thân bool là một câu query, bạn hoàn toàn có thể nhét một khối bool khác vào bên trong must, should, hoặc filter của nó.
Ví dụ: "Lọc sản phẩm Cetaphil giá < 300k HOẶC La Roche-Posay giá < 400k".
JSON
"query": {
"bool": {
"should": [
{
"bool": {
"filter": [
{ "term": { "brand.raw": "Cetaphil" } },
{ "range": { "price": { "lt": 300000 } } }
]
}
},
{
"bool": {
"filter": [
{ "term": { "brand.raw": "La Roche-Posay" } },
{ "range": { "price": { "lt": 400000 } } }
]
}
}
]
}
}
Việc lồng ghép (Nesting) này mang lại sức mạnh không giới hạn. Nhưng hãy cẩn thận! Với code backend (PHP/Golang), nếu bạn nối mảng không tốt, khối JSON sinh ra có thể sâu tới 10 tầng, làm cho Elasticsearch tốn quá nhiều CPU để "gỡ rối" (parse) logic và gây ra nghẽn cổ chai.
Tóm lại, bool query chính là "khung xương" để bạn xây dựng mọi tính năng tìm kiếm và lọc. Đã đến lúc chúng ta nhìn kỹ hơn vào cái gọi là Relevance Score (Điểm liên quan) mà nãy giờ chúng ta nhắc tới. Làm sao Elasticsearch biết sản phẩm A xứng đáng được 1.5 điểm, còn sản phẩm B chỉ được 0.8 điểm?
All rights reserved