MySQL 5.6 では、MyISAM
でのみ全文パーサープラグインがサポートされます。全文パーサープラグインについての概要は、セクション24.2.3.2「全文パーサープラグイン」を参照してください。
全文パーサーサーバープラグインは、組み込みの全文パーサーの代わりにするか、それを変更するために使用できます。このセクションでは、simple_parser
という名前の全文パーサープラグインを記述する方法について説明します。このプラグインは、MySQL の組み込み全文パーサーによって使用されるものよりも簡単なルールに基づいて構文解析を実行し、単語は空白文字を含まない文字列です。
この手順では、MySQL ソース配布の plugin/fulltext
ディレクトリ内のソースコードを使用しているため、このディレクトリに場所を変更してください。次の手順では、プラグインライブラリを作成する方法について説明します。
-
全文パーサープラグインを記述するために、プラグインソースファイルで次のヘッダーファイルをインクルードします。プラグインの機能および要件によっては、ほかの MySQL のヘッダーファイルまたは一般的なヘッダーファイルが必要になることもあります。
#include <mysql/plugin.h>
plugin.h
は、MYSQL_FTPARSER_PLUGIN
サーバープラグインタイプ、およびプラグインを宣言するために必要なデータ構造体を定義します。 -
プラグインライブラリファイルのライブラリディスクリプタをセットアップします。
このディスクリプタには、サーバープラグインの一般プラグインディスクリプタが含まれています。全文パーサープラグインの場合、タイプは
MYSQL_FTPARSER_PLUGIN
である必要があります。これは、FULLTEXT
インデックスの作成時にWITH PARSER
句で使用する場合に、プラグインが正当なものであることを識別する値です。(ほかのプラグインタイプは、この句に対して正当ではありません。)たとえば、
simple_parser
という名前の単一の全文パーサープラグインを格納するライブラリのライブラリディスクリプタは、次のようになります。mysql_declare_plugin(ftexample) { MYSQL_FTPARSER_PLUGIN, /* type */ &simple_parser_descriptor, /* descriptor */ "simple_parser", /* name */ "Oracle Corporation", /* author */ "Simple Full-Text Parser", /* description */ PLUGIN_LICENSE_GPL, /* plugin license */ simple_parser_plugin_init, /* init function (when loaded) */ simple_parser_plugin_deinit,/* deinit function (when unloaded) */ 0x0001, /* version */ simple_status, /* status variables */ simple_system_variables, /* system variables */ NULL, 0 } mysql_declare_plugin_end;
name
メンバー (simple_parser
) は、INSTALL PLUGIN
、UNINSTALL PLUGIN
などのステートメントでプラグインを参照するために使用する名前を示しています。これは、SHOW PLUGINS
またはINFORMATION_SCHEMA.PLUGINS
によって表示される名前でもあります。詳細は、セクション24.2.4.2.1「サーバープラグインライブラリおよびプラグインディスクリプタ」を参照してください。
-
タイプ固有のプラグインディスクリプタをセットアップします。
ライブラリディスクリプタの各一般プラグインディスクリプタは、タイプ固有のディスクリプタを指しています。全文パーサープラグインの場合、タイプ固有のディスクリプタは
plugin.h
ファイル内のst_mysql_ftparser
構造体のインスタンスです。struct st_mysql_ftparser { int interface_version; int (*parse)(MYSQL_FTPARSER_PARAM *param); int (*init)(MYSQL_FTPARSER_PARAM *param); int (*deinit)(MYSQL_FTPARSER_PARAM *param); };
構造体定義に示されているように、ディスクリプタにはインタフェースバージョン番号があり、3 つの関数へのポインタが含まれています。
インタフェースのバージョン番号はシンボルを使用して指定し、
MYSQL_
という形式です。全文パーサープラグインの場合、シンボルは「xxx
_INTERFACE_VERSIONMYSQL_FTPARSER_INTERFACE_VERSION
」です。ソースコードには、include/mysql/plugin_ftparser.h
に定義されている全文パーサープラグインの実際のインタフェースバージョン番号があります。init
メンバーおよびdeinit
メンバーは、関数を指すようにするか、関数が不要な場合は 0 に設定します。parse
メンバーは、構文解析を実行する関数を指している必要があります。simple_parser
宣言では、そのディスクリプタは&simple_parser_descriptor
によって示されています。ディスクリプタは、全文プラグインインタフェースのバージョン番号 (MYSQL_FTPARSER_INTERFACE_VERSION
によって指定されます)、プラグインの構文解析関数、初期化関数、および初期化解除関数を指定します。static struct st_mysql_ftparser simple_parser_descriptor= { MYSQL_FTPARSER_INTERFACE_VERSION, /* interface version */ simple_parser_parse, /* parsing function */ simple_parser_init, /* parser init function */ simple_parser_deinit /* parser deinit function */ };
全文パーサーサーバープラグインは、インデックス設定と検索の 2 つの異なるコンテキストで使用されます。両方のコンテキストで、サーバーはプラグインを呼び出した各 SQL ステートメントの処理の開始時と終了時に初期化関数および初期化解除関数を呼び出します。ただし、ステートメントの処理中に、サーバーはコンテキストに固有の方法でメインの構文解析関数を呼び出します。
インデックス設定の場合、サーバーはインデックス設定される各カラム値に対してパーサーを呼び出します。
検索の場合、サーバーは検索文字列を構文解析するためにパーサーを呼び出します。パーサーはステートメントによって処理される行に対して呼び出されることもあります。自然言語モードでは、サーバーがパーサーを呼び出す必要はありません。クエリー拡張を使用したブールモードフレーズ検索または自然言語検索の場合、インデックスにない情報についてカラム値を構文解析するためにパーサーが使用されます。また、
FULLTEXT
インデックスのないカラムに対してブールモード検索が実行された場合は、組み込みパーサーが呼び出されます。(プラグインは特定のインデックスに関連付けられます。インデックスがない場合、プラグインは使用されません。)
一般プラグインディスクリプタのプラグイン宣言には、初期化関数および初期化解除関数を指している
init
メンバーおよびdeinit
メンバーがあり、指している先のタイプ固有のプラグインディスクリプタにもこれらがあります。ただし、これらの関数のペアは目的が異なり、異なる理由で呼び出されます。一般プラグインディスクリプタのプラグイン宣言の場合、初期化関数および初期化解除関数は、プラグインがロードおよびアンロードされるときに呼び出されます。
タイプ固有のプラグインディスクリプタの場合、初期化関数および初期化解除関数は、プラグインが使用される SQL ステートメントごとに呼び出されます。
プラグインディスクリプタに指定されている各インタフェース関数は、成功の場合はゼロ、および失敗の場合はゼロ以外を返し、構文解析するコンテキストが含まれている
MYSQL_FTPARSER_PARAM
構造体を指している引数を受け取ります。この構造体の定義は次のとおりです。typedef struct st_mysql_ftparser_param { int (*mysql_parse)(struct st_mysql_ftparser_param *, char *doc, int doc_len); int (*mysql_add_word)(struct st_mysql_ftparser_param *, char *word, int word_len, MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info); void *ftparser_state; void *mysql_ftparam; struct charset_info_st *cs; char *doc; int length; int flags; enum enum_ftparser_mode mode; } MYSQL_FTPARSER_PARAM;
構造体メンバーは次のように使用されます。
-
mysql_parse
: サーバーの組み込みパーサーを呼び出すコールバック関数へのポインタ。プラグインが組み込みパーサーのフロントエンドとして動作する場合は、このコールバックを使用します。つまり、プラグインの構文解析関数が呼び出されたとき、その関数は入力を処理してテキストを抽出し、テキストをmysql_parse
コールバックに渡します。このコールバック関数の最初のパラメータは、
param
値自体となります。param->mysql_parse(param, ...);
フロントエンドプラグインは、テキストを抽出して一度にすべてのテキストを組み込みパーサーに渡すか、テキストを抽出して一度にテキストの一部分ずつを組み込みパーサーに渡すことができます。ただし、この場合、組み込みサーバーはテキストの一部分同士の間に暗黙的な単語の分割があるかのように処理します。
-
mysql_add_word
: 全文インデックスまたは検索語のリストに単語を追加するコールバック関数へのポインタ。このコールバックは、組み込みパーサーをパーサープラグインに置き換えた場合に使用します。つまり、プラグインの構文解析関数が呼び出されたとき、その関数が入力を単語に構文解析し、各単語についてmysql_add_word
コールバックが呼び出されます。このコールバック関数の最初のパラメータは、
param
値自体となります。param->mysql_add_word(param, ...);
ftparser_state
: これは一般的なポインタです。プラグインは独自の目的のために内部で使用される情報を指すようにこれを設定できます。mysql_ftparam
: これはサーバーによって設定されます。これは最初の引数としてmysql_parse
またはmysql_add_word
コールバックに渡されます。cs
: テキストの文字セットについての情報へのポインタであり、情報がない場合は 0 です。doc
: 構文解析されるテキストへのポインタ。length
: 構文解析されるテキストのバイト単位の長さ。-
flags
: パーサーのフラグ。特別なフラグがない場合、これはゼロです。現時点で、ゼロ以外のフラグはMYSQL_FTFLAGS_NEED_COPY
のみであり、これはmysql_add_word()
が単語のコピーを保存する必要がある (つまり、単語は上書きされるバッファー内にあるため、単語へのポインタを使用できない) ことを意味します。このメンバーは MySQL 5.1.12 で追加されました。このフラグは、MySQL (パーサープラグインを呼び出す前)、パーサープラグイン自体、または
mysql_parse()
関数が設定またはリセットできます -
mode
: 構文解析のモード。この値は次の定数のいずれかです。MYSQL_FTPARSER_SIMPLE_MODE
: 単純で高速なモードで構文解析し、インデックス設定および自然言語クエリーに使用されます。パーサーは、インデックスを設定する単語のみをサーバーに渡します。パーサーが長さ制限またはストップワードリストを使用して無視する単語を判別する場合、パーサーはそのような単語をサーバーに渡しません。MYSQL_FTPARSER_WITH_STOPWORDS
: ストップワードモードで構文解析します。これはフレーズ照合のためのブール検索で使用されます。パーサーは、ストップワードや通常の長さ制限の範囲外にある単語であっても、すべての単語をサーバーに渡します。MYSQL_FTPARSER_FULL_BOOLEAN_INFO
: ブールモードで構文解析します。これはブールクエリー文字列の構文解析に使用されます。パーサーは単語だけでなくブールモード演算子も認識し、mysql_add_word
コールバックを使用してこれらをトークンとしてサーバーに渡します。渡されるトークンの種類をサーバーに通知するために、プラグインはMYSQL_FTPARSER_BOOLEAN_INFO
構造体に値を設定して、この構造体へのポインタを渡す必要があります。
パーサーがブールモードで呼び出された場合、
param->mode
値はMYSQL_FTPARSER_FULL_BOOLEAN_INFO
になります。サーバーにトークン情報を渡すためにパーサーが使用するMYSQL_FTPARSER_BOOLEAN_INFO
構造体は次のようになります。typedef struct st_mysql_ftparser_boolean_info { enum enum_ft_token_type type; int yesno; int weight_adjust; char wasign; char trunc; /* These are parser state and must be removed. */ char prev; char *quot; } MYSQL_FTPARSER_BOOLEAN_INFO;
パーサーは構造体メンバーに次のように値を設定します。
-
type
: トークンのタイプ。許容されるタイプを次の表に示します。表 24.3 全文パーサーのトークンタイプ
トークン値 意味 FT_TOKEN_EOF
データの終わり FT_TOKEN_WORD
通常の単語 FT_TOKEN_LEFT_PAREN
グループまたは部分式の始まり FT_TOKEN_RIGHT_PAREN
グループまたは部分式の終わり FT_TOKEN_STOPWORD
ストップワード
yesno
: 一致が発生するために単語が存在する必要があるかどうか。0 の場合、単語はオプションでですが、存在する場合は一致の関連性が増加することを意味します。0 より大きい値は、単語が存在する必要があることを意味します。0 より小さい値は、単語が存在していない必要があることを意味します。weight_adjust
: 単語の一致の重要度を決定する重み付けの要素。これは、関連性計算での単語の重要性を増加または減少させるために使用できます。値がゼロの場合は、重み付けによる調整がないことを示します。ゼロより大きい値または小さい値は、重みが大きいことまたは小さいことをそれぞれ意味します。<
および>
演算子を使用するセクション12.9.2「ブール全文検索」の例は、重み付けがどのように機能するかを示しています。wasign
: 重み付け要素の符号。負の値は~
ブール検索演算子のように作用し、これによって、関連性に対する単語の貢献度がマイナスになります。trunc
: ブールモードの*
切り捨て演算子が指定された場合のように、照合を実行するかどうか。
プラグインで、
MYSQL_FTPARSER_BOOLEAN_INFO
構造体のprev
メンバーおよびquot
メンバーを使用しないでください。注記ブール演算子
@ distance
は現在のプラグインパーサーフレームワークによってサポートされません。ブール全文検索の演算子については、セクション12.9.2「ブール全文検索」を参照してください。 -
プラグインインタフェース関数をセットアップします。
ライブラリディスクリプタ内の一般プラグインディスクリプタは、サーバーがプラグインをロードおよびアンロードするときに呼び出す初期化関数および初期化解除関数を指定します。
simple_parser
の場合、これらの関数は何も行いませんが、成功したことを示すためにゼロを返します。static int simple_parser_plugin_init(void *arg __attribute__((unused))) { return(0); } static int simple_parser_plugin_deinit(void *arg __attribute__((unused))) { return(0); }
これらの関数は実際に何も行わないため、これらを省略して、プラグイン宣言でそれぞれに 0 を指定できます。
simple_parser
のタイプ固有のプラグインディスクリプタは、プラグインが使用されるときにサーバーが呼び出す初期化関数、初期化解除関数、および構文解析関数を指定します。simple_parser
の場合、初期化関数および初期化解除関数は何も行いません。static int simple_parser_init(MYSQL_FTPARSER_PARAM *param __attribute__((unused))) { return(0); } static int simple_parser_deinit(MYSQL_FTPARSER_PARAM *param __attribute__((unused))) { return(0); }
ここでも、これらの関数は何も行わないため、これらを省略して、プラグインディスクリプタでそれぞれに 0 を指定できます。
メインの構文解析関数
simple_parser_parse()
は組み込みの全文パーサーの代わりに動作するため、テキストを単語に分割して各単語をサーバーに渡す必要があります。構文解析関数の最初の引数は、構文解析するコンテキストが含まれている構造体へのポインタです。この構造体には、構文解析されるテキストを指しているdoc
メンバー、およびテキストの長さを示すlength
メンバーがあります。このプラグインによって実行される単純な構文解析では、空白文字を含まない文字列を単語とみなすため、次のように単語を識別します。static int simple_parser_parse(MYSQL_FTPARSER_PARAM *param) { char *end, *start, *docend= param->doc + param->length; for (end= start= param->doc;; end++) { if (end == docend) { if (end > start) add_word(param, start, end - start); break; } else if (isspace(*end)) { if (end > start) add_word(param, start, end - start); start= end + 1; } } return(0); }
パーサーは単語を検出するごとに、関数
add_word()
を呼び出して単語をサーバーに渡します。add_word()
はヘルパー関数にすぎず、プラグインインタフェースの一部ではありません。パーサーは、構文解析されるコンテキストへのポインタ、単語へのポインタ、および長さの値をadd_word()
に渡します。static void add_word(MYSQL_FTPARSER_PARAM *param, char *word, size_t len) { MYSQL_FTPARSER_BOOLEAN_INFO bool_info= { FT_TOKEN_WORD, 0, 0, 0, 0, ' ', 0 }; param->mysql_add_word(param, word, len, &bool_info); }
ブールモード構文解析の場合、前に
st_mysql_ftparser_boolean_info
構造体の説明で示したように、add_word()
はbool_info
構造体のメンバーに値を設定します。 -
ステータス変数をセットアップします。
simple_parser
プラグインの場合、次のステータス変数の配列は、1 つのステータス変数を静的テキストの値で設定し、別のステータス変数を long 整数変数に格納されている値で設定しています。long number_of_calls= 0; struct st_mysql_show_var simple_status[]= { {"static", (char *)"just a static text", SHOW_CHAR}, {"called", (char *)&number_of_calls, SHOW_LONG}, {0,0,0} };
プラグインがインストールされると、プラグイン名と
name
値がアンダースコアで結合されて、SHOW STATUS
によって表示される名前が形成されます。上記の配列の場合、生成されるステータス変数名はsimple_parser_static
およびsimple_parser_called
です。この規則は、プラグインの変数をプラグイン名を使用して簡単に表示できることを意味します。mysql> SHOW STATUS LIKE 'simple_parser%'; +----------------------+--------------------+ | Variable_name | Value | +----------------------+--------------------+ | simple_parser_static | just a static text | | simple_parser_called | 0 | +----------------------+--------------------+
プラグインライブラリのオブジェクトファイルをコンパイルおよびインストールするには、セクション24.2.4.3「プラグインライブラリのコンパイルおよびインストール」の手順を使用します。ライブラリファイルを使用するには、ライブラリファイルがプラグインディレクトリ (
plugin_dir
システム変数で指定されているディレクトリ) にインストールされている必要があります。simple_parser
プラグインの場合、ソースから MySQL をビルドするときにコンパイルおよびインストールされます。これはバイナリ配布にも含められます。ビルド処理では、mypluglib.so
という名前の共有オブジェクトライブラリが生成されます (サフィクスはプラットフォームによって異なる場合があります)。-
プラグインを使用するには、プラグインをサーバーに登録します。たとえば、プラグインを実行時に登録するには次のステートメントを使用します (必要に応じてサフィクスを変更します)。
mysql> INSTALL PLUGIN simple_parser SONAME 'mypluglib.so';
プラグインのロードについての追加情報は、セクション5.1.8.1「プラグインのインストールおよびアンインストール」を参照してください。
プラグインのインストールを検証するには、
INFORMATION_SCHEMA.PLUGINS
テーブルを調査するか、SHOW PLUGINS
ステートメントを使用します。-
プラグインをテストして、正しく動作することを確認します。
文字列カラムを含むテーブルを作成し、パーサープラグインをそのカラムの
FULLTEXT
インデックスに関連付けます。mysql> CREATE TABLE t (c VARCHAR(255), -> FULLTEXT (c) WITH PARSER simple_parser -> ) ENGINE=MyISAM; Query OK, 0 rows affected (0.01 sec)
このテーブルにいくつかのテキストを挿入して検索を実行します。これらにより、パーサープラグインは空白文字でないすべての文字を単語文字として処理することが確認されます。
mysql> INSERT INTO t VALUES -> ('latin1_general_cs is a case-sensitive collation'), -> ('I\'d like a case of oranges'), -> ('this is sensitive information'), -> ('another row'), -> ('yet another row'); Query OK, 5 rows affected (0.02 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> SELECT c FROM t; +-------------------------------------------------+ | c | +-------------------------------------------------+ | latin1_general_cs is a case-sensitive collation | | I'd like a case of oranges | | this is sensitive information | | another row | | yet another row | +-------------------------------------------------+ 5 rows in set (0.00 sec) mysql> SELECT MATCH(c) AGAINST('case') FROM t; +--------------------------+ | MATCH(c) AGAINST('case') | +--------------------------+ | 0 | | 1.2968142032623 | | 0 | | 0 | | 0 | +--------------------------+ 5 rows in set (0.00 sec) mysql> SELECT MATCH(c) AGAINST('sensitive') FROM t; +-------------------------------+ | MATCH(c) AGAINST('sensitive') | +-------------------------------+ | 0 | | 0 | | 1.3253291845322 | | 0 | | 0 | +-------------------------------+ 5 rows in set (0.01 sec) mysql> SELECT MATCH(c) AGAINST('case-sensitive') FROM t; +------------------------------------+ | MATCH(c) AGAINST('case-sensitive') | +------------------------------------+ | 1.3109166622162 | | 0 | | 0 | | 0 | | 0 | +------------------------------------+ 5 rows in set (0.01 sec) mysql> SELECT MATCH(c) AGAINST('I\'d') FROM t; +--------------------------+ | MATCH(c) AGAINST('I\'d') | +--------------------------+ | 0 | | 1.2968142032623 | | 0 | | 0 | | 0 | +--------------------------+ 5 rows in set (0.01 sec)
組み込みパーサーとは異なり、「case」および「insensitive」は「case-insensitive」と一致していません。