Java의 비속어 필터 성능


9

Java 기반 웹 응용 프로그램에서 사용자의 제출에서 비속어를 필터링해야합니다. 클라이언트는 Scunthorpe ProblemClbuttic Problem 을 모두 알고 있으며 그 결과를 받아 들였습니다. 검열이 없다는 장점에 대해서는 토론하고 싶지 않습니다.

두 비트의 데이터가 있습니다 :

  1. 잠재적으로 500 단어 정도를 포함 할 수있는 사용자의 제출;
  2. 허용되지 않는 단어가 포함 된 단일 열 데이터베이스 테이블입니다. 이 테이블에는 수천 개의 레코드가있을 수 있습니다.

현재 해결책이 나에게 잘못 된 것 같습니다.

  1. 전체 테이블은 시작할 때 정적 String []에 싱글 톤 (따라서 메모리에 상주)으로로드됩니다.
  2. 각 사용자 제출에 대해 배열을 반복하고 .indexOf ()를 수행하여 제출에 String []의 특정 단어가 나타나는지 확인합니다.
  3. 표시되면 % $ # @ % 스타일 문자로 바뀝니다. 이는 사용자 제출을 토큰 화하고 전체 사용자 제출을 토큰으로 반복 (루프)하고 찾은 단어의 각 인스턴스를 대체하여 수행됩니다.

이 솔루션에는 훌륭 할 수 있지만 회의적입니다. 그리고 그것을 잠시 동안 본 후에는 과거의 길을 찾을 수 없습니다.

질문은, 내가 들어 본 적이없는 모호한 단어를 걸러 내지 못해서 해고 된 후에도 미래의 개발자가 유지할 수있는 좋은 성능을 제공하고 합리적으로 제정 될 수있는 솔루션은 무엇입니까?


당신은 왜 그것이 잘못되었다고 생각하는지 말하지 않고 당신에게 잘못되었다고 말합니다. 그런 다음 현재 솔루션으로는 어떤 방식으로도 충분하지 않은 방식으로 성능 솔루션을 요구합니다. 초당 몇 개의 텍스트를 얻을 수 있습니까? 얼마나 많은 텍스트를 처리 할 수 ​​있습니까?
사용자가 알 수 없음

내가 일하고있는 코드베이스가 부적절하고 조잡했기 때문에 해결책이 잘못되었다고 생각했습니다. 내 편견을 감안할 때, 나는 내 자신의 불신을 믿지 않았다. 나는 다른 사람들의 의견이 유익 할 것이라고 생각했습니다. 나를 위해 알람을 설정 한 것은 String [] (무엇입니까, 1999 년입니까?)이며, 사용자가 제출하는 훨씬 작은 데이터 세트 대신 매우 큰 String []을 반복하고, String [] 루프 안에 루프를 중첩시킵니다. 토큰 화 된 사용자 제출 등이 있습니다. 예상되는 사용률은 지정되어 있지 않으며, 이상적인 성능을 갖춘 우아한 솔루션은 이상적입니다.
blueishgoldfish

2
'합리적인 성능'은 무엇이든 의미 할 수 있습니다. 구체적인 목표가 없다면 목표 달성 여부를 알 수 없습니다. 프로세스 속도를 높이면 프로세스가 100 배 빨라집니다. 이것이 목표입니까? 사용자가 1ms 또는 1 / 10s를 기다리는 경우? 사용자는 당신의 일로부터 이익을 얻지 못할 것입니다.
사용자가 알 수 없음

답변:


18

단어 필터를 지능적으로 수행하는 유일한 방법은 파닉 매칭 시스템을 사용하는 것입니다. 몇 년 전 자바에서 트윈과 십대를위한 매우 인기있는 대규모 멀티 플레이어 온라인 게임을위한 매우 효과적인 비속어 필터를 작성했습니다.

그것은 가능한 한 많은 것들과 일치하는 기본값 대신 보다 정확 하도록 수정 된 Double MetaPhone 알고리즘을 기반으로했습니다 . 실제 단어와 똑같은 철자 및 음성 철자를 선택했기 때문에 매우 효과적이었습니다. MetaPhone 알고리즘에도 말하기와 말하기를 추가 하여 Triple / Quad Metaphone 알고리즘에 더 가깝게 만들었습니다.l33ttxt

그것은 실행 문자를 압축하고 문자 w o r d s를 지능적으로 압축하고 같은 실행 중복을 제거하여 같은 것을 넣는 아이들과 같은 것을 감지하는 전처리기를 특징으로 wwoorrddss했습니다. 영어 전용으로 매우 전문적이었습니다.

단일 코어 CPU 시스템에서 수만 명의 사용자가 눈에 띄는 지연없이 8 시간 전에 실시간 채팅 시스템 스트림에서 사용하기에 충분히 빠릅니다.

우리는 데이터베이스의 테이블에 메타 폰으로 인코딩 된 단어 목록을 가지고 있었고 놀랍게도 작은 정적 맵에로드되었으며 금지 된 단어 목록에 액세스하기 위해 특별한 작업을 수행 할 필요가 없었습니다. 거의 무료로 동일한 기술을 사용하여 구문 탐지.

물론 실시간으로 시스템을 중단하려는 수천 명의 아이들의 채팅 내용이 모두 기록되어있어서 포괄적 인 데이터 집합을 사용할 수있었습니다. 내가 로깅을 한 방법은 누군가가 긍정적으로 필터를 트리거했을 때 필터를 트리거 하지 않은 다음 몇 가지 채팅 메시지를 기록했습니다. 그러면 특정 단어 또는 문구 주위에서 길을 찾은 경우 내 시스템을 적응시키고 그것을 잡아라. 몇 주만에 방탄이되었습니다.


