Javaにおける冒とく的なフィルターのパフォーマンス


9

JavaベースのWebアプリケーションでユーザーの投稿から冒とく的な表現を除外する必要があります。クライアントはScunthorpe問題Clbuttic問題の両方を認識しており、その結果を受け入れています。どうか、検閲の欠如の利点についての議論を望まないでください。

2ビットのデータがあります。

  1. ユーザーの提出物。500語程度になる可能性があります。
  2. 許可されていない単語を含む単一列のデータベーステーブル。このテーブルには何千ものレコードがある場合があります。

現在の解決策は私には間違っているようです:

  1. 起動時に、テーブル全体が静的String []に読み込まれ、シングルトンに(したがって、メモリに常駐します)。
  2. ユーザーが送信するたびに、配列をループ処理し、.indexOf()を実行して、String []内の特定の単語が送信に表示されるかどうかを確認します。
  3. 表示される場合は、%$#@%スタイルの文字に置き換えます。これは、ユーザー送信をトークン化し、ユーザー送信全体をトークンとして(再度)ループし、見つかった単語の各インスタンスを置き換えることによって行われます。

このソリューションには輝きがあるかもしれませんが、私は懐疑的です。そして、しばらくそれを見たとき、私はそれを通り越す方法を見つけることができません。

質問は、私が聞いたことのないあいまいな単語を除外できなかったために解雇された後、将来の開発者が維持するために良いパフォーマンスを提供し、うまくいけば合理的に正気であるソリューションは何ですか?


あなたはそれがあなたがそれが間違っていると思う理由を私たちに言わずにあなたにそれが間違っているように見えると言います。次に、私たちに言わずに、現在の解決策では不十分なパフォーマンスの高い解決策を求めます。1秒間にいくつのテキストを取得できますか、それらのうちいくつ処理できますか?
不明なユーザー

主に私が作業しているコードベースが不十分でずさんであるため、解決策は間違っていると思いました。私の偏見を考えると、私は自分の不信を信用しませんでした。他人の意見が有益だと感じました。アラームを発しているのはString [](何、これは1999年か?)で、ユーザーが送信するはるかに小さなデータセットの代わりに非常に大きなString []をループし、String []ループ内にループをネストしました。トークン化されたユーザー送信など。期待される使用率は指定されていません。理想的には、妥当なパフォーマンスを備えたエレガントなソリューションが理想的です。
blueishgoldfish 2011

2
「リーズナブルなパフォーマンス」は何を意味することができます。具体的な目標がなければ、到達したかどうかわかりません。プロセスを100倍高速にする場合、これは目標ですか?ユーザーが1ミリ秒または1/10秒待機している場合 ユーザーはあなたの仕事の恩恵を受けません。
ユーザー不明。

回答:


18

単語フィルターをインテリジェントに行う唯一の方法は、フォニックマッチングシステムを使用することです。私は、数年前にJavaでトゥイーンとティーン向けの非常に人気のある大規模マルチプレイヤーオンラインゲーム用の非常に効果的な冒とくフィルターを書きました。

これは高度に変更されたDouble MetaPhoneアルゴリズムに基づいており、できるだけ多くのものに一致するデフォルトではなく、より正確になるように調整されています。実際の単語とまったく同じようにスペルミスや音声スペルを拾ったため、非常に効果的でした。MetaPhoneアルゴリズムにもl33t発言とtxt発言を追加し、トリプル/クワッドメタフォンアルゴリズムのようにしました。

これは、実行中の文字をw o r d s圧縮し、文字を一緒にインテリジェントに圧縮し、実行中の重複を排除することによって、子供が物を置くようなものを検出するプリプロセッサを備えていましたwwoorrddss。これは英語専用です。

シングルコアCPUシステムで何万人ものユーザーがいる場合でも、8年前には十分な速度でリアルタイムチャットシステムストリームで使用でき、顕著なレイテンシはありませんでした。

Metaphoneでエンコードされた単語のリストがデータベースのテーブルにあり、驚くほど小さい静的マップに読み込まれ、禁止された単語のリストにアクセスするために特別なことをする必要がなかったため、追加できました。ほぼ無料で同じテクニックを使用したフレーズ検出。

もちろん、私はリアルタイムでシステムを壊そうとしている何千人もの子供たちからのすべてのチャットの実行中のログを持っていたので、かなり広範囲のデータを処理する必要がありました。私がログを記録した方法は、誰かがポジティブでフィルターをトリガーしたときでした。フィルターをトリガーしなかった次のいくつかのチャットメッセージをログに記録しました。特定の単語またはフレーズを回避する方法を見つけた場合、私のシステムを適応させ、それをキャッチします。ほんの数週間後、私はかなり弾丸の証拠でした。


