Referensi

Contoh Query DSL Siap Pakai

Katalog contoh Query DSL Elasticsearch dan OpenSearch yang paling sering dipakai. Setiap contoh dilengkapi penjelasan singkat agar Anda paham kapan memakainya. Semua body JSON dikirim ke endpoint POST /<index>/_search.

Dasar Query DSL

Query DSL (Domain Specific Language) adalah struktur JSON untuk mendefinisikan pencarian. Secara garis besar ada dua konteks:

  • Query context — menjawab "seberapa cocok?" dan menghasilkan skor relevansi (_score).
  • Filter context — menjawab "cocok atau tidak?" tanpa skor, lebih cepat, dan dapat di-cache.

1. Full-Text: match, match_phrase, multi_match

match untuk pencarian full-text biasa, match_phrase bila urutan kata penting, multi_match untuk mencari di banyak field sekaligus.

# match — token dianalisis, default OR antar kata
{ "query": { "match": { "judul": "panduan elasticsearch" } } }

# match dengan operator AND (semua kata harus ada)
{ "query": { "match": { "judul": { "query": "panduan elasticsearch", "operator": "and" } } } }

# match_phrase — frasa berurutan persis
{ "query": { "match_phrase": { "isi": "tanpa downtime" } } }

# multi_match — cari di beberapa field, boost judul 3x
{ "query": { "multi_match": { "query": "shard", "fields": [ "judul^3", "isi" ] } } }

2. Exact: term, terms

Untuk pencocokan persis pada field keyword, angka, atau boolean. Jangan pakai term pada field text yang dianalisis.

# term — satu nilai persis
{ "query": { "term": { "status": "published" } } }

# terms — cocok bila nilai termasuk dalam daftar
{ "query": { "terms": { "kategori": [ "referensi", "panduan" ] } } }
Field text dianalisis (lowercase, dipecah). Untuk exact match buat sub-field keyword, lalu gunakan nama.keyword.

3. Rentang: range

Untuk angka dan tanggal. Mendukung gte, gt, lte, lt dan math tanggal seperti now-7d.

# Rentang angka
{ "query": { "range": { "harga": { "gte": 100000, "lte": 500000 } } } }

# Rentang tanggal: 7 hari terakhir
{ "query": { "range": { "waktu": { "gte": "now-7d/d", "lte": "now/d" } } } }

4. Gabungan: bool (must / should / must_not / filter)

Klausa bool menggabungkan beberapa kondisi. must & should memengaruhi skor; filter & must_not tidak.

{
  "query": {
    "bool": {
      "must":     [ { "match": { "isi": "elasticsearch" } } ],
      "should":   [ { "match": { "tag": "produksi" } } ],
      "must_not": [ { "term":  { "status": "draft" } } ],
      "filter": [
        { "term":  { "bahasa": "id" } },
        { "range": { "waktu": { "gte": "now-30d/d" } } }
      ],
      "minimum_should_match": 1
    }
  }
}
Pindahkan kondisi yang tidak butuh skor (status, kategori, rentang tanggal) ke filter agar query lebih cepat dan bisa di-cache.

5. Pola Teks: wildcard, prefix

Untuk pencocokan pola pada field keyword. Hati-hati: wildcard dengan * di awal bisa lambat.

# prefix — diawali "log"
{ "query": { "prefix": { "nama_index": "log" } } }

# wildcard — pola dengan * dan ?
{ "query": { "wildcard": { "host": "web-*-prod" } } }
Wildcard berawalan * (mis. *error) memaksa pemindaian penuh dan sangat lambat pada index besar. Hindari bila memungkinkan.

6. Keberadaan & Nested: exists, nested

exists menyaring dokumen yang punya nilai pada suatu field. nested mencari pada array objek yang dipetakan sebagai tipe nested.

# exists — hanya dokumen yang punya field "email"
{ "query": { "exists": { "field": "email" } } }

# nested — cari di array objek "komentar"
{
  "query": {
    "nested": {
      "path": "komentar",
      "query": {
        "bool": {
          "must": [
            { "match": { "komentar.teks": "bagus" } },
            { "range": { "komentar.rating": { "gte": 4 } } }
          ]
        }
      }
    }
  }
}

