4.3. ストレージモード#
ここでは Mroonga におけるストレージモードの利用方法を説明します。
4.3.1. 全文検索の利用方法#
インストールが確認できたら、テーブルを1つ作成してみましょう。 ENGINE = Mroonga
とMroongaを指定するところがポイントです。
CREATE TABLE diaries (
id INT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(255),
FULLTEXT INDEX (content)
) ENGINE = Mroonga DEFAULT CHARSET utf8;
-- Query OK, 0 rows affected (0.10 sec)
INSERT
でデータを投入してみましょう。
INSERT INTO diaries (content) VALUES ("It'll be fine tomorrow.");
-- Query OK, 1 row affected (0.01 sec)
INSERT INTO diaries (content) VALUES ("It'll rain tomorrow");
-- Query OK, 1 row affected (0.00 sec)
全文検索を実行してみます。
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.3.2. 検索スコアの取得方法#
注釈
1.0.0以前のMroongaではMySQLの標準的な検索スコアの取得方法ではなく、 _score
という専用のカラムを作成するという独自の方法でした。1.0.0からはMySQLの標準的な取得方法になっています。
全文検索を行う際、指定したキーワードにより内容が一致するレコードを上位に表示したいというような場合があります。そうしたケースでは検索スコアを利用します。
検索スコアはMySQLの標準的な方法 [1] で取得できます。つまり、SELECTの取得するカラム名を指定するところやORDER BYのところにMATCH...AGAINSTを指定します。
それでは実際にやってみましょう。
INSERT INTO diaries (content) VALUES ("It's fine today. It'll be fine tomorrow as well.");
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO diaries (content) VALUES ("It's fine today. But it'll rain tomorrow.");
-- Query OK, 1 row affected (0.00 sec)
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
を使って下さい。
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.3.3. 全文検索用パーサの変更#
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_tokenizer
変数を利用してください。
トークナイザーに指定できるのは以下の値です。Mroongaで言う「トークナイザー」とMySQLで言う「パーサー」は同じものです。
トークナイザー |
説明 |
---|---|
|
( |
|
Added in version 8.07: トークナイズしません。"off"は |
|
バイグラムでトークナイズする。ただし、連続したアルファベット・連続した数字・連続した記号はそれぞれ1つのトークンとして扱う。そのため、3文字以上のトークンも存在する。これはノイズを減らすためである。 デフォルト値。 |
|
MeCabを用いてトークナイズする。groongaがMeCabサポート付きでビルドされている必要がある。 |
|
バイグラムでトークナイズする。 TokenBigramではなく |
|
バイグラムでトークナイズする。
|
|
バイグラムでトークナイズする。
|
|
バイグラムでトークナイズする。
|
|
バイグラムでトークナイズする。
|
|
バイグラムでトークナイズする。
|
|
バイグラムでトークナイズする。
|
|
空白区切りでトークナイズする。 「 |
|
null文字( 「 |
|
ユニグラムでトークナイズする。ただし、連続したアルファベット・連続した数字・連続した記号はそれぞれ1つのトークンとして扱う。そのため、2文字以上のトークンも存在する。これはノイズを減らすためである。 |
|
トリグラムでトークナイズする。ただし、連続したアルファベット・連続した数字・連続した記号はそれぞれ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:
SET GLOBAL mroonga_default_tokenizer = TokenMecab;
-- Query OK, 0 rows affected (0.00 sec)
4.3.4. ノーマライザーの指定方法#
Mroongaは、文書のエンコーディング(照合順序)に応じたノーマライザーを使用します。これはテキストをトークナイズするときとテーブルのキーを保存するときに使われます。
utf8_general_ci
または utf8mb4_general_ci
の場合、NormalizerMySQLGeneralCI
ノーマライザーが使用されます。
utf8_unicode_ci
または utf8mb4_unicode_ci
の場合、NormalizerMySQLUnicodeCI
ノーマライザーが使用されます。
utf8_bin
の場合、ノーマライザーは使用されません。
以下は、 utf8_unicode_ci
の照合順序を指定して NormalizerMySQLUnicodeCI
ノーマライザーを使用する例です。
SET NAMES utf8;
-- Query OK, 0 rows affected (0.00 sec)
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)
INSERT INTO diaries VALUES ("2013-04-23", "ブラックコーヒーを飲んだ。");
-- Query OK, 1 row affected (0.00 sec)
SELECT *
FROM diaries
WHERE MATCH (content) AGAINST ("+ふらつく" IN BOOLEAN MODE);
-- +------------+-----------------------------------------+
-- | day | content |
-- +------------+-----------------------------------------+
-- | 2013-04-23 | ブラックコーヒーを飲んだ。 |
-- +------------+-----------------------------------------+
-- 1 row in set (0.00 sec)
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
のノーマライザーを使用する例です。
SET NAMES utf8;
-- Query OK, 0 rows affected (0.00 sec)
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)
INSERT INTO diaries VALUES ("2013-04-23", "ブラックコーヒーを飲んだ。");
-- Query OK, 1 row affected (0.00 sec)
SELECT *
FROM diaries
WHERE MATCH (content) AGAINST ("+ふらつく" IN BOOLEAN MODE);
-- Empty set (0.00 sec)
SELECT *
FROM diaries
WHERE MATCH (content) AGAINST ("+ブラック" IN BOOLEAN MODE);
-- +------------+-----------------------------------------+
-- | day | content |
-- +------------+-----------------------------------------+
-- | 2013-04-23 | ブラックコーヒーを飲んだ。 |
-- +------------+-----------------------------------------+
-- 1 row in set (0.00 sec)
4.3.5. トークンフィルターの指定方法#
Mroongaは、Groongaのトークンフィルターを指定する以下のような構文を持っています。:
FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStem"'
以下は、TokenFilterStem
のトークンフィルターを使用する例です。
SELECT mroonga_command('register token_filters/stem');
-- +------------------------------------------------+
-- | mroonga_command('register token_filters/stem') |
-- +------------------------------------------------+
-- | true |
-- +------------------------------------------------+
-- 1 row in set (0.00 sec)
CREATE TABLE memos (
id INT NOT NULL PRIMARY KEY,
content TEXT NOT NULL,
FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto", token_filters "TokenFilterStem"'
) Engine=Mroonga DEFAULT CHARSET=utf8;
-- Query OK, 0 rows affected (0.18 sec)
INSERT INTO memos VALUES (1, "I develop Groonga");
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO memos VALUES (2, "I'm developing Groonga");
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO memos VALUES (3, "I developed Groonga");
-- Query OK, 1 row affected (0.00 sec)
SELECT *
FROM memos
WHERE MATCH (content) AGAINST ("+develops" IN BOOLEAN MODE);
-- +----+------------------------+
-- | id | content |
-- +----+------------------------+
-- | 1 | I develop Groonga |
-- | 2 | I'm developing Groonga |
-- | 3 | I developed Groonga |
-- +----+------------------------+
-- 3 rows in set (0.01 sec)
詳細は Groongaのトークンフィルターのドキュメント を確認してください。
以下は、TokenFilterStopWord
のトークンフィルターを使用する例です。
SELECT mroonga_command("register token_filters/stop_word");
-- +-----------------------------------------------------+
-- | mroonga_command("register token_filters/stop_word") |
-- +-----------------------------------------------------+
-- | true |
-- +-----------------------------------------------------+
-- 1 row in set (0.00 sec)
CREATE TABLE terms (
term VARCHAR(64) NOT NULL PRIMARY KEY,
is_stop_word BOOL NOT NULL
) Engine=Mroonga COMMENT='tokenizer "TokenBigram", token_filters "TokenFilterStopWord"' DEFAULT CHARSET=utf8;
-- Query OK, 0 rows affected (0.12 sec)
CREATE TABLE memos (
id INT NOT NULL PRIMARY KEY,
content TEXT NOT NULL,
FULLTEXT INDEX (content) COMMENT 'table "terms"'
) Engine=Mroonga DEFAULT CHARSET=utf8;
-- Query OK, 0 rows affected (0.17 sec)
INSERT INTO terms VALUES ("and", true);
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO memos VALUES (1, "Hello");
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO memos VALUES (2, "Hello and Good-bye");
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO memos VALUES (3, "Good-bye");
-- Query OK, 1 row affected (0.00 sec)
SELECT *
FROM memos
WHERE MATCH (content) AGAINST ('+"Hello and"' IN BOOLEAN MODE);
-- +----+--------------------+
-- | id | content |
-- +----+--------------------+
-- | 1 | Hello |
-- | 2 | Hello and Good-bye |
-- +----+--------------------+
-- 2 rows in set (0.01 sec)
これは、全文検索用の語彙表テーブルを指定する方法を使用しています。
4.3.6. Groongaのカラムフラグの指定方法#
Mroongaは、Groongaのカラムフラグを指定する以下のような構文を持っています。:
content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZLIB"'
以下は、COMPRESS_ZLIB
フラグを使用する例です。
CREATE TABLE entries (
id INT UNSIGNED PRIMARY KEY,
content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZLIB"'
) Engine=Mroonga DEFAULT CHARSET=utf8;
-- Query OK, 0 rows affected (0.12 sec)
Groongaのカラムフラグの詳細については Groongaのドキュメント を参照してください。
4.3.7. 位置情報検索の利用方法#
ストレージモードでは全文検索だけではなく位置情報検索も高速に実行できます。ただし、MyISAMとは異なりデータとして格納できるのはPOINT型のみです。LINEなどの他のデータ型は保存できません。また、インデックスを用いた高速な検索に対応しているのはMBRContainsだけです。MBRDisjointなどには対応していません。
位置情報検索を利用する場合のテーブル定義はMyISAMと同様にPOINT型のカラムを定義し、そのカラムに対してSPATIAL INDEXを指定します。
CREATE TABLE shops (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
location POINT NOT NULL,
SPATIAL INDEX (location)
) ENGINE = Mroonga;
-- Query OK, 0 rows affected (0.06 sec)
データの登録方法もMyISAMのときと同様にGeomFromText()関数を使って文字列からPOINT型の値を作成します。
INSERT INTO shops VALUES (null, 'Nezu''s Taiyaki', GeomFromText('POINT(139.762573 35.720253)'));
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO shops VALUES (null, 'Naniwaya', GeomFromText('POINT(139.796234 35.730061)'));
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO shops VALUES (null, 'Yanagiya Taiyaki', GeomFromText('POINT(139.783981 35.685341)'));
-- Query OK, 1 row affected (0.00 sec)
池袋駅(139.7101 35.7292)が左上の点、東京駅(139.7662 35.6815)が右下の点となるような長方形内にあるお店を探す場合は以下のようなSELECTになります。
SELECT id, name, AsText(location)
FROM shops
WHERE MBRContains(GeomFromText('LineString(139.7101 35.7292, 139.7662 35.6815)'), location);
-- +----+-----------------------+------------------------------------------+
-- | id | name | AsText(location) |
-- +----+-----------------------+------------------------------------------+
-- | 1 | Nezu's Taiyaki | POINT(139.762572777778 35.7202527777778) |
-- +----+-----------------------+------------------------------------------+
-- 1 row in set (0.00 sec)
位置情報で検索できていますね!
4.3.8. レコードIDの取得方法#
Groongaではテーブルにレコードを追加した際にレコードを一意に識別するための番号が割当てられます。
Mroongaではアプリケーションの開発を容易にするため、このレコードIDをSQLで取得できるようになっています。
レコードIDを取得するためには、テーブル定義時に _id
という名前のカラムを作成して下さい。
CREATE TABLE memos (
_id INT,
content VARCHAR(255),
UNIQUE KEY (_id) USING HASH
) ENGINE = Mroonga;
-- Query OK, 0 rows affected (0.04 sec)
_id
カラムのデータ型は整数型(TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT)である必要があります。
また_idカラムにはインデックスを作成することが可能ですが、HASH形式である必要があります。
INSERTでテーブルにレコードを追加してみましょう。_idカラムは仮想カラムとして実装されており、また_idの値であるレコードIDはGroongaにより割当てられるため、SQLによる更新時に値を指定することはできません。更新対象から外すか、値に null
を使用する必要があります。
INSERT INTO memos VALUES (null, "Saury for today's dinner.");
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO memos VALUES (null, "Update mroonga tomorrow.");
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO memos VALUES (null, "Buy some dumpling on the way home.");
-- Query OK, 1 row affected (0.00 sec)
INSERT INTO memos VALUES (null, "Thank God It's meat day.");
-- Query OK, 1 row affected (0.00 sec)
レコードIDを取得するには、_idカラムを含むようにしてSELECTを行います。
SELECT * FROM memos;
-- +------+------------------------------------------+
-- | _id | content |
-- +------+------------------------------------------+
-- | 1 | Saury for today's dinner. |
-- | 2 | Update mroonga tomorrow. |
-- | 3 | Buy some dumpling on the way home. |
-- | 4 | Thank God It's meat day. |
-- +------+------------------------------------------+
-- 4 rows in set (0.00 sec)
また直前のINSERTにより割当てられたレコードIDについては、last_insert_grn_id関数により取得することもできます。
INSERT INTO memos VALUES (null, "Just one bottle of milk in the fridge.");
-- Query OK, 1 row affected (0.00 sec)
SELECT last_insert_grn_id();
-- +----------------------+
-- | last_insert_grn_id() |
-- +----------------------+
-- | 5 |
-- +----------------------+
-- 1 row in set (0.00 sec)
last_insert_grn_id関数はユーザ定義関数(UDF)としてMroongaに含まれていますが、インストール時にCREATE FUNCTIONでMySQLに追加していない場合には、以下の関数定義DDLを実行しておく必要があります。
CREATE FUNCTION last_insert_grn_id RETURNS INTEGER SONAME 'ha_mroonga.so';
ご覧のように_idカラムやlast_insert_grn_id関数を通じてレコードIDを取得することができました。ここで取得したレコードIDは後続のUPDATEなどのSQL文で利用すると便利です。
UPDATE memos SET content = "So much milk in the fridge." WHERE _id = last_insert_grn_id();
-- Query OK, 1 row affected (0.00 sec)
-- Rows matched: 1 Changed: 1 Warnings: 0
4.3.9. スニペット(キーワード周辺のテキスト)の取得方法#
Mroongaは周辺テキスト付きでキーワードを取得する機能を提供しています。この機能は mroonga_snippet() UDFとして実装されています。
4.3.10. 類似文書検索の利用方法#
類似文書検索では、クエリーにキーワードの代わりに文書の内容を指定します。
類似文書検索は、関連する文書を見つけるのに便利です。
実行例で使用するスキーマ定義はこちら。
CREATE TABLE similarities (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(32),
content VARCHAR(255),
FULLTEXT INDEX (content)
) ENGINE = Mroonga DEFAULT CHARSET utf8;
実行例で使用するサンプルデータはこちら。
INSERT INTO similarities (title, content)
VALUES ('Groonga similar search', 'Groonga is an open-source fulltext search engine and column store.');
INSERT INTO similarities (title, content)
VALUES ('Mroonga similar search', 'Mroonga is an open-source storage engine for fast fulltext search with MySQL.');
INSERT INTO similarities (title, content)
VALUES ('Rroonga library', 'A library to use Groonga features from Ruby.');
以下は文書の内容による類似文書検索の出力例です。
SELECT title FROM similarities WHERE MATCH(content) AGAINST ('There are many open-source fulltext search engine.' IN NATURAL LANGUAGE MODE);
AGAINST('...' IN NATURAL LANGUAGE MODE) に文書の内容を指定する必要があることに注意してください。
SELECT title FROM similarities WHERE MATCH(content) AGAINST ('There are many open-source fulltext search engine.' IN NATURAL LANGUAGE MODE);
-- +------------------------+
-- | title |
-- +------------------------+
-- | Groonga similar search |
-- | Mroonga similar search |
-- +------------------------+
-- 2 rows in set (0.00 sec)
類似度合いを向上させるには、言語特有のパーサーを使うとか、タグ付けされたデータを使って望ましくない検索結果を取り除く必要があります。
例えば、日本語の文書の類似文書検索をするなら、TokenMecab をパーサーに指定するのがおすすめです。以下は TokenMecab を使うスキーマ定義の例です。:
CREATE TABLE similarities (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(32),
content VARCHAR(255),
FULLTEXT INDEX (content) COMMENT 'tokenizer "TokenMecab"'
) ENGINE = Mroonga DEFAULT CHARSET utf8;
4.3.11. Groongaコマンドの実行方法#
ストレージモードではMroongaはすべてのデータをGroongaのデータベースに保存します。Mroongaを使うことでSQLでGroongaのデータベースにアクセスできるようになります。SQLはとても強力ですが、ファセット検索などのようないくつかの操作が得意ではありません。
最近ではファセット検索は一般的なものになりました。amazon.comやebay.comのように多くのオンラインショッピングサイトがファセット検索をサポートしています。ファセット検索はユーザが検索結果を絞り込む前に絞り込み検索をし、その絞り込み検索の結果を表示します。ユーザは絞りこまれた結果から自分が探しているものを選ぶだけです。ファセット検索を使うとユーザは以下のようなメリットがあります。
ユーザはどうやって検索結果を絞り込むかを考える必要はありません。単に表示された絞り込み結果から選ぶだけです。
ユーザは「見つかりませんでした」ページを見ることがありません。ファセット検索では絞り込んだ結果のうち、ヒットする項目がある結果だけを表示します。
絞り込み検索は検索結果に対して複数の GROUP BY
操作を実行する必要があります。SQLでファセット検索をやろうとすると、複数の SELECT
リクエストが必要になります。これは効率的ではありません。
Groongaは1回のgroongaコマンドでファセット検索をできます。これは効率的です。Groongaには select
コマンドというファセット検索に対応した検索コマンドがあります。Groongaではファセット検索は「ドリルダウン(drilldown)」と呼んでいます。Groongaの select
コマンドの詳細については Groongaのドキュメント を参照してください。
Mroongaは mroonga_command()
関数を提供しています。この関数を使えばSQLの中で好きなGroongaコマンドを実行できます。しかし、使うのは select
コマンドだけにしておくべきです。スキーマやデータを変更するコマンドを使うと一貫性が壊れてしまうかもしれません。
実行例で使用するスキーマ定義はこちら。
CREATE TABLE diaries (
id INT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(255),
date DATE,
year YEAR,
`year_month` VARCHAR(9),
tag VARCHAR(32),
FULLTEXT INDEX (content)
) ENGINE = Mroonga DEFAULT CHARSET utf8;
実行例で使用するサンプルデータはこちら。
INSERT INTO diaries (content, date, year, `year_month`, tag)
VALUES ('Groonga is an open-source fulltext search engine and column store.',
'2013-04-08',
'2013',
'2013-04',
'groonga');
INSERT INTO diaries (content, date, year, `year_month`, tag)
VALUES ('Mroonga is an open-source storage engine for fast fulltext search with MySQL.',
'2013-04-09',
'2013',
'2013-04',
'MySQL');
INSERT INTO diaries (content, date, year, `year_month`, tag)
VALUES ('Tritonn is a patched version of MySQL that supports better fulltext search function with Senna.',
'2013-03-29',
'2013',
'2013-03',
'MySQL');
各レコードには tag
として groonga
あるいは MySQL
が付いています。各レコードは year
と year_month
カラムも持っています。ファセット検索のキーとして tag
、 year
、 year_month
を使えます。
Groongaはファセット検索のことをドリルダウンと呼んでいます。そのため、Groongaでのパラメータ名は --drilldown
となっています。Groongaは検索結果をJSONで返します。そのため、 mroonga_command()
も検索結果をJSONで返します。これはSQLらしくありません。JSON形式の検索結果は自分でパースしないといけません。
以下は利用可能なファセット検索キーをすべて使った例です。(結果のJSONは整形済み)
SELECT mroonga_command("select diaries --output_columns _id --limit 0 --drilldown tag,year,year_month") AS faceted_result;
-- +-----------------------------+
-- | faceted_result |
-- +-----------------------------+
-- | [[[3], |
-- | [["_id","UInt32"]]], |
-- | [[2], |
-- | [["_key","ShortText"], |
-- | ["_nsubrecs","Int32"]], |
-- | ["groonga",1], |
-- | ["MySQL",2]], |
-- | [[1], |
-- | [["_key","Time"], |
-- | ["_nsubrecs","Int32"]], |
-- | [1356998400.0,3]], |
-- | [[2], |
-- | [["_key","ShortText"], |
-- | ["_nsubrecs","Int32"]], |
-- | ["2013-04",2], |
-- | ["2013-03",1]]] |
-- +-----------------------------+
-- 1 row in set (0.00 sec)
最初の要素 [[3], [["_id","UInt32"]]]
は通常の検索の結果です。これはファセット検索の結果ではありません。
2番目、3番目、4番目の要素がファセット検索の結果です。
[[2],
[["_key","ShortText"],
["_nsubrecs","Int32"]],
["groonga",1],
["MySQL",2]]
[[1],
[["_key","Time"],
["_nsubrecs","Int32"]],
[1356998400.0,3]]
[[2],
[["_key","ShortText"],
["_nsubrecs","Int32"]],
["2013-04",2],
["2013-03",1]]
ファセット検索の結果の順序は --drilldown
に指定した値に対応します。この例では、 --drilldown
の値に tag
と year
と year_month
を指定しています。そのため、最初のファセット検索の結果は tag
用の結果で、2番目は year
用の結果で、 3番目は year_month
用の結果です。
各ファセット検索の結果は次のフォーマットになります。このフォーマットは通常の検索の結果と同じです。
[[${THE_NUMBER_OF_RECORDS}],
[[${OUTPUT_COLUMN_NAME_0}, ${OUTPUT_COLUMN_TYPE_0}],
[${OUTPUT_COLUMN_NAME_1}, ${OUTPUT_COLUMN_TYPE_1}],
...,
[${OUTPUT_COLUMN_NAME_N}, ${OUTPUT_COLUMN_TYPE_N}]]
[${OUTPUT_COLUMN_VALUE_0_FOR_RECORD_0},
${OUTPUT_COLUMN_VALUE_1_FOR_RECORD_0},
...,
${OUTPUT_COLUMN_VALUE_N_FOR_RECORD_0}],
[${OUTPUT_COLUMN_VALUE_0_FOR_RECORD_1},
${OUTPUT_COLUMN_VALUE_1_FOR_RECORD_1},
...,
${OUTPUT_COLUMN_VALUE_N_FOR_RECORD_1}],
...
[${OUTPUT_COLUMN_VALUE_0_FOR_RECORD_M},
${OUTPUT_COLUMN_VALUE_1_FOR_RECORD_M},
...,
${OUTPUT_COLUMN_VALUE_N_FOR_RECORD_M}]]
ファセット検索の結果の _key
カラムの値はファセット検索で使用したキーを示します。
たとえば、最初のファセット検索の結果( tag
のファセット検索の結果)はマッチしたレコード(今回のケースではすべてのレコード)は tag
の値として groonga
と MySQL
があることを示しています。
[[2],
[["_key","ShortText"],
["_nsubrecs","Int32"]],
["groonga",1],
["MySQL",2]]
ファセット検索の結果の _nsubrecs
カラムの値は対応するファセット検索のキーを持つレコードが何件あるかを示します。
たとえば、最初のファセット検索の結果( tag
のファセット検索の結果)は tag
の値として groonga
を持つレコードは1件あり、 tag
の値として MySQL
を持つレコードは2件あることを示しています。
[[2],
[["_key","ShortText"],
["_nsubrecs","Int32"]],
["groonga",1],
["MySQL",2]]
詳細は Groongaのselectコマンドのドキュメント を確認してください。
4.3.12. 正規表現検索の利用方法#
ストレージモードでは、すでに述べたようにMroongaからGroongaの機能が使えます。つまりGroongaの機能を使って正規表現で検索できます。
Mroongaで正規表現を使うにはいくつか条件があります。
COMMENT
にてTokenRegexp
トークナイザーを指定してインデックスを作成するWHERE MATCH ... AGAINST
にて*SS
プラグマを使う
以下は正規表現による検索の出力例です。
CREATE TABLE paths (
content text,
FULLTEXT INDEX content_index (content) COMMENT 'tokenizer "TokenRegexp", normalizer "NormalizerAuto"'
) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
INSERT INTO paths VALUES ('/usr/bin/groonga');
INSERT INTO paths VALUES ('/var/log/auth.log');
INSERT INTO paths VALUES ('/var/log/messages');
INSERT INTO paths VALUES ('/tmp/local/var/log/auth.log');
SELECT * FROM paths WHERE MATCH(content) AGAINST ('*SS content @~ "\\\\A/var/log/auth"' IN BOOLEAN MODE);
-- +-------------------+
-- | content |
-- +-------------------+
-- | /var/log/auth.log |
-- +-------------------+
-- 1 row in set (0.024 sec)
*SS プラグマを使うことにより、 content @~ "\\\\A/var/log/auth"
で /var/log/auth
ではじまるレコードを検索できます。 @~
はGroongaで正規表現検索するためのオペレーターで、 "\\\\A/var/log/auth"
は前方一致検索を行うので、 /var/log/auth.log
だけがマッチします。 /tmp/local/var/log/auth.log
がマッチしないのは、/var/log/auth
ではじまっていないからです。
構文の詳細は Groongaの正規表現のドキュメント を確認してください。
4.3.13. ログ出力#
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文で動的に出力レベルを変更することもできます。
SHOW VARIABLES LIKE 'mroonga_log_level';
-- +-------------------+--------+
-- | Variable_name | Value |
-- +-------------------+--------+
-- | mroonga_log_level | NOTICE |
-- +-------------------+--------+
-- 1 row in set (0.00 sec)
SET GLOBAL mroonga_log_level=DUMP;
-- Query OK, 0 rows affected (0.00 sec)
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サーバを停止せずにログのローテートを行いたいような場合には、以下の手順で実行すると良いでしょう。
groonga.log
ファイルの名前を変更(OSコマンドのmvなどで)MySQLサーバに対して"FLUSH LOGS"を実行(mysqlコマンドあるいはmysqladminコマンドにて)
4.3.14. 次のステップ#
これでストレージモードでMroongaを使えるようになりました!Mroongaをもっと速くしたい場合は 最適化 も参照してください。
脚注