3
このソリューションが最善のようです。問題は(またはこの時点で)午後に解決しなければならないことです。十分な時間があれば、私はDouble MetaPhoneアプローチを採用するか、それを行うようにあなたを雇います。:-)
blueishgoldfish 2011

だから、私は半分の人が今ゲームをするのをやめると思います:D
DavorŽdralo11年

2

マッチングを効率的に行いたい場合は、Aho Corasickアルゴリズムがかなり良いオプションです(Java実装が見つかるはずです)。

もちろん、送信を前処理してスペルの不規則性を置き換える必要があるでしょう( '$'-> 's'、 '@'-> 'a'、 '| <'-> 'k'など)。


正確に私が探していたもの、ありがとう!Java実装は次のとおり
RemiMélisson2013

0

静的String []にロードする代わりに、HashMap []または他のタイプのバイナリツリー(検索を改善したい場合)を利用して、文字列をハッシュ内のキーにします。文字列をスペースで区切り、句読点を削除します。次に、文字列分割内の各単語についてHashMapをクエリできます。ハッシュマップがnull以外で戻ってきた場合は、悪い言葉を持っていることがわかります。

ここで失敗するのは、誰かが悪い単語exの周りにランダムな文字を追加するClbuttic問題です。 bhassda


私は最後の警告がこのソリューションをほとんど役に立たないものにしていると思います-全単語一致以外にそれを拡張する方法はありません。

それは公平な声明です。しかし、冒とく的なフィルターを回避するために人間の心が思いつく可能性のあるすべての可能性を捉えることは困難になります。すべてのオプションを組み合わせて、正規表現を入力と照合するORステートメントを使用して、巨大な正規表現を常に作成できます。または、入力に対してRLIKEを使用して、データベースからの「悪い単語フィールド」でデータベースから選択を行うことができます。Returnは悪い単語を示し、悪い単語も返します。

@Suroot私の質問が話しているように、音声マッチングを使用してほぼすべての単語またはフレーズをキャプチャすることは難しくありません。絶対一致は機能しませんし、スケーリングもしませんが、音声一致は、調整後、可能な限り100%近くの時間で機能します。

-1

フォニックシステムを使用することが唯一の解決策ではありませんが、そのようなことを行うオープンソースライブラリがたくさんあるので、最も簡単な方法かもしれません。

難しい部分は常にアルゴリズムのマッチング部分であり、あなたのマッチはかなり遅く素朴なようです。なんらかの形の補助チェックがなければ、indexOfが正しく一致するとは限りません。

さらに、文字列全体をN回ループすることになります。Nはブラックリストの単語数です。SetまたはHashMapを使用するための提案は、間違いなく多少改善するでしょう。

ほとんどの場合、線形状態ベースのアルゴリズムが最良かつ最速です。私はClean Speakのソリューションを作成し、このタイプのアルゴリズムを前処理のフォニックマッチングシステムで使用しています。これは、冒とく的な表現が埋め込まれているときに複雑にならない唯一のソリューションであり(fooが冒とく的な場合、埋め込みはfoosuckerです)、高いレベルのパフォーマンスを維持できました。また、新しいコーデックを実装することなく、他の言語にもうまく対応できます。

最後に、フォームの前処理は一般に回避すべきものです。ほとんどの場合、文字列の各文字を処理するのと同じように、直線的に同じことができます。

もちろん、ユーザー生成コンテンツを処理するほとんどのアプリケーションでは、冒とく的なフィルタリングよりも複雑であるため、長期的には他のソリューションを検討することをお勧めします。多くの場合、電子メールや社会保障番号などの個人情報や、URLのようなものもフィルタリングする必要があります。さらに、ほとんどのアプリケーションには何らかの形のモデレートシステムとコンテンツ検索が必要であることがわかりました。これらはかなり複雑になります。


-2

このような場合にしたいことは、2つの単語リストのどちらが小さいかを判断することです。「verboten」リストに2000ワードが含まれ、ユーザーの最大投稿数は500ワードであるとします。その場合は、ユーザー送信の単語のリストを反復処理し、禁止された単語のリストで1つずつ検索します。逆も同様です。

私が行うもう1つの変更は、禁止された単語のリストをString []に保持しないことです。配列を検索すると、ユーザー送信の単語ごとにO(n)検索が行われます。それはかなり悪いです。調べているデータ構造を、より良いルックアップパフォーマンスを持つある種の連想コンテナまたはツリー構造(nではなくlog n)に入れようと思います。ここでの課題は、ユーザーの送信をこのコンテナーに入れる場合、単語の位置を追跡して、入力を再構築するか、検索ヒットがあった場合に入力文字列を更新できるようにすることです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.