Search for a command to run...
본 챕터의 예제는 gymynnym/learn-pgroonga를 참고해주세요.
Mecab-ko 는 오픈소스 한국어 형태소 분식기입니다. Mecab(일본어 형태소 분석기)의 포크 프로젝트로, 한국어의 특성에 맞는 기능이 추가된 MeCab의 포크 프로젝트입니다.
$ echo "개발자커뮤니케이션보고서" | mecab
개발자 NNG,*,F,개발자,Compound,*,*,개발/NNG/행위+자/NNG/*
커뮤니케이션 NNG,행위,T,커뮤니케이션,*,*,*,*
보고서 NNG,*,F,보고서,Compound,*,*,보고/NNG/*+서/NNG/*
EOS
Mecab-ko는 위와 같이 문장을 형태소 단위로 분리하고, 각 형태소의 품사 정보를 함께 제공합니다. 이제 PGroonga에서 Mecab-ko를 사용하여 한국어 텍스트를 효과적으로 검색하는 방법을 알아보겠습니다.
Groonga는 토크나이저로 TokenMecab을 지원합니다. Groonga 빌드 시, DGRN_WITH_MECAB=ON 옵션을 전달하면 Mecab 기반 토크나이저를 사용할 수 있습니다.
이때 Mecab 본체와 사전은 별도로 설치해야 합니다. 일본어 텍스트를 처리하려면 일반적으로 Mecab과 IPA 사전을 설치하지만, 한국어 텍스트를 처리하려면 Mecab-ko와 Mecab-ko-dic를 설치해야 합니다.
PGroonga의 공식 도커 이미지에는 Mecab(일본어 형태소 분석기) 가 설치되어 있기에, 새로운 도커 이미지를 빌드해보겠습니다.
이 예제는 okamyuji/pgroonga 레포지토리의 포크입니다.
다음은 PGroonga와 Mecab-ko를 함께 사용하는 Dockerfile 예제입니다.
FROM postgres:18-alpine AS builder
ENV PGROONGA_VERSION=4.0.4 \
GROONGA_VERSION=15.2.0 \
MECAB_KO_VERSION=0.996-ko-0.9.2 \
MECAB_KO_DIC_VERSION=2.1.1-20180720
RUN apk add --no-cache \
apache-arrow-dev \
build-base \
clang19-dev \
cmake \
gettext-dev \
linux-headers \
llvm19 \
lz4-dev \
msgpack-c-dev \
postgresql-dev \
rapidjson-dev \
ruby \
samurai \
wget \
xsimd-dev \
xxhash-dev \
zlib-dev \
zstd-dev
COPY alpine/build.sh /
RUN chmod +x /build.sh && \
/build.sh ${PGROONGA_VERSION} ${GROONGA_VERSION} ${MECAB_KO_VERSION} ${MECAB_KO_DIC_VERSION}
FROM postgres:18-alpine
ENV PGROONGA_VERSION=4.0.4 \
GROONGA_VERSION=15.2.0 \
LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
RUN apk add --no-cache \
libarrow \
libgomp \
libxxhash \
msgpack-c \
zlib \
zstd
COPY --from=builder /usr/local/lib/libmecab* /usr/local/lib/
COPY --from=builder /usr/local/lib/libgroonga* /usr/local/lib/
COPY --from=builder /usr/local/lib/groonga /usr/local/lib/groonga
COPY --from=builder /usr/local/lib/postgresql/pgroonga* /usr/local/lib/postgresql/
COPY --from=builder /usr/local/lib/mecab /usr/local/lib/mecab
COPY --from=builder /usr/local/share/postgresql/extension/pgroonga* /usr/local/share/postgresql/extension/
COPY --from=builder /usr/local/bin/mecab* /usr/local/bin/
COPY --from=builder /usr/local/bin/groonga* /usr/local/bin/
COPY --from=builder /usr/local/bin/grn* /usr/local/bin/
COPY --from=builder /usr/local/etc/mecabrc /usr/local/etc/
build.sh 스크립트를 실행builder 스테이지에서 빌드된 바이너리와 라이브러리 복사(Mecab-ko, Groonga, PGroonga)#!/bin/sh
set -eux
PGROONGA_VERSION=$1
GROONGA_VERSION=$2
MECAB_KO_VERSION=$3
MECAB_KO_DIC_VERSION=$4
# Build and install MeCab-ko
cd /tmp
wget "https://bitbucket.org/eunjeon/mecab-ko/downloads/mecab-${MECAB_KO_VERSION}.tar.gz"
tar xf "mecab-${MECAB_KO_VERSION}.tar.gz"
cd "mecab-${MECAB_KO_VERSION}"
./configure --prefix=/usr/local --with-charset=utf8
make
make install
cd /tmp
rm -rf "mecab-${MECAB_KO_VERSION}" "mecab-${MECAB_KO_VERSION}.tar.gz"
# Build and install MeCab-ko dictionary
cd /tmp
wget "https://bitbucket.org/eunjeon/mecab-ko-dic/downloads/mecab-ko-dic-${MECAB_KO_DIC_VERSION}.tar.gz"
tar xf "mecab-ko-dic-${MECAB_KO_DIC_VERSION}.tar.gz"
cd "mecab-ko-dic-${MECAB_KO_DIC_VERSION}"
./configure --prefix=/usr/local --with-charset=utf8 --with-mecab-config=/usr/local/bin/mecab-config
make
make install
cd /tmp
rm -rf "mecab-ko-dic-${MECAB_KO_DIC_VERSION}" "mecab-ko-dic-${MECAB_KO_DIC_VERSION}.tar.gz"
# Build and install Groonga with MeCab support
cd /tmp
wget "https://packages.groonga.org/source/groonga/groonga-${GROONGA_VERSION}.tar.gz"
tar xf "groonga-${GROONGA_VERSION}.tar.gz"
cd "groonga-${GROONGA_VERSION}"
cmake \
-S . \
-B ../groonga.build \
--preset=release-maximum \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DGRN_WITH_MRUBY=OFF \
-DGRN_WITH_MECAB=ON
cmake --build ../groonga.build
cmake --install ../groonga.build
cd /tmp
rm -rf "groonga-${GROONGA_VERSION}" "groonga-${GROONGA_VERSION}.tar.gz" groonga.build
# Build and install PGroonga
cd /tmp
wget "https://packages.groonga.org/source/pgroonga/pgroonga-${PGROONGA_VERSION}.tar.gz"
tar xf "pgroonga-${PGROONGA_VERSION}.tar.gz"
cd "pgroonga-${PGROONGA_VERSION}"
make HAVE_MSGPACK=1 HAVE_XXHASH=1 \
PG_CPPFLAGS="-I/usr/local/include/groonga -DPGRN_VERSION='\"${PGROONGA_VERSION}\"'" \
SHLIB_LINK="-L/usr/local/lib -lgroonga"
make install
cd /tmp
rm -rf "pgroonga-${PGROONGA_VERSION}" "pgroonga-${PGROONGA_VERSION}.tar.gz"
$ docker build -t pgroonga-mecab-ko .
services:
...
pgroonga-mecab-ko:
container_name: pgroonga-mecab-ko
image: pgroonga-mecab-ko
shm_size: 128mb
env_file: .env.postgres
$ docker compose up -d
이제 위 Dockerfile을 빌드하고, 기존 예제와 비교하기 위해 docker-compose.yml 파일에 pgroonga-mecab-ko 서비스를 추가합니다.
$ docker exec -it pgroonga-mecab-ko sh -c 'echo "개발자커뮤니케이션보고서" | mecab'
개발자 NNG,*,F,개발자,Compound,*,*,개발/NNG/행위+자/NNG/*
커뮤니케이션 NNG,행위,T,커뮤니케이션,*,*,*,*
보고서 NNG,*,F,보고서,Compound,*,*,보고/NNG/*+서/NNG/*
EOS
정상적으로 Mecab-ko가 설치되었는지 확인합니다.
$ docker exec -it pgroonga-mecab-ko psql -U root
CREATE EXTENSION pgroonga;
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title TEXT,
content TEXT
);
CREATE INDEX articles_pgroonga_idx
ON public.articles USING pgroonga ((ARRAY [title, content]))
WITH (tokenizer='TokenMecab');
INSERT INTO articles (title, content) VALUES
('개발자커뮤니케이션보고서', '오늘 회의에서 API응답지연문제가 다시 논의되었습니다. 팀원들은 커피부족현상 때문에 집중력이 떨어졌다고 주장했습니다.'),
('서비스장애원인분석일지', '새벽에 발생한 DB커넥션폭주현상은 캐시미스연쇄작용 때문에 발생한 것으로 확인되었습니다. 담당자는 정신적피해보상요청서를 제출했습니다.'),
('개발자업무효율개선프로젝트', '개발환경자동화도구를 도입한 이후 빌드속도개선효과가 나타났습니다. 그러나 야근지수상승현상은 여전히 해결되지 않았습니다.');
위 쿼리에서 추가하는 데이터에는 띄어쓰기 처리가 되지 않은 한국어 텍스트가 포함되어 있습니다.
SELECT id, title FROM articles
WHERE ARRAY[title, content] &@~ '보고서';
-- id | title
-- ----+--------------------------
-- 1 | 개발자커뮤니케이션보고서
Mecab-ko 토크나이저는 "개발자커뮤니케이션보고서"를 "개발자", "커뮤니케이션", "보고서"로 분리합니다. 따라서, "보고서" 검색어로도 해당 레코드를 정확히 찾아낼 수 있습니다.
$ docker exec -it my-pgroonga sh -c 'echo "개발자커뮤니케이션보고서" | mecab'
개발자커뮤니케이션보고서 記号,一般,*,*,*,*,*
EOS
Mecab(일본어 형태소 분석기) 으로는 한국어 텍스트를 제대로 분리하지 못하는 모습이 나타납니다.
SELECT id, title FROM articles
WHERE ARRAY[title, content] &@~ '보고서';
-- id | title
-- ----+-------
-- (0 rows)
따라서 "보고서" 검색어로는 Mecab-ko가 찾아낸 레코드를 찾아낼 수 없습니다.