Ефективність фільтра профанації на Java


9

У мене є вимога відфільтрувати нецензурну лексику з подань користувачів у веб-додатку на базі Java. Клієнт знає як про проблему Сканторпа, так і про проблему клібутика і прийняв наслідки. Будь ласка, я не бажаю дебатів щодо достоїнства відсутності цензури.

Є два біти даних:

  1. Подання користувача, яке потенційно може містити 500 слів або близько того;
  2. Таблиця бази даних з одним стовпцем, що містить заборонені слова. У цій таблиці може бути багато тисяч записів.

Це рішення мені здається неправильним:

  1. Вся таблиця завантажується в статичну String [] при запуску в Singleton (таким чином залишаючись у пам'яті).
  2. Для кожного подання користувача ми переходимо через масив і робимо .indexOf (), щоб побачити, чи є якесь задане слово в рядку [] у поданні.
  3. Якщо це з'явиться, ми замінюємо символи стилю% $ # @%. Це робиться токенізацією подання користувача, прокручуванням всього подання користувача як лексеми (знову ж таки) та заміною кожного екземпляра знайденого слова.

У цьому рішенні може бути яскравість, але я скептично ставлюсь. І дивлячись на це деякий час, я не можу знайти свій шлях повз нього.

Питання в тому, що таке рішення, яке дасть хороші показники роботи та, сподіваємось, має бути достатньо розумним для майбутніх розробників, коли вони будуть звільнені за те, що я не відфільтрував якесь незрозуміле слово, про яке я ніколи не чув?


Ви кажете, що вам здається неправильним, не повідомляючи нам, чому ви вважаєте, що це неправильно. Тоді ви запитаєте про ефективне рішення, не повідомляючи нам, яким способом поточне рішення недостатньо. Скільки текстів за секунду ви отримуєте, скільки з них ви можете обробити?
користувач невідомий

Я вважав, що рішення було неправильним, перш за все тому, що база даних, в якій я працюю, неадекватна і неохайна. Враховуючи свою упередженість, я не довіряв власній недовірі. Я відчував, що думка інших буде корисною. Що для мене викликало тривогу: String [] (що, це 1999 рік?), Перебираючи дуже велику String [] замість набагато меншого набору даних, який подає користувач, вкладаючи цикл у цикл String [] з токенізованим поданням користувача тощо. Очікуване використання не визначене, ідеально елегантне рішення з розумною ефективністю було б прекрасним.
blueishgoldfish

2
"Розумна робота" може означати що завгодно. Якщо у вас немає конкретної мети, ви не можете знати, чи досягли ви її. Якщо ви прискорите процес, такий, що він в 100 разів швидший - це мета? Якщо користувач чекає 1 мс або 1/10? Користувач не отримає користі від вашої роботи.
користувач невідомий

Відповіді:


18

Єдиний спосіб зробити інтелектуальний фільтр слів - це використовувати звукову систему відповідності. Я написав дуже ефективний фільтр для нецензурної лексики для дуже популярної масово багатокористувацької онлайн-ігри для підлітків і підлітків кілька років тому на Яві.

Вона була заснована на досить зміненому Double Metaphone алгоритм , який був перероблений , щоб бути більш точним , а не за замовчуванням , який повинен відповідати , як багато речей , як це можливо. Це було настільки надзвичайно ефективно, оскільки він підбирав неправильні написання та фонетичні написання так само, як і фактичні слова. Я додав l33tговорити і txtговорити з алгоритмом MetaPhone, що робить його більше алгоритмом Triple / Quad Metaphone.

У ньому був попередній процесор, який стискав запущені літери і виявляв такі речі, як діти, які w o r d sскладають такі речі, як інтелектуальне стиснення букв разом та усунення запущених дублікатів, як-от wwoorrddss, він був дуже спеціалізований лише для англійської мови.

Це було досить швидко 8 років тому, щоб його використовувати в режимі чату в режимі реального часу без помітної затримки з десятками тисяч користувачів в одній основній системі процесора.

У нас був список слів, які Metaphone були закодовані в таблиці в базі даних, і він був завантажений в статичну карту, яка була на диво невеликою, і нам ніколи не довелося робити нічого особливого, щоб отримати доступ до списку заборонених слів, я зміг додати виявлення фрази з використанням одних і тих же методів майже безкоштовно.

Звичайно, у мене був журнал ведення всіх чатів від тисяч дітей, які намагалися зламати систему в режимі реального часу, тому у мене був досить вичерпний набір даних, з якими можна працювати. Так, як я робив журнал, коли хтось спрацьовував фільтр із позитивом, я записував кілька наступних повідомлень чату, які не запускали фільтр у них. Таким чином, якщо вони знайдуть шлях до певного слова чи фрази, я міг би адаптуйте мою систему і зрозумійте це. Я був досить кулезахисним лише через пару тижнів.


3
Таке рішення видається найкращим. Проблема полягає в тому, що мені довелося вирішити її вдень. Якщо буде достатньо часу, я або прийму подвійний підхід MetaPhone, або наймаю вас для цього. :-)
blueishgoldfish

