4.4. ラッパーモード — Mroonga vmrn_version documentation

本文へスキップ
`Ctrl`+`K`

# 4.4. ラッパーモード

ここでは Mroonga におけるラッパーモードの利用方法を説明します。

バージョン 12.02 で変更: MySQL 8.0以降でラッパーモードのサポートをやめました。

## 4.4.1. ラッパーモードの利用方法

ラッパーモードでは、既存のストレージエンジンをラップするかたちで Mroonga が動作します。ラップする対象となるストレージエンジンは、現在のところ SQL のコメントを利用して `COMMENT = 'engine "InnoDB"'` のように指定するようになっています。

注釈

現在のところ、ラッパーモードではテーブルに必ずプライマリーキーを設定する必要があります。ストレージモードはこの限りではありません。

注釈

ラッパーモードでは現在ストレージモードでサポートされていない、以下をサポートしています。

- null値

- トランザクション (ストレージエンジンがサポートしている場合。ロールバックするとインデックスの不整合が発生します。インデックスを使った検索に影響するので、その場合にはMroongaのインデックスを再作成します。)

## 4.4.2. 全文検索の利用方法

インストールが確認できたら、テーブルを1つ作成してみましょう。 `ENGINE = Mroonga` とMroongaを指定するところがポイントです。:

    mysql> CREATE TABLE diaries (
        ->   id INT PRIMARY KEY AUTO_INCREMENT,
        ->   content VARCHAR(255),
        ->   FULLTEXT INDEX (content)
        -> ) ENGINE = Mroonga COMMENT = 'engine "InnoDB"' DEFAULT CHARSET utf8;
    Query OK, 0 rows affected (0.52 sec)

INSERTでデータを投入してみましょう。

    mysql> INSERT INTO diaries (content) VALUES ("It'll be fine tomorrow.");
    Query OK, 1 row affected (0.01 sec)

    mysql> INSERT INTO diaries (content) VALUES ("It'll rain tomorrow");
    Query OK, 1 row affected (0.00 sec)

全文検索を実行してみます。

    mysql> SELECT * FROM diaries WHERE MATCH(content) AGAINST("+fine" IN BOOLEAN MODE);
    +----+-----------------------------------------+
    | id | content                                 |
    +----+-----------------------------------------+
    |  1 | It'll be fine tomorrow. |
    +----+-----------------------------------------+
    1 row in set (0.00 sec)

おぉぉー。検索できましたね。

## 4.4.3. 検索スコアの取得方法

全文検索を行う際、指定したキーワードにより内容が一致するレコードを上位に表示したいというような場合があります。そうしたケースでは検索スコアを利用します。

検索スコアはMySQLの標準的な方法 [1] で取得できます。つまり、SELECTの取得するカラム名を指定するところやORDER BYのところにMATCH...AGAINSTを指定します。

それでは実際にやってみましょう。:

    mysql> INSERT INTO diaries (content) VALUES ("It's fine today. It'll be fine tomorrow as well.");
    Query OK, 1 row affected (0.00 sec)

    mysql> INSERT INTO diaries (content) VALUES ("It's fine today. But it'll rain tomorrow.");
    Query OK, 1 row affected (0.00 sec)

    mysql> SELECT *, MATCH (content) AGAINST ("+fine" IN BOOLEAN MODE) FROM diaries WHERE MATCH (content) AGAINST ("+fine" IN BOOLEAN MODE) ORDER BY MATCH (content) AGAINST ("+fine" IN BOOLEAN MODE) DESC;
    +----+--------------------------------------------------+---------------------------------------------------+
    | id | content                                          | MATCH (content) AGAINST ("+fine" IN BOOLEAN MODE) |
    +----+--------------------------------------------------+---------------------------------------------------+
    |  3 | It's fine today. It'll be fine tomorrow as well. |                                                 2 |
    |  1 | It'll be fine tomorrow.                          |                                                 1 |
    |  4 | It's fine today. But it'll rain tomorrow.        |                                                 1 |
    +----+--------------------------------------------------+---------------------------------------------------+
    3 rows in set (0.00 sec)

検索対象の文字列 `fine` をより多く含む、すなわち検索スコアの高い `id = 3` のメッセージが上に来ていることが確認できます。また、SELECT句にMATCH AGAINSTを記述しているため、検索スコアも取得できています。

属性名を変更したい場合は `AS` を使って下さい。

    mysql> SELECT *, MATCH (content) AGAINST ("+fine" IN BOOLEAN MODE) AS score FROM diaries WHERE MATCH (content) AGAINST ("+fine" IN BOOLEAN MODE) ORDER BY MATCH (content) AGAINST ("+fine" IN BOOLEAN MODE) DESC;
    +----+--------------------------------------------------+-------+
    | id | content                                          | score |
    +----+--------------------------------------------------+-------+
    |  3 | It's fine today. It'll be fine tomorrow as well. |     2 |
    |  1 | It'll be fine tomorrow.                          |     1 |
    |  4 | It's fine today. But it'll rain tomorrow.        |     1 |
    +----+--------------------------------------------------+-------+
    3 rows in set (0.00 sec)

## 4.4.4. 全文検索用パーサの変更

MySQLは全文検索用のパーサ [2] を指定する以下のような構文を持っています。:

    FULLTEXT INDEX (content) WITH PARSER parser_name

しかし、この構文を利用する場合は、あらかじめすべてのパーサをMySQLに登録しておく必要があります。一方、Groongaはトークナイザー（MySQLでいうパーサ）を動的に追加することができます。そのため、Mroongaでもこの構文を採用するとGroonga側に動的に追加されたトークナイザーに対応できなくなります。Groongaに動的に追加されるトークナイザーにはMeCabを用いたトークナイザーもあり、この制限に縛られることは利便性を損なうと判断し、以下のようなコメントを用いた独自の構文を採用することにしました。:

    FULLTEXT INDEX (content) COMMENT 'tokenizer "TokenMecab"'

注釈

`FULLTEXT INDEX` に `COMMENT` を指定できるのはMySQL 5.5からになります。MySQL 5.1を利用している場合は後述の `mroonga_default_parser` 変数を利用してください。

トークナイザーに指定できるのは以下の値です。

利用可能なトークナイザー一覧
トークナイザー | 説明
--- | ---
`off` | (`非推奨`) トークナイズしません。 `off` は `content` をそのまま扱いたい場合に使います。例えば、この値は前方一致検索のために指定します。
`none` | Added in version 8.07: トークナイズしません。"off"は `content` をそのまま扱いたい場合に使います。例えば、この値は前方一致検索のために指定します。
`TokenBigram` | バイグラムでトークナイズする。ただし、連続したアルファベット・連続した数字・連続した記号はそれぞれ1つのトークンとして扱う。そのため、3文字以上のトークンも存在する。これはノイズを減らすためである。 デフォルト値。
`TokenMecab` | MeCabを用いてトークナイズする。groongaがMeCabサポート付きでビルドされている必要がある。
`TokenBigramSplitSymbol` | バイグラムでトークナイズする。 `TokenBigram` と異なり、記号が連続していても特別扱いして1つのトークンとして扱わず通常のバイグラムの処理を行う。 TokenBigramではなく `TokenBigramSplitSymbol` を利用すると「 `Is it really!?!?!?` 」の「 `!?!?!?` 」の部分に「 `!?` 」でマッチする。 `TokenBigram` の場合は「 `!?!?!?` 」でないとマッチしない。
`TokenBigramSplitSymbolAlpha` | バイグラムでトークナイズする。 `TokenBigramSplitSymbol` に加えて、連続したアルファベットも特別扱いせずに通常のバイグラムの処理を行う。 `TokenBigram` ではなく `TokenBigramSplitSymbolAlpha` を利用すると「 `Is it really?` 」に「 `real` 」でマッチする。 `TokenBigram` の場合は「 `really` 」でないとマッチしない。
`TokenBigramSplitSymbolAlphaDigit` | バイグラムでトークナイズする。 `TokenBigramSplitSymbolAlpha` に加えて、連続した数字も特別扱いせずに通常のバイグラムの処理を行う。つまり、すべての字種を特別扱いせずにバイグラムの処理を行う。 `TokenBigram` ではなく `TokenBigramSplitSymbolAlphaDigit` を利用すると「 `090-0123-4567` 」に「 `567` 」でマッチする。 `TokenBigram` の場合は「 `4567` 」でないとマッチしない。
`TokenBigramIgnoreBlank` | バイグラムでトークナイズする。 `TokenBigram` と異なり、空白を無視して処理する。 `TokenBigram` ではなく `TokenBigramIgnoreBlank` を利用すると「 `み な さ ん 注 目` 」に「 `みなさん` 」でマッチする。 `TokenBigram` の場合は「 `み な さ ん` 」でないとマッチしない。
`TokenBigramIgnoreBlankSplitSymbol` | バイグラムでトークナイズする。 `TokenBigramSplitSymbol` と異なり、空白を無視して処理する。 `TokenBigramSplitSymbol` ではなく `TokenBigramIgnoreBlankSplitSymbol` を利用すると「 `! !? ??` 」に「 `???` 」でマッチする。 `TokenBigramSplitSymbol` の場合は「 `? ??` 」でないとマッチしない。
`TokenBigramIgnoreBlankSplitSymbolAlpha` | バイグラムでトークナイズする。 `TokenBigramSplitSymbolAlpha` と異なり、空白を無視して処理する。 `TokenBigramSplitSymbolAlpha` ではなく `TokenBigramIgnoreBlankSplitSymbolAlpha` を利用すると「 `I am a pen.` 」に「 `ama` 」でマッチする。 `TokenBigramSplitSymbolAlpha` の場合は「 `am a` 」でないとマッチしない。
`TokenBigramIgnoreBlankSplitSymbolAlphaDigit` | バイグラムでトークナイズする。 `TokenBigramSplitSymbolAlphaDigit` と異なり、空白を無視して処理する。 `TokenBigramSplitSymbolAlphaDigit` ではなく `TokenBigramIgnoreBlankSplitSymbolAlphaDigit` を利用すると「 `090 0123 4567` 」に「 `9001` 」でマッチする。 `TokenBigramSplitSymbolAlphaDigit` の場合は「 `90 01` 」でないとマッチしない。
`TokenDelimit` | 空白区切りでトークナイズする。 「 `movie horror topic` 」をトークナイズすると「 `movie` 」、「 `horror` 」、「 `topic` 」になります。
`TokenDelimitNull` | null文字（ `\\0` ）区切りでトークナイズする。 「 `movie\\0horror\\0topic` 」をトークナイズすると「 `movie` 」、「 `horror` 」、「 `topic` 」になります。
`TokenUnigram` | ユニグラムでトークナイズする。ただし、連続したアルファベット・連続した数字・連続した記号はそれぞれ1つのトークンとして扱う。そのため、2文字以上のトークンも存在する。これはノイズを減らすためである。
`TokenTrigram` | トリグラムでトークナイズする。ただし、連続したアルファベット・連続した数字・連続した記号はそれぞれ1つのトークンとして扱う。そのため、4文字以上のトークンも存在する。これはノイズを減らすためである。

デフォルトのパーサは `configure` の `--with-default-tokenizer` オプションでビルド時に指定することができます。:

    ./configure --with-default-tokenizer TokenMecab ...

また、my.cnfまたはSQL内で `mroonga_default_tokenizer` 変数を指定することでも指定できます。my.cnfで指定するとMySQLを再起動しても値は変更されたままですが、反映させるために再起動しなければいけません。一方、SQLで指定した場合はすぐに設定が反映されますが、MySQLが再起動すると設定は失われます。

my.cnf:

    [mysqld]
    mroonga_default_tokenizer=TokenMecab

SQL:

    mysql> SET GLOBAL mroonga_default_tokenizer = TokenMecab;
    Query OK, 0 rows affected (0.00 sec)

## 4.4.5. ノーマライザーの指定方法

Mroongaは、文書のエンコーディング(照合順序)に応じたノーマライザーを使用します。これはテキストをトークナイズするときとテーブルのキーを保存するときに使われます。

`utf8_general_ci` または `utf8mb4_general_ci` の場合、`NormalizerMySQLGeneralCI` ノーマライザーが使用されます。

`utf8_unicode_ci` または `utf8mb4_unicode_ci` の場合、`NormalizerMySQLUnicodeCI` ノーマライザーが使用されます。

`utf8_bin` の場合、ノーマライザーは使用されません。

以下は、 `utf8_unicode_ci` の照合順序を指定して `NormalizerMySQLUnicodeCI` ノーマライザーを使用する例です。:

    mysql> SET NAMES utf8;
    Query OK, 0 rows affected (0.00 sec)

    mysql> CREATE TABLE diaries (
        ->   day DATE PRIMARY KEY,
        ->   content VARCHAR(64) NOT NULL,
        ->   FULLTEXT INDEX (content)
        -> ) Engine=Mroonga DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    Query OK, 0 rows affected (0.18 sec)

    mysql> INSERT INTO diaries VALUES ("2013-04-23", "ブラックコーヒーを飲んだ。");
    Query OK, 1 row affected (0.00 sec)

    mysql> SELECT * FROM diaries
        ->        WHERE MATCH (content) AGAINST ("+ふらつく" IN BOOLEAN MODE);
    +------------+-----------------------------------------+
    | day        | content                                 |
    +------------+-----------------------------------------+
    | 2013-04-23 | ブラックコーヒーを飲んだ。 |
    +------------+-----------------------------------------+
    1 row in set (0.00 sec)

    mysql> SELECT * FROM diaries
        ->        WHERE MATCH (content) AGAINST ("+ﾌﾞﾗｯｸ" IN BOOLEAN MODE);
    +------------+-----------------------------------------+
    | day        | content                                 |
    +------------+-----------------------------------------+
    | 2013-04-23 | ブラックコーヒーを飲んだ。 |
    +------------+-----------------------------------------+
    1 row in set (0.00 sec)

Mroongaは、Groongaのノーマライザーを指定する以下のような構文を持っています。:

    FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'

詳細は Groongaのノーマライザーのドキュメント を確認してください。

以下は、`NormalizerAuto` のノーマライザーを使用する例です。:

    mysql> SET NAMES utf8;
    Query OK, 0 rows affected (0.00 sec)

    mysql> CREATE TABLE diaries (
        ->   day DATE PRIMARY KEY,
        ->   content VARCHAR(64) NOT NULL,
        ->   FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
        -> ) Engine=Mroonga DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    Query OK, 0 rows affected (0.19 sec)

    mysql> INSERT INTO diaries VALUES ("2013-04-23", "ブラックコーヒーを飲んだ。");
    Query OK, 1 row affected (0.00 sec)

    mysql> SELECT * FROM diaries
        ->        WHERE MATCH (content) AGAINST ("+ふらつく" IN BOOLEAN MODE);
    Empty set (0.00 sec)

    mysql> SELECT * FROM diaries
        ->        WHERE MATCH (content) AGAINST ("+ﾌﾞﾗｯｸ" IN BOOLEAN MODE);
    +------------+-----------------------------------------+
    | day        | content                                 |
    +------------+-----------------------------------------+
    | 2013-04-23 | ブラックコーヒーを飲んだ。 |
    +------------+-----------------------------------------+
    1 row in set (0.00 sec)

## 4.4.6. スニペット（キーワード周辺のテキスト）の取得方法

Mroongaは周辺テキスト付きでキーワードを取得する機能を提供しています。この機能は mroonga_snippet() UDFとして実装されています。

## 4.4.7. ログ出力

Mroongaではデフォルトでログの出力を行うようになっています。

ログファイルはMySQLのデータディレクトリ直下に `groonga.log` というファイル名で出力されます。

以下はログの出力例です。

    2010-10-07 17:32:39.209379|n|b1858f80|mroonga 1.10 started.
    2010-10-07 17:32:44.934048|d|46953940|hash get not found (key=test)
    2010-10-07 17:32:44.936113|d|46953940|hash put (key=test)

ログのデフォルトの出力レベルはNOTICE（必要な情報のみ出力。デバッグ情報などは出力しない）となっております。

ログの出力レベルは `mroonga_log_level` というシステム変数で確認することができます（グローバル変数）。またSET文で動的に出力レベルを変更することもできます。

    mysql> SHOW VARIABLES LIKE 'mroonga_log_level';
    +-------------------+--------+
    | Variable_name     | Value  |
    +-------------------+--------+
    | mroonga_log_level | NOTICE |
    +-------------------+--------+
    1 row in set (0.00 sec)

    mysql> SET GLOBAL mroonga_log_level=DUMP;
    Query OK, 0 rows affected (0.00 sec)

    mysql> SHOW VARIABLES LIKE 'mroonga_log_level';
    +-------------------+-------+
    | Variable_name     | Value |
    +-------------------+-------+
    | mroonga_log_level | DUMP  |
    +-------------------+-------+
    1 row in set (0.00 sec)

設定可能なログレベルは以下の通りです。

- NONE

- EMERG

- ALERT

- CRIT

- ERROR

- WARNING

- NOTICE

- INFO

- DEBUG

- DUMP

詳細は mroonga_log_level を参照してください。

またFLUSH LOGSでログの再オープンを行うことができます。MySQLサーバを停止せずにログのローテートを行いたいような場合には、以下の手順で実行すると良いでしょう。

1. `groonga.log` ファイルの名前を変更（OSコマンドのmvなどで）

2. MySQLサーバに対して"FLUSH LOGS"を実行（mysqlコマンドあるいはmysqladminコマンドにて）

## 4.4.8. 次のステップ

これでラッパーモードでMroongaを使えるようになりました！Mroongaをもっと速くしたい場合は 最適化 も参照してください。

脚注

[1]

MySQL 5.1 リファレンスマニュアル :: 11 関数と演算子 :: 11.7 全文検索関数

[2]

Groongaではトークナイザーと呼んでいる。