Menyusun pencarian kompleks: bool query dengan must, should, must_not, dan filter; boosting query, constant_score, dis_max; filter caching serta strategi memakai filter vs query untuk performa optimal.

Query dasar di episode 6 bagus untuk kasus sederhana, tapi dunia nyata jarang sesederhana itu: pengguna ingin "kaos polos, warna hitam, harga di bawah 100 ribu, merek tertentu, tapi bukan ukuran anak-anak". Query DSL solonya tidak cukup — kalian butuh query compound: menyusun beberapa query menjadi satu dengan logika boolean dan pengendali relevansi.
Episode 8 membahas query-query compound utama: bool dengan must, should, must_not, dan filter; boosting, constant_score, dan dis_max; plus strategi filter caching yang menentukan performa pencarian di production.
bool adalah query compound paling penting di Elasticsearch — ibarat WHERE + OR + NOT di SQL, tapi jauh lebih ekspresif. Ia memiliki empat klausa:
| Klausa | Perilaku | Skor relevansi |
|---|---|---|
must | Dokumen harus cocok (logika AND) | Dihitung |
should | Dokumen lebih baik cocok (logika OR) | Dihitung |
must_not | Dokumen tidak boleh cocok | Tidak dihitung |
filter | Dokumen harus cocok, hasil di-cache | Tidak dihitung |
{
"query": {
"bool": {
"must": [
{ "match": { "name": "kaos polos" } }
],
"should": [
{ "match": { "description": "bahan katun" } }
],
"must_not": [
{ "term": { "size.keyword": "kids" } }
],
"filter": [
{ "term": { "category.keyword": "fashion" } },
{ "range": { "price": { "lte": 100000 } } }
]
}
}
}Mari baca perlahan: dokumen harus mengandung kata "kaos polos" di nama, lebih relevan jika deskripsinya menyebut "bahan katun", tidak boleh bertipe kids, dan harus ber-kategori fashion dengan harga di bawah 100 ribu. Perhatikan should: tanpa must/filter, minimal satu should wajib cocok; dengan must/filter, should hanya menjadi bonus relevansi.
Klausa should meningkatkan skor dokumen yang cocok dengannya. Ini trik umum untuk mengatur prioritas: cari yang wajib cocok dengan must, lalu gunakan should untuk menaikkan dokumen yang paling relevan ke atas. Kalian bisa mengontrolnya lebih jauh dengan minimum_should_match jika perlu menuntut minimal jumlah klausa should yang cocok.
Ada kalanya kita tidak ingin mengecualikan dokumen, hanya menurunkan prioritas-nya. boosting terdiri dari positive (yang dicari, dengan boost) dan negative (yang dihukum, dengan negative_boost antara 0 dan 1):
{
"query": {
"boosting": {
"positive": {
"match": { "name": "kaos" }
},
"negative": {
"term": { "rating.keyword": "low" }
},
"negative_boost": 0.2
}
}
}Dokumen dengan rating "low" tetap muncul, tapi skornya dikalikan 0.2 — secara efektif tenggelam di bawah hasil lain.
constant_score membungkus query dan memberinya skor konstan — biasanya digabung dengan filter. Karena filter tidak menghitung skor, hasilnya memakai skor default yang bisa diatur dengan boost:
{
"query": {
"constant_score": {
"filter": {
"term": { "category.keyword": "fashion" }
},
"boost": 1.5
}
}
}Kapan memakainya? Saat kalian hanya butuh penyaringan tanpa peduli seberapa relevan — misalnya daftar produk dalam satu kategori yang di-sort berdasarkan harga, bukan skor. Hasilnya seragam dan cepat.
dis_max (disjunction max) menggabungkan beberapa query ke beberapa field, tapi mengambil skor tertinggi di antara mereka, bukan menjumlahkan. Ini ideal ketika kata yang sama bisa berada di field yang berbeda dan kalian tidak ingin skor "ganda" mendistorsi peringkat:
{
"query": {
"dis_max": {
"queries": [
{ "match": { "name": "kaos" } },
{ "match": { "brand": "kaos" } }
],
"tie_breaker": 0.3
}
}
}Jika sebuah dokumen cocok di name dan brand sekaligus, dis_max tidak menjumlahkan keduanya — ia mengambil yang tertinggi, lalu menambahkan tie_breaker (0–1) dikali skor kedua sebagai bonus kecil. Hasilnya peringkat lebih adil daripada bool must yang menjumlahkan skor.
Tip
Pilihannya: bool untuk logika AND/OR dengan kontrol penuh, dis_max untuk memilih field terbaik tanpa hukuman kecocokan ganda, constant_score untuk penyaringan murni. Sebagian besar production search memakai bool sebagai kerangka luarnya.
Inilah alasan utama filter di-cache: hasil query yang sama dijalankan berulang — misalnya filter kategori yang sama di setiap halaman — bisa di-cache di memori sehingga query berikutnya tidak perlu menghitung ulang. Query dengan skor tidak di-cache dengan cara ini. Di beban tinggi, memindahkan kriteria yang jarang berubah ke filter bisa menurunkan latensi pencarian secara drastis.
| Kriteria | Tempat yang Tepat |
|---|---|
| Kategori, status, harga, tanggal | filter — ya/tidak, di-cache |
| Pencarian teks bebas | must atau should — butuh skor |
| Pengecualian tanpa skor | must_not |
| Batasan yang wajib tapi tanpa memengaruhi skor | filter |
Aturan praktis: jika kriteria tidak mengubah peringkat relevansi, taruh di filter. Filter yang jarang berubah (kategori, rentang harga) memberi keuntungan cache terbesar; filter yang selalu berubah (misalnya filter berdasarkan lokasi pengguna yang dinamis) tidak akan dimanfaatkan cache sebaik itu.
Warning
Filter cache memakai memori JVM. Terlalu banyak filter yang berbeda-beda justru menekan cache dan memicu pressure — tanda bahwa filter terlalu "unik" untuk bermanfaat. Pantau lewat node stats filter_cache; kita bahas metrik ini di episode 21.
must untuk kriteria yang tidak perlu skor. Kategori dan harga di must memaksa perhitungan skor yang sia-sia — pindahkan ke filter.
must_not memakai match bukan term. Untuk field keyword, term lebih tepat; match menganalisis teks dan bisa menghasilkan kejutan.
Menaruh seluruh filter di query_string. Query string rawan error parsing; pecah menjadi bool terstruktur.
Terlalu banyak should tanpa minimum_should_match. Hasil bisa jadi terlalu longgar atau tidak terduga.
Boosting yang tidak proporsional. boost yang ekstrem membuat hasil tidak masuk akal — naikkan bertahap dan evaluasi.
Di episode 8 kalian menguasai query compound: bool dengan must, should, must_not, dan filter; boosting untuk menurunkan prioritas; constant_score untuk penyaringan berskor konstan; dis_max untuk memilih field terbaik; serta strategi filter caching dan kapan memakai filter vs query.
Inti yang harus dibawa pulang:
bool adalah kerangka utama query production — kuasai keempat klausanya.should memberi bonus relevansi saat must/filter sudah ada.filter di-cache dan tidak menghitung skor — tempatkan kriteria ya/tidak di sana.dis_max mengambil skor terbaik, cocok untuk kata yang bisa di beberapa field.Pencarian yang relevan saja tidak cukup — kalian juga ingin tahu gambaran datanya: berapa total penjualan, rata-rata harga per kategori, tren per bulan. Itu tugas aggregation. Di episode 9 kita bahas aggregations: metrics (sum, avg, stats, cardinality, percentiles), bucket (terms, histogram, date_histogram, nested), dan pipeline (moving average, derivative, cumulative sum, bucket sorting). Sampai jumpa!