textsearch-ja 모듈을 이용한 한글 full text search

들어가며
사전준비
세부분이 필요합니다.
mecab-ko
mecab 프로젝트의 한국어판이라는데, 뭘 고쳤는지는 모르겠지만, 이 프로그램을 설치합니다.$ git clone https://bitbucket.org/eunjeon/mecab-ko.git $ cd mecab-ko $ ./configure $ make all && make install
mecab-ko-dic
한국어 사전을 만듭니다. 이놈은 git clone으로 잘 안되네요.https://bitbucket.org/eunjeon/mecab-ko-dic/downloads
페이지의 마지막 파일을 다운로드하고 압축 풀고 설치합니다.
$ wget https://bitbucket.org/eunjeon/mecab-ko-dic/downloads/mecab-ko-dic-1.6.1-20140814.tar.gz $ tar xzf mecab-ko-dic-1.6.1-20140814.tar.gz $ cd mecab-ko-dic-1.6.1-20140814 $ ./configure $ make all && make install
형태소분석기 테스트
$ echo '설치가 완료되었습니다.' | mecab 설치 NNG,*,F,설치,*,*,*,*,* 가 JKS,*,F,가,*,*,*,*,* 완료 NNG,*,F,완료,*,*,*,*,* 되 XSV,*,F,되,*,*,*,*,* 었 EP,*,T,었,*,*,*,*,* 습니다 EF,*,F,습니다,*,*,*,*,* . SF,*,*,*,*,*,*,*,* EOS
잘 안되면 mecab-ko 프로젝트 작업자에게 연락하세요.
이제 이 프로그램을 textsearch-ja 모듈에 심는 작업을 진행합니다.
textsearch-ja
일단 설치.
$ wget http://pgfoundry.org/frs/download.php/2943/textsearch_ja-9.0.0.tar.gz $ tar xzf textsearch_ja-9.0.0.tar.gz $ cd textsearch_ja-9.0.0
해킹
이 모듈은 일본어 전용으로 만들어졌습니다.
최소한의 변경으로 한국어 지원을 가능하도록 이리 저리 소스를 살펴보고, 다음 정도만 고치면 충분히 한국어 환경에서 사용할 수 있겠더군요.
$ diff textsearch_ja.c textsearch_ko.c 39c39 < #define MECAB_BASIC 6 /* 基本形 */ --- > #define MECAB_BASIC 3 /* 基本形 */ $ diff encoding_utf8.c.orig encoding_utf8.c 453a454,479 > /* for korean */ > static const char JOSA_JKS[] = "JKS,"; > static const char JOSA_JKC[] = "JKC,"; > static const char JOSA_JKG[] = "JKG,"; > static const char JOSA_JKO[] = "JKO,"; > static const char JOSA_JKB[] = "JKB,"; > static const char JOSA_JKV[] = "JKV,"; > static const char JOSA_JKQ[] = "JKQ,"; > static const char JOSA_JX[] = "JX,"; > static const char JOSA_JC[] = "JC,"; > static const char KOSIGN_SF[] = "SF,"; > static const char KOSIGN_SE[] = "SE,"; > static const char KOSIGN_SSO[] = "SSO,"; > static const char KOSIGN_SSC[] = "SSC,"; > static const char KOSIGN_SC[] = "SC,"; > static const char KOSIGN_SY[] = "SY,"; > static const char KONN_NNB[] = "NNB,"; > static const char KONN_NP[] = "NP,"; > static const char KOIC[] = "IC,"; > static const char KOTAIL_EP[] = "EP,"; > static const char KOTAIL_EF[] = "EF,"; > static const char KOTAIL_EC[] = "EC,"; > static const char KOTAIL_ETN[] = "ETN,"; > static const char KOTAIL_ETM[] = "ETM,"; > > 456,463c482,512 < { lengthof(JOSHI), JOSHI }, /* 助詞 */ < { lengthof(JODOU), JODOU }, /* 助動詞 */ < { lengthof(KIGOU), KIGOU }, /* 記号 */ < { lengthof(BYWORD), BYWORD }, /* 名詞,代名詞 */ < { lengthof(INSUFF), INSUFF }, /* 名詞,非自立 */ < { lengthof(KANDO), KANDO }, /* 感動詞 */ < { lengthof(FILLER), FILLER }, /* フィラー */ < { lengthof(OTHERS), OTHERS }, /* その他 */ --- > // { lengthof(JOSHI), JOSHI }, /* 助詞 */ > // { lengthof(JODOU), JODOU }, /* 助動詞 */ > // { lengthof(KIGOU), KIGOU }, /* 記号 */ > // { lengthof(BYWORD), BYWORD }, /* 名詞,代名詞 */ > // { lengthof(INSUFF), INSUFF }, /* 名詞,非自立 */ > // { lengthof(KANDO), KANDO }, /* 感動詞 */ > // { lengthof(FILLER), FILLER }, /* フィラー */ > // { lengthof(OTHERS), OTHERS }, /* その他 */ > { lengthof(JOSA_JKS)-1, JOSA_JKS }, /* 조사들 */ > { lengthof(JOSA_JKC)-1, JOSA_JKC}, > { lengthof(JOSA_JKG)-1, JOSA_JKG}, > { lengthof(JOSA_JKO)-1, JOSA_JKO}, > { lengthof(JOSA_JKB)-1, JOSA_JKB}, > { lengthof(JOSA_JKV)-1, JOSA_JKV}, > { lengthof(JOSA_JKQ)-1, JOSA_JKQ}, > { lengthof(JOSA_JX)-1, JOSA_JX}, > { lengthof(JOSA_JC)-1, JOSA_JC}, > { lengthof(KOSIGN_SF)-1, KOSIGN_SF}, /* 기호들 */ > { lengthof(KOSIGN_SE)-1, KOSIGN_SE}, > { lengthof(KOSIGN_SSO)-1, KOSIGN_SSO}, > { lengthof(KOSIGN_SSC)-1, KOSIGN_SSC}, > { lengthof(KOSIGN_SC)-1, KOSIGN_SC}, > { lengthof(KOSIGN_SY)-1, KOSIGN_SY}, > { lengthof(KONN_NNB)-1, KONN_NNB}, /* 의존명사 */ > { lengthof(KONN_NP)-1, KONN_NP}, /* 대명사 */ > { lengthof(KOIC)-1, KOIC}, /* 감탄사 */ > { lengthof(KOTAIL_EP)-1, KOTAIL_EP}, /* 선어말어미 */ > { lengthof(KOTAIL_EF)-1, KOTAIL_EF}, /* 종결어미 */ > { lengthof(KOTAIL_EC)-1, KOTAIL_EC}, /* 연결어미 */ > { lengthof(KOTAIL_ETN)-1, KOTAIL_ETN}, /* 명사전성어미 */ > { lengthof(KOTAIL_ETM)-1, KOTAIL_ETM}, /* 관형사전성어미 */
두 개 파일만 수정하고, 모듈을 만듭니다.
$ make USE_PGXS=1 $ make USE_PGXS=1 install
이 작업은 알아서 잘 하세요.
테스트
모듈설치가 잘 끝났으면, 이제 이 모듈을 사용하는 함수와 textsearch 관련 환경 설정을 합니다.
다음은 install_textsearch_ko.sql 파일의 내용입니다.
이것을 실행하면 해당 데이터베이스에 한국어 full text search 기능을 사용할 수 있습니다.
CREATE FUNCTION ts_ja_start(internal, integer) RETURNS internal LANGUAGE c STRICT AS '$libdir/textsearch_ja', 'ts_ja_start'; CREATE FUNCTION ts_ja_gettoken(internal, internal, internal) RETURNS internal LANGUAGE c STRICT AS '$libdir/textsearch_ja', 'ts_ja_gettoken'; CREATE FUNCTION ts_ja_end(internal) RETURNS void LANGUAGE c STRICT AS '$libdir/textsearch_ja', 'ts_ja_end'; CREATE TEXT SEARCH PARSER pg_catalog.korean ( START = ts_ja_start, GETTOKEN = ts_ja_gettoken, END = ts_ja_end, HEADLINE = pg_catalog.prsd_headline, LEXTYPES = pg_catalog.prsd_lextype ); CREATE FUNCTION ts_ja_lexize(internal, internal, internal, internal) RETURNS internal LANGUAGE c STRICT AS '$libdir/textsearch_ja', 'ts_ja_lexize'; CREATE TEXT SEARCH TEMPLATE pg_catalog.mecab ( LEXIZE = ts_ja_lexize ); CREATE TEXT SEARCH DICTIONARY pg_catalog.korean_stem ( TEMPLATE = pg_catalog.mecab ); CREATE TEXT SEARCH CONFIGURATION pg_catalog.korean(PARSER = korean); ALTER TEXT SEARCH CONFIGURATION pg_catalog.korean ADD MAPPING FOR email, url, url_path, host, file, version, sfloat, float, int, uint, numword, hword_numpart, numhword WITH simple; ALTER TEXT SEARCH CONFIGURATION pg_catalog.korean ADD MAPPING FOR asciiword, hword_asciipart, asciihword WITH english_stem; ALTER TEXT SEARCH CONFIGURATION pg_catalog.korean ADD MAPPING FOR word, hword_part, hword WITH korean_stem; CREATE FUNCTION web_query(text) RETURNS text AS $$ SELECT regexp_replace(regexp_replace(regexp_replace($1, E'(^|\\s+)-', E'\\1!', 'g'), E'\\s+OR\\s+', '|', 'g'), E'\\s+', '&', 'g'); $$ LANGUAGE sql IMMUTABLE STRICT;
작업 최소화를 위해서 쓸 수 있는 것은 일본 것 그대로 사용했습니다.
이 작업이 다 끝나면, 이제 실재 쿼리를 실행해서 의도된 대로 작동 하는지 확인해봅니다.
$ psql psql (9.3.5) Type "help" for help. postgres=# select to_tsvector('korean','설치가 완료되었습니다'); to_tsvector -------------------------- '되':3 '설치':1 '완료':2 (1 row)
나머지는 http://postgresql.kr/docs/current/textsearch.html 페이지에서 설명하고 있는 그대로 하면 됩니다.
마무리
아무 생각 없이 막 작업을 하면서 기록을 남겨 놓으니, 글이 많이 어수선 하지만, 개인적으로는 지금까지 작업한 한글 형태소 분석 기반 처리 가운데 그나마 제일 깔끔했습니다.
이 모듈은 엄격하게 따지면, 일본 mecab 프로젝트에 기반을 두고 있는데, 이 프로젝트의 라이선스가 GPL, LGPL, BSD 온갖 라이선스를 다 쓰고 있다고 합니다. 구체적으로 어떻게 쓰고 있고, 실무에서 어떻게 영향을 주는지는 모르겠지만, 일단 KST 프로젝트의 GPL 보다는 좀 더 유연한 것은 확실 할 것 같습니다. 구체적인 라이선스 영향에 대해서는 저보다는 오픈소스 라이선스 전문가가 살펴보는 것이 좋을 것 같습니다.
작업을 마무리 하면서 한 가지 아쉬운 점이 있다면, 동사 활용에 있어 동사 원형을 사용하는 것과 제외 단어들의 설정이 없다는 것입니다. 이 부분에 대한 것은 관심 있는 분의 참여로 남겨두어야 할 것 같습니다. 또한 원래의 mecab 프로젝트와 협업하여, 한국어와 일본어를 아우르는 모습으로 바뀌어가면 더 좋겠죠.
공개 프로젝트로 전환 [소스보기]
2014-12-15
textsearch_ja 코드를 전부 읽고 함수명, 변수명, 주석 등을 모두 한국어 기반으로 다시 정리했습니다.처음에는 mecab-ko 프로젝트 쪽으로 요구사항을 전달했으나, 그쪽에서는 범용 라이브러리이기 때문에, 최대한 코드 변경을 안하겠다는 의견을 주어서, textsearch_ja 쪽에서 필요한 부분을 작업하기 시작했는데, 이도 textsearch_ja 쪽을 mecab 범용 형태소 분석기로 작업 하려고 했으나, 별 의미가 없어 아에 독립 프로젝트로 분리를 해버렸습니다.
이 작업을 github 공개 프로젝트로 준비했습니다.
뜻 있는 분의 많은 참여 바랍니다.