http://www.mysqlkorea.co.kr
한글매뉴얼 5.0 , 한글매뉴얼 5.1 , MySQL 5.1 HA , 사용자매뉴얼
Advanced Knowle...  
엔지니어 노트  
블로그존  
글로벌 MySQL  
MySQL 5.5 GA  
MySQL 5.6 Developer  
최신글
슬로우쿼리 발생 …
안녕하세요... ma…
FTS_xxxx.ibd 파…
MySQL Notifier :…
table size관련 …
 
InnoDB FTS(Full Text Search) 개요 및 시작
글쓴이 : taeguni   날짜 : 11-10-07 10:42   조회수 : 15562

InnoDB FTS(Full Text Search) 개요 및 시작

이번 테스트 버전은 InnoDB의 중요한 기능 - FTS가 포함되어 있습니다. 이 기능은 크게 텍스트 검색 및 innodb의 검색기능을 강화합니다. 이 기능은 트랜잭션 스토리지 엔진을 위해 설계되었기 때문에, 기본 아키텍처 설계와 구현은 MyISAM의 기능과 완전히 다릅니다. InnoDB의 FTS(full text search) 기능에 몇 가지 중요한 개념과 이 기능을 더욱더 활용할 수 있도록 기능에 대한 기술적 검토를 간단히 제공하고자 합니다.
이 주제에 관현 몇 가지 다른 자료가 있습니다. 존 러셀은 InnoDB FTS 명령과 구문에 대한 간단한 자습서를 제공합니다. 또 다른 자료에는 MyISAM full text 검색과 다른 점을 비교 설명합니다.

디자인 :

다음은 이 기능을 더 많이 이해하는데 도움이 되는 몇 가지 주요 설개 개념을 설명합니다.
  • 역인덱스 - 다양한 DBMS full text 검색 엔진과 마찬가지로, InnoDB FTS도 역시 역인덱스를로 설계되어 있고, 입력된 텍스트는 각각의 단어로 토큰화되며, 하나이상의 보조 테이블에 저장됩니다. 각 단어에 대해, 문서 ID와 단어 위치가 쌍으로 저장됩니다. 이와 같이 문서의 ID와 Position이 쌍으로 되어 있는 목록을 "ilist"라고 부릅니다. 그런 이유로 역인덱스 테이블에거 가장 중요한 컬럼은 "word"와 "ilist" 입니다. "word" 컬럼에 인덱스가 있고, 각 단어에 대한 위치 저장하여, "근접 검색"을 할 수 있습니다. 하지만, MyISAM full text 검색에서는 이런 기능 부족했습니다.
  • InnoDB FTS의 인덱스 테이블(보조테이블) - 이 테이블은 앞에 언급했듯이 역인덱스 단어 테이블에 저장됩니다. 그리고 이런 종류의 테이블을 "인덱스 테이블"이라고 합니다. 그리고 full text 인덱스는 주로 매핑을 문서에 word를 저장하는 테이블 집합으로 구성되어 있습니다. InnoDB FTS의 디자인에서 인덱스 테이블은 여러 테이블에 "파티션"입니다. 그래서 하나의 보조 테이블 대신, 지금 여섯개의 보조테이블이 있고, 첫문장에 따라서 분할 단어를 개별적으로 포함하고 있습니다.
분할된 디자인은 작업을 비교하는 것이 쉬워집니다. 현재는 인덱스를 만드는 작업을 비교하지만, 분명히 나중에는 쿼리와 full text 검색을 하기 위한 확장을 할 수 있습니다.
  • FTS "인덱스 캐시" - full text 인덱스가 디스크에 있는 "인덱스 보조 테이블"의 집합으로 표현되고 있지만, "인덱스 테이블"에 내려쓰거나 동기화(flush/sync) 하기 전에는 인덱스 캐시에 존재합니다. "인덱스 캐시는" 워드 단위로 ID / Position (ilist) 정보를 저장하기 때문에, 실제로 "red-black tree"(* binary tree의 일종)입니다. "인덱스 테이블"의 words컬럼은 관계형 테이블 질의 안에서 직접 질의 합니다. 그리고 인덱스 테이블에서 질의한 결과는 clients에 보내기 전에 인덱스 캐시의 결과에 병합(union) 합니다. 만약에 빈번한 Insert나 Update로 인해서 FTS의 "인덱스 캐시"에 의한 "인덱스 테이블"에 적용하는 작업이 많다면, 인덱스 캐시가 설정된 용량만큼 가득 찰때, 한번만 인덱스 테이블에 적용할 수 있도록 상호작용하여, 잦은 업데이트로 인한 InnoDB 상태를 완화합니다. "인덱스 테이블"에 포함된 각각의 단어에 다한 항목의 수를 최소화 하여 적용하는 것은 또 다른 이점이 있습니다. 그래서 하나의 문서를 토큰화 한뒤 각각의 단어를 단일 "ilist" 항목과 함께 적용하는 대신 "인덱스 테이블"에 같은 단어를 입력하고 다른 문서에 여러 문서로 부터 ID/Position 로 이루어진 다중 "ilist"를 만듭니다. 이것은 인덱스의 중복을 줄이고, "인덱스 테이블"을 크기를 축소합니다.
  • FTS "Document ID" - 가용성에 영향을 미칠 수있는 또 다른 중요한 개념은 문서 ID 관리입니다. 대부분의 FTS 엔진으로, 단어에서 문서에 매핑 고유한 (문서) ID를 통해 변화했습니다. InnoDB FTS의 경우에는, 그것은 우리가 자동으로 사용자의 테이블에 추가되어 "FTS_DOC_ID" 항목으로 표시됩니다. FTS_DOC_ID 컬럼 자체는 "BIGINT UNSIGNED NOT NULL" 형식 이어야 합니다. 그리고 해당 컬럼에 FTS_DOC_ID_INDEX와 유니크 인덱스가 만들어집니다. 한편, 사용자가 사용자에 의해서 추가된 컬럼으로부터 추가하는 것을 차단하지 않고, 이 경우에 사용자가 적절하게 문서 ID 컬럼을 관리하여야하며, 문서가 부적절하게 표시되더라도 책임을 지지 않습니다..
위 단계는 다음단계로 가기위한 간단한 개념입니다. 이제 FTS를 사용할 수 있습니다.

InnoDB Fulltext Index 사용하기

1. FTS 정의문과 Query 문법

InnoDB FTS는 MySQL의 MyISAM/FTS 쿼리 구문을 계속 사용합니다. 만약 MySQL의 FTS 구문에 익수하다면, 바로 InnoDB FTS를 사용할 수 있습니다. "Boolean 검색"에 근접한 검색을 추가한 것을 제외하고 MyISAM 검색의 모든 형식이 지원됩니다. 문법은 다른 문서에서 다루고, 여기서는 InnoDB의 FTS를 사용할 때 알아야 할 몇 가지 특별한 사항에 대한 자세한 내용을 다룰 것입니다.

2. Create index:

일반적으로, FTS 인덱스를 만들기 전에 데이터를 테이블에 불러오는 것이 좋습니다. 이렇게 하는 것은 FTS를 만들고 문서를 입력하는 것보다 더 빠를것입니다.FTS를 위한 인덱스를 빠르게 생성(FIC: Fst Index Creation)하기 위해서, 병렬 정렬을 지원을 추가했습니다. 그리고 FIC는 실제로 토근 정렬 및 병렬 FTS 인덱스를 만들 수 있습니다.
병렬 정렬의 차수를 제어하기 위해, 새로운 "innodb_ft_sort_pll_degree" 시스템 구성 변수(기본 2, 최대 32)를 사용할 수 있습니다. 이것은 토큰나이저 및 정렬 작업을 비교하고 싶을때, 얼마나 병렬 작업의 수를 지정하는데 사용됩니다. 그리고 I/O가 제한 받지 않는 시스템에서 CPU의 수와 "innodb_ft_sort_pll_degree"와 함께 인덱스틑 생성하는 성능 척도를 보여줍니다.
다음 표는 8코어 시스템에서 2.7Gb의 위키디피아 데이터의 FTS를 생성하는 결과를 보여줍니다.
Server Time (min)
MyISAM 11분 47.90초
InnoDB (default) 7분 25.2초
InnoDB pll_degree 5분 34.98초
InnoDB pll_degree = 8 4분 9초
InnoDB pll_degree = 16 3분 39.51초
인덱스를 만드는 방법에 대한 또 다른 트릭은 문서의 ID 처리에 관한 것입니다. 만약 사용가자 "FTS_DOC_ID"열을 사용하지 않는 경우 InnoDB는 테이블에 숨겨진 열을 추가 합니다. 이것은 비용이 많이 들 수 있는 모든 보조 인덱스와 함께 클러스터 인덱스를 다시 생성하는 결과가 발생합니다. 만약 사용자가 "FTS_DOC_ID"를 오리지털 테이블에 정의하여 포함 시킬수 있다면, 클러스터 인덱스 테이블의 다시 생성을 저장 할 수 있습니다. 이렇게 하려면, 사용자는 테이블에 있는 "FTS_DOC_ID" 컬럼을 모두 대문자로 하여 포함시켜야 합니다. 컬럼은 "BIGINT UNSIGNED NOT NULL" 데이터 유형이여야만 합니다. 그것은 auto_increment 컬럼으로 만들 필요가 없지만, 문제를 일으키지 않습니다.
예를 들면 다음과 같습니다.
1) CREATE TABLE fts_test (
   FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
   title VARCHAR(200),
   body TEXT
   ) ENGINE=InnoDB;
2) CREATE UNIQUE INDEX FTS_DOC_ID_INDEX on fts_test(FTS_DOC_ID);
3) Load data
4) CREATE FULLTEXT INDEX idx on fts_test (title, body);
참고로, 컬럼 이름 "FTS_DOC_ID"는 대소문자를 구분하고 InnoDB에 있는 컬럼의 이름은 대문자로 되어야합니다. 다음번 릴리즈에서, "FTS_DOC_ID" 컬럼에 대한 이름 요건을 완화할 것이고, 사용자는 이 ID 컬럼에 대한 컬럼명을 지절할 수 있을 것입니다.

3. DMLs

- FTS Index Updated on Commit:

모든 트랜잭션 DBMS에 대한 Full Text 검색은, Full text 검색 인덱스에 업데이트가 항상 문제가 되었습니다. 전형적인 예를 든면, 오라클 텍스트는 FTS를 하기 위해서 정기적 또는 수동으로 동기화 하였습니다. 11g 부터는, 사용자가 데이터 업데이트의 full text 인덱스에 반영될 때를 수동, 또는 정기적인 간격으로 반영하는 것을 지정할 수 있습니다. InnoDB Full text 검색을 위한 FTS 인덱스는 트랜잭션이 반영되는 시간에만 적용됩니다. 그래서 문서의 토큰은 트랜잭션을 반영한 후에만 FTS 인덱스 (캐시)에 넣습니다. 그러나 FTS 인덱스 데이터의 처리와 지연 업데이트를 혼동하면 안 됩니다. 모든 데이터 조작은 여전히 원래의 규칙을 따릅니다. 단지 FTS 인덱스에 대한 업데이트가 트랜잭션 반영 시간에 이루어질 뿐입니다.

- Insert 처리

삽입된 문서는 반영 시점에 토큰화 하고 "인덱스 캐시"에 삽입됩니다. 이 캐시는 32Mb의 기본 구성 크기( "innodb_ft_cache_size")를 가지고 있습니다. innodb_ft_cache_size의 용량이 가득차면, 메모리에 있는 데이터를 "인덱스 테이블"에 동기화 될 것입니다. 서버가 정상 종료하는 동안에도, "인덱스 캐시"의 내용이 디스크에 있는 "인덱스 테이블"에 동기화 될 것 입니다. 그러나 서버에 장애가 발생하였고, "인덱스 캐시"의 내용이 "인덱스 테이블"로 반영되지 않았다면, 서버를 재부팅 한 뒤에 처음에 테이블에 FTS 인덱스(검색하거나 삽입)를 사용할 때, 누락된 문서의 원본 테이블과 다시 토큰화된 데이터부터 "인덱스 캐시"를 추가합니다.

- Delete 처리

삽인된 문서가 토큰화 되거나 FTS "인덱스 캐시"에 삽입된 것을 반영하는 시간 동안 이러한 항목이 FTS 인덱스 테이블에 이미 있는 경우라면 삭제하기 위한 어떠한 문서라도 삭제하면 안 됩니다. 대신, 삭제 보조테이블에 삭제될 문서 ID를 기록합니다. 각각의 검색에 대해서 삭제된 문서를 필터링하는 "삭제" 테이블을 참조합니다. 이 디자인으로, 삭제 작업은 삭제 문서에 대한 단어 항목에 대한 수많은 업데이트가 필요하지 않고 삭제 작업을 간단하고 빠르게 수행할 수 있습니다. 단점은 단어의 항목이 FTS 인덱스에서 제거되지 않기 때문에 인덱스는 점점 커질 것 입니다. 이것은 "인덱스 최적화"로 해결되었습니다.

4. 인덱스 최적화

마찬가지 논의로, full text 인덱스에서 사용되어진 DML 에서는 인덱스가 시간에 지남에 따라서 "비대"해 질 수 있습니다. 색인 테이블에 인덱스 항목에 대한 주기적 삭제를 실행하지 않는 대신, "삭제" 보조 테이블에서 삭제된 문서 ID를 기록합니다. 실제로 문서를 제거하더라도 시간이 지남에 따라서 인덱스 테이블 자체는 커질 수밖에 없습니다. 이 문제를 해결하려면, 인덱스 최적화를 해야 합니다. 이 작업은 두 가지가 있습니다.
1) 단어에 대한 문서 ID와 position에 대한 목록 (ilist)에서 삭제된 문서 ID를 제거
2) 문서 ID/Position 값이 다중 목록 (ilist)로 통합하는 것이 가능한 경우, 하나 (또는 이하)의 동일한 단어 항목에 대해 여러 개의 항목을 통합합니다.
현재, "innodb_optimize_fulltext_only" 시스템 별수를 구성하는 경우에만, "Optimize Table" 명령어를 사용하여 최적화 작업을 할 때 과부하가 발생할 수 있습니다.
mysql> set global innodb_optimize_fulltext_only=1;
 
mysql> optimize table articles;
테이블이 커질수록, 최적화 하는 시간이 엄청나게 걸릴 수 있기 때문에, 최적화를 특정 단계에서만 실행할 수 있습니다. 각각의 "optimize table" 명령문을 에서 얼마나 많은 단어를 최적화 할 것인지에 대해서 "innodb_ft_num_word_optimize" 시스템 변수를 지정하여 설정할 수 있습니다. 기본 값은 2000이며, 이 값의 의미는 optimize가 실행될 때마다 2000 단어를 최적화한다는 의미입니다. 그리고 다음 "optimize table" 명령문이 실행되면, 서버는 마지막 실행시 최적화한 다음 부분부터 시작하여 계속 최적화를 실행합니다.
사실, 이 최적화 과정은 백그라운드 프로세스를 활용하여, 실시간으로 실행할 수 있지만, 이번 릴리즈에서는 사용할 수 없습니다. 어떤 방법이 더 적합한지, 그리고 최소한으로 영향을 줄 수 있는지를 이 옵션을 지켜보고 평가할 것입니다.

5. Stopword 처리

FTS의 stopwords를 위해서, stopwords의 두 가지 소스를 제공합니다.
1) 서버에서 기본 제공하는 stopwords - 이것은 서버에서 제공되는 고정적인 stopwords 목록입니다. 사용자 stopword가 지정되지 않은 경우라면 기본 stopword 목록이 사용됩니다.
당신은 INFORMATION_SCHEMA 테이블에 질의하여 이 목록을 볼 수 있습니다:
INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD:
mysql> select * from INNODB_FT_DEFAULT_STOPWORD;
2) 사용자 정의 stopwords - 사용자는 사용자 테이블에 "varchar" 형식의 "value"라고 명칭한 하나의 컬럼을 이용하여 자신의 stopword를 정의 할 수 있습니다. 그리고 stopword 목록을 지정하도록 "innodb_ft_server_stopword_table" 전역변수를 사용합니다. 서버는 FTS 인덱스를 만들때, 기본 stopword 목록 보다 사용자 테이블에서 stopword를 참조합니다. 예를들만 다음과 같습니다:
  • 올바른 형식의 사용 stopword 테이블을 정의하기
    create table user_stopword(value varchar(30)) engine = innodb;
    
  • "데이터베이스 명/테이블 명"으로 stopword 테이블을 지정하기
    set global innodb_ft_server_stopword_table = “test/user_stopword”;
    

6. Ranking

초기 릴리즈에서, 우리는 문서의 결과 순위에 대한 아주 간단한 순위 메카니즘 (검색 주기별, 역 문서 빈도)를 사용합니다. 이것은 더 많은 단어가 사용된 문서와 적은 단어가 사용된 문서를 비교하여, 더 많은 단어가 사용된 문서를 선택하는 것을 의미합니다. 우리는 보다 정교한 순위 메커니즘을 추가하고, 사용자가 둔의 계산에 가중치를 설정할 수 있도록 계획을 세우고 있습니다.

7. 제한 사항

마지막으로, 초기 릴리즈에 대한 제약사항 몇 가지에 대해서 이야기 하겠습니다:
  1. InooDB Full Text 검색은 오직 테이블당 하나의 FTS 인덱스를 지원합니다.
  2. MyISAM과 같은, 단일 테이블 내의 다중 문자의 사용이 지원되지만, full text 인덱스에 있는 모든 열은 동일한 문자열을 사용해야 합니다.
  3. CJK(중국어, 일본어, 한국어)와 같은 언어에 대한 구체적인 사례가 단어의 경계 기호를 가지고 있지 않다면, MyISAM과 비슷하고, 아직 N-GRAM 분석을 지원하지 않습니다. 하지만 이것은 우리의 기능 의제에 있습니다.

요약:

요약하면, InnoDB full text 검색은 InnoDB에게 텍스트 파일 처리에 중요한 기능을 제공합니다. 그리고 새로 추가된 플랫폼은 이미 인덱스의 확장성과 DML 처리의 유연성을 보여주고 있습니다. 우리는 또한 그 이상의 성능 향상을 위해서 쿼리와 DML 작업에 병렬 처리를 고려하고 있습니다. 이렇게 말했지만, 그것은 아직까지 초기 단계에 있습니다. 우리는 기능과 옵션을 추가하고, 성능을 튜닝하고, 경쟁력 있는 기능을 만들기 위해 최선을 다할 것입니다.
이전글 Multi-threaded Slave에 대한 업데이트 
다음글 7.2.5. Other Optimization Tips 
MySQL Korea 사이트의 컨텐츠 소유권은 (주)상상이비즈에 있으므로 무단전재를 금합니다.
ⓒ 2010-2011 ssebiz All Rights Reserved.