Тож, мабуть, половина людей перестане грати зараз у гру: D
Давор Ждрало

2

Якщо ви хочете виконати відповідність ефективно, алгоритм Aho Corasick є досить хорошим варіантом (я впевнений, що ви можете знайти реалізацію Java, що пливе навколо).

Звичайно, ви, ймовірно, хочете попередньо обробити подання, щоб замінити орфографічні нерівності ('$' -> 's', '@' -> 'a', '| <' -> 'k' тощо)


Саме те, що я шукав, дякую! Ось реалізація Java: hkn.eecs.berkeley.edu/~dyoo/java
Remi Mélisson

0

Замість завантаження в статичну String [] використовуйте HashMap [] або інший тип двійкового дерева (якщо ви хочете покращити пошук), роблячи рядок вашим ключем у хеші. Розбийте рядок за пробілами та видаліть розділові знаки. Тоді ви можете запитувати HashMap для кожного слова в розділеному рядку; якщо хешмап повертається з ненульовим значенням, то ви знаєте, що у вас погане слово.

Тут не вдається проблема Clbuttic, коли хтось додає випадкових символів навколо поганого слова, наприклад. bhassda


Я думаю, що останній застереження - це те, що робить це рішення вкрай марним - немає жодного способу поширити його на що-небудь, крім цілих словосполучень.

Це справедлива заява; але стає важко зафіксувати все можливе, що може придумати людський розум, щоб ухилитися від фільтра нецензурної лексики. Ви завжди можете створити величезний регулярний вираз із операторами АБО, щоб об'єднати всі параметри, а потім зіставити регулярний вираз із вхідними. АБО ви можете зробити вибір із бази даних із "полем поганого слова" з бази даних з RLIKE проти введення. Повернення вказує на погане слово, а також поверне погане слово.

@Suroot не важко зафіксувати майже будь-яке слово чи фразу з фонетичною відповідністю, як це стосується мого питання. Абсолютні відповідники ніколи не спрацьовують та не змінюються, але фонетична відповідність працює приблизно в 100% часу, коли ви налаштовуєтесь, як це можливо.

-1

Використання фонічної системи не є єдиним рішенням будь-якими способами, але це може бути найпростішим, оскільки існує багато бібліотек з відкритим кодом, які роблять подібні речі.

Важка частина завжди буде частиною відповідності будь-якого алгоритму, і це здається, що ваша відповідність досить повільна і наївна. Ви не можете припустити, що indexOf буде відповідати правильно без якоїсь форми допоміжної перевірки.

Крім того, ви закінчите циклічно працювати протягом усього рядка N, де N - кількість слів у вашому чорному списку. Пропозиції використовувати Set або HashMap, безумовно, дещо покращать речі.

У більшості випадків алгоритм на основі лінійного стану найкращий і швидкий. Я написав рішення для Clean Speak, і він використовує цей тип алгоритму із системою відповідності фонічного попереднього процесу. Це єдине рішення, яке не ускладнилося, коли вкладаються нецензурні лексики (якщо foo - це ненормативна лексика, вкладення - foosucker) і змогло зберегти високий рівень продуктивності. Це також добре масштабує для інших мов без реалізації нових кодексів.

Нарешті, попередня обробка будь-якої форми - це взагалі чогось уникати. У більшості випадків ви можете робити те ж саме лінійним способом, як обробляти кожен із символів у рядку.

Звичайно, я пропоную переглянути інші рішення в довгостроковій перспективі, оскільки в більшості додатків обробка вмісту, створеного користувачем, є складнішим, ніж просто фільтрація нецензурної лексики. Часто ви хочете також фільтрувати особисту інформацію, таку як електронні листи та номери соціального страхування, а іноді й такі, як URL-адреси. Крім того, ми виявили, що більшості програм потрібна певна форма системи модерації та пошуку вмісту. Вони значно збільшують складність.


-2

Що ви хочете зробити у такому випадку, це визначити, який із двох списків слів є меншим. Скажімо, ваш список "багатослівних" містить 2000 слів, а максимальна кількість користувачів - 500 слів. У цьому випадку ви переймете список слів у поданні користувача та будете шукати їх одне за одним у списку заборонених слів і навпаки.

Інша зміна, яку я хотів би зробити, - це те, що ви не зберігаєте список заборонених слів у рядку [] - якщо ви шукаєте в масиві, ви отримали пошук O (n) за словом у поданні користувача. Це досить погано. Я б спробував розмістити структуру даних, яку ви шукаєте, у якийсь асоціативний контейнер або структуру дерева, що має кращу ефективність пошуку (log n замість n). Проблема тут полягає в тому, що якщо ви помістите подання користувача в цей контейнер, вам доведеться відслідковувати позицію слова, щоб ви могли або реконструювати вхід, або оновити рядок введення, якщо у вас є пошук.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.