전문 검색 인덱스
- 앞서 정리한 인덱스 알고리즘은 일반적으로 크지 않은 데이터 또는 이미 키워드화한 작은 값에 대한 인덱싱 알고리즘이다.
- MySQL의 B-Tree 인덱스는 실제 칼럼의 값이 1MB더라도 1000바이트(MyISAM) 또는 3072바이트(InnoDB)까지만 잘라서 인덱스 키로 사용한다.
- 전문 검색 인덱스는 문서 전체에 대한 분석과 검색을 위한 인덱스 알고리즘이다.
- 전문(Full Text) 검색은 문서 내용 전체를 인덱스화해서 특정 키워드가 포함된 문서를 검색하는 것이다.
- 전문 검색 인덱스는 일반화된 기능의 명칭이지 전문 검색 알고리즘의 이름을 지칭하는 것이 아니다.
인덱스 알고리즘
- 전문 검색에서는 문서 본문의 내용에서 사용자가 검색하게 될 키워드를 분석해 내고, 빠른 검색용으로 사용할 수 있게 이러한 키워드로 인덱스를 구축한다.
- 전문 검색 인덱스는 문서의 키워드를 인덱싱하는 기법에 따라 크게 두 가지로 구분할 수 있다.
어근 분석 알고리즘
- MySQL 서버의 전문 검색 인덱스는 다음 과정을 거쳐 색인 작업이 수행된다.
- 불용어(Stop Word) 처리
- 어근 분석(Stremming)
불용어 처리
- 검색에서 별 가치가 없는 단어를 모두 필터링해서 제거하는 작업
- 불용어의 개수는 많지 않아서 다음처럼 사용한다.
- 알고리즘을 구현한 코드에 모두 상수로 정의해서 사용한 경우가 많다.
- 유연성을 위해 불용어 자체를 데이터베이스화해서 사용자가 추가하거나 삭제할 수 있게 구현하는 경우
- 현재 MySQL 서버는 불용어가 소스코드에 정의되어 있다.
- 이를 무시하고 사용자가 별도로 불용어를 정의할 수 있는 기능도 제공한다.
어근 분석
- 검색어로 선정된 단어의 뿌리인 원형을 찾는 작업
- MySQL 서버에서는 오픈소스 형태소 분석 라이브러리인 MeCab을 플러그인 형태로 사용할 수 있게 지원한다.
- 각 국가의 언어가 서로 문법이 다르고 다른 방식으로 발전해왔기 때문에 형태소 분석이나 어근 분석 또한 언어별로 방식이 모두 다르다.
- MeCab은 일본어를 위한 형태소 분석 프로그램이며, 서구권 언어를 위한 형태소 분석기는 MongoDB에서 사용되는 Snowball이 있다.
- 한글이나 일본어의 경우 영어와 같이 단어의 변형 자체는 거의 없기 때문에 어근 분석보다는 문장의 형태소를 분석해서 명사와 조사를 구분하는 기능이 더 중요한 편이다.
- MeCab을 위한 형태소 분석은 매우 전문적인 전문 검색 알고리즘이어서 만족할 만한 결과를 내기 위해서는 많은 노력과 시간을 필요로 한다.
- 전문적인 검색 엔진을 고려하는 것이 아니라면 범용적으로 적용하기는 쉽지 않다.
n-gram 알고리즘
- 단순히 키워드를 검색해내기 위한 인덱싱 알고리즘이다.
- MeCab의 단점을 보완하기 위한 방법으로 도입되었다.
- n-gram이란 본문을 무조건 몇 글자씩 잘라서 인덱싱하는 방법이다.
- 형태소 분석보다는 알고리즘이 단순하다.
- 국가별 언어에 대한 이해와 준비 작업이 필요 없다.
- 만들어진 인덱스의 크기는 상당히 큰 편이다.
- n-gram에서 n은 인덱싱할 키워드의 최소 글자 수를 의미한다.
- 일반적으로는 2-gram(또는 Bi-gram) 방식이 많이 사용된다.
- 각 단어는 다음과 같이 띄어쓰기(공백)와 마침표(.)를 기준으로 구분하고, 2글자씩 중첩해서 토큰으로 분리한다.
- 10글자 단어라면 (10-1)개의 토큰으로 구분된다.
- 이렇게 구분된 각 토큰을 인덱스에 저장한다.
- 이때, 중복된 토큰은 하나의 인덱스로 엔트로 병합되어 저장된다.
- MySQL 서버는 생성된 토큰들에 대해 불용어를 걸러내는 작업을 수행한다.
- MySQL 서버는 이렇게 구분된 토큰을 단순한 B-Tree 인덱스에 저장한다.
- 성능 향상을 위한 Merge-Tree 같은 기능을 가지고 있다.
- 전문 검색을 더 빠르게 하기 위해 2단계 인덱싱(프런트엔드와 백엔드 인덱스)과 같은 방법도 있다.
불용어 변경 및 삭제
- 불용어 처리는 사용자에게 도움이 되기보다 사용자를 더 혼란스럽게 하는 기능일 수 있다.
- 따라서 다음과 같은 방법을 권장한다.
- 불용어 처리 자체를 완전히 무시하거나
- MySQL 서버에 내장된 불용어 대신 사용자가 직접 불용어를 등록하는 방법
전문 검색 인덱스의 불용어 처리 무시
불용어 처리를 무시하는 방법은 두 가지가 있다.
-
스토리지 엔진에 관계없이 MySQL 서버의 모든 전문 검색 인덱스에 대해 불용어를 완전히 제거
- MySQL 서버의 설정 파일(my.cnf)의
ft_stopword_file
시스템 변수에 빈 문자열을 설정한다.
ft_stopword_file
를 변경하면 MySQL 서버를 재시작해야 변경사항이 반영된다.
-
InnoDB 스토리지 엔진을 사용하는 테이블의 전문 검색 인덱스에 대해서만 불용어 처리를 무시
innodb_ft_enable_stopword
시스템 변수를 OFF로 설정한다.
SET GLOBAL innodb_ft_enable_stopword=OFF;
- MySQL 서버의 다른 스토리지 엔진(MyISAM 스토리지 엔진)을 사용하는 테이블은 여전히 내장 불용어 처리를 사용한다.
innodb_ft_enable_stopword
는 MySQL 서버가 실행 중인 상태에서도 변경할 수 있다.
사용자 정의 불용어 사용
사용자 정의 불용어를 사용하는 방법은 두 가지가 있다.
-
불용어 목록을 파일로 정의한다.
- MySQL 서버 설정 파일에서 파일의 경로를
ft_stopword_file
설정에 등록한다.
ft_stopword_file='/data/my_custom_stopword.txt'
-
불용어의 목록을 테이블로 저장하는 방식
- InnoDB 스토리지 엔진을 사용하는 테이블의 전문 검색 인덱스에서만 사용할 수 있다.
- 불용어 테이블을 생성하고
innodb_ft_server_stopword_table
시스템 변수에 불용어 테이블을 설정한다.
- 이때, 불용어 목록을 변경한 이후 전문 검색 인덱스가 생성되어야만 변경된 불용어가 적용된다.
CREATE TABLE my_stopword(value VARCHAR(30)) ENGIN = INNODB;
INSERT INTO my_stopword(value) VALUES('MySQL');
SET GLOBAL innodb_ft_server_stopword_table='mydb/my_stopword';
ALTER TABLE tb_bi_gram
ADD fuLLTEXT indEX ft_title_body(title, body) With PARSER ngram;
SET GLOBAL innodb_ft_user_stopword_table='mydb/my_stopword';
전문 검색 인덱스의 가용성
전문 검색 인덱스를 사용하려면 반드시 다음 두 가지 조건을 갖춰야 한다.
- 쿼리 문장이 전문 검색을 위한 문법(
MATCH … AGAINST …
)을 사용
- 테이블이 전문 검색 대상 칼럼에 대해서 전문 인덱스 보유
CREATE TABLE tb_test (
doc_id INT,
doc_body TEXT,
PRIMARY KEY (doc_id).
FULLTEXT KEY fx_docbody (doc_body) WITh PARSER ngram
) ENGIN=InnoDB;
SELECT * FROM tb_test
WHERE MATCH(doc_body) AGAINST('애플' IN BOOLEAN MODE);
Reference
참고 서적
📔 Real MySQL 8.0