오늘은 간단하게 형태소 분석기 까지는 필요없는 자동완성 기능을 만들때 빠르게 만들 수 있는 방법을 해보려고 한다.
실제로 회사에도 적용한 방법이다 :)
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
'Spring' 카테고리의 다른 글
Kotlin Spring 에서 Required = false 대신 ?(nullable) 을 사용가능한 이유 (0) | 2022.03.17 |
---|---|
Hibernate 1 차 Cache 에 대해서 알아보자 (0) | 2022.03.10 |
Spring 에서 왜 Private Method 는 Cglib Proxy 에 포함이 되지않을까? (0) | 2022.02.22 |
Redisson 으로 분산 Lock 구현하기 (0) | 2022.02.10 |
[Spring Batch] Data 를 CSV 파일로 만들기 (0) | 2022.01.23 |