9 poin oleh GN⁺ 2025-11-18 | Belum ada komentar. | Bagikan ke WhatsApp
  • Mengimplementasikan arsitektur mesin pencari yang berjalan tanpa layanan eksternal dengan memanfaatkan database yang sudah ada, berfokus pada tokenisasi, bobot, dan skoring
  • Ide intinya adalah men-tokenisasi semua teks lalu menyimpannya, kemudian saat pencarian mencocokkan token dengan cara yang sama untuk menghitung relevansi
  • Menggabungkan tokenizer Word, Prefix, dan N-Gram untuk menangani kecocokan tepat, kecocokan parsial, dan toleransi typo, dengan setiap tokenizer memiliki bobot unik
  • Melalui sistem bobot dan algoritme skoring berbasis SQL, sistem mengevaluasi panjang dokumen, keragaman token, kualitas rata-rata, dan faktor lainnya secara menyeluruh
  • Memiliki skalabilitas dan transparansi yang tinggi, sehingga penambahan tokenizer atau tipe dokumen baru, penyesuaian bobot, dan perubahan skoring dapat dilakukan dengan leluasa

Alasan membuat mesin pencari sendiri

  • Layanan eksternal seperti Elasticsearch atau Algolia memang kuat, tetapi ada beban mempelajari API yang kompleks dan mengelola infrastruktur
  • Jika yang dibutuhkan hanyalah fitur pencarian yang terintegrasi dengan database yang ada dan mudah di-debug, membangunnya sendiri bisa sangat berguna
  • Tujuannya adalah mesin pencari sederhana yang mengembalikan hasil relevan tanpa dependensi eksternal

Konsep inti: tokenisasi dan pencocokan

  • Prinsip dasarnya adalah men-tokenisasi semua teks dan menyimpannya, lalu saat pencarian menghasilkan token dengan cara yang sama untuk dicocokkan
  • Pada tahap indexing, konten dipecah menjadi unit token lalu disimpan bersama bobotnya
  • Pada tahap pencarian, kueri ditokenisasi dengan cara yang sama untuk menemukan token yang cocok dan menghitung skor
  • Pada tahap skoring, bobot yang tersimpan digunakan untuk menghasilkan skor relevansi

Desain skema database

  • Menggunakan dua tabel: index_tokens dan index_entries
    • index_tokens: menyimpan token unik dan bobot per tokenizer
    • index_entries: menghubungkan token dan dokumen, serta menyimpan skor akhir yang mencerminkan bobot field, dokumen, dan tokenizer
  • Rumus perhitungan bobot akhir:
    field_weight × tokenizer_weight × ceil(sqrt(token_length))
  • Indeks disiapkan untuk pencarian dokumen, pencarian token, kueri per field, dan pemfilteran bobot

Sistem tokenisasi

  • WordTokenizer: memisahkan berdasarkan kata, menghapus kata pendek, untuk kecocokan tepat (bobot 20)
  • PrefixTokenizer: membuat prefiks kata, untuk autocomplete dan kecocokan parsial (bobot 5)
  • NGramsTokenizer: membuat kombinasi karakter dengan panjang tetap, untuk menangani typo dan kecocokan parsial (bobot 1)
  • Semua tokenizer sama-sama melakukan konversi huruf kecil, penghapusan karakter khusus, dan normalisasi spasi

Sistem bobot

  • Bobot field: mencerminkan tingkat kepentingan seperti judul, isi, dan kata kunci
  • Bobot tokenizer: urutannya Word > Prefix > N-Gram
  • Bobot dokumen: dihitung dengan menggabungkan dua faktor di atas dan panjang token
  • Fungsi ceil(sqrt()) digunakan untuk mengurangi pengaruh token panjang, dan jika perlu dapat diubah ke fungsi logaritmik atau linear

Layanan indexing

  • Hanya dokumen yang mengimplementasikan IndexableDocumentInterface yang bisa diindeks
  • Saat dokumen dibuat atau diubah, indexing dijalankan melalui event listener atau perintah (app:index-document, app:reindex-documents)
  • Prosedurnya:
    • Menghapus indeks lama lalu membuat token baru
    • Menjalankan semua tokenizer untuk setiap field
    • Memeriksa keberadaan token lalu membuatnya jika belum ada (findOrCreateToken)
    • Melakukan batch insert ke index_entries dengan bobot yang sudah dihitung
  • Strukturnya dirancang untuk mencegah duplikasi, meningkatkan performa, dan menangani pembaruan

Layanan pencarian

  • Kueri diproses dengan tokenizer yang sama untuk mendapatkan set token yang identik dengan saat indexing
  • Token dideduplikasi lalu diurutkan berdasarkan panjangnya (token lebih panjang didahulukan), dengan batas maksimum 300 token
  • Melalui kueri SQL, token dan dokumen di-join, lalu skor relevansi dihitung dan diurutkan
  • Hasil dikembalikan dalam bentuk SearchResult(documentId, score)

Algoritme skoring

  • Skor dasar: SUM(sd.weight)
  • Koreksi keragaman token: LOG(1 + COUNT(DISTINCT token_id))
  • Koreksi bobot rata-rata: LOG(1 + AVG(weight))
  • Penalti panjang dokumen: 1 / (1 + LOG(1 + token_count))
  • Normalisasi: dibagi dengan skor maksimum agar berada dalam rentang 0~1
  • Melalui filter bobot token minimum (st2.weight >= ?), sistem menghapus kecocokan berbobot rendah yang tidak bermakna

Pemrosesan hasil

  • Hasil pencarian dikembalikan sebagai ID dokumen dan skor, lalu diubah menjadi dokumen aktual melalui repository
  • Dengan fungsi FIELD(), urutan hasil pencarian tetap dipertahankan saat mengambil dokumen

Skalabilitas sistem

  • Tokenizer baru dapat ditambahkan dengan mengimplementasikan TokenizerInterface
  • Tipe dokumen baru dapat didaftarkan dengan mengimplementasikan IndexableDocumentInterface
  • Logika bobot atau skoring dapat disesuaikan hanya dengan memodifikasi SQL

Kesimpulan

  • Struktur ini adalah mesin pencari sederhana tetapi benar-benar berfungsi, dan memberikan performa yang memadai tanpa infrastruktur eksternal
  • Keunggulannya adalah logika yang jelas, kontrol penuh, dan debugging yang mudah
  • Ini menekankan bahwa dibanding sistem yang kompleks, kode yang bisa dipahami dan dikendalikan langsung sering kali lebih berharga

Belum ada komentar.

Belum ada komentar.