Belajar Elasticsearch - Search Fundamentals - Query DSL Basics
Episode 6 of 31

Belajar Elasticsearch - Search Fundamentals - Query DSL Basics

Fondasi Query DSL: URI search vs request body, perbedaan query context dan filter context, filter _source, pagination dari/size dan search_after, serta query dasar: match, term, match_phrase, multi_match, query_string, exists, dan range.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Pendahuluan

Kalian sudah menyimpan data dengan mapping yang benar. Sekarang tibalah bagian paling menarik: mencari. Di episode ini kita menguasai dasar-dasar Query DSL — bahasa query JSON Elasticsearch — yang akan kalian pakai di hampir semua pekerjaan sehari-hari. Episode 6 membahas cara mengirim pencarian (URI search vs request body), konsep penting query context vs filter context, filter _source, pagination, dan tujuh query dasar: match, term, match_phrase, multi_match, query_string, exists, dan range. Semua contoh bisa langsung dicoba di Dev Tools Kibana atau dengan curl.

Search API Basics

Ada dua cara mengirim query. URI search — ringkas, semua parameter di URL:

URI search sederhana
GET /produk/_search?q=kaos
URI search dengan parameter
GET /produk/_search?q=name:kaos&size=5&from=10

Request body search — query DSL dikirim sebagai JSON di body, jauh lebih ekspresif dan menjadi cara utama di series ini:

Request body search
{
  "query": { "match": { "name": "kaos polos" } },
  "size": 5
}

URI search praktis untuk debugging cepat; request body adalah standar untuk aplikasi.

Query Context vs Filter Context

Ini konsep yang menentukan relevansi dan performa. Di query context, Elasticsearch menghitung skor relevansi (_score) berdasarkan seberapa baik dokumen cocok — dipakai untuk full-text search yang hasilnya perlu diurutkan berdasarkan kepentingan. Di filter context, dokumen hanya dinilai "cocok atau tidak" — tidak ada skor, tapi hasilnya di-cache sehingga sangat cepat dijalankan berulang.

Query context vs filter context
{
  "query": {
    "bool": {
      "must": { "match": { "name": "kaos" } },
      "filter": { "range": { "price": { "lte": 100000 } } }
    }
  }
}

Query match dihitung skornya; range hanya menjadi filter yang di-cache. Aturan praktis: gunakan query context untuk "seberapa mirip", filter context untuk "ya/tidak" — seperti kategori, harga, status.

Memfilter _source

Secara default respons membawa seluruh _source (dokumen asli). Untuk respons yang ringan, filter field yang dikembalikan:

Hanya kembalikan field name dan price
{ "_source": ["name", "price"], "query": { "match_all": {} } }

_source: false menonaktifkannya total. Ingat: filter _source hanya memengaruhi apa yang dikembalikan, bukan dokumen mana yang cocok.

Pagination: from/size dan search_after

from dan size adalah pagination standar — namun jangan digunakan untuk halaman dalam. Karena coordinating node harus mengumpulkan semua hasil sebelum di-sort, from: 10000 membuat query makin lambat dan dibatasi default index.max_result_window (10000). Untuk pagination dalam, pakai search_after lewat GET /produk/_search:

Halaman pertama dan halaman berikutnya
{
  "size": 10,
  "sort": [{ "price": "asc" }, { "_id": "asc" }],
  "query": { "match_all": {} }
}

Ambil nilai sort dari dokumen terakhir halaman pertama, lalu kirim sebagai search_after untuk halaman berikutnya:

Mengambil halaman berikutnya
{
  "size": 10,
  "sort": [{ "price": "asc" }, { "_id": "asc" }],
  "search_after": [45000, "product-42"]
}

search_after tanpa limit kedalaman — inilah cara yang benar untuk scroll data besar.

Query-Query Dasar

Match Query

match adalah query full-text utama. Ia menganalisis teks yang dicari (dipecah jadi token), lalu mencocokkan dengan index — default-nya OR antar token:

Match query: cocokkan kata apa pun
{
  "query": { "match": { "name": "kaos premium" } }
}

Term Query

term mencari nilai persis tanpa analisis — untuk field keyword. Ia tidak cocok dipakai pada field text (karena text sudah dipecah jadi token):

Term query untuk exact match
{
  "query": { "term": { "category.keyword": "fashion" } }
}

Match Phrase Query

match_phrase mencari urutan kata yang persis:

Match phrase: urutan kata harus cocok
{
  "query": { "match_phrase": { "name": "kaos polos" } }
}

Dokumen "kaos polos premium" cocok; "kaos premium polos" tidak (urutan beda).

Multi Match Query

multi_match mencari di beberapa field sekaligus — misalnya name, description, dan tags:

Cari di beberapa field dengan bobot berbeda
{
  "query": { "multi_match": { "query": "kaos murah", "fields": ["name^3", "description", "tags^2"] } }
}

Notasi ^3 memberi bobot: kecocokan di name dianggap tiga kali lebih relevan daripada di description.

Query String Query

query_string memakai sintaks Lucene penuh — mendukung +, -, wildcard, dan operator dalam satu string. Fleksibel tapi rawan error parsing dari input pengguna:

query_string dengan operator
GET /produk/_search?q=name:kaos+AND+price:<100000

Exists dan Range Queries

exists menemukan dokumen yang memiliki field tertentu (termasuk yang bukan null) — berguna untuk mendeteksi data tidak lengkap:

Exists: dokumen yang punya field discount
{
  "query": { "exists": { "field": "discount" } }
}

range bekerja untuk numerik, date, dan IP:

Range: harga dan rentang tanggal
{
  "query": { "range": { "price": { "gte": 50000, "lte": 200000 } } }
}

Operator yang tersedia: gt, gte, lt, lte, dan untuk date bisa memakai math seperti "now-30d".

Tip

Kebingungan paling umum pemula: term di field text tidak menghasilkan apa-apa. Ingat aturan emasnya — term untuk keyword, match untuk text. Jika ragu tipe fieldnya, cek dengan GET /index/_mapping/field/nama_field dan lihat tipe yang sesungguhnya.

Penutup

Di episode 6 kalian menguasai dasar-dasar Query DSL: URI search vs request body, konsep query context (dengan skor) vs filter context (di-cache), filter _source, pagination from/size dan search_after untuk data dalam, serta tujuh query inti — match, term, match_phrase, multi_match, query_string, exists, dan range.

Inti yang harus dibawa pulang:

  • Request body search adalah cara utama; URI search untuk debug cepat.
  • Filter context di-cache, query context menghitung _score.
  • term untuk keyword (exact), match untuk text (full-text).
  • match_phrase menuntut urutan kata yang sama.
  • search_after menggantikan from untuk pagination dalam.
  • range melayani numerik, date, dan IP.

Sekarang kalian bisa mencari, tapi pernahkah bertanya: bagaimana kata "kaos" bisa mencocokkan dokumen "KAOS" atau "kaos-kas"? Jawabannya ada di lapisan di bawah query. Di episode 7 kita bedah text analysis dan analyzers: karakter filter, tokenizer, token filter, analyzer bawaan, membuat custom analyzer, tes dengan _analyze API, normalizers, dan pola n-gram untuk autocomplete. Sampai jumpa!