3
이 솔루션이 가장 좋습니다. 문제는 오후에 문제를 해결해야한다는 것입니다. 시간이 충분하면 Double MetaPhone 방식을 사용하거나 고용 할 것입니다. :-)
blueishgoldfish

그래서, 절반의 사람들이 지금 게임을 중단 할 것 같습니다 : D
Davor Ždralo

2

매칭을 효율적으로 수행하려면 Aho Corasick 알고리즘이 매우 좋은 옵션입니다 (Java 구현이 떠 다니는 것을 확신합니다).

물론 철자 불규칙 ( '$'-> 's', '@'-> 'a', '| <'-> 'k'등)을 대체하기 위해 제출을 사전 처리하고 싶을 것입니다.


정확하게 내가 찾던 것, 감사합니다! Java 구현은 다음과 같습니다. hkn.eecs.berkeley.edu/~dyoo/java
Remi Mélisson

0

정적 String []에로드하는 대신 HashMap [] 또는 검색을 개선하려는 경우 다른 유형의 이진 트리를 사용하여 해시에서 문자열을 키로 만듭니다. 문자열을 공백으로 나누고 문장 부호를 제거하십시오. 그런 다음 문자열 분할의 각 단어에 대해 HashMap을 쿼리 할 수 ​​있습니다. 만약 해시 맵이 null이 아닌 상태로 돌아 오면 잘못된 단어가 있다는 것을 알게됩니다.

여기서 실패한 것은 누군가 나쁜 단어 ex 주위에 임의의 문자를 추가하는 Clbuttic 문제입니다. bhassda


마지막 경고는이 솔루션을 거의 쓸모 없게 만드는 것이라고 생각합니다. 단어 전체를 제외하고는 확장 할 수있는 방법이 없습니다.

그것은 공정한 진술입니다. 그러나 욕설 필터를 피하기 위해 인간의 마음이 떠 올릴 수있는 모든 것을 포착하는 것이 어려워집니다. 모든 옵션을 결합한 다음 정규식을 입력과 일치시키기 위해 항상 OR 문으로 거대한 정규식을 작성할 수 있습니다. 또는 입력에 대해 RLIKE를 사용하여 데이터베이스의 "잘못된 단어 필드"를 사용하여 데이터베이스에서 선택할 수 있습니다. 반환은 잘못된 단어를 나타내며 잘못된 단어도 반환합니다.

@ Suroot 내 질문에서 말하는 것과 같이 발음이 일치하는 단어 나 문구 만 캡처하는 것은 어렵지 않습니다. 절대 일치는 작동하지 않거나 크기가 조정되지 않지만 가능한 한 조정하면 발음 일치가 시간의 100 %에 가깝게 작동합니다.

-1

파닉스 시스템을 사용하는 것이 어떤 방법으로나 유일한 해결책은 아니지만, 그런 종류의 일을하는 오픈 소스 라이브러리가 많기 때문에 가장 간단 할 수 있습니다.

어려운 부분은 항상 알고리즘의 일치하는 부분이 될 것이며 일치하는 것이 느리고 순진한 것처럼 들립니다. 어떤 형태의 보조 검사없이 indexOf가 올바르게 일치한다고 가정 할 수 없습니다.

또한 전체 문자열을 N 번 반복합니다. 여기서 N은 블랙리스트의 단어 수입니다. Set 또는 HashMap을 사용하는 제안은 분명히 다소 향상 될 것입니다.

대부분의 경우 선형 상태 기반 알고리즘이 가장 좋고 빠릅니다. Clean Speak에 대한 솔루션을 작성했으며 전처리 파닉 매칭 시스템과 함께 이러한 유형의 알고리즘을 사용합니다. 이것은 욕설이 포함되어있을 때 (foo가 욕설이면 포함이 foosucker 임) 복잡하지 않은 유일한 솔루션이었으며 높은 수준의 성능을 유지할 수있었습니다. 또한 새로운 코덱을 구현하지 않고도 다른 언어에 맞게 확장 할 수 있습니다.

마지막으로, 모든 형태의 사전 처리는 일반적으로 피해야합니다. 대부분의 경우 문자열의 각 문자를 처리 할 때와 동일한 방식으로 선형으로 수행 할 수 있습니다.

물론 사용자 생성 콘텐츠를 처리하는 대부분의 응용 프로그램에서 욕설 필터링보다 더 복잡하기 때문에 장기적으로 다른 솔루션을 살펴 보는 것이 좋습니다. 이메일 및 주민등록번호와 같은 개인 정보 및 때로는 URL과 같은 개인 정보도 필터링하려고합니다. 또한 대부분의 응용 프로그램에는 일종의 중재 시스템 및 콘텐츠 검색이 필요하다는 것을 알았습니다. 이것은 복잡성을 상당히 증가시킵니다.


-2

이 경우에 당신이하고 싶은 것은 두 단어 목록 중 작은 단어를 결정하는 것입니다. "verboten"목록에 2000 단어가 있고 최대 사용자 제출이 500 단어라고 가정하십시오. 이 경우 사용자 제출에서 단어 목록을 반복하여 금지 단어 목록에서 하나씩 검색하고 그 반대로도 검색합니다.

다른 변경 사항은 String []에 금지 된 단어 목록을 유지하지 않는다는 것입니다. 배열에서 검색하면 사용자 제출에서 단어 당 O (n) 검색이 수행됩니다. 꽤 나쁘다. 조회하는 데이터 구조를 조회 성능이 더 좋은 일종의 연관 컨테이너 또는 트리 구조 (n 대신 log n)에 넣으려고합니다. 여기서 사용자가 제출 한 내용을이 컨테이너에 넣을 경우 단어 위치를 추적하여 입력을 재구성하거나 검색 히트가있는 경우 입력 문자열을 업데이트해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.