| | 1 | [[PageOutline]] |
| | 2 | = Mroonga = |
| | 3 | https://mroonga.org/docs/ |
| | 4 | |
| | 5 | MariaDB가 기본 제공하는 Full-Text 검색 엔진은 구분자 기준 색인을 하기 때문에 띄어쓰기가 잘못된 경우는 검색하지 못한다. 특히나 띄어쓰기 없이 조사를 붙이거나 합성어를 붙여쓰는 경우가 많은 한국어의 특징에 맞지 않아 잘 안쓴다. |
| | 6 | |
| | 7 | Mroonga는 N-Gram 색인을 지원하기 때문에 경우에 따라서 한국어에도 유용하게 사용할 수 있는 Full-Text 검색 엔진이다. N-Gram 색인이란 N개의 글자만큼 무조건 잘라서 색인을 만드는 방법이다. N-Gram 색인을 하면 '아이폰'으로 검색했을 때 '애플아이폰'이라고 되어 있는 텍스트도 검색할 수 있다. |
| | 8 | |
| | 9 | == 설치 == |
| | 10 | RHEL 8의 기본 배포본은 Mroonga를 지원하지 않는다. |
| | 11 | |
| | 12 | 굳이 컴파일해서 설치하느니 ["MariaDB 설치#MariaDB사이트패키지" MariaDB 사이트에서 제공하는 MariaDB 패키지를 설치]하는 것이 나아 보인다. |
| | 13 | |
| | 14 | MariaDB 사이트에서 설치했다면 다음과 같이 Mroonga 엔진을 이용할 수 있다. |
| | 15 | {{{ |
| | 16 | [mariadb] |
| | 17 | ... |
| | 18 | plugin_load_add=ha_mroonga |
| | 19 | ... |
| | 20 | }}} |
| | 21 | |
| | 22 | MariaDB 설정 파일에 지정하지 않고 다음과 깉은 SQL문을 실행해도 된다. |
| | 23 | {{{ |
| | 24 | INSTALL SONAME 'ha_mroonga'; |
| | 25 | }}} |
| | 26 | |
| | 27 | SHOW ENGINES 명령을 내리면 제대로 Mroonga 검색 엔진이 설치되어 있는지를 확인할 수 있다. |
| | 28 | |
| | 29 | == 예제 입력 == |
| | 30 | {{{ |
| | 31 | -- MariaDB 기본 Full-Text 검색 엔진 |
| | 32 | create or replace table fulltext_test (apt_name varchar(100) not null primary key, FULLTEXT(apt_name)) ENGINE=INNODB; |
| | 33 | |
| | 34 | insert into fulltext_test (apt_name) values ('KCC 스위첸 웰츠타워'); |
| | 35 | insert into fulltext_test (apt_name) values ('스위트 스위첸 웰츠타워'); |
| | 36 | insert into fulltext_test (apt_name) values ('KCC 웰츠타워'); |
| | 37 | |
| | 38 | -- Mroonga |
| | 39 | create or replace table mroonga_test (apt_name varchar(100) not null primary key, FULLTEXT(apt_name)) ENGINE=MROONGA; |
| | 40 | |
| | 41 | insert into mroonga_test (apt_name) values ('KCC 스위첸 웰츠타워'); |
| | 42 | insert into mroonga_test (apt_name) values ('스위트 스위첸 웰츠타워'); |
| | 43 | insert into mroonga_test (apt_name) values ('KCC 웰츠타워'); |
| | 44 | }}} |
| | 45 | |
| | 46 | 다음과 같이 여러 컬럼을 합쳐서 FULLTEXT 인덱스를 생성할 수도 있다. |
| | 47 | {{{ |
| | 48 | create 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 검색 엔진은 '타워'라고 검색하면 검색 결과가 나오지 않는다. |
| | 55 | select * from fulltext_test where MATCH(apt_name) AGAINST('타워'); |
| | 56 | select * from mroonga_test where MATCH(apt_name) AGAINST('타워'); |
| | 57 | |
| | 58 | -- 둘다 대소문자 구분을 하지 않는다. |
| | 59 | select * from fulltext_test where MATCH(apt_name) AGAINST('kcc'); |
| | 60 | select * from mroonga_test where MATCH(apt_name) AGAINST('kcc'); |
| | 61 | |
| | 62 | -- 유사어도 검색한다. |
| | 63 | select * from fulltext_test where MATCH(apt_name) AGAINST('스위스'); |
| | 64 | select * from mroonga_test where MATCH(apt_name) AGAINST('스위스'); |
| | 65 | }}} |
| | 66 | |
| | 67 | 여러 컬럼을 합쳐서 FULLTEXT 인덱스를 생성한 경우에는 MATCH에서도 동일한 컬럼을 지정해줘야 한다. |
| | 68 | {{{ |
| | 69 | select * from mroonga_test where MATCH(apt_name,address) AGAINST('스위스'); |
| | 70 | }}} |
| | 71 | |
| | 72 | == 정렬 == |
| | 73 | 일치하는 정도(유사도 점수)가 높은 것이 먼저 나오길 바란다면 다음과 같이 한다. |
| | 74 | {{{ |
| | 75 | select *, 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 == |
| | 82 | Mroonga 스토리지 엔진의 기본 검색 모드는 NATURAL LANGUAGE MODE다. 그러나 BOOLEAN MODE가 웹 검색 엔진의 사용법과 비슷해 더 친숙하게 검색할 수 있다. |
| | 83 | |
| | 84 | 단, 유사어 검색은 BOOLEAN MODE에서 지원하지 않는다. |
| | 85 | {{{ |
| | 86 | select * from mroonga_test where MATCH(apt_name) AGAINST('스위스'); |
| | 87 | select * from mroonga_test where MATCH(apt_name) AGAINST('스위스' IN BOOLEAN MODE); |
| | 88 | }}} |
| | 89 | |
| | 90 | === 검색어에 특별한 표시가 없을 때 === |
| | 91 | BOOLEAN MODE에서 특별한 표시 없이 검색어 두 개를 나열하면 OR 검색이 된다. |
| | 92 | |
| | 93 | 예를 들어 '스위스'이나 '타워' 둘 중 하나가 있는 데이터를 검색하려면 다음과 같다. |
| | 94 | {{{ |
| | 95 | select * |
| | 96 | from mroonga_test |
| | 97 | where MATCH(apt_name) AGAINST('스위스 타워' IN BOOLEAN MODE); |
| | 98 | }}} |
| | 99 | |
| | 100 | NATURAL LANGUAGE MODE에서는 검색어 두 개를 나열하면 OR가 아니다. |
| | 101 | {{{ |
| | 102 | select * |
| | 103 | from mroonga_test |
| | 104 | where MATCH(apt_name) AGAINST('스위스 타워'); |
| | 105 | }}} |
| | 106 | 1. 먼저 '스위', '위스', '스위스', '타워' 이렇게 네 개의 토큰으로 검색어를 분할한다. |
| | 107 | 2. 일치하지 않는 토큰을 제거한다. 여기서는 '위스', '스위스' 두 개의 토큰이 제거된다. |
| | 108 | 3. 토큰별 가중치를 구한다. 토큰이 포함된 레코드의 갯수가 적은 것이 가중치가 높다. '스위'가 두 레코드와 일치하고 '타워'가 세 레코드와 일치하므로 '스위'가 가중치가 높다. |
| | 109 | 4. 상위 N개의 토큰을 구한다. 이 때 N은 토큰 갯수/8 + 1 이 되는데, 여기서는 2/8 + 1, 약 1이므로 상위 한 개의 토큰만 구하게 된다. 따라서 '타워'는 토큰에서 배제된다. |
| | 110 | 5. 레코드 내에서 토근이 많이 나온 횟수 기준으로 유사도 점수를 구한다. '스위'가 두 번 나온 '스위트 스위첸 웰츠타워'가 유사도 점수가 높다. 따라서 유사도 점수로 정렬하면 제일 먼저 나온다. |
| | 111 | |
| | 112 | === +와 - === |
| | 113 | + 표시는 반드시 있어야 하는 검색어 앞에, - 표시는 없어야 하는 검색어 앞에 적어준다. |
| | 114 | {{{ |
| | 115 | select * |
| | 116 | from mroonga_test |
| | 117 | where MATCH(apt_name) AGAINST('+스위첸 +타워' IN BOOLEAN MODE); |
| | 118 | |
| | 119 | select * |
| | 120 | from mroonga_test |
| | 121 | where MATCH(apt_name) AGAINST('-스위첸' IN BOOLEAN MODE); |
| | 122 | |
| | 123 | select * |
| | 124 | from mroonga_test |
| | 125 | where MATCH(apt_name) AGAINST('-스위첸 +타워' IN BOOLEAN MODE); |
| | 126 | }}} |
| | 127 | |
| | 128 | - '스위트'는 없고 |
| | 129 | - '스위첸'이나 '센트럴' 중 하나는 반드시 있는 데이터를 검색한다면 |
| | 130 | {{{ |
| | 131 | select * |
| | 132 | from mroonga_test |
| | 133 | where MATCH(apt_name) AGAINST('-스위트 +(스위첸 센트럴)' IN BOOLEAN MODE); |
| | 134 | }}} |
| | 135 | |
| | 136 | === 정확한 구문 === |
| | 137 | 두 검색어의 OR 검색이 아니라 전체를 한 검색어로 보려면 겹따옴표를 쓴다. |
| | 138 | {{{ |
| | 139 | select * |
| | 140 | from mroonga_test |
| | 141 | where MATCH(apt_name) AGAINST('"웰츠타워 스위첸"' IN BOOLEAN MODE); |
| | 142 | }}} |
| | 143 | |
| | 144 | == tokenizer == |
| | 145 | Mroonga는 검색 효율성을 높이기 위해 특정 형태로 텍스트를 분할하여 인덱싱한다. 이 때 인덱싱하는 단위를 토큰이라고 하고, 텍스트를 토큰으로 분할하는 것을 tokenizer라고 한다. |
| | 146 | |
| | 147 | CREATE TABLE 명령문에서 tokenizer를 주석으로 지정해서 원하는 tokenizer를 설정할 수 있다. |
| | 148 | |
| | 149 | {{{ |
| | 150 | -- 테스트 테이블 생성 |
| | 151 | create or replace table Off (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "off"') ENGINE=MROONGA; |
| | 152 | create or replace table Bigram (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigram"') ENGINE=MROONGA; |
| | 153 | create or replace table BigramIgnoreBlank (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramIgnoreBlank"') ENGINE=MROONGA; |
| | 154 | create or replace table BigramSplitSymbol (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramSplitSymbol"') ENGINE=MROONGA; |
| | 155 | create or replace table BigramSplitSymbolAlpha (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramSplitSymbolAlpha"') ENGINE=MROONGA; |
| | 156 | create or replace table BigramIgnoreBlankSplitSymbol (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramIgnoreBlankSplitSymbol"') ENGINE=MROONGA; |
| | 157 | create or replace table BigramIgnoreBlankSplitSymbolAlpha (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramIgnoreBlankSplitSymbolAlpha"') ENGINE=MROONGA; |
| | 158 | create or replace table BigramIgnoreBlankSplitSymbolAlphaDigit (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenBigramIgnoreBlankSplitSymbolAlphaDigit"') ENGINE=MROONGA; |
| | 159 | create or replace table Delimit (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenDelimit"') ENGINE=MROONGA; |
| | 160 | create or replace table DelimitNull (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenDelimitNull"') ENGINE=MROONGA; |
| | 161 | create or replace table Trigram (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenTrigram"') ENGINE=MROONGA; |
| | 162 | create or replace table Unigram (txt varchar(100) not null primary key, FULLTEXT(txt) COMMENT 'tokenizer "TokenUnigram"') ENGINE=MROONGA; |
| | 163 | }}} |
| | 164 | |
| | 165 | 다음과 같이 컬럼 별로 다른 tokenizer를 지정할 수도 있다. |
| | 166 | {{{ |
| | 167 | create 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 | |
| | 188 | mroonga 명령을 사용하면 각 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 | -- 테스트 데이터 입력 |
| | 213 | insert into Off values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 214 | insert into Bigram values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 215 | insert into BigramIgnoreBlank values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 216 | insert into BigramSplitSymbol values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 217 | insert into BigramSplitSymbolAlpha values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 218 | insert into BigramIgnoreBlankSplitSymbol values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 219 | insert into BigramIgnoreBlankSplitSymbolAlpha values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 220 | insert into BigramIgnoreBlankSplitSymbolAlphaDigit values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 221 | insert into Delimit values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 222 | insert into DelimitNull values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 223 | insert into Trigram values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 224 | insert into Unigram values ('1000원만!?@#'), ('1000 원 만 !?@#'), ('1 0 0 0 원 만 ! ? @ #'), ('동해물과 백두산이,마르고.닳도록'), ('1000cents!?@#'), ('1000 cents !?@#'); |
| | 225 | |
| | 226 | -- 테스트 |
| | 227 | select txt from Off where match(txt) against('?@#' IN BOOLEAN MODE); |
| | 228 | }}} |
| | 229 | |
| | 230 | == 제한 == |
| | 231 | Mroonga 스토리지 엔진에서 테이블을 만들 때는 다음과 같은 제한이 있다. 이 제한은 조건에 따라 달라질 수 있다. |
| | 232 | * 최대 레코드 갯수: 1,073,741,823 (2^30^ - 1) |
| | 233 | - 일반적인 PRIMARY KEY USING BTREE 테이블일 경우. |
| | 234 | * 한 키의 최대 크기: 4kB |
| | 235 | * 키의 크기 총합 : 4GB |
| | 236 | * 컬럼의 최대 크기: 256GB |
| | 237 | |
| | 238 | == Null 사용시 주의 사항 == |
| | 239 | Mroonga 스토리지 엔진은 특정 값을 자동으로 변환한다. |
| | 240 | |
| | 241 | Null은 DATE나 DATETIME 컬럼에서 '1970-01-01 00:00:00'으로 변환해서 저장한다. |
| | 242 | |
| | 243 | Null은 문자열 컬럼에서는 ''(빈 문자열)로, 숫자형 컬럼에서는 0으로 변환해서 저장한다. |
| | 244 | |
| | 245 | {{{ |
| | 246 | create 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 | -- 데이터 입력 |
| | 255 | insert into mroonga_conversion (id) values (default); |
| | 256 | |
| | 257 | -- 결과 확인 |
| | 258 | select * from mroonga_conversion; |
| | 259 | }}} |
| | 260 | |
| | 261 | == UDF == |
| | 262 | |
| | 263 | === mroonga_highlight_html() === |
| | 264 | 특정 단어를 강조해서 웹에서 보여주고 싶을 때가 있다. 이 때 사용할 수 있는 것이 mroonga_highlight_html() 함수다. |
| | 265 | |
| | 266 | mroonga_highlight_html() 함수는 지정한 단어에 <span class="keyword">...</span> 태그를 붙여준다. |
| | 267 | |
| | 268 | mroonga_highlight_html() 함수는 UDF로 Mroonga에 포함되어 있지만 CREATE FUNCTION 명령으로 함수를 등록해야만 사용할 수 있다. |
| | 269 | {{{ |
| | 270 | CREATE FUNCTION mroonga_highlight_html RETURNS STRING SONAME 'ha_mroonga.so'; |
| | 271 | }}} |
| | 272 | |
| | 273 | 구문은 다음과 같다. |
| | 274 | {{{ |
| | 275 | mroonga_highlight_html(컬럼이나 텍스트, 키워드1, ..., 키워드N) |
| | 276 | }}} |
| | 277 | |
| | 278 | |
| | 279 | {{{ |
| | 280 | select apt_name, MROONGA_HIGHLIGHT_HTML(apt_name, '웰츠', 'KCC') from mroonga_test where MATCH(apt_name) AGAINST ('웰츠'); |
| | 281 | }}} |
| | 282 | |
| | 283 | === mroonga_snippet() === |
| | 284 | mroonga_highlight_html() 함수의 결과값을 커스터마이징하고 싶은 경우나 검색어와 주변 텍스트를 검색 결과로 추출하고 싶은 경우가 있다. |
| | 285 | |
| | 286 | 검색어와 주변 텍스트를 컨텍스트 내 키워드, snippet이라고 한다. mroonga_snippet() 함수는 검색 결과에서 snippet을 가져오는 방법을 지정할 수 있다. |
| | 287 | |
| | 288 | mroonga_snippet() 함수는 UDF로 Mroonga에 포함되어 있지만 CREATE FUNCTION 명령으로 함수를 등록해야만 사용할 수 있다. |
| | 289 | {{{ |
| | 290 | CREATE FUNCTION mroonga_snippet RETURNS STRING SONAME 'ha_mroonga.so'; |
| | 291 | }}} |
| | 292 | |
| | 293 | 구문은 다음과 같다. |
| | 294 | {{{ |
| | 295 | mroonga_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 | {{{ |
| | 320 | select 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() === |
| | 325 | mroonga_command() 함수는 mroonga 명령을 직접 실행할 때 쓴다. MariaDB 명령보다 빠르다. |
| | 326 | |
| | 327 | ~~mroonga_command() 함수는 UDF로 Mroonga에 포함되어 있지만 CREATE FUNCTION 명령으로 함수를 등록해야만 사용할 수 있다.~~ |
| | 328 | {{{ |
| | 329 | CREATE FUNCTION mroonga_command RETURNS STRING SONAME 'ha_mroonga.so'; |
| | 330 | }}} |
| | 331 | |
| | 332 | mroonga_command() 함수의 예는 다음과 같다. |
| | 333 | {{{ |
| | 334 | select MROONGA_COMMAND('reindex mroonga_test'); |
| | 335 | }}} |
| | 336 | - reindex 명령만 내리면 현재 데이터베이스의 모든 인덱스가 대상이 된다. |
| | 337 | |
| | 338 | == Wrapper 모드 == |
| | 339 | Mroonga에는 Storage 모드와 wrapper 모드가 있다. |
| | 340 | |
| | 341 | * Storage 모드는 Full-Text 검색과 데이터 저장 모두에 Mroonga를 사용한다. 스토리지 엔진의 모든 기능을 Mroonga로 구현하기 때문에 Full-Text 검색이 빠르다. |
| | 342 | * Wrapper 모드는 Full-Text 검색 기능에만 Mroonga를 사용하고 MyISAM, InnoDB와 같은 다른 기존 스토리지 엔진은 데이터 저장에 사용한다. Mroonga는 SQL을 처리하는 SQL Handler와 기존 스토리지 엔진 사이에서 모든 데이터를 처리한다. |
| | 343 | |
| | 344 | Wrapper 모드로 사용할 때는 다음을 주의한다. |
| | 345 | * 반드시 PK가 있어야 한다. |
| | 346 | * Null 값을 사용할 수 있다. |
| | 347 | * InnoDB를 사용하면 트랜잭션을 사용할 수 있다. |
| | 348 | - 다만, rollback을 할 때 Full-Text 인덱스까지 롤백되지 않기 때문에 잘못된 결과가 나올 수 있다. 그런 경우에는 인덱스를 재생성해야 한다. |
| | 349 | |
| | 350 | Wrapper 모드로 테이블을 생성하려면 다음과 같이 COMMENT 항목에서 기존 스토리지 엔진을 적어주면 된다. |
| | 351 | {{{ |
| | 352 | create 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 처음으로] |