MySQL Full Text Search Index 사용하기
전문 검색(Full Text Search)은 검색 기능을 서비스에 도입하고 싶은 분들에게 필요한 기능입니다.
기존의 인덱스와 다른 방식의 인덱스입니다.
MySQL의 B-Tree Index ( 보통 그냥 Index 라고 불림 )
: Index의 경우에는 한 컬럼 안에서 비슷한 형식의 데이터 중에서 원하는 데이터를 찾는 경우 사용하는 것이 일반적입니다.
예를 들면,
위도, 경도, 나이 등등, 비슷한 특정한 범위 안에서 데이터를 찾을 수 있게 인덱싱을 도와주는 경우입니다.
위도 -90.0~+90, 경도 -180~+180, 나이 0~150
MySQL의 Full-text Index ( 보통 Full-text Index 라고 부름 )
: Full-text Index의 경우에는 한 컬럼 안에서 많은 형태의 데이터가 담겨있어서 효율적으로 데이터를 찾는 경우 사용하는 것이 일반적입니다.
예를 들면,
컨텐츠 내용과 같이 사용자가 쓰기 나름인 데이터를 토큰 단위로 쪼개서 검색에 용이하게 합니다.
컨텐츠 내용 : "나는 오늘 seoul의 sky를 바라보면서 베스킨라빈스31에서 맛있는 요리를 먹었다! 정말 기분 좋았다." 와 같이 한글, 영어, 숫자가 섞여 있거나 긴 내용을 검색할 때 사용됩니다.
그럼 이제부터 Full-text Index를 사용하는 방법에 대해서 이야기해보겠습니다.
Full-text Index의 데이터를 인덱싱하는 기법
: 데이터를 인덱싱하는 이유는 사용자가 검색하게 될 키워드를 빠르게 검색할 수 있게 하기 위해서 다음 두 가지 종류의 parser를 이용해서 인덱스를 구축합니다.
위 그림 예시에서도 er과 ra는 n-gram parsing은 되었지만 인덱싱 되지 않습니다.
N-gram Full-text Index 생성 과정
: 1) 인덱스 대상 문서 => 1) n글자로 구성된 서브 그룹 => 2) 백엔드 인덱스 => 3) 인덱스 대상 서브 그룹 => 4) 2-Gram 서브 그룹 => 5) 프론트엔드 인덱스 : 생성
1) 인덱싱 대상 문서를 n-gram 의 n보다 큰 값의 토큰으로 서브 그룹을 나눕니다. 아래 그림에서는 4크기의 토큰으로 정하고 서브그룹을 구성했습니다.
- 서브그룹 생성 방식은 해당 문서 데이터의 왼쪽을 시작으로 4글자 토큰을 만들고 토큰의 마지막 글자부터 다시 4글자 토큰을 만들어서 데이터의 끝까지 생성.
- 각 문서에 대한 4글자 토큰 서브그룹을 생성 해줍니다.
2) 위 1) 단계에서 추출된 서브그룹 중에서 중복되는 서브그룹별로 토큰 분류하고, 백엔드 인덱스를 만듭니다.
- 중복되지 않는 4글자로 구성된 서브그룹 리스트를 만듭니다. 그래서 백엔드 인덱스를 만드는데에 사용합니다.
- 백엔드 인덱스에 중복되지 않는 4글자로 구성된 서브 그룹을 활용해서 백엔드 인덱스에 문서위치와 같이 생성을 합니다.
- 문서위치는 해당 서브그룹이 1)에서 위치하는 곳에 (문서번호,문서열번호)를 넣습니다.
3) 백엔드 인덱스에서 중복되지 않은 서브그룹에서 다시한번 n-gram용 서브그룹을 만듭니다.
- 각 서브그룹을 다시 한번 2-gram 방식으로 서브그룹을 2글자 토큰으로 나눕니다.
- n-gram 토크나이징 방식은 왼쪽부터 1글자씩 오른쪽으로 이동하면서 연속된 n글자로 토큰을 구성합니다.
- ex) 가나다라마 일때, n=2 => 가나,나다,다라,라마
n=3 => 가나다,나다라,다라마
n=4 => 가나다라,나다라마
4) 3)과정에서 생성된 2-Gram 토큰을 분류하고, 중복되지 않은 2-Gram 서브 그룹을 생성합니다.
5) 3), 4) 과정에서 n-gram 방식으로 토크나이징한 서브그룹 정보를 이용해서 프론트엔드 인덱스를 생성합니다.
- 프론트엔드 인덱스에서 서브 그룹과 그룹 위치로 구성을 합니다.
- 그룹 위치는 3) 과정 인덱스 대상 서브그룹에서 (서브그룹번호,서브그룹열번호) 로 구성됩니다.
N-gram Full-text Index 검색 과정
1) 인덱스의 검색 과정은 생성되는 반대로 입력된 검색어를 n-gram의 n바이트 단위로 동일하게 자른다.
ex) "마바사"를 검색합니다.
1) 마바 2) 바사 를 동일하게 자릅니다.
2) 동일하게 자른 검색용 n-gram 토큰을 이용해서 프론트엔드 인덱스를 검색한다.
ex) 프론트엔드 인덱스에서 마바(1,1), 바사(1,2) 정보를 검색하였습니다. => 그룹위치의 행#이 마바에서 1, 바사에서 1이므로 서브그룹 1이 이 토큰에 연관.
3) 검색된 결과 정보를 백엔드 인덱스의 검색 대상 후보 리스트로 두고, 백엔드 인덱스를 통해서 최종 확인을 거쳐 일치하는 결과를 가져옵니다.
ex) 프론트엔드 인덱스에서 찾아낸 서브그룹 정보 1(="라마바사")로 문서 위치를 찾는다.
최종적으로 "마바사"의 위치는 서브그룹 정보 1인 "라마바사"의 정보 (0,1),(1,2)에서 행인 0,1의 문서0,문서1을 찾습니다.
1) 검색 속도
- 검색어 바이트 수가 많아질수록, 쿼리 실행 시간이 Stop-word parser > N-gram parser 입니다. 즉, N-gram 검색이 빠릅니다.
2) 인덱스 용량
- 저장 데이터 바이트 수가 많아질수록, 인덱스 스토리지 사용량은 Stop-word parser < N-gram parser 입니다. 즉, N-gram이 더 많은 용량을 사용합니다.
Full-text Search 검색 쿼리
: Full-text Search 쿼리는 다음 쿼리를 사용해야합니다.
"SELECT * FROM "테이블명" WHERE MATCH("검색할컬럼명"[, ...]) AGAINST('"검색할키워드식" "검색모드");
검색 모드의 종류
1) 자연어 검색(natural search)
- 검색 문자열을 단어 단위로 분리한 후, 해당 단어 중 하나라도 포함되는 행을 찾는다.
ex) SELECT * FROM “테이블명" WHERE MATCH (“검색컬럼명") AGAINST (‘맛집' IN NATURAL LANGUAGE MODE);
2) 불린 모드 검색(boolean mode search)
이상으로 글을 마치겠습니다.