Skip to content

Mengapa "Artikel Populer" Tetap Menampilkan Item Lama

Adityo Guni Waluyo

Query sort=popular pakai view_count total bikin artikel lama selalu menang. Perbaikan: skor 7 hari rolling + tiebreak deterministik + random filler limit 9.

Ringkasan

KotaPortal punya masalah di artikel populer. Skor total bukan skor sekarang. Perbaikan pakai skor 7 hari rolling.

Masalah: Skor Total Bukan Skor Sekarang

Saat saya buka halaman publik KotaPortal minggu lalu, bagian "Artikel Populer" menampilkan item yang sama persis dari dua minggu lalu. Saya kira cuma masalah cache. Ternyata bukan — query sort=popular pakai view_count total sejak awal, jadi artikel lama dengan view tinggi selalu menang.

Perbaikan: Skor 7 Hari Rolling + Tiebreak Deterministik

Commit 40ade74 memperbaiki ini dengan dua hal: skor 7 hari rolling (entity_view_daily hari ini + 6 hari sebelumnya) + tiebreak deterministik (view_score → view_count → id). Untuk pengisi (filler) supaya tidak statis, tambah sort=random pakai ORDER BY RAND() limit 9.

Kenapa ORDER BY RAND() Aman Di Sini?

Karena limit kecil (9 baris). Vlad Mihalcea bilang ORDER BY RANDOM() lambat di result set besar, tapi OK di yang kecil [3]. StackOverflow punya pola JOIN (SELECT id ORDER BY RAND() LIMIT N) yang cepat karena sort cuma di kolom ID terindeks [2].

Implementasi & Performa

func publicOrderClause(sort string) (string, []any) {
    switch sort {
    case "popular":
        return `ORDER BY view_score DESC, view_count DESC, id ASC`, nil
    case "random":
        return `ORDER BY RAND()`, nil
    default:
        return `ORDER BY created_at DESC`, nil
    }
}

view_score dihitung dari entity_view_daily 7 hari — ini yang bikin artikel yang sedang dibaca naik, bukan yang dulu dibaca. Tiebreak view_count → id bikin urutan pasti, tidak acak tiap refresh.

MySQL bisa pakai index untuk ORDER BY kalau kolomnya cocok, jadi hindar filesort [1]. Kalau tabel entity_view_daily punya index (entity_id, date), query 7 hari ini cepat.

Test coverage: sort_clause_test.go (unit), popular_sort_test.go (integration), sort_passthrough_test.go (passthrough). Semua hijau.

Sumber

  1. MySQL ORDER BY Optimization — index usage avoids filesort
  2. StackOverflow: JOIN + ORDER BY RAND() on ID column only = fast on 200K rows
  3. Vlad Mihalcea: ORDER BY RANDOM() slow on large result sets, fine on small ones

Artikel terkait