Tetrapod.js 는 변형된 욕설 단어 표현들을 파악하고 탐지하기 위해 개발 되고 있는 모듈형 프로그램입니다. 한국어에서 존재하는 욕설 단어들을 우선적으로 탐지 대상으로 정하여 개발되고 있으며, 향후 모든 언어에서 변형된 욕설 표현을 탐지하는데 사용될 수 있습니다.
현재 초기 개발 진행 중에 있는 프로젝트입니다.
대체로 분위기가 좋지 않으면, 언어 또한 그렇게 된다. (When the general atmosphere is bad, language must suffer)
인터넷 상에서 다수가 모여서 대화 중 분위기가 나빠지거나 사회 내 분위기가 나쁘게 되면, 이에따라 사람들이 사용하는 언어 또한 과격하게 되거나 욕설나 저속한 단어를 섞어 사용하는 사람들이 등장하게 됩니다. 이러한 상황의 근본적 원인은 사회적 문제일 수도, 개인적 문제일 수도 있습니다. 이러한 표현은 당사자의 감정을 담고 있으며 이를 본 사람들 또한 감정이 상하게 되는 경우가 생깁니다.
생각이 언어를 오염시킨다면, 언어 역시 생각을 오염시킬 수 있다. (If thought corrupts language, language can also corrupt thought.)
언어는 감정을 실을 수 있는 매개체로써, 어떠한 언어적 표현을 보고 기분이 나쁘게 만드는 것 뿐만 아니라, 어떠한 감정을 전달하기 위한 목적만을 위해서 사회적으로 개인 또는 집단에 의해서 모두가 사용하는 언어가 변형될 수 있습니다. 그렇게 언어에 담기는 감정에는 성적인 감정이 담길 수도, 폭력적인 감정이 담길 수도 있으며 그 유형은 매우 다양합니다.
한국어는 자음과 모음을 모아서 쓸 수 있는 모아쓰기가 가능한 점에서 기존 다른 언어권과는 다르게 어떠한 단어가 변형되어 생길 수 있는 파생단어의 수가 매우 많이 존재할 수 있으며, 이렇게 변형 & 파생된 욕설 단어를 기계적으로 탐지하기 매우 어려운 구조를 갖추고 있습니다.
자신이 쓰는 언어를 간결하게 한다면, 가장 어리석은 통설로부터 자유로워질 수 있다. 불필요한 관용어를 쓸 수 없으며, 어리석은 표현을 쓰면 그 어리석음이 스스로에게도 분명히 드러나 보이게 된다. (If you simplify your English, you are freed from the worst follies of orthodoxy. You cannot speak any of the necessary dialects, and when you make a stupid remark its stupidity will be obvious, even to yourself.)
이 프로젝트의 목표는 인터넷 상에서 범람하는 욕설이 무분별하게 퍼지는 것을 방지할 수 있는 어떠한 방파제와 같은 모듈을 개발하는 것입니다. 모듈이 많은 곳에서 사용되도록 하는 것을 목적으로 하기에 이 프로젝트의 저작권은 Copyleft 로 구성되며 상업적 비상업적 구분을 가리지 않고 어떠한 서비스든 무료로 자유로운 사용이 가능하게끔 하였습니다.
MIT Licensed
기존의 필터링은 문장 단위로 욕설 문자가 문자열 상에 존재하는지 만을 확인합니다. 가령 바보
라는 욕설를 차단하려 할때 이용자가 안녕 바보야
라는 메세지를 입력했다면, 바보
라는 문장이 존재하는 경우와 같이, 변형되지 않은 욕설이 존재하는 메시지에 한해서만 탐지가 가능합니다. 그러나 아래와 같은 변형에 대해서는 대처하지 못합니다.
- 문자 사이사이에 불규칙한 글자를 섞었을 때
안녕 바111보야
,안녕 바아아아보야
- 발음 상 또는 모양 상 유사한 표현으로 대체한 경우
안녕 빠아뽀오야!
,안녕 ba보야!
- 한글 받침 등 특수한 조합을 이용해 변형한 욕설의 경우
값삾핪닚닶
- 문자를 일부 뒤집어서 표현한경우
제발 좀 입 닥쳐!
=>제발 좀 입 쳐닥!
또한 욕설를 일부 포함하고 있지만 정상적으로 쓰일 수 있는 단어들이 존재하여 일부 표현을 오탐지할 확률을 높이기도 합니다.
- 한자 발음상 동일한 단어이나 뜻이 다른 표현이 일부 더해져 있는 경우
그 사건의 시발점은 A씨였다.
Tetrapod.js 은 이러한 욕설 탐지 알고리즘의 한계를 극복하기위해서, 정상단어를 먼저 찾아서 탐지 범위에서 배제한다음, 욕설 단어를 한 글자 씩 존재여부를 파악합니다. 또한 한국어 욕설을 수집하고 해당 욕설의 변형유형을 음운
, 음절
, 어절
3단계에 걸쳐서 가능한 모든 변형가능한 형태를 파악합니다.
Tetrapod.js 에서 사용하는 욕설 탐지 알고리즘의 구성은 다음과 같습니다.
시발점
과 같은 단어의 오탐지를 막기 위해서 사전에 문자열에서 찾아서 욕설 탐지시 탐지대상에서 제외시킬 용도의 정상단어 목록을 구성합니다.
- 여러 욕설 단어의 변형을 모두 파악하기 위해서,
음운
,음절
,어절
3단계에 걸쳐서 각 글자 요소들의 변형을 모두 파악하여서 욕설 단어 목록을 구성합니다. 해당 내용은 하단에 Bias 구성란 에서 자세히 설명합니다.
Tetrapod.js 에서 사용하는 욕설 탐지 알고리즘의 진행과정은 다음과 같습니다.
- 메시지에서 정상단어를 찾아서 해당 문자열의 시작 위치와 끝나는 위치를 기록합니다. 해당 문자열 범위는 이후 알고리즘 탐지시 범위에서 배제됩니다.
- 모든 문자열은 15자 단위의 청크 메시지 로 분리됩니다.
- 갖추고 있는 모든 욕설 문자를 글자단위로 모두 분리합니다. 그 후 청크 메시지에 해당 욕설 문자의 글자가 존재하는지, 몇번째 위치에 존재하는지를 파악합니다.
- 만약 문자들이 모두 존재할 경우 해당 문자들의 위치를 해당 욕설 단어의 글자순서대로 정렬합니다. 이때 만약 순서가 일관되지 않다면 글자가 섞여있는 것으로 간주합니다.
- 만약 글자가 섞여있는 경우 욕설 단어의 사이에 완성된 한글 문자가 존재하는지를 확인하고 존재한다면 이를 욕설 목록에서 제외합니다. (
ㄱ
,ㅙ
는 완성된 한글이 아니며 완성된 한글은 유니코드로가
(0xAC00) ~힣
(0xD7A3) 사이의 글자를 뜻합니다.) 또한 완성형 글자이더라도 자음이ㅇ
인경우에는 욕설 예외처리를 하지 않습니다.예: 바아아보오 와 같이 이어주는 음의 경우 욕설 처리가 필요합니다.
- 욕설 단어는 음운마다 발음이 약간씩 달라지거나 모양이 약간씩 달라지는 변형 단어가 파생될 수 있으므로, 각 음운별로 모든 변형 가능한 조합을 알아내야할 필요가 있습니다. 이를 명확하게 파악하기 위해서 모든 음운과 음절, 어절에 쓰일 수 있는 구조를 1차원 배열 또는 2차원 배열로 표현하여서 변형구조를 어절단계에서 파악할 수 있는 어떠한 데이터 구조가 필요합니다. 이를 위해서 개발된 데이터 구조가 Bias 데이터 포멧입니다.
- Bias 데이터 포멧은 필터에 사용될 욕설를 2차원 배열을 중첩해나가면서 조합될 단어의 목록을 구성할 수 있게 돕습니다. 2차원 배열은 before+after 구조로, 각 차원 데이터가 합쳐져서 단어를 구성하게 됩니다. 이를 RecursiveList 라고 하며 다음과 같은 예시형태로 구성될 수 있습니다.
let data = [[
"바",
"ba"
],[
"보",
"bo"
]]
let result = Bias.recursiveList(data)
let resultCheck = [
"바보",
"바bo",
"ba보",
"babo"
]
console.log(result == resultCheck)
// true
RecursiveList 로는 자음과 모음의 변형과정을 세분화해서 명시하는데 적합한 구조를 갖추고 있습니다. 하지만 자음 모음을 합성해서 완성된 한글문자로 합친다던지, 자음과 모음을 재활용할 수 있는 어떠한 구조는 RecursiveComponent 에서 다룹니다.
let data = [[
[[
'ㅂ',
'ㅃ'
],[
'ㅏ',
'ㅑ'
]],
"ba"
],[
"보",
"bo"
]]
let result = Bias.recursiveList(data)
let resultCheck = [
"ㅂㅏ보",
"ㅂㅑ보",
"ㅃㅏ보",
"ㅃㅑ보",
"ㅂㅏbo",
"ㅂㅑbo",
"ㅃㅏbo",
"ㅃㅑbo",
"ba보",
"babo"
]
console.log(result == resultCheck)
// true
RecursiveComponent 는 RecursiveList 의 재사용성을 높이고 배열 상에서 사용가능한 부가적인 함수개념을 제공합니다.
RecursiveComponent 는 변수
와 코드
가 존재하며, 자음과 모음 같이 한글문자의 최소 단위인 음운
을 RecursiveList 로 표현할 때 재활용성을 높이기 위해서 변수
를 사용하며, 해당 음운
들로 어떠한 최종적인 음절
을 구성할 때 코드
를 구성합니다.
RecursiveComponent 를 구성할 때 한국어의 경우 음운
, 음절
, 어절
의 형태로 구성될 수 있지만, 향후 개발 과정에서 새로운구조가 필요하거나, 차후 다른 언어에 확장형태로 다른 구조를 취해야할 가능성이 있기에, 보다 유연하게 데이터를 분리해야할 필요가 있습니다. 이를 위해서 JSON 형태로 데이터를 표현할 수 있게 허용하고 있으며, JSON 데이터는 해당 소스폴더 안에만 있다면 내부에 얼마나 중첩된 폴더아래에 JSON파일이 존재하던, 어떤 이름으로 폴더가 존재하던, 어떤 이름으로 JSON 파일이 존재하던 이를 모두 수집해서 구성할 수 있게끔 RecursiveComponent 를 구성하였고, 이를 통해서 자유롭게 데이터 명칭 부여를 하고 자유로운 데이터 카테고리 부여가 가능합니다.
JSON 에서 객체를 하나 생성후 그 안에 var
라는 이름의 객체를 하나 담으면, 그 var
객체 안에 변수를 생성할 수 있습니다. 한국어 데이터의 경우엔 이를 통해서 음운
데이터를 구성하며, 이 과정에서 한 음운
의 발음변형
과 모양변형
데이터를 RecursiveComponent 로 모두 구성합니다. 이렇게 구성된 ㅂ
의 음운 데이터화 예시는 다음과 같습니다.
{
"var": {
"ㅂ_발음변형": [
"ㅂ",
"ㅃ",
"ㅍ"
],
"ㅂ_모양변형": [
"ㅂ",
"ㅃ",
"ㅍ",
"b",
"f"
]
}
}
JSON 형태로 Bias 데이터를 구성할 때 변수를 구성할 수 있는데, 이 변수 내에서 다른 변수를 써야하는 상황이 생길 수 있습니다. 한국어는 주로 음절
데이터 구성시 음운
변수를 불러와야함과 동시에 자신도 변수여야하는 상황이 발생하는데, 이런 상황을 위해서 변수가 변수를 참조할 수 있도록 구성되어 있습니다. 변수는 RecursiveList 를 사용할때 요소 앞에 *
를 붙여서 사용하면 해당 위치에 변수 데이터가 참조됩니다. 음절
데이터 구성 시 자음과 모음을 합쳐서 완성된 한글 글자를 만들어야하는 경우가 생기는데, 이럴 때를 위한 자모합성
함수기능 또한 구현되어 있습니다. 자모를 합성해서 완성된 한글 글자를 만들지 않고 자모를 각각 분리된 글자처럼 취급하는 것은 단어병합
함수 라고 합니다. 기본적으로 RecursiveList 는 단어병합
알고리즘으로 작동되지만, 자모합성
과 차이를 명확하게 하기 위해서 함수명을 표기해서 구분할 수 있습니다.
{
"var": {
"시": [
{
"type": "단어병합",
"data": [[
"*ㅅ_모양변형"
], [
""
]]
},
{
"type": "자모합성",
"data": [
[
"ㅅ",
"ㅆ"
], [
"*ㅣ_발음변형"
]
],
"exclude": ["쇠"]
}
]
}
}
code
는 변수를 사용해서 최종적으로 정의될 데이터를 정의하는 공간입니다. 한글에서는 어절
을 정리할 때 사용됩니다. 최종적으로 산출된 결과물 중 배제하고 싶은 단어를 exclude
부분에 입력해주면 해당 단어는 결과물에서 삭제된채로 반환됩니다.
{
"code": [
{
"type": "단어병합",
"data": [[
"*바"
],[
"*보"
]],
"exclude": [
"babo"
]
}
]
}
- 단어병합 함수는 한글 글자 자모에 각각 한글자씩을 할당해서 병합하는 함수를 뜻합니다. (예: ㅂㅏㅂㅗ-> ㅂㅏㅂㅗ)
- 자음만으로 욕설가 될 수 있는 욕설의 경우엔 단어병합시 모음을 절대 추가로 표기하지 않습니다.
- 불필요한 모음을 추가하면 불필요한 용량증가와 처리속도 지연을 불러옵니다.
- 자모합성 함수는 한글 글자 자모를 최대한 한글자로 몰아서 병합하는 함수를 뜻합니다. (예: ㅂㅏㅂㅗ-> 바보)
ㅂㅗㅑ
와 같이 한글자로 합성될 수 없는 단어 합성을 절대적으로 피해야합니다.
현재 파악한 욕설 탐지 체계의 한계를 기록해놓습니다.
해당 프로젝트는 문맥을 이해하고 문맥상에서 어떠한 단어가 부적절한 의도로 사용되었는지, 표현의도
를 판단하지는 못합니다. 그러나 그러한 표현의도를 파악하고자하는 프로젝트를 누군가 진행하게 될 때에, 표현의도를 분석할 수 있는 참조 데이터가 될 수 있게끔 이 프로젝트를 통해서 데이터와 변형 구조를 파악하고자 합니다.
- 단어상 동음이의어로 표현 상 구별점이 존재하지 않는 경우
2016년 병신년(丙申年)에는 이러한 일이 있었습니다.
- 정상단어를 의도가 불순하게 사용하는 경우
너는 어머니가 없구나
- 욕설로 오해가능한 정상단어를 의도가 불순하게 사용하는 경우
너가 시발점이야 이 시발점아!
기본적으로 Tetrapod.js 는 명확하게 욕설로써 주로 사용되는 단어를 주 필터링 대상으로 사용합니다. 그렇기에 동음이의어 등으로 인해 오탐지율이 높을 수 있는 단어나, 명확한 욕설로 쓰이기 보단 일반적인 용도로 사용될 가능성이 많은 단어의 경우 탐지대상으로 포함시키지 않습니다.
그렇기에 Tetrapod.js 는 확장 패키지 개념을 제공합니다. 이는 Tetrapod.js 에 추가할 수 있는 필터링 대상 단어 모음 사전으로, Tetrapod.js 에서 제공하는 Bias 체계를 사용하여서 욕설이 아닌 폭력성 단어나, 음란성 단어 등 필터링 원하는 단어 사전을 자유롭게 구성할 수 있도록 돕습니다.
- 국립국어원에서의 한국어 정상 단어 목록 확보
- 인터넷 상에서 쓰이는 욕설 데이터 1차 수집
- 문자열 상에서 정상단어를 찾아서 모든 정상단어 위치를 파악하는 알고리즘
- 글자단위 욕설 단어 탐지 알고리즘
- 뒤집히거나 뒤섞인 욕설 단어 표현의 경우 사람이 인지 가능한 수준만을 욕설로 선정해서 차단하는 알고리즘 추가
- 욕설단어 만을 삭제하거나 특정 특수문자로 대치하는 표현 정정 함수
- 욕설 단어의 변형 예를
음운
,음절
,어절
3단계로 나누어서 정리해나갈 수 있는 분할된 JSON 기반 파일 데이터 병합 체계 - 배열형태로 단어를 전/후 값으로 나눠서 구성할 수 있는 Bias 데이터 포멧 (예: 바를
ㅂ/ㅏ
로 나누어서 표현할 수 있게 하는 체계를 뜻합니다.) - n차원 형태로 중첩시킬 수 있는 Bias 데이터 포멧 구성 (
바/보
라는 단어의 변형 예를 모두 구할때, 별도로 존재하는ㅂ/ㅏ
와ㅂ/ㅗ
데이터를 연결시켜서 구성시킬 수 있는 체계를 뜻합니다.) - n차원의 데이터를 병합할 수 있는 Bias 데이터 포멧
- Bias 데이터 포멧에서의 음절 변수
- Bias 데이터 포멧에서의 응용 함수
- Bias 데이터 포멧에서의 자모합성 함수
- Bias 데이터 포멧에서의 결과배제 함수
- Bias 데이터 포멧에서 테스트 중 중복생선된 단어 탐지 및 삭제 필터
- Bias 데이터 포멧의 단어 자동 변형 파악 개념 추가 (만능변형인자)
- 1차 수집된 욕설 데이터의 Bias 재해석
- Bias 데이터 포멧의 패키지 개념 추가 (욕설단어 / 성적단어 / 폭력성단어 / 약물성단어)
- LZString 을 통한 Bias 데이터의 minify 화 및 압축 추출 및 메모리 로드 체계
- 전체 욕설 단어 목록을 사전에 저장하는 형태가 아닌, 욕설 단어 탐지가 발생할때 해당 단어 목록을 실시간으로 구성하여서 쓰다가, 이를 메모리상에 LRU 캐싱 해놓고 씀으로 전체 데이터 용량을 줄이는 동적인 Bias 데이터 해석 체계
- 청크 메시지의 15자->30자 확대 및, 청크 메시지가 연속될 경우, 중간의 15자끼리 이어서 새로운 청크메시지를 임의로 만들어서 검사를 돌리는 보완체계 (청크 메시지 사이에 걸려서 필터링 되지 않는 예외 상황 해결)
- 청크 메시지에서 욕설 단어의 글자가 메시지 상에 있는지 확인할 때 중첩적으로 존재하는 글자가 존재하는 경우, 이를 모두 수집한 후 모든 경우수를 다 계산해서 욕설 검산하는 알고리즘 구현
- 검색엔진 기반 웹 크롤링을 통한 욕설 탐지시도 및 변형단어 수집시도
- 테스트 페이지 및 테스트 서버 구성
- gpu.js 쉐이더 기반의 GPU 병렬 연산 가속화 구현 (모든 청크메시지를 숫자 배열화 한 후 코어단에 이를 공유된 메모리 형태로 전달하고, 숫자 배열화 된 욕설 문자들을 코어에게 전달하면 이를 모든 코어 하나하나가 각각의 숫자배열 일치 유무를 파악하는 구조)