Ubuntu 16.04上のMySQL 5.6で全文検索を使用してデータベース検索を改善する方法

前書き

フルテキスト検索、またはFTSは、データベースで結果を見つけるために検索エンジンで使用される手法です。 これを使用して、ショップ、検索エンジン、新聞などのWebサイトの検索結果を強化できます。

具体的には、FTSは検索条件に完全に一致しないドキュメントを取得します。 _Documents_は、テキストデータを含むデータベースエンティティです。 これは、たとえば、ユーザーが「猫と犬」を検索する場合、FTSに裏付けられたアプリケーションは、単語(「猫」または「犬」のみ)を含む結果を返すことができることを意味します。 (「犬と猫」)、または単語の変形(「猫」または「犬」)が含まれています。 これにより、ユーザーが何を意味しているのかを推測し、より関連性の高い結果をより迅速に返すという点で、アプリケーションに利点がもたらされます。

技術的に言えば、MySQLのようなデータベース管理システム(DBMS)は通常、 `+ LIKE +`句を使用して部分的なテキストルックアップを許可します。 ただし、これらの要求は、大規模なデータセットではパフォーマンスが低下する傾向があります。 また、ユーザーの入力と正確に一致するように制限されているため、関連情報を含むドキュメントがあってもクエリは結果を生成しない可能性があります。

FTSを使用すると、より高度なツールに余分な依存関係を導入することなく、より強力なテキスト検索エンジンを構築できます。 このチュートリアルでは、MySQL 5.6を使用して全文検索を使用してデータベースをクエリし、検索入力との関連性によって結果を定量化し、最適な一致のみを表示します。

前提条件

このチュートリアルを始める前に、次のものが必要です。

  • このhttps://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-16-04 [Ubuntu 16.04での初期サーバー設定]ガイド(sudo nonを含む)に従ってセットアップされた1つのUbuntu 16.04サーバー-rootユーザーとファイアウォール。

  • https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-16-04 [Ubuntu 16.04にMySQLをインストールする方法]ガイドに従ってインストールされたMySQL 5.6以降。

ステップ1-テストデータの作成

全文検索を試すには、いくつかのデータが必要です。 このステップでは、「+ news 」というテーブルを持つ「 testdb +」というデータベースを作成し、架空のニュースアグリゲーターサイトの記事を表すサンプルデータを追加します。

まず、MySQLコンソールにアクセスします。 MySQLのインストール時に設定した* root *パスワードの入力を求められます。

mysql -u root -p

接続すると、プロンプトが「+ mysql> +」に変わります。

次に、 `+ testdb +`という新しいデータベースを作成します。 このデータベースにはテストデータが含まれます。

CREATE DATABASE testdb;

デフォルトで `+ testdb +`データベースを使用するように切り替えると、データベースの名前を指定してデータベースを作成したり更新したりする必要がなくなります。

USE testdb;

次に、データベースに「+ news +」という名前のテーブルを作成し、ニュースアグリゲーターの記事の例の列を追加します。

CREATE TABLE news (
  id INT NOT NULL AUTO_INCREMENT,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  author TEXT NOT NULL,

  PRIMARY KEY (id)
);

このコマンドの機能を見ていきましょう。

  • `+ CREATE TABLE +`は、他の多くのデータベースと同様に、テーブルを作成するSQLコマンドです。

  • `+ news +`はテーブルの名前です。

  • 「+ title」、「+ content」、および「+ author」は、長さ無制限のテキスト列です。

  • `+ NOT NULL +`はhttps://dev.mysql.com/doc/refman/5.7/en/working-with-null.html[null values]を持つことができない列をマークするために使用される宣言です(ただし、空の文字列)。

  • `+ id `は特別なタイプ ` AUTO_INCREMENT +`を持つテーブルのプライマリインデックスで、IDフィールドに次に使用可能なIDが自動的に入力されます。

次に、いくつかのサンプルデータをテーブルに追加します。

INSERT INTO news (id, title, content, author) VALUES
   (1, 'Pacific Northwest high-speed rail line', 'Currently there are only a few options for traveling the 140 miles between Seattle and Vancouver and none of them are ideal.', 'Greg'),
   (2, 'Hitting the beach was voted the best part of life in the region', 'Exploring tracks and trails was second most popular, followed by visiting the shops and then traveling to local parks.', 'Ethan'),
   (3, 'Machine Learning from scratch', 'Bare bones implementations of some of the foundational models and algorithms.', 'Jo');

このコマンドの機能を見ていきましょう。

  • `+ INSERT +`はデータを挿入します。

  • `+ INTO `は、データを挿入する場所を指定します。 この場合、それは「 news +」テーブルです。

  • `+(id、title、content、author)VALUES +`は、各エントリのデータ値を保存する列を指定します。

  • 最後の3行は、テーブルに追加する3行のデータです。 それぞれには、「+ title 」、いくつかの「 content 」、および「 author +」の名前を持つニュースWebサイトのサンプル記事が含まれています。

