* MySQLoCfBO

* Senna MySQLoCfBOƂ?

MySQĹAo[W3.23.23ȍ~AFULLTEXTCfbNXT|[gĂA
VARCHAR, TEXT^̃tB[hɑ΂đSs邱Ƃł܂A
1) {̃T|[gsSA2) t[YxA3) XVxA
Ƃ_܂B

Senna MySQLoCfBÓAMySQLFULLTEXTCfbNXu`
SennaCugݍނ̂ŁAL̖_SĉA
ExSenna̓MySQLtɎgp\ɂ܂B

܂SɊւ\́AMySQL̃IWiFULLTEXTCfbNX
\̂܂܎gp\Ȃ߁AX[YɓKp邱Ƃł܂B

* g

Senna MySQLoCfBOgp邽߂ɂ́ASennagݍݔłMySQLCXg[܂B
SennagݍݔłMySQLCXg[ɂ͓̕@܂B

+ Senna MySQLoCfBOgݍݍς݂̃oCipbP[WCXg[
+ MySQL̃\[XSenna MySQLoCfBOpb`𓖂ĂăRpCECXg[

CXg[AMySQLT[oN΁A
http://dev.mysql.com/doc/refman/4.1/ja/fulltext-search.html
ɏĂ@Sennafulltext index\zA
S@\gp邱Ƃł悤ɂȂ܂B

* @\Ɛ

- 4.0n, 4.1n, 5.0n, 5.1n̊eŐVo[WMySQLŎgpł܂B
- IN BOOLEAN MODEƃftHg(NLQ MODE)̑S(MATCH AGAINST)NGT|[g܂B
- IN BOOLEAN MODEł́A+, -, <, >, (, ), ~, *, " ̑SZqgpł܂B
- EUC, SJIS, UTF83ނ̃GR[fBOgpł܂B
- K@\gpł܂BUTF8̏ꍇNFKCKT|[g܂B
- ֘A@\gpł܂B
- ߖT(ߐ)@\gpł܂B
- MyISAM  MERGE2ނ̃Xg[WGWT|[g܂B(MERGE4.0.27̂)
- Xjybg@\gpł܂B
- PCfbNX(mecabgp), NGRAMCfbNX, 󔒋؂CfbNX3ނIł܂B
- fulltextCfbNXƑ̃CfbNXgݍ킹Č@\܂(2ind patch)
- qbg擾LIMITw茟@\܂(skipmode patch) (4.0.27̂)

* CXg[菇ڍ

[[install]]QƉB

* Ǝg@\

Senna MySQLoCfBOł́ApIȑSAvP[V
MySQLgpł悤ɂ̊g@\Ă܂B
(g@\񋟂ĂGREȄ򂳂AiYappȏ򂳂ɐ[ӂ܂)

** CREATE TABLE / CREATE INDEX ̊g

 Senna ̊ep[^wł܂B

*** CfbNX^Cv̎w

PCfbNX, NGRAMCfbNX, DELIMITEDCfbNX3̂ꂩIł܂B

**** P(mecab)CfbNX쐬ꍇ

CfbNX^Cvw肵ȂΒPCfbNXgp܂B

()

   CREATE TABLE test (
     id INTEGER AUTO_INCREMENT,
     PRIMARY KEY (id),
     text TEXT NOT NULL,
     FULLTEXT INDEX (text)
   );

**** NGRAMCfbNX쐬ꍇ

USING NGRAMw肵܂B

()

   CREATE TABLE test (
     id INTEGER AUTO_INCREMENT,
     PRIMARY KEY (id),
     text TEXT NOT NULL,
     FULLTEXT INDEX USING NGRAM (text)
   );

**** DELIMITEDCfbNX쐬ꍇ

USING DELIMITEDw肷ƁA󔒂ŋ؂ꂽPʂŃCfbNX쐬܂B

()

   CREATE TABLE test (
     id INTEGER AUTO_INCREMENT,
     PRIMARY KEY (id),
     text TEXT NOT NULL,
     FULLTEXT INDEX USING DELIMITED (text)
   );

**** MySQL̑ffulltext index쐬(sennaCfbNXgpȂ)ꍇ

USING NO SENNAw肵܂B

()

   CREATE TABLE test (
     id INTEGER AUTO_INCREMENT,
     PRIMARY KEY (id),
     text TEXT NOT NULL,
     FULLTEXT INDEX USING NO SENNA (text)
   );

**** K@\̎gp/sgp

ftHgł͐K@\LɂȂ܂B
邽߂ɂ́AUSING NO NORMALIZEw肵܂B

() KȂNGRAMCfbNX쐬ꍇ

   CREATE TABLE test (
     id INTEGER AUTO_INCREMENT,
     PRIMARY KEY (id),
     text TEXT NOT NULL,
     FULLTEXT INDEX USING SENNA, NO NORMALIZE, NGRAM (text)
   );

**** INITIAL_N_SEGMENTSw

USING lw肷邱ƂɂāAINITIAL_N_SEGMENTS
(CfbNXobt@̈̏l)CfbNX쐬ɐݒł܂B

() INITIAL_N_SEGMENTS=2048ŃCfbNX쐬ꍇ

   CREATE TABLE test (
     id INTEGER AUTO_INCREMENT,
     PRIMARY KEY (id),
     text TEXT NOT NULL,
     FULLTEXT INDEX USING SENNA, 2048 (text)
   );

** SHOW INDEX ̊g

CREATE TABLE / CREATE INDEX ̊gɔ SHOW INDEX gāAgpĂCfbNX̎ނ𒲂ׂ邱Ƃł悤ɂȂ܂B

  mysql> SHOW INDEX FROM test;
  +-------+------------+----------+- ... -+--------+------+--------------------------------+---------+
  | Table | Non_unique | Key_name |       | Packed | Null | Index_type                     | Comment |
  +-------+------------+----------+- ... -+--------+------+--------------------------------+---------+
  | test  |          0 | PRIMARY  |       | NULL   |      | BTREE                          |         |
  | test  |          1 | text     |       | NULL   | YES  | FULLTEXT,SENNA,NORMALIZE,NGRAM |         |
  +-------+------------+----------+--... -+--------+------+--------------------------------+---------+ 
  2 rows in set (0.04 sec)

** SHOW TABLE STATUS ̊g

SHOW TABLE STATUS  ɂāAe[uŎgĂ Senna ̓]ue[ube[ũR[h̍vACfbNXt@C̃TCYm邱Ƃł悤ɂȂ܂B̑SCfbNXƂɂ͂܂Ӗ܂...B

  +-------+--------+ ... -------+----------------+----------------+--------------------+---------+
  | Name  | Type   | ... k_time | Create_options | Senna_key_size | Senna_lexicon_size | Comment | 
  +-------+--------+ ... -------+----------------+----------------+--------------------+---------+
  | test1 | MyISAM | ...        |                |              0 |                  0 |         |
  | test2 | MyISAM | ...        |                |              0 |                  0 |         |
  | test3 | MyISAM | ...        |                |              0 |                  0 |         |
  | test4 | MyISAM | ...        |                |              0 |                  0 |         |
  | test5 | MyISAM | ...        |                |              0 |                  0 |         |
  +-------+--------+ ... -------+----------------+----------------+--------------------+---------+

̃JǉĂ܂B

- Senna_keys_size

V{\ (.SEN) ̃R[h̍v܂B

- Senna_keys_file_size

V{\ (.SEN) ̃t@CTCY̍v܂B

- Senna_lexicon_size

be[u (.SEN.I) ̃R[h̍v܂B

- Senna_lexicon_file_size

be[u (.SEN.I) ̃t@CTCY̍v܂B

- Senna_inv_seg_size

]ue[ũobt@ (.SEN.i) ̃t@CTCY܂B

- Senna_inv_chunk_size

]ue[u (.SEN.i.c) ̃t@CTCY܂B

** 2ind patch(2CfbNXgp@\)

*** 2ind patchƂ

MySQLŃNGsۂɂ́A
P̃e[uɑ΂ĂP̃CfbNXpł܂B

ʏ̃NG̏ꍇ́A
̃Jɂ܂CfbNXpӂ邱ƂɂāA
Iɂ̐邱Ƃł܂B

ASp̃CfbNXpꍇA
̃CfbNXpłȂ߁A
ȉ̂悤Ȗ肪܂B

1. limitwŏo͂𐧌Ăx

   select columns from table where match(a) against(b) limit 1000, 10

̂悤ɁAItZbgɑ傫Ȓlw肷ƃe[uXLA
xȂ܂B

2. count(*)Ō擾邾łx

   select count(*) from table where match(a) against(b);

̂悤Ɍ擾邾łe[uXLA
xȂ܂B

3. SȊȌōi荞ޏx

   select columns from table where match(a) against(b) and c like 'hoge%';

̂悤ɁASȊOɑ̃JɊւw肵ꍇA
̃JɃCfbNXĂĂe[uXLA
xȂ܂B

4. SȊȌŃ\[g鏈x

   select columns from table where match(a) against(b) order by c;

̂悤ɁA\[gw肵ꍇÃJɃCfbNX
ĂĂe[uXLAxȂ܂BB

̂悤Ȗ邽߂ɁA
MySQLSp̃CfbNXƒʏ̃CfbNX̗𕹗pł悤ɂ2ind-patchpb`gpł܂B

*** 2ind patch̃CXg[(\[XCXg[ꍇ)

MySQL\[XɁAmysql-x.x.x.senna.diff 𓖂ĂƁA

 patch -p1 < {senna-package}/bindings/mysql/mysql-x.x.x.senna.2ind.diff

̂悤ɎsāA2ind patch𓖂Ă܂B̑̎菇[[install]]̒ʂłB

*** 2ind-patch̎g
- 1. 2.̃p^ɂẮAɈӎ邱ƂȂAʏʂSQL𔭍s邾2ind-patcȟʂ܂B
- 3. 4.̃p^ɂẮAi荞݂\[gɎgpCfbNXȉ̂悤ɖIɎw肷Kv܂B
   select columns from table force index(c) where match(a) against(b) and c like 'hoge%';

   select columns from table force index(c) where match(a) against(b) order by c;

(L[ł force index(PRIMARY) ̂悤Ɏw肵܂)

*** 2ind-patch̒ӓ_

-Oq4̃NGp^ȊOł͌ʂƂ͌܂BSőʂ̃R[hqbg邱ƂɂĔfBXNI/O\jQvłꍇɂ̂݌ʂ҂ł܂B
-{pb`͂܂łłBMySQL̈萫ɋyڂe͖mFłB

** snippet UDF

ʂ\ۂɁÃL[[h̎ӂ݂̂\ꍇ܂B
̃L[[h̎ӂ̃eLXgAsnippet܂KWIC(KeyWord In Context)ƌĂт܂B
̋@\̂Asnippet UDFłB

***snippet UDF̃CXg[

UDF̃fBNgɈړ
 > cd {senna-package}/bindings/mysql/udf/
''Subversion\[X擾ꍇ̂݁A''autogen.sh̎s
 > ./autogen.sh
configure
 > ./configure --prefix=/usr
make܂B
 > make
install܂B
 > sudo make install
MySQLUDFgݍ݂܂B
Ȃ݂ɁAmake loadł́umysql -u root -pvR}hĂяoUDFo^Ă܂B
MySQLroot[ŨpX[h͂B
 > make load

*** snippet UDF̎g
snippet UDF͑ψ̑MySQL̊֐łB

 SELECT snippet(, snippet̒̍őoCg, snippet̍ő, ̕R[h, 
   htmlGR[fBO̗L, snippet̊Jn^O, snippet̏I^O, 
   P1, P1̑Oɂ^O, P1̌ɂ^O, 
   P2, P2̑Oɂ^O, P2̌ɂ^O, ...);

R[h́Asjis, ujis, utf8, default̂ꂩw肭B
htmlGR[fBO̗ĹA01w肭B
1̏ꍇ͕<,>,&,"ꂼ&lt;,&gt;,&amp;,&quot;ɕϊďo͂܂B

͈ȉ̂ƂłB

 SELECT snippet(body, 120, 3, 'ujis', 
   1, '...', '...<br>\n', 
   '', '<span class="word1">', '</span>', 
   '', '<span class="word2">', '</span>'
 )
 FROM contents
 WHERE MATCH(body) AGAINST('*D+  ' IN BOOLEAN MODE)
 LIMIT 0,10;

** skipmode-patch

skipmode-patch́ANG[ɂăqbg擾LIMITw茟@\łB
MySQL-4.0.27ł̂ݎgp邱Ƃł܂B

*** skipmode patch̃CXg[

MySQL\[XɁAmysql-x.x.x.senna.diff 𓖂ĂƁA

 patch -p1 < {senna-package}/bindings/mysql/mysql-x.x.x.senna.2ind.diff
 patch -p1 < {senna-package}/bindings/mysql/mysql-x.x.x.senna.2ind.skipmode.diff

̂悤ɎsāA2ind patchskipmode patch̗𓖂Ă܂B
̑̎菇[[install]]̒ʂłB
