Saya memiliki persyaratan untuk menyaring kata-kata kotor dari kiriman pengguna dalam aplikasi web berbasis Java. Klien menyadari Masalah Scunthorpe dan Masalah Clbuttic dan telah menerima konsekuensinya. Tolong, saya tidak ingin debat tentang kekurangan sensornya.
Ada dua bit data:
- Pengiriman pengguna, yang berpotensi mengandung 500 kata atau lebih;
- Tabel database satu kolom yang berisi kata-kata yang tidak diizinkan. Mungkin ada ribuan catatan dalam tabel ini.
Solusi saat ini tampaknya salah bagi saya:
- Seluruh tabel dimuat ke String statis [] pada startup ke Singleton (dengan demikian berada dalam memori).
- Untuk setiap pengiriman pengguna, kami mengulang-ulang array dan melakukan .indexOf () untuk melihat apakah ada kata yang diberikan dalam String [] muncul dalam pengiriman.
- Jika muncul, kami ganti dengan% $ # @% - karakter gaya. Ini dilakukan dengan tokenizing pengiriman pengguna, perulangan melalui seluruh pengiriman pengguna sebagai token (lagi), dan mengganti setiap instance dari kata yang ditemukan.
Mungkin ada kecemerlangan dalam solusi ini, tapi saya skeptis. Dan setelah melihatnya sebentar saya tidak dapat menemukan jalan saya melewatinya.
Pertanyaannya adalah, apa solusi yang akan memberikan kinerja yang baik dan semoga cukup masuk akal untuk dipelihara oleh pengembang di masa depan setelah saya dipecat karena gagal menyaring kata-kata tidak jelas yang belum pernah saya dengar?
Jawaban:
Satu-satunya cara untuk melakukan filter kata secara cerdas adalah dengan menggunakan sistem pencocokan phonik. Saya menulis filter kata-kata kotor yang sangat efektif untuk permainan online multi-pemain besar-besaran yang sangat populer untuk remaja dan remaja beberapa tahun yang lalu di Jawa.
Itu didasarkan pada algoritma Double MetaPhone yang sangat dimodifikasi yang di-tweak untuk lebih akurat daripada default yang sesuai dengan banyak hal sebanyak mungkin. Itu sangat sangat efektif karena mengambil salah ejaan dan ejaan fonetik sama seperti kata-kata yang sebenarnya. Saya menambahkan
l33t
berbicara dantxt
berbicara ke algoritma MetaPhone juga, menjadikannya lebih dari algoritma Triple / Quad Metaphone.Ini menampilkan pra-prosesor yang mengompresi surat-surat yang berjalan dan mendeteksi hal-hal seperti anak-anak menempatkan hal-hal seperti
w o r d s
dengan secara cerdas mengompresi surat-surat dan menghilangkan duplikat yang sedang berjalan sepertiwwoorrddss
, itu sangat khusus untuk bahasa Inggris saja.Itu cukup cepat 8 tahun yang lalu untuk digunakan dalam aliran sistem obrolan real-time tanpa latensi nyata dengan puluhan ribu pengguna pada sistem CPU single core.
Kami memiliki daftar kata-kata yang disandikan Metafon dalam tabel dalam database, dan itu dimuat ke dalam Peta statis yang mengejutkan kecil dan kami tidak pernah harus melakukan sesuatu yang khusus untuk mengakses daftar kata-kata yang dilarang, saya dapat menambahkan deteksi frase menggunakan teknik yang sama hampir gratis.
Tentu saja saya memiliki log yang sedang berjalan dari semua obrolan dari ribuan anak yang mencoba memecahkan sistem secara real time sehingga saya memiliki satu set data yang cukup komprehensif untuk dikerjakan. Cara saya melakukan pencatatan adalah ketika seseorang memicu filter dengan positif, saya mencatat beberapa pesan obrolan berikutnya yang tidak memicu filter dari mereka, seperti itu jika mereka menemukan jalan di sekitar kata atau frasa tertentu, saya bisa menyesuaikan sistem saya dan menangkapnya. Saya cukup bukti setelah beberapa minggu.
sumber
Jika Anda ingin melakukan pencocokan secara efisien, algoritma Aho Corasick adalah opsi yang cukup bagus (saya yakin Anda dapat menemukan implementasi Java yang beredar).
Tentu saja Anda mungkin ingin melakukan pra-proses pengiriman untuk mengganti penyimpangan ejaan ('$' -> 's', '@' -> 'a', '| <<->' k ', dll.)
sumber
Alih-alih memuat ke String statis [], gunakan HashMap [] atau jenis pohon biner lainnya (jika Anda ingin meningkatkan pencarian) menjadikan string sebagai kunci Anda dalam hash. Pisahkan String Anda dengan spasi dan hapus tanda baca. Kemudian Anda dapat meminta HashMap untuk setiap kata dalam string split Anda; jika hashmap kembali dengan non null maka Anda tahu Anda memiliki kata yang buruk.
Hal yang gagal di sini adalah masalah Clbuttic di mana seseorang menambahkan karakter acak di sekitar kata buruk ex.
bhassda
sumber
Menggunakan sistem phonic bukan satu-satunya solusi dengan cara apa pun, tetapi itu mungkin yang paling sederhana karena ada banyak perpustakaan open source yang melakukan hal semacam itu.
Bagian yang sulit selalu akan menjadi bagian yang cocok dari algoritma apa pun dan kedengarannya seperti pertandingan Anda sangat lambat dan naif. Anda tidak dapat mengasumsikan bahwa indexOf akan cocok dengan benar tanpa beberapa bentuk pemeriksaan tambahan.
Selain itu, Anda akan berakhir mengulang seluruh string N kali, di mana N adalah jumlah kata dalam daftar hitam Anda. Saran untuk menggunakan Set atau HashMap pasti akan sedikit memperbaiki keadaan.
Dalam kebanyakan kasus, algoritma berbasis keadaan linier adalah yang terbaik dan tercepat. Saya menulis solusi untuk Clean Speak dan menggunakan algoritme jenis ini dengan sistem pencocokan phonik pra-proses. Ini adalah satu-satunya solusi yang tidak menjadi rumit ketika kata-kata kotor tertanam (jika foo adalah kata-kata kotor, embedding adalah foosucker) dan mampu mempertahankan tingkat kinerja yang tinggi. Ini juga skala baik untuk bahasa lain tanpa implementasi codex baru.
Terakhir, pra-pemrosesan bentuk apa pun umumnya adalah sesuatu yang harus dihindari. Dalam kebanyakan kasus, Anda dapat melakukan hal yang sama dalam mode linier saat Anda menangani setiap karakter dalam string.
Tentu saja, saya sarankan melihat solusi lain dalam jangka panjang karena di sebagian besar aplikasi penanganan konten yang dibuat pengguna lebih kompleks daripada hanya penyaringan kata-kata kotor. Seringkali Anda ingin juga memfilter informasi pribadi seperti email dan nomor jaminan sosial dan kadang-kadang hal-hal seperti URL. Plus, kami telah menemukan bahwa sebagian besar aplikasi memerlukan beberapa bentuk sistem moderasi dan pencarian konten. Ini meningkatkan kompleksitas.
sumber
Apa yang ingin Anda lakukan dalam kasus seperti ini adalah menentukan mana dari dua daftar kata yang lebih kecil. Katakanlah daftar "verboten" Anda berisi 2000 kata dan pengiriman maksimum pengguna adalah 500 kata. Dalam hal ini, Anda akan mengulangi daftar kata-kata dalam pengiriman pengguna dan mencarinya satu per satu dalam daftar kata-kata terlarang dan sebaliknya.
Perubahan lain yang akan saya buat adalah bahwa Anda tidak menyimpan daftar kata-kata terlarang dalam String [] - jika Anda mencari dalam array, Anda mendapat pencarian O (n) per kata dalam pengiriman pengguna. Itu sangat buruk. Saya akan mencoba untuk menempatkan struktur data yang Anda cari ke dalam semacam wadah asosiatif atau struktur pohon yang memiliki kinerja pencarian yang lebih baik (log n bukannya n). Tantangannya di sini adalah bahwa jika Anda memasukkan kiriman pengguna ke dalam wadah ini, Anda harus melacak posisi kata sehingga Anda dapat merekonstruksi input atau memperbarui string input jika Anda memiliki hit pencarian.
sumber