7. Aggregations Dasar

Agregasi merangkum data. Set size: 0 agar hanya hasil agregasi yang dikembalikan tanpa dokumen.

# terms — top kategori + rata-rata harga per kategori
{
  "size": 0,
  "aggs": {
    "per_kategori": {
      "terms": { "field": "kategori", "size": 10 },
      "aggs": {
        "harga_rata": { "avg": { "field": "harga" } }
      }
    }
  }
}

# date_histogram — jumlah dokumen per hari
{
  "size": 0,
  "aggs": {
    "per_hari": {
      "date_histogram": { "field": "waktu", "calendar_interval": "day" }
    }
  }
}

8. Urutan & Paginasi: sort, from/size, search_after

Atur urutan hasil dan telusuri data berhalaman. Untuk dataset besar gunakan search_after.

# sort + paginasi dangkal
{
  "from": 0,
  "size": 20,
  "sort": [ { "waktu": "desc" }, { "_id": "asc" } ],
  "query": { "match_all": {} }
}

# search_after — lanjut dari hasil terakhir halaman sebelumnya
{
  "size": 20,
  "sort": [ { "waktu": "desc" }, { "_id": "asc" } ],
  "search_after": [ 1718870400000, "doc-123" ],
  "query": { "match_all": {} }
}
Hindari from bernilai besar (mis. from: 10000). Elasticsearch harus memuat semua hasil sebelumnya di memori. Pakai search_after dengan sort yang unik (sertakan _id sebagai tiebreaker).

9. Highlight

Menyorot bagian teks yang cocok pada hasil pencarian.

{
  "query": { "match": { "isi": "downtime" } },
  "highlight": {
    "fields": {
      "isi": { "pre_tags": [ "<mark>" ], "post_tags": [ "</mark>" ] }
    }
  }
}

Tabel Ringkasan Klausa

KlausaKonteksPakai untuk
matchQuery (skor)Full-text pada field text.
match_phraseQuery (skor)Frasa berurutan persis.
multi_matchQuery (skor)Cari di beberapa field.
term / termsFilterExact match keyword/angka.
rangeFilterRentang angka / tanggal.
boolKeduanyaGabungan beberapa kondisi.
prefix / wildcardQueryPola teks pada keyword.
existsFilterField memiliki nilai.
nestedQueryArray objek tipe nested.
aggsRingkasan / statistik data.

Poin Penting

  • Pakai match untuk teks dan term untuk nilai persis.
  • Letakkan kondisi tanpa skor di filter agar cepat dan dapat di-cache.
  • Untuk data besar gunakan search_after, bukan from yang besar.
  • Set size: 0 saat hanya butuh hasil agregasi.

FAQ Query DSL

Apa perbedaan match dan term?

match menganalisis teks input (memecah jadi token, lowercase, dll) lalu mencari di field text — cocok untuk pencarian full-text. term mencari nilai persis tanpa analisis dan dipakai pada field keyword, angka, tanggal, atau boolean.

Kapan memakai filter dan kapan memakai must?

Gunakan filter bila Anda hanya butuh kecocokan ya/tidak tanpa skor relevansi — lebih cepat dan bisa di-cache. Gunakan must bila kecocokan harus memengaruhi skor relevansi (_score) hasil pencarian.

Bagaimana paginasi data dalam jumlah besar?

Untuk halaman dangkal pakai from/size. Untuk menelusuri ribuan hasil, hindari from besar karena boros memori — gunakan search_after dengan sort yang stabil, atau Point in Time (PIT) untuk konsistensi.

Apakah contoh ini berlaku di OpenSearch?

Ya. Query DSL dasar (match, term, bool, range, aggregations) identik antara Elasticsearch dan OpenSearch karena akar kode yang sama. Perbedaan hanya pada fitur lanjutan tertentu.

Uji Query Lebih Cepat

nusabet88 menyediakan editor query dengan validasi JSON dan tampilan hasil yang rapi. Tempel contoh di atas dan jalankan langsung.

Panduan Instalasi