各エントリには、データベースインデックスに自動的に入力される一意の「+ id +」識別子もあります。 _データベースインデックス_は、データ取得操作のパフォーマンスを向上させるデータ構造です。 このインデックスは、メインデータとは別に保存されます。 テーブルの内容が変更されると更新が行われますが、追加の書き込みと比較的小さなストレージスペースが必要になります。 その小さなサイズと調整されたデータ構造により、クエリの選択にメイン表スペースを使用するよりもはるかに効率的にインデックスを操作できます。

データが用意できたので、FTSを使用してそのデータを検索するクエリの作成を開始できます。

ステップ2-FTSインデックスの作成とFTS関数の使用

FTSを使用できるように、テキスト列のインデックスを作成しましょう。

これを行うには、 `+ FULLTEXT +`と呼ばれるMySQL専用のコマンドを使用します。 このコマンドは、FTSで検索できるようにするすべてのフィールドを内部インデックスに入れるようMySQLに指示します。

ALTER TABLE news ADD FULLTEXT (title, content, author);

これは、すべてのテキスト列を組み合わせてサニタイズすることで機能します(例: 句読点を削除し、大文字を小文字にします)。 このインデックスが作成されたので、ソーステーブルのコンテンツを変更するSQLクエリによって更新されます。

次に、関数 `+ MATCH()AGAINST()+`を使用して、「シアトルビーチ」の全文検索を実行してみてください。

SELECT * FROM news WHERE MATCH (title,content,author) AGAINST ('' IN NATURAL LANGUAGE MODE)\G

コマンドの `+ MATCH()`部分は、FTSを使用してインデックス付けされる列のセットを指定します。インデックスの作成に使用した列リストと一致する必要があります。 ` AGAINST()+`部分は、全文検索を実行する単語を指定します。この例では、「シアトルビーチ」です。

`+ IN NATURAL LANGUAGE MODE +`は、検索語が前処理なしでユーザー入力から直接提供されることを意味します。 MySQLはデフォルトで自然言語モードを想定しているため、明示的に指定する必要はありません。

上記のクエリの最後にある「+ \ G +」は、出力の各列を新しい行に出力します。 これにより、長い結果が少し読みやすくなります。 上記のコマンドの出力は次のようになります。

Output*************************** 1. row ***************************
    id: 1
 title: Pacific Northwest high-speed rail line
content: Currently there are only a few options for traveling the 140 miles between  and Vancouver and none of them are ideal.
author: Greg
*************************** 2. row ***************************
    id: 2
 title: Hitting the  was voted the best part of life in the region
content: Exploring tracks and trails was second most popular, followed by visiting the shops and then traveling to local parks.
author: Ethan
2 rows in set (0.00 sec)

エントリには「Seattle beach」というフレーズは含まれていませんが、フルテキスト検索を使用したため、2つの結果が得られました。最初の行には「Seattle」という単語のみが含まれ、2番目の行には単語のみが含まれます"ビーチ"。 キーワードを変更して結果を表示することにより、追加の検索を試すことができます。

SQLクエリでFTS関数を使用して、検索入力に関連する行を検索できるようになったので、それらの結果をより関連性の高いものにすることができます。

ステップ3-FTS結果の調整

全文検索結果の関連性を高めるのに役立つ2つの手法があります。 1つは結果の関連性スコアによるフィルタリングで、もう1つは「+ IN BOOLEAN +」を使用して結果から特定の単語を除外し、検索語間の最大距離を指定することです。

関連性スコアの使用

結果の_関連性スコア_は、検索用語に対する一致の程度を定量化します。0はまったく関連しません。 関連性スコアは、特定のドキュメントで用語が検出される頻度や、用語を含むドキュメントの数など、いくつかの要因に基づいています。 MySQLの全文検索ドキュメントは、この数値の計算の背後にある数学に当てはまります。

「公園への旅行」というクエリに基づいて、各行の関連性スコアを取得します。

SELECT id, MATCH (title,content,author) AGAINST ('') as score FROM news;

このコマンドの「+ as score 」部分は、出力の2番目の列に「 score 」というラベルを付けます。 それ以外の場合は、データを取り込むために使用されるコマンドでラベル付けされます。この場合は、「 MATCH(title、content、author)AGAINST( 'parking to parks')+」です。

結果は次のようになります。

Output+----+----------------------+
| id | score                |
+----+----------------------+
|  1 | 0.031008131802082062 |
|  2 |  0.25865283608436584 |
|  2 |  0                    |
+----+----------------------+
3 rows in set (0.00 sec)

3行目には、検索語が表示されないため、関連性スコアが0になります。 最初の行には単語「traveling」が含まれていますが、「to」または「parks」は含まれておらず、関連性スコアは「0.03」と非常に低くなっています。 すべての単語を含む2行目は、関連性スコアが最も高く「0.25」です。

これらのスコアを使用して、最も関連性の高い結果を最初に返すか、特定の関連性範囲を超える結果のみを返すことができます。 関連性スコアはデータセットによって異なるため、カットオフポイントを選択するには手動で調整する必要があります。

次のコマンドは同じクエリを実行しますが、2つのことを追加します。

  • `+ WHERE MATCH(title、content、author)AGAINST( '')> 0 +`を追加することにより、ゼロ以外の関連性スコアを持つ行のみを表示します

  • `+ ORDER BY score DESC +`を追加することにより、関連性によって結果をソートします

SELECT id, MATCH (title,content,author) AGAINST ('') as score FROM news WHERE MATCH (title,content,author) AGAINST ('') > 0 ORDER BY score DESC;

`+ WHERE `句で ` MATCH()AGAINST()+`関数を繰り返す必要があるのは、その句に含めることができるものに対するSQLの制限のためです。

出力は次のようになります。

Output+----+----------------------+
| id | score                |
+----+----------------------+
|  2 |  0.25865283608436584 |
|  1 | 0.031008131802082062 |
+----+----------------------+
2 rows in set (0.01 sec)

最も関連性の高い結果である行2が最初に表示され、次に関連性の低い行1が表示されます。 行3は、関連性スコアが0であるため、まったく表示されません。

カットオフを変更して、結果の微調整を続けることができます。 たとえば、カットオフとして「0」ではなく「0.1」を使用すると、行2のみが返されます。

IN BOOLEANの使用

ステップ2では、クエリ用語を指定するときにデフォルトモードの「+ IN NATURAL LANGUAGE」を使用しました。 「+ IN BOOLEAN +」という別のモードがあります。このモードでは、検索から特定の単語を除外したり、入力内の単語が互いに離れていなければならない範囲を定義したりできます。

クエリから用語を省略するには、マイナス演算子と「+ IN BOOLEAN +」を使用します。 次のコマンドは、「traveling」という単語を含むが「Seattle」という単語を含まない結果を返します。

SELECT * FROM news WHERE MATCH (title,content,author) AGAINST ()\G

結果には行2のみが表示されます。

Output*************************** 1. row ***************************
    id: 2
 title: Hitting the beach was voted the best part of life in the region
content: Exploring tracks and trails was second most popular, followed by visiting the shops and then traveling to local parks.
author: Ethan
1 row in set (0.01 sec)

これは、マイナス演算子がDMSに、除外された単語で関連性スコア0のドキュメントをマークするように指示するためです。 このモードでは、関連性スコアがゼロ以外の結果のみが表示されます。

`+ IN BOOLEAN MODE +`を使用して、検索語間の最大距離を指定することもできます。 この距離は単語で測定され、重要なことに、検索語が含まれます。 たとえば、「猫と犬」というフレーズの距離は3です。

次のコマンドは、「traveling」と「miles」という単語が2単語以内で表示される結果を返します。

SELECT * FROM news WHERE MATCH (title,content,author) AGAINST ()\G

2行目の「+ content」の「+ traveling the 140 miles」に一致する結果が1つ表示されます。

Output*************************** 1. row ***************************
    id: 1
 title: Pacific Northwest high-speed rail line
content: Currently there are only a few options for traveling the 140 miles between Seattle and Vancouver and none of them are ideal.
author: Greg
1 row in set (0.00 sec)

元のコマンドで「+ @ 4 」を「 @ 3 +」に変更した場合、結果は表示されません。

検索用語間の距離によって検索結果を制限することは、多様な語彙を持つ非常に大きなドキュメントを検索するときに役立ちます。 クエリ用語間のギャップが小さいほど、結果はより正確になりますが、距離の微調整は作業中のドキュメントのセットに依存します。 たとえば、一連の科学論文は3の小さなワードギャップでうまく機能しますが、フォーラムの投稿の検索は、結果をどの程度広くしたいか狭くしたいかによって、ギャップ8以上でより良くなる場合があります。

結論

このガイドでは、MySQLの全文検索機能を使用しました。 ドキュメント駆動型データベースのデータベーススキーマを作成するときにインデックスを作成し、特別な演算子を使用して、クエリを実行するときに最も関連性の高い結果を見つけました。

MySQLのFTS機能をさらに詳しく知りたい場合は、https://dev.mysql.com/doc/refman/5.6/en/fulltext-search.html [全文検索に関するMySQL 5.6公式ドキュメント]をご覧ください。

Related