몇년 전에 파이썬의 konlpy 라이브러리를 이용해서 okt를 써보았던 적이 있다. konlpy는 한국어 정보처리를 위한 파이썬 패키지로, 여러 종류의 한국어 자연어 처리기를 쉽게 사용할 수 있도록 돕는다. 나는 이번에 okt를 스프링부트에서 사용하기 위해서 자바로 직접 사용해보았다.
1. gradle
인코딩을 utf-8로 설정한다.
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
그 후 dependencies에 다음을 추가한다.
implementation('org.openkoreantext:open-korean-text:2.1.0')
2. 분석코드
분석을 위해 작성한 클래스다.
analyseText 함수는 파라미터로 text와 선택할 품사태그배열을 받는다.
그 다음 정규화시킨 텍스트를 형태소 단위로 쪼갠다.
쪼갠 형태소는 모두 result라는 hashmap에 담아서 반환하는데, 이 때 key는 형태소, value는 카운팅횟수이다.
pickMorpheme 함수는 text를 받아서 다시 analyseText(text, {명사, 동사, 형용사}) 를 반환한다.
pickNouns 함수는 text를 받아서 다시 analyseText(text,{명사})를 반환한다.
@Component
public class MorphemeAnalyzer {
public Map<String, Integer> analyseText(String text, Enumeration.Value[] pos){
CharSequence normalized = OpenKoreanTextProcessorJava.normalize(text); //정규화
Seq<KoreanTokenizer.KoreanToken> tokens = OpenKoreanTextProcessorJava.tokenize(normalized); //토큰화
List<KoreanPhraseExtractor.KoreanPhrase> phrases = OpenKoreanTextProcessorJava.extractPhrases(tokens, true, false);
Map<String,Integer> result = new HashMap<>();
for (KoreanPhraseExtractor.KoreanPhrase phrase : phrases) {
Iterator<KoreanTokenizer.KoreanToken> iter = phrase.tokens().iterator();
int cnt = 0;
StringBuilder val = new StringBuilder();
while (iter.hasNext() && cnt < 2) {
KoreanTokenizer.KoreanToken token = iter.next();
for(Enumeration.Value p:pos){
if(token.pos().equals(p)){
val.append(token.text().trim()).append(' ');
break;
}
}
cnt++;
}
if(val.length() > 0) result.put(val.toString().trim(), result.getOrDefault(val.toString(),0)+1);
}
return result;
}
public Map<String, Integer> pickMorpheme(String text) {
return analyseText(text,new Enumeration.Value[]{KoreanPos.Noun(),KoreanPos.Verb(), KoreanPos.Adjective()});
}
public List<String> pickNouns(String text){
return new ArrayList<>(analyseText(text, new Enumeration.Value[]{KoreanPos.Noun()}).keySet());
}
}
예시
예를 들어,
1) "안녕하세욬ㅋㅋㅋㅋㅋ오늘도 공부중입니다. 바나나필통 귀엽다."라는 텍스트를 pickMorpheme의 파라미터로 넣어서 호출하면
2) 정규화 된 텍스트, 즉 normalized 변수에는 "안녕하세요ㅋㅋㅋ오늘도 공부중입니다. 바나나필통 귀엽다."가 저장된다.
3) phrases에는 다음이 저장된다. 바나나필통은 두 단어가 붙어있는 형태인데, okt에서는 두 단어가 붙어있을 때의 의미가 달라지는 경우도 파악하기 위해서 바나나필통은 바나나필통, 바나나, 필통 이렇게 세 가지 경우로 분류를 한다. 그런데 이때도 바나나필통으로 바로 분류하는 것이 아니라 그 안에서 tokens 리스트에 바나나, 필통 이라는 값을 저장해둔다.
4) 바나나필통이라는 phrase는 그 안의 tokens를 iterator로 불러서 반복하며 값을 저장한다. tokens에 바나나, 필통이 들어가있으니 두 번 반복한다. 띄어쓰기를 제대로 하지 않은 텍스트의 경우 이 tokens 길이가 무한대로 길어질 수 있다. 나는 이 함수를 검색할 때 사용하기 때문에 빠른 실행을 위해서 두 단어 조합까지만 보고 그 이후로는 끊어주었다.
5) iter.next는 파라미터로 받은 pos 중 하나와 품사태그가 일치해야 StringBuilder에 append시킨다.
6) iter를 전부 돌았거나 cnt >2(두 단어 조합 끝)이고, StringBuilder의 길이가 0보다 클 때만 result에 결과를 더해주었다. StringBuilder의 길이를 비교하는 이유는 pos에 해당하지 않는 형태소만 있을 경우를 대비하기 위해서다.
7) 결론적으로 result에는 마지막에 다음과 같이 저장된다.
'기록 > 그 외 프로젝트 기록' 카테고리의 다른 글
[Hadoop] Map Reduce를 위한 maven project 만들기 (0) | 2022.10.11 |
---|---|
[Hadoop] Map Reduce - timed out after 600secs (0) | 2022.09.28 |
[Hadoop] Python으로 wordcount하기(Hadoop Streaming) (0) | 2022.09.22 |
댓글