MySQL 5.6 リファレンスマニュアル  /  ...  /  MySQL の全文検索の微調整

12.9.6 MySQL の全文検索の微調整

MySQL の全文検索機能には、ユーザーが調整できるパラメータがほとんどありません。一部の変更でソースコードを変更する必要があるために、MySQL ソース配布を持っている場合は、全文検索の動作をさらに制御できます。セクション2.9「ソースから MySQL をインストールする」を参照してください。

全文検索の有効性は、慎重に調整されます。ほとんど場合、デフォルトの動作を変更すると、実際には有効性が低くなる可能性があります。使用方法を理解していない場合は、MySQL ソースは変更しないでください

このセクションで説明するほとんどの全文変数は、サーバーの起動時に設定する必要があります。変更するには、サーバーの再起動が必要です。サーバーが動作しているときは、変更できません。

一部の変数を変更するには、テーブル内の FULLTEXT インデックスを再構築する必要があります。これを行う手順については、このセクションの後半で説明します。

単語の最小長と最大長の構成

インデックスが付けられる単語の最小長および最大長は、InnoDB 検索インデックスの場合は innodb_ft_min_token_size および innodb_ft_max_token_sizeMyISAM 検索インデックスの場合は ft_min_word_len および ft_max_word_len で定義されます。これらのオプションのいずれかを変更したら、変更を有効にするために FULLTEXT インデックスを再構築してください。たとえば、2 文字の単語を検索可能にするには、オプションファイルに次の行を配置します。

[mysqld]
innodb_ft_min_token_size=2
ft_min_word_len=2

次に、サーバーを再起動し、FULLTEXT インデックスを再構築します。MyISAM テーブルについては、MyISAM の全文インデックスを再構築する際に従う手順で、myisamchk に関する備考に注意してください。

自然言語検索のしきい値の構成

MyISAM 検索インデックスでは、選択された特定の重み付けスキームによって、自然言語検索で 50% のしきい値が決定されます。これを無効にするには、storage/myisam/ftdefs.h で次の行を検索してください。

#define GWS_IN_USE GWS_PROB

この行を次のように変更します。

#define GWS_IN_USE GWS_FREQ

次に、MySQL を再コンパイルします。この場合、インデックスを再構築する必要はありません。

注記

このように変更すると、MATCH() 関数に適切な関連性値を提供する MySQL の能力が大幅に低下します。このような一般的な単語を検索する必要がある場合は、代わりに、50% のしきい値に従わない IN BOOLEAN MODE を使用して検索する方が適切です。

ブール全文検索演算子の変更

MyISAM テーブル上でブール全文検索に使用される演算子を変更するには、ft_boolean_syntax システム変数を設定します。(InnoDB には同等の設定がありません。)この変数はサーバーの実行中に変更できますが、そのためには SUPER 権限を持っている必要があります。この場合は、インデックスを再構築する必要はありません。この変数を設定する方法を制御するルールについては、セクション5.1.4「サーバーシステム変数」を参照してください。

文字セットの変更

次のリストで説明するように、単語文字とみなされる文字セットは複数の方法で変更できます。変更が完了したら、任意の FULLTEXT インデックスを含むテーブルごとにインデックスを再構築します。ハイフン文字 (' - ') を単語文字として処理すると仮定します。次の方法のいずれかを使用します。

  • MySQL ソースを変更します。storage/innobase/handler/ha_innodb.cc (InnoDB の場合) または storage/myisam/ftdefs.h (MyISAM の場合) で、true_word_char() および misc_word_char() マクロを参照してください。それらのマクロのいずれかに '-' を追加し、MySQL を再コンパイルします。

  • 文字セットファイルを変更します。再コンパイルする必要はありません。true_word_char() マクロでは、英数字とその他の文字を区別するために character type テーブルが使用されます。文字セット XML ファイルのいずれかで <ctype><map> 配列の内容を編集すると、'-'英字になるように指定できます。次に、FULLTEXT インデックスに指定された文字セットを使用します。<ctype><map> 配列の書式については、セクション10.3.1「文字定義配列」を参照してください。

  • インデックス付きのカラムで使用される文字セットに新しい照合順序を追加し、その照合順序が使用されるようにカラムを変更します。照合順序の追加に関する一般的な情報については、セクション10.4「文字セットへの照合順序の追加」を参照してください。全文インデックス作成に固有の例については、セクション12.9.7「全文インデックス作成用の照合順序の追加」を参照してください。

InnoDB 全文インデックスの再構築

インデックス作成に影響を与える全文変数 (innodb_ft_min_token_sizeinnodb_ft_max_token_sizeinnodb_ft_server_stopword_tableinnodb_ft_user_stopword_tableinnodb_ft_enable_stopword) を変更する場合は、変更したあとに FULLTEXT インデックスを再構築する必要があります。innodb_ft_min_token_size および innodb_ft_max_token_size 変数は動的に設定できないため、変更するにはサーバーを再起動し、インデックスを再構築する必要があります。

InnoDB テーブルの FULLTEXT インデックスを再構築するには、DROP INDEX および ADD INDEX オプションを付けて ALTER TABLE を使用して、各インデックスを削除してから再作成します。

InnoDB 全文インデックスの最適化

全文インデックス付きのテーブル上で OPTIMIZE TABLE を実行すると、全文インデックスが再構築され、削除済みのドキュメント ID が削除され、同じ単語に対応する複数のエントリが連結されます (可能な場合)。

全文インデックスを最適化するには、innodb_optimize_fulltext_only を有効にして、OPTIMIZE TABLE を実行します。

mysql> set GLOBAL innodb_optimize_fulltext_only=ON;
Query OK, 0 rows affected (0.01 sec)

mysql> OPTIMIZE TABLE opening_lines;
+--------------------+----------+----------+----------+
| Table              | Op       | Msg_type | Msg_text |
+--------------------+----------+----------+----------+
| test.opening_lines | optimize | status   | OK       |
+--------------------+----------+----------+----------+
1 row in set (0.01 sec)    

大きなテーブルで全文インデックスの再構築時間が長くなることを回避するには、innodb_ft_num_word_optimize オプションを使用すれば、最適化を段階的に実行できます。innodb_ft_num_word_optimize オプションでは、OPTIMIZE TABLE が実行されるたびに最適化される単語の数が定義されます。デフォルト設定は 2000 です。これは、OPTIMIZE TABLE が実行されるたびに 2000 個の単語が最適化されることを表します。後続の OPTIMIZE TABLE 演算は、先行する OPTIMIZE TABLE 演算が終了した場所から続行されます。

MyISAM 全文インデックスの再構築

インデックス作成に影響を与える全文変数 (ft_min_word_lenft_max_word_len、または ft_stopword_file) を変更する場合や、ストップワードファイル自体を変更する場合は、変更して、サーバーを再起動したあとに、FULLTEXT インデックスを再構築する必要があります。

MyISAM テーブルの FULLTEXT インデックスを再構築するには、QUICK 修復演算を実行すれば十分です。

mysql> REPAIR TABLE tbl_name QUICK;

または、先ほど説明した ALTER TABLE を使用します。これは、修復演算よりも高速になる可能性もあります。

任意の FULLTEXT インデックスを含む各テーブルは、上記のように修復する必要があります。それ以外の場合は、テーブルのクエリーで不正な結果が生成される可能性があり、テーブルを変更すると、サーバーでは、テーブルが破損していて修復が必要であるとみなされます。

myisamchk を使用して、MyISAM テーブルインデックスを変更する演算 (修復や分析など) を実行する場合は、ほかに指定がなければ、単語の最小長、単語の最大長、およびストップワードファイルのデフォルトの全文パラメータ値を使用して、FULLTEXT インデックスが再構築されます。これにより、クエリーに失敗する可能性があります。

この問題は、これらのパラメータがサーバーでのみ認識されていることが原因で発生します。MyISAM インデックスファイルには格納されていません。サーバーで使用される単語の最小長や最大長、またはストップワードファイルの値を変更した場合の問題を回避するには、mysqld で使用される myisamchk と同じ ft_min_word_lenft_max_word_len、および ft_stopword_file 値を指定します。たとえば、単語の最小長を 3 に設定した場合は、次のように myisamchk を使用してテーブルを修復できます。

shell> myisamchk --recover --ft_min_word_len=3 tbl_name.MYI

myisamchk およびサーバーで全文パラメータに必ず同じ値が使用されるようにするには、オプションファイルの [mysqld][myisamchk] の両方のセクションにそれぞれを配置してください。

[mysqld]
ft_min_word_len=3

[myisamchk]
ft_min_word_len=3

MyISAM テーブルインデックスの変更に myisamchk を使用する方法の代替として、REPAIR TABLEANALYZE TABLEOPTIMIZE TABLE、または ALTER TABLE ステートメントを使用します。これらのステートメントは、適切に使用される全文パラメータ値が認識されているサーバーで実行されます。


User Comments
  Posted by John Navratil on May 10, 2007
How I added '-' to the list of word characters:

The documentation is weak in two regards: (1) it doesn't explain how to modify the map and (2) it doesn't touch on the implications of doing so. I'll try to solve (1), but cannot begin to speak to (2)

The charsets files exist at the location specified by the "character_sets_dir" system variable (use SHOW VARIABLES to see this) and is typically compiled in as "/usr/share/mysql/charsets". The name of the file is given by the "character_set_...' variables. Typically the default is "latin1". Thus the file I needed to change was /usr/share/mysql/charsets/latin1.xml

The <ctype><map> is the one we are after (other maps are "upper", "lower", "unicode" and the various collation maps).

The "ctype" map differs from the others in that is has a leading 0x00 before the character map, the meaning of which is unclear to me. Each entry of the map appears to classify the corresponding character according to the following bitmask:

0x01 Upper-case word character
0x02 Lower-case word character
0x04 Decimal digit
0x08 Printer control (Space/TAB/VT/FF/CR)
0x10 Not-white, not a word
0x20 Control-char (0x00 - 0x1F)
0x40 Space
0x80 Hex digit (0-9, a-f, A-F)

In my case, I needed the dash '-', but nothing else, so I altered the corresponding character position (0x2D - third row, third from the right) from 0x10 (Not-white, not a word) to 0x01 (Upper-case word).

There is little on the web to address this, but some commentary in the forums suggested that this was NOT the way to do this, but rather to write ones own full-text engine as the changing of the <ctype> map has implications for the SQL parser. This may be true, but I suspect SQL parsing would require a stricter classification of characters. The SQL statement "SELECT a-b FROM test" worked for me after this change.

Altering latin1.xml and restarting the server had the desired result.

Finally, there does not appear to be a way to create a new character set or collation without recompiling. If this is true, it might be desirable for the standard distribution to include a "custom" character set for just this sort of thing.
  Posted by Sebastien Salou on July 4, 2007
Based on your example with the dash `-`, I had a look to make the single quote `'` (which is a word character by default), a non word character.
Thus,
I had a look on a ascii table, the single quote is corresponding to the hexadecimal value 27.
I opened the file share/mysql/charsets/latin1.xml, I went to the upper map (0x27 is actually on the 3rd rows, 8th col from the left).
I went to this position in the ctype map, and surprised !!! This character is already set to 0x10 Not-white, not a word whereas it is a word character during tests !

From there, I'm pretty lost. Why the single quote is not detected as a non word as it should be ?

Modifying the mysql source in myisam/ftdefs.h works.
I modified the line #define misc_word_char(X) ((X)=='\'')
Is it the only way ?

Sebastien Salou
  Posted by Scott Noyes on November 19, 2009
John Navratil very nearly has it, but to get fulltext to treat characters as words, you also have to add a new collation. I've written it up at http://www.thenoyes.com/littlenoise/?p=91
Sign Up Login You must be logged in to post a comment.