ETC/MySQL

[mysql] fulltext index ngram parser

seokhyun2 2023. 4. 23. 16:36

개요

fulltext index에 대해서 정리를 한 번 했었는데(https://seokhyun2.tistory.com/92), fulltext index에서 토큰을 나누는 기본 방식은 띄어쓰기를 기준으로 분리를 합니다.

띄어쓰기를 기준으로만 분리를 하게 되면, 한국어에서는 조사가 다 붙어있어서 검색이 어렵습니다.

예를 들면 '한국'이란 명사에 대해서 '한국은', '한국에서', '한국의' 와 같이 조사가 붙어서 띄어쓰기로만 토큰을 나누게 되면 다 별도의 토큰으로 인식이 되어, '한국'이라는 명사가 있는 문장만 찾고 싶은데 찾을 수 없게 됩니다.

그래서 추가적으로 제공되는 기능이 바로 ngram parser입니다.

원리

ngram parser가 무엇인지, 원리를 알아볼텐데요.

ngram에서 n은 숫자이고, 기본적으로는 2로 세팅되어 있습니다.

2-gram은 문자를 2글자씩 잘라서 토큰으로 만들겠다는 뜻입니다.

그래서 기본적인 fulltext index는 띄어쓰기로 토큰을 나누는데 ngram을 사용하면 추가적으로 2글자씩 문자를 토큰을 나누어 사용합니다.

- 기본 방식: '마이클 잭슨' -> '마이클', '잭슨'

- 2-gram 방식: '마이클 잭슨' -> '마이', '이클', '잭슨

token을 나누고 나면 이제 token별로 문서 정보가 저장되는 구조는 동일하다고 생각하면 됩니다.

이것이 ngram parser의 원리입니다.

참고로 기본으로 2로 세팅되어 있지만, 설정을 변경해서 사용 할 수 있습니다.

사용법

먼저 ngram setting을 확인하는 쿼리는 아래와 같습니다.

show global variables like 'ngram_token_size'

기본적으론 2로 설정이 되어 있기 때문에, 2라는 값이 출력되는 것을 보실 수 있을겁니다.

 

그러면 이제는 실제로 어떻게 사용해야 하는지 알아보겠습니다.

우선, fulltext index에 ngram parser를 추가적으로 적용하여 생성하는 방법입니다.

생성 방법은 아래와 같이 3가지 방법이 있습니다.

# 테이블 생성 시 정의
CREATE TABLE 테이블이름(
  …,
  열이름 데이터형식,
  …,
  FULLTEXT INDEX 인덱스이름 (열이름) WITH PARSER 'ngram'
);

ngram을 사용하더라도 조회 쿼리는 동일하게 아래와 같이 match와 against라는 구문을 활용해야 합니다.

SELECT * FROM 테이블 WHERE MATCH(열이름) AGAINST('토큰');

아래는 실제 예시 쿼리입니다.

#테이블 생성
CREATE TABLE company(
	id int AUTO_INCREMENT PRIMARY KEY,
	name TEXT NOT NULL,
	FULLTEXT INDEX ft_idx_name (name) WITH PARSER `ngram`
);
# 데이터 생성
INSERT INTO company(name) VALUES ('삼성전기'), ('삼성전자'), ('삼성')
# 조회
SELECT * FROM company
WHERE MATCH(name) AGAINST('삼성전자')

 

위의 예시대로 실행을 하면 검색 단어인 '삼성전자'에 대해서 '삼성', '성전', '전자'로 나뉘어지고 세 개의 토큰 중 하나만 일치해도 결과에 포함이 되게 됩니다.

그래서, '삼성전자', '삼성전기', '삼성' 3개 모두 검색이 되는 결과를 받게 됩니다.

참고로 제일 많이 일치하는 '삼성전자'가 우선순위가 높게 정렬이 되어서 나오게 됩니다.

 

'삼성전자'가 정확하게 포함되는 경우에만 결과를 반환받고 싶을 수 있는데, 이 때는 검색할 때 아래와 같이 'IN BOOLEAN MODE'라는 옵션을 추가하면 됩니다.

SELECT * FROM company
WHERE MATCH(name) AGAINST('삼성전자' IN BOOLEAN MODE)

이제 이렇게 ngram parser까지 사용하면 엄청나게 느린 LIKE 문을 사용하지 않고도 복잡한 한국어에서 빠른 검색을 할 수 있게 됩니다.

 

'ETC > MySQL' 카테고리의 다른 글

[mysql] docker로 mysql 실행하기  (0) 2024.01.31
[mysql] fulltext index  (1) 2023.04.09