Rlog

MySQL 으로 형태소 분석기 없는 자동완성만들기 본문

Spring

MySQL 으로 형태소 분석기 없는 자동완성만들기

dev_roach 2022. 2. 24. 20:17
728x90

오늘은 간단하게 형태소 분석기 까지는 필요없는 자동완성 기능을 만들때 빠르게 만들 수 있는 방법을 해보려고 한다.

실제로 회사에도 적용한 방법이다 :)

Ngram-Parser 를 택한 이유

일단 MySQL 에 ngram parser 를 이용한 방법인데 ngram parser 를 선택한 이유는 아래와 같았다.

 

첫째, 자동완성으로 검색되야 할 데이터 들이 MySQL 에서 관리되야 할 대상들이였다. -> 사실 NoSQL 로 가져가면 대표적으로 ES 형태소 분석 parser 나 빠른 검색등이 가능하다고 알려져 있으나 내 조건은 위와 같았다.

 

두번째, 딱히 ES 를 이것만을 사용하자고 추가하기에는 자원의 낭비이다. -> 굳이 MySQL 로도 가능한데 얼마 차이 안나는 성능때문에? 의문이다. 그리고 ROW 수가 적기 때문도 있다 ㅎㅎ

 

세번째, 5.7 이상 버전을 이용 중인데 5.7 버전 부터 InnoDB 내장 인덱스로 ngram-parser 가 추가되었다. 

 

네번째, 가장 중요한데 사실 형태소 분석까지 필요한 비즈니스 요구사항이 아니였다. (형태소 분석이였다면 동전한닢 플러그인을 고려해봤을거 같기도 하다.)

 

따라서 위의 조건들로 인해 현재 상황에서는 지금 가지고 있는 자원들을 활용하며 구현할 수 있다고 생각했다.

구현

일단 간단하게 사용자의 이메일과 이름을 검색하는 로직을 만든다고 해보자.

일단 '정' 만 입력해도 '정승현' | '정찰대' | '김정태' .. 이런식으로 결과가 도출되어야 한다고 해보자.

혹은 이메일을 입력해도 'r' 을 입력했을때 'roach@baemin.com' | 'rroach@codesquade.com' 이런식으로 되야한다고 해보자.

 

일단 ngram_token_size 를 조절해보자.

쉽게 말해 ngram token 은 ngram 이 몇글자 단위로 인덱스를 구성할 것인지 라고 생각하면 편하다

따라서 우리는 한글자 단위로 인덱스 된 결과를 도출 할 것이므로 token_size 를 1 로 조정해야 한다.

cd /etc/mysql

vi my.cnf

mysql 설정을 조정하기 위해 설정 파일을 켜도록 하자.

위처럼 입력하면 된다.

ngram_token_size 파라미터는 static 파라미터 이므로 MySQL 을 Restart 해야 한다는 귀찮음이 있다. (실무에서 잘 생각해야 한다)

일단 껐다 켜보자.

SHOW VARIABLES LIKE 'ngram_token_size';

ngram_token_size 가 1 이 나온다면 잘 적용된 것이다.

 

이제 우리가 사용할 테이블을 만들어보자.

CREATE TABLE `users` (
	`id` INT(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,
	`email` VARCHAR(30) NOT NULL,
	`name` VARCHAR(20) NOT NULL
) ENGINE='innoDB';

CREATE FULLTEXT INDEX full_text_id_user_email_name ON users(email, name) with parser ngram;

이렇게 되면 정상적으로 생성된 것이다. 이제 데이터를 추가해보자.

위와 같이 대략적으로 11 건을 추가했다.

이제 쿼리를 날리는 방식에 대해 알아봐야 하는데 일단 MATCH ... AGAINST 이용해야 한다.

SELECT * FROM users WHERE match(email, name) AGAINST('ro');

근데 위와 같이 입력하면 'roach' 만 나와야 할거 같지만 결과가 아래와 같이 나온다 왜일까?

바로 AGAINST 안의 내용들을 OR 로 연결하고 있기 때문이다.

쉽게 설명 해서 지금 검색을 'r' OR 'o' 로 검색하고 있는 것이다. 

하지만 자동완성은 우리가 붙여 이어진것들에 대해서만 나오게 해야한다. 즉 'r' AND 'o' 로 검색되야 한다는 것이다.

위와 같은 요건 사항을 만족하기 위해서는 IN BOOLEAN MODE 를 이용하면 된다.

SELECT * FROM users WHERE match(email, name) AGAINST('ro' IN BOOLEAN MODE);

결과 또한 깔끔하다.

Spring Boot 에 붙이는 부분은 블로그에 까지 적기에는 너무 설명이 필요하지는 않은 부분이라 적지는 않겠다.

 

궁금하다면 아래 깃허브를 참조해도 좋다. 

https://github.com/tmdgusya/blog-auto-completion-example