Changes between Initial Version and Version 1 of MariaDB Mroonga


Ignore:
Timestamp:
Nov 11, 2025, 10:34:56 AM (4 weeks ago)
Author:
yongwoo
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • MariaDB Mroonga

    v1 v1  
     1[[PageOutline]]
     2= Mroonga =
     3https://mroonga.org/docs/
     4
     5MariaDB가 기본 제공하는 Full-Text 검색 엔진은 구분자 기준 색인을 하기 때문에 띄어쓰기가 잘못된 경우는 검색하지 못한다. 특히나 띄어쓰기 없이 조사를 붙이거나 합성어를 붙여쓰는 경우가 많은 한국어의 특징에 맞지 않아 잘 안쓴다.
     6
     7Mroonga는 N-Gram 색인을 지원하기 때문에 경우에 따라서 한국어에도 유용하게 사용할 수 있는 Full-Text 검색 엔진이다. N-Gram 색인이란 N개의 글자만큼 무조건 잘라서 색인을 만드는 방법이다. N-Gram 색인을 하면 '아이폰'으로 검색했을 때 '애플아이폰'이라고 되어 있는 텍스트도 검색할 수 있다.
     8
     9== 설치 ==
     10RHEL 8의 기본 배포본은 Mroonga를 지원하지 않는다.
     11
     12굳이 컴파일해서 설치하느니 ["MariaDB 설치#MariaDB사이트패키지" MariaDB 사이트에서 제공하는 MariaDB 패키지를 설치]하는 것이 나아 보인다.
     13
     14MariaDB 사이트에서 설치했다면 다음과 같이 Mroonga 엔진을 이용할 수 있다.
     15{{{
     16[mariadb]
     17...
     18plugin_load_add=ha_mroonga
     19...
     20}}}
     21
     22MariaDB 설정 파일에 지정하지 않고 다음과 깉은 SQL문을 실행해도 된다.
     23{{{
     24INSTALL SONAME 'ha_mroonga';
     25}}}
     26
     27SHOW ENGINES 명령을 내리면 제대로 Mroonga 검색 엔진이 설치되어 있는지를 확인할 수 있다.
     28
     29== 예제 입력 ==
     30{{{
     31-- MariaDB 기본 Full-Text 검색 엔진
     32create or replace table fulltext_test (apt_name varchar(100) not null primary key, FULLTEXT(apt_name)) ENGINE=INNODB;
     33
     34insert into fulltext_test (apt_name) values ('KCC 스위첸 웰츠타워');
     35insert into fulltext_test (apt_name) values ('스위트 스위첸 웰츠타워');
     36insert into fulltext_test (apt_name) values ('KCC 웰츠타워');
     37
     38-- Mroonga
     39create or replace table mroonga_test (apt_name varchar(100) not null primary key, FULLTEXT(apt_name)) ENGINE=MROONGA;
     40
     41insert into mroonga_test (apt_name) values ('KCC 스위첸 웰츠타워');
     42insert into mroonga_test (apt_name) values ('스위트 스위첸 웰츠타워');
     43insert into mroonga_test (apt_name) values ('KCC 웰츠타워');
     44}}}
     45
     46다음과 같이 여러 컬럼을 합쳐서 FULLTEXT 인덱스를 생성할 수도 있다.
     47{{{
     48create or replace table mroonga_test (apt_name varchar(100) not null primary key, address varchar(100) not null, FULLTEXT(apt_name,address)) ENGINE=MROONGA;
     49}}}
     50
     51
     52== 검색 방법 ==
     53{{{
     54-- MariaDB의 기본 Full-Text 검색 엔진은 '타워'라고 검색하면 검색 결과가 나오지 않는다.
     55select * from fulltext_test where MATCH(apt_name) AGAINST('타워');
     56select * from mroonga_test where MATCH(apt_name) AGAINST('타워');
     57
     58-- 둘다 대소문자 구분을 하지 않는다.
     59select * from fulltext_test where MATCH(apt_name) AGAINST('kcc');
     60select * from mroonga_test where MATCH(apt_name) AGAINST('kcc');
     61
     62-- 유사어도 검색한다.
     63select * from fulltext_test where MATCH(apt_name) AGAINST('스위스');
     64select * from mroonga_test where MATCH(apt_name) AGAINST('스위스');
     65}}}
     66
     67여러 컬럼을 합쳐서 FULLTEXT 인덱스를 생성한 경우에는 MATCH에서도 동일한 컬럼을 지정해줘야 한다.
     68{{{
     69select * from mroonga_test where MATCH(apt_name,address) AGAINST('스위스');
     70}}}
     71
     72== 정렬 ==
     73일치하는 정도(유사도 점수)가 높은 것이 먼저 나오길 바란다면 다음과 같이 한다.
     74{{{
     75select *, MATCH(apt_name) AGAINST('스위스') as score
     76        from mroonga_test
     77        where MATCH(apt_name) AGAINST('스위스')
     78        ORDER BY score DESC;
     79}}}
     80
     81== BOOLEAN MODE ==
     82Mroonga 스토리지 엔진의 기본 검색 모드는 NATURAL LANGUAGE MODE다. 그러나 BOOLEAN MODE가 웹 검색 엔진의 사용법과 비슷해 더 친숙하게 검색할 수 있다.
     83
     84단, 유사어 검색은 BOOLEAN MODE에서 지원하지 않는다.
     85{{{
     86select * from mroonga_test where MATCH(apt_name) AGAINST('스위스');
     87select * from mroonga_test where MATCH(apt_name) AGAINST('스위스' IN BOOLEAN MODE);                       
     88}}}
     89
     90=== 검색어에 특별한 표시가 없을 때 ===
     91BOOLEAN MODE에서 특별한 표시 없이 검색어 두 개를 나열하면 OR 검색이 된다.
     92
     93예를 들어 '스위스'이나 '타워' 둘 중 하나가 있는 데이터를 검색하려면 다음과 같다.
     94{{{
     95select *
     96  from mroonga_test
     97 where MATCH(apt_name) AGAINST('스위스 타워' IN BOOLEAN MODE);
     98}}}
     99
     100NATURAL LANGUAGE MODE에서는 검색어 두 개를 나열하면 OR가 아니다.
     101{{{
     102select *
     103  from mroonga_test
     104 where MATCH(apt_name) AGAINST('스위스 타워');
     105}}}
     1061. 먼저 '스위', '위스', '스위스', '타워' 이렇게 네 개의 토큰으로 검색어를 분할한다.
     1072. 일치하지 않는 토큰을 제거한다. 여기서는 '위스', '스위스' 두 개의 토큰이 제거된다.
     1083. 토큰별 가중치를 구한다. 토큰이 포함된 레코드의 갯수가 적은 것이 가중치가 높다. '스위'가 두 레코드와 일치하고 '타워'가 세 레코드와 일치하므로  '스위'가 가중치가 높다.
     1094. 상위 N개의 토큰을 구한다. 이 때 N은 토큰 갯수/8 + 1 이 되는데, 여기서는 2/8 + 1, 약 1이므로 상위 한 개의 토큰만 구하게 된다. 따라서 '타워'는 토큰에서 배제된다.
     1105. 레코드 내에서 토근이 많이 나온 횟수 기준으로 유사도 점수를 구한다. '스위'가 두 번 나온 '스위트 스위첸 웰츠타워'가 유사도 점수가 높다. 따라서 유사도 점수로 정렬하면 제일 먼저 나온다.
     111
     112=== +와 - ===
     113+ 표시는 반드시 있어야 하는 검색어 앞에, - 표시는 없어야 하는 검색어 앞에 적어준다.
     114{{{
     115select *
     116        from mroonga_test
     117        where MATCH(apt_name) AGAINST('+스위첸 +타워' IN BOOLEAN MODE);
     118
     119select *
     120        from mroonga_test
     121        where MATCH(apt_name) AGAINST('-스위첸' IN BOOLEAN MODE);
     122
     123select *
     124        from mroonga_test
     125        where MATCH(apt_name) AGAINST('-스위첸 +타워' IN BOOLEAN MODE);
     126}}}
     127
     128- '스위트'는 없고
     129- '스위첸'이나 '센트럴' 중 하나는 반드시 있는 데이터를 검색한다면
     130{{{
     131select *
     132        from mroonga_test
     133        where  MATCH(apt_name) AGAINST('-스위트 +(스위첸 센트럴)' IN BOOLEAN MODE);
     134}}}
     135
     136=== 정확한 구문 ===
     137두 검색어의 OR 검색이 아니라 전체를 한 검색어로 보려면 겹따옴표를 쓴다.
     138{{{
     139select *
     140        from mroonga_test
     141        where MATCH(apt_name) AGAINST('"웰츠타워 스위첸"' IN BOOLEAN MODE);
     142}}}
     143
     144== tokenizer ==
     145Mroonga는 검색 효율성을 높이기 위해 특정 형태로 텍스트를 분할하여 인덱싱한다. 이 때 인덱싱하는 단위를 토큰이라고 하고, 텍스트를 토큰으로 분할하는 것을 tokenizer라고 한다.
     146
     147CREATE TABLE 명령문에서 tokenizer를 주석으로 지정해서 원하는 tokenizer를 설정할 수 있다.
     148
     149{{{
     150-- 테스트 테이블 생성
     151create or replace table Off (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "off"') ENGINE=MROONGA;
     152create or replace table Bigram (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigram"') ENGINE=MROONGA;
     153create or replace table BigramIgnoreBlank (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramIgnoreBlank"') ENGINE=MROONGA;
     154create or replace table BigramSplitSymbol (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramSplitSymbol"') ENGINE=MROONGA;
     155create or replace table BigramSplitSymbolAlpha (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramSplitSymbolAlpha"') ENGINE=MROONGA;
     156create or replace table BigramIgnoreBlankSplitSymbol (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramIgnoreBlankSplitSymbol"') ENGINE=MROONGA;
     157create or replace table BigramIgnoreBlankSplitSymbolAlpha (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramIgnoreBlankSplitSymbolAlpha"') ENGINE=MROONGA;
     158create or replace table BigramIgnoreBlankSplitSymbolAlphaDigit (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramIgnoreBlankSplitSymbolAlphaDigit"') ENGINE=MROONGA;
     159create or replace table Delimit (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenDelimit"') ENGINE=MROONGA;
     160create or replace table DelimitNull (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenDelimitNull"') ENGINE=MROONGA;
     161create or replace table Trigram (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenTrigram"') ENGINE=MROONGA;
     162create or replace table Unigram (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenUnigram"') ENGINE=MROONGA;
     163}}}
     164
     165다음과 같이 컬럼 별로 다른 tokenizer를 지정할 수도 있다.
     166{{{
     167create or replace table test (name varchar(100) not null primary key, address varchar(100) not null, address1 varchar(100) not null,
     168                                FULLTEXT(name) COMMENT 'tokenizer "TokenBigramIgnoreBlank"',
     169                                FULLTEXT(address, address1) COMMENT 'tokenizer "TokenBigram"') ENGINE=MROONGA;
     170}}}
     171
     172다음 tokenizer 설정을 사용할 수 있다.
     173|| tokenizer || 설명 ||
     174|| off ||텍스트를 분할하는 작업을 하지 않는다. ||
     175|| {{{TokenBigram}}} ||디폴트. 텍스트를 2글자씩 묶어서 분할한다. 예를 들어, '한글 검색'은 '한글', '글_', '_검', '검색', '색', 이렇게 분할한다. 단, 아스키 문자, 숫자, 기호는 두 글짜씩 나누지 않고 공백이나 구두점으로 나눈다.||
     176|| {{{TokenBigramIgnoreBlank}}} ||공백을 없애고 두 글짜씩 묶어서 분할한다. 단, 아스키 문자, 숫자, 기호는 두 글짜씩 나누지 않고 공백이나 구두점으로 나눈다. ||
     177|| {{{TokenBigramSplitSymbol}}} ||{{{TokenBigram}}}과 같지만 기호도 두 글짜씩 묶어서 분할한다. 단, 아스키 문자, 숫자는 두 글짜씩 나누지 않고 공백이나 구두점으로 나눈다.||
     178|| {{{TokenBigramSplitSymbolAlpha}}} ||{{{TokenBigram}}}과 같지만 아스키 문자와 기호도 두 글짜씩 묶어서 분할한다. 단, 숫자는 두 글짜씩 나누지 않고 공백이나 구두점으로 나눈다.||
     179|| {{{TokenBigramIgnoreBlankSplitSymbol}}} ||{{{TokenBigramIgnoreBlank}}}와 같지만 기호도 두 글짜씩 묶어서 분할한다. 단, 아스키 문자, 숫자는 두 글짜씩 나누지 않고 공백이나 구두점으로 나눈다. ||
     180|| {{{TokenBigramIgnoreBlankSplitSymbolAlpha}}} ||{{{TokenBigramIgnoreBlank}}}와 같지만 아스키 문자와 기호도 두 글짜씩 묶어서 분할한다. 단, 숫자는 두 글짜씩 나누지 않고 공백이나 구두점으로 나눈다.||
     181|| {{{TokenBigramIgnoreBlankSplitSymbolAlphaDigit}}} ||{{{TokenBigramIgnoreBlank}}}와 같지만 아스키 문자, 숫자, 기호까지 두 글짜씩 묶어서 분할한다. ||
     182|| {{{TokenDelimit}}} ||공백이나 구두점을 기준으로 토큰을 나눈다. ||
     183|| {{{TokenDelimitNull}}} ||null characters (\0)로 토큰을 나눈다. ||
     184|| {{{TokenMecab}}} ||일본어 형태소 분석기를 사용해 토큰을 나눈다. 아쉽게 한국어는 형태소 분석기를 지원하지 않는다. ||
     185|| {{{TokenTrigram}}} ||연속된 세 글자를 잘라서 토큰으로 한다. 단, 아스키 문자, 숫자, 기호는 세 글짜씩 나누지 않고 공백이나 구두점으로 나눈다.||
     186|| {{{TokenUnigram}}} ||텍스트를 한 글자 단위로 분할하여 저장하고 검색할 때 사용한다. 단, 아스키 문자, 숫자, 기호는 한 글짜씩 나누지 않고 공백이나 구두점으로 나눈다.||
     187
     188mroonga 명령을 사용하면 각 tokenizer가 어떻게 주어진 텍스트를 토큰으로 분할하는지 테스트할 수 있다. 한글이 안 깨지려면 터미널 창에서 실행해야 한다.
     189{{{
     190> select MROONGA_COMMAND('tokenize TokenBigram "한글 검색"');
     191[{"value":"한글","position":0,"force_prefix":false},{"value":"글 ","position":1,"force_prefix":false},{"value":" 검","position":2,"force_prefix":false},{"value":"검색","position":3,"force_prefix":false},{"value":"색","position":4,"force_prefix":false}] 
     192}}}
     193
     194{{{NormalizerAuto}}}를 붙여야 실제로 인덱싱하는 토큰을 알 수 있다.
     195{{{
     196>  select MROONGA_COMMAND('tokenize TokenUnigram "한글 검색" NormalizerAuto');
     197 [{"value":"한글","position":0,"force_prefix":false},{"value":"글","position":1,"force_prefix":false},{"value":"검색","position":2,"force_prefix":false},{"value":"색","position":3,"force_prefix":false}]
     198}}}
     199 - {{{NormalizerAuto}}}를 붙이기 전과 비교하면 공백이 사라졌고, " 검"이라는 토큰이 사라졌다.
     200 - 아마 공백을 제외하면 "검'이라는 토큰만 남는데 "검색'이라는 토큰의 첫 글자가 "검"이므로 "검"만 따로 인덱싱하지 않아도 되므로 생략한 것이 아닌가 한다.
     201
     202{{{NormalizerAuto}}}는 다음 작업을 수행한다.
     203 - 대소문자 통일: 모든 텍스트를 소문자로 변환한다.
     204  * Hello를 hello로 변환.
     205 - 반각/전각 문자 변환: 반각과 전각 문자를 서로 다르게 인식하지 않도록 모두 반각 문자로 변환한다.
     206  * abc → abc (전각에서 반각으로 변환)
     207 - 조합형 변환: 한국어의 조합형을 유니코드 문자로 변환
     208  * 한글의 조합형 ({{{ᄒ}}}{{{ᅡ}}}{{{ᆫ}}}{{{ᄀ}}}{{{ᅳ}}}{{{ᆯ}}})을 한글로 변환.
     209 - 공백 및 특수 문자 처리: 불필요한 공백이나 특수 문자를 제거
     210
     211{{{
     212-- 테스트 데이터 입력
     213insert into Off values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     214insert into Bigram values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     215insert into BigramIgnoreBlank values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     216insert into BigramSplitSymbol values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     217insert into BigramSplitSymbolAlpha values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     218insert into BigramIgnoreBlankSplitSymbol values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     219insert into BigramIgnoreBlankSplitSymbolAlpha values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     220insert into BigramIgnoreBlankSplitSymbolAlphaDigit values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     221insert into Delimit values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     222insert into DelimitNull values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     223insert into Trigram values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     224insert into Unigram values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#');
     225
     226-- 테스트
     227select txt from Off where match(txt) against('?@#' IN BOOLEAN MODE);
     228}}}
     229
     230== 제한 ==
     231Mroonga 스토리지 엔진에서 테이블을 만들 때는 다음과 같은 제한이 있다. 이 제한은 조건에 따라 달라질 수 있다.
     232* 최대 레코드 갯수: 1,073,741,823 (2^30^ - 1)
     233 - 일반적인 PRIMARY KEY USING BTREE 테이블일 경우.
     234* 한 키의 최대 크기: 4kB
     235* 키의 크기 총합 : 4GB
     236* 컬럼의 최대 크기: 256GB
     237
     238== Null 사용시 주의 사항 ==
     239Mroonga 스토리지 엔진은 특정 값을 자동으로 변환한다.
     240
     241Null은 DATE나 DATETIME 컬럼에서 '1970-01-01 00:00:00'으로 변환해서 저장한다.
     242
     243Null은 문자열 컬럼에서는 ''(빈 문자열)로, 숫자형 컬럼에서는 0으로 변환해서 저장한다.
     244
     245{{{
     246create or replace table mroonga_conversion (
     247  id int primary key auto_increment,
     248  date DATE null,
     249  datetime DATETIME null,
     250  string VARCHAR(10) null,
     251  number INT null
     252) ENGINE=MROONGA;
     253
     254-- 데이터 입력
     255insert into mroonga_conversion (id) values (default);
     256
     257-- 결과 확인
     258select * from mroonga_conversion;
     259}}}
     260
     261== UDF ==
     262
     263=== mroonga_highlight_html() ===
     264특정 단어를 강조해서 웹에서 보여주고 싶을 때가 있다. 이 때 사용할 수 있는 것이 mroonga_highlight_html() 함수다.
     265
     266mroonga_highlight_html() 함수는 지정한 단어에 <span class="keyword">...</span> 태그를 붙여준다.
     267
     268mroonga_highlight_html() 함수는 UDF로 Mroonga에 포함되어 있지만 CREATE FUNCTION 명령으로 함수를 등록해야만 사용할 수 있다.
     269{{{
     270CREATE FUNCTION mroonga_highlight_html RETURNS STRING SONAME 'ha_mroonga.so';
     271}}}
     272
     273구문은 다음과 같다.
     274{{{
     275mroonga_highlight_html(컬럼이나 텍스트, 키워드1, ..., 키워드N)
     276}}}
     277
     278
     279{{{
     280select apt_name, MROONGA_HIGHLIGHT_HTML(apt_name, '웰츠', 'KCC') from mroonga_test where MATCH(apt_name) AGAINST ('웰츠');
     281}}}
     282
     283=== mroonga_snippet() ===
     284mroonga_highlight_html() 함수의 결과값을 커스터마이징하고 싶은 경우나 검색어와 주변 텍스트를 검색 결과로 추출하고 싶은 경우가 있다.
     285 
     286검색어와 주변 텍스트를 컨텍스트 내 키워드, snippet이라고 한다. mroonga_snippet() 함수는 검색 결과에서 snippet을 가져오는 방법을 지정할 수 있다.
     287
     288mroonga_snippet() 함수는 UDF로 Mroonga에 포함되어 있지만 CREATE FUNCTION 명령으로 함수를 등록해야만 사용할 수 있다.
     289{{{
     290CREATE FUNCTION mroonga_snippet RETURNS STRING SONAME 'ha_mroonga.so';
     291}}}
     292
     293구문은 다음과 같다.
     294{{{
     295mroonga_snippet(document,
     296                max_length,
     297                max_count,
     298                encoding,
     299                skip_leading_spaces,
     300                html_escape,
     301                snippet_prefix,
     302                snippet_suffix,
     303                word1, word1_prefix, word1_suffix,
     304                ...,
     305                [wordN, wordN_prefix, wordN_suffix])
     306}}}
     307* document: 컬럼이나 텍스트
     308* max_length:  snippet의 최대 길이. 단위 바이트. 대부분의 한글은 3바이트.
     309* max_count: snippet의 최대 갯수
     310* encoding: document의 collation. utf8_general_ci, euckr_korean_ci, ascii_general_ci, ...
     311* skip_leading_spaces: 1은 맨 앞 공백 제거. 0은 제거하지 않음
     312* html_escape: 1은 HTML 태그 변환. 0은 변환하지 않음
     313* snippet_prefix: snippet의 시작. 보통 ... 과 같은 앞 부분이 생략되었다는 텍스트를 많이 쓴다.
     314* snippet_suffix: snippet의 끝. 보통 ... 과 같은 뒷 부분이 생략되었다는 텍스트를 많이 쓴다.
     315* word1: snippet의 키워드
     316* word1_prefix: word1의 앞에 붙일 텍스트. 보통 강조하는 HTML 태그를 많이 쓴다.
     317* word1_suffix: word1의 끝에 붙일 텍스트.
     318
     319{{{
     320select apt_name, MROONGA_SNIPPET(apt_name, 22, 3, 'UTF8_GENERAL_CI', 1, 1, '...', '...<br>', '웰츠', '<span class="w1">', '</span>') as snippet
     321        from mroonga_test WHERE MATCH(apt_name) AGAINST ('웰츠');
     322}}}
     323
     324=== mroonga_command() ===
     325mroonga_command() 함수는 mroonga 명령을 직접 실행할 때 쓴다. MariaDB 명령보다 빠르다.
     326
     327~~mroonga_command() 함수는 UDF로 Mroonga에 포함되어 있지만 CREATE FUNCTION 명령으로 함수를 등록해야만 사용할 수 있다.~~
     328{{{
     329CREATE FUNCTION mroonga_command RETURNS STRING SONAME 'ha_mroonga.so';
     330}}}
     331
     332mroonga_command() 함수의 예는 다음과 같다.
     333{{{
     334select MROONGA_COMMAND('reindex mroonga_test');
     335}}}
     336- reindex 명령만 내리면 현재 데이터베이스의 모든 인덱스가 대상이 된다.
     337
     338== Wrapper 모드 ==
     339Mroonga에는 Storage 모드와 wrapper 모드가 있다.
     340
     341* Storage 모드는  Full-Text 검색과 데이터 저장 모두에 Mroonga를 사용한다. 스토리지 엔진의 모든 기능을 Mroonga로 구현하기 때문에  Full-Text 검색이 빠르다.
     342* Wrapper 모드는 Full-Text 검색  기능에만 Mroonga를 사용하고 MyISAM, InnoDB와 같은 다른 기존 스토리지 엔진은 데이터 저장에 사용한다. Mroonga는 SQL을 처리하는 SQL Handler와 기존 스토리지 엔진 사이에서 모든 데이터를 처리한다.
     343
     344Wrapper 모드로 사용할 때는 다음을 주의한다.
     345* 반드시 PK가 있어야 한다.
     346* Null 값을 사용할 수 있다.
     347* InnoDB를 사용하면 트랜잭션을 사용할 수 있다.
     348 - 다만, rollback을 할 때 Full-Text 인덱스까지 롤백되지 않기 때문에 잘못된 결과가 나올 수 있다. 그런 경우에는 인덱스를 재생성해야 한다.
     349
     350Wrapper 모드로 테이블을 생성하려면 다음과 같이 COMMENT 항목에서 기존 스토리지 엔진을 적어주면 된다.
     351{{{
     352create or replace table mroonga_test (apt_name varchar(100) not null primary key, FULLTEXT(apt_name)) ENGINE=MROONGA COMMENT='engine "InnoDB"';
     353}}}
     354
     355----
     356[WikiStart 처음으로]