[FILMEET] 금칙어 마스킹 개발기
[이동현님의 리뷰] : 이 영화 진짜 ***** 웃김
개요
FILMEET 프로젝트에서 고도화로 부정한 리뷰를 자동으로 탐지하고 금칙어를 마스킹하는 기능이 필요하다는 결론에 도달했습니다.
해당 기능의 목표는 리뷰 텍스트에서 금칙어를 실시간으로 탐지하여 빠르고 정확하게 마스킹 처리하는 것이었습니다.
설계 과정
금칙어 마스킹 기능을 구현하기 위해 다양한 방법을 검토했을 때, 크게 두 가지 방법이 있었습니다.
- 학습된 AI 모델을 사용한 API 서버 구축
- 기존에 학습된 자연어 처리 모델을 활용하여 부정적인 리뷰를 탐지
- 장점 : 기존 기술을 빠르고 정확하게 적용
- 단점 : 기능을 위한 서버가 하나 더 필요함, 실시간으로 적용하기에 느릴 수 있고, 비용이 발생
- 금칙어 목록 + 문자열 탐색 알고리즘
- 금칙어를 사전에 정의하고 문자열 탐색 알고리즘을 통해 탐지
- 장점 : 알고리즘 설계에 따른 성능 제어, 실시간 처리에 유리
- 단점 : 금칙어 사전을 수동으로 관리
위와 같은 장단점과 함께, 이미 학습된 모델을 사용하는 것보다 직접 알고리즘을 활용하는 것이 좋은 경험이 될 것이라고 생각했습니다.
이러한 고민으로 선택한 방법은 금칙어 목록 + 문자열 탐색 알고리즘이었습니다.
알고리즘 선택 과정
문자열 탐색 알고리즘을 직접 실행시켜서 성능을 비교한 블로그가 있어 참고한 내용을 참고했습니다.
벤치마크 환경
- 금지어 리스트를 .txt 에 저장하고 서버 메모리에 로딩 (10kb)
- 기준: 10KB input string + 500개 금지어 리스트
1. 정규 표현식
- 성능 : 14,260K ns/op
- 메모리 사용 : 4,321 B/op
- 할당 횟수 : 24 allocs/op
특징 : 패턴의 복잡성이 높아질수록, 특히 대용량 데이터를 처리할 때 성능이 급격히 저하됨
2. 단순 문자열 검사 (strings.Contains)
- 성능 : 1,066K ns/op
- 메모리 사용 : 322 B/op
- 할당 횟수 : 2 allocs/op
특징 : 메모리 사용량과 할당 횟수가 적음
3. 병렬 처리 문자열 검사 (goroutines)
- 성능 : 194,213K ns/op
- 메모리 사용 : 51,573 B/op
- 할당 횟수 : 1,072 allocs/op
strings.Contains를 금지어마다 goroutines 불러서(스레드 개념) 병렬 처리
특징 : 메모리 사용량이 가장 많음 (각 고루틴이 독립적인 스택 메모리를 사용)
위 3가지에 대한 그래프는 다음과 같습니다.
병렬 처리가 속도는 좋지만 메모리를 많이 사용했습니다. 3개의 방식 모두 부족한 부분이 있어서 적합하지 않았습니다.
4. 아호코라식
아호코라식 알고리즘은 여러 개의 패턴을 동시에 검색할 수 있는 효율적인 문자열 매칭 알고리즘입니다.
이 알고리즘의 주요 특징은 다음과 같습니다.
- 트라이 구조 사용: 모든 패턴을 트라이(trie) 자료구조에 저장합니다.
- 실패 링크: 매칭 실패 시 효율적으로 다음 상태로 전이할 수 있는 실패 링크를 구축합니다.
- 출력 링크: 각 상태에서 매칭되는 패턴을 빠르게 찾을 수 있는 출력 링크를 만듭니다.
- 선형 시간 복잡도: O(n + m + z) 시간 복잡도를 가집니다. 여기서 n은 텍스트 길이, m은 모든 패턴의 길이 합, z는 매칭 횟수입니다.
- 한 번의 탐색: 텍스트를 한 번만 탐색하여 모든 패턴을 찾을 수 있습니다.
아호코라식 알고리즘은 여러 패턴을 동시에 검색해야 하는 상황에서 매우 효율적이며, 검색 엔진, 바이러스 검사, 자연어 처리 등 다양한 분야에서 활용됩니다.
문자열 패턴 매칭에서 매우 빠른 속도를 보여주지만, 알고리즘 복잡도가 높습니다.
5. DAT (Double Array Trie)
Double array trie는 효율적인 문자열 검색을 위한 자료구조입니다. 이 구조는 두 개의 배열(base와 check)을 사용하여 trie를 구현합니다.
주요 특징:
- 공간 효율성: 일반적인 trie보다 메모리 사용이 효율적입니다.
- 빠른 검색: 문자열 검색 속도가 매우 빠릅니다.
- 구현: base 배열은 다음 상태로의 전이를 나타내고, check 배열은 유효한 전이인지 확인합니다.
- 응용: 자동완성, 사전 검색 등 문자열 관련 작업에 주로 사용됩니다.
- 삽입: 데이터 삽입 단계에서 재배치 작업으로 인해 Trie에 비해 속도가 느림
Double array trie는 공간과 시간 복잡도 면에서 효율적이지만, 구현이 복잡할 수 있다는 단점이 있습니다.
또한 일반 Trie에 비해 삽입 시 속도가 느릴 수 있지만, 금칙어 탐지 기능은 조회 작업이 대부분을 차지하며 삽입 작업은 상대적으로 적기 때문에, DAT의 삽입 성능 저하는 전체 시스템 성능에 미치는 영향이 미미하다고 판단하여 적용했습니다.
뛰어난 성능으로 널리 알려진 일대다 패턴매칭 알고리즘 아호코라식 알고리즘을 테스트 해보려고 했습니다.
또한, 아호코라식 알고리즘에서 필요한 Trie 구조에서 메모리 효율성과 검색 속도를 개선한 DAT를 적용하여 테스트한 결과는 아래와 같습니다.
앞선 자료들이 보여주는 정보를 통해서 성능이 가장 좋고, 나머지 지표들도 준수한 성능을 보여주는 DAT + 아호코라식 알고리즘을 채택하는 것을 결정했습니다.
하지만 DAT + Aho-Corasick은 알고리즘 구현 복잡도가 높기 때문에 GitHub에서 자바로 구현됐고 가장 높은 Star를 받은 라이브러리를 활용하여 구현했습니다.
AhoCorasickDoubleArrayTrie
사용한 라이브러리 링크
위와 같은 과정을 통해 기능을 구현했지만, 해당 기능을 고민하고 개발하는데 할애할 시간이 2일 밖에 주어지지 않았습니다.
그래서 아쉬움을 해결하기 위해서 예상되는 문제점과 해결 방안을 분석해 보았습니다.
문제점과 고민
FILMEET 프로젝트의 금칙어 마스킹 기능은 리뷰 텍스트에서 부정적인 표현을 탐지하고 마스킹 처리하는 데 초점을 맞췄습니다. 그러나 아래와 같은 문제점이 발생했습니다.
- 우회 문자 탐지 실패
- 공백 삽입, 특수문자 추가, 유사 문자 치환 등으로 금칙어 탐지가 어려웠습니다. 예를 들어,
금칙어를금!칙@어로 입력하면 탐지하지 못했습니다.
- 정규식 사용의 딜레마
- 우회 문자 처리를 위해 정규식을 사용하면 DAT + Aho-Corasick 알고리즘의 성능 최적화 효과가 감소할 가능성이 있었습니다.
- 사전 관리의 한계
- 우회 문자 변형을 모두 금칙어 사전에 등록하려면 관리가 복잡하고 사전 크기가 비효율적으로 증가할 우려가 있었습니다.
- 허용 단어 처리
- “여기 고르곤졸라가 졸라 맛있어요.” → “여기 고르곤**가 ** 맛있어요.”
- 아버지를 아버지라고 부를 수 없는 문제가 있었습니다. 😭
해결 사례
우아한형제들 기술 블로그에서는 금칙어 탐지와 관련된 우회 문자 및 허용 단어 문제를 해결하기 위해 다음과 같은 접근 방식을 제안했습니다.
1. 우회 문자 문제 해결
- 정규화된 문자열 생성
- 입력 문자열을 탐지 전에 정규화하여 공백, 특수문자, 유사 문자를 제거.
- 중복된 탐지 방지
- 정규화된 문자열에서 동일한 단어가 반복적으로 탐지되지 않도록 처리.
- 전처리와 탐지 알고리즘 결합
- 정규화된 문자열을 탐지 알고리즘에 전달하여 탐지 성능을 향상.
2. 허용 단어 문제 해결
- 허용 단어 목록의 Trie 자료형 구성
- 허용 단어 목록도 Trie 자료구조를 사용하여 금칙어 목록과 동일한 알고리즘(Aho-Corasick)을 적용.
- 이를 통해 탐지 로직을 재사용하며 성능과 개발 편의성을 모두 확보할 수 있음.
- 허용 단어 검증 단계 추가
- 금칙어 탐지 후, 탐지된 단어가 허용 단어 Trie에 포함되었는지 검증.
- 허용 단어와 금칙어 탐지 통합
- 금칙어 탐지 로직과 허용 단어 검증 로직을 통합하여 동일한 자료구조와 탐지 흐름을 활용.
- 탐지된 금칙어가 허용 단어 Trie에서 탐지될 경우, 마스킹을 생략.
개선된 로직
위 해결 사례를 통해 개선된 로직을 설계했습니다.
- 전처리 로직 추가
- 입력 문자열을 정규화하여 탐지 전에 공백, 특수 문자, 유사 문자를 제거.
- DAT + Aho-Corasick 알고리즘 활용
- 정규화된 문자열을 DAT 기반 Aho-Corasick 탐지 알고리즘에 전달하여 금칙어를 탐지.
- 허용 단어 Trie 검증
- 허용 단어 목록을 Trie 자료형으로 구성하여 금칙어와 동일한 탐지 알고리즘을 활용.
이를 통해 다음과 같은 효과를 기대할 수 있습니다.
개선 효과와 기대
- 탐지 정확도 향상
- 우회 문자 제거 및 허용 단어 검증으로 금칙어 탐지 정확도가 크게 향상됩니다.
- 허용 단어 문제 해결
- 허용 단어 검증 로직 추가로 정상적인 단어를 마스킹하지 않아 사용자 경험을 개선할 수 있습니다.
- 성능 유지 및 개발 편의성 향상
- 허용 단어 검증에도 금칙어 탐지와 동일한 자료구조와 알고리즘을 활용하여 성능을 유지하면서 개발 효율성을 높일 수 있습니다.
- 사전 관리 효율화
- 금칙어와 허용 단어를 각각 Trie로 관리하며, 확장성과 유지보수성을 강화할 수 있습니다.
- 확장 가능성
전처리 → 금칙어 탐지 → 허용 단어 검증 → 마스킹흐름을 통해 확장성과 모듈성을 확보할 수 있습니다.
읽어주셔서 감사합니다!