序章

全文検索(FTS)は、検索エンジンがデータベース内の結果を検索するために使用する手法です。 ショップ、検索エンジン、新聞などのWebサイトの検索結果を強化するために使用できます。

具体的には、FTSは、検索条件に完全に一致しないテキストデータを含むデータベースエンティティであるドキュメントを取得します。 つまり、ユーザーが「猫と犬」を検索すると、たとえば、FTSに基づくアプリケーションは、単語を個別に含む結果(「猫」または「犬」のみ)を返し、異なる順序で単語を含めることができます。 (「犬と猫」)、または単語の変形を含む(「猫」または「犬」)。 これにより、アプリケーションは、ユーザーが何を意味するのかを推測し、より関連性の高い結果をより早く返すことができるという利点があります。

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

FTSを使用すると、より高度なツールに余分な依存関係を導入することなく、より強力なテキスト検索エンジンを構築できます。 このチュートリアルでは、PostgreSQLを使用して、架空のニュースWebサイトの記事を含むデータを保存し、FTSを使用してデータベースにクエリを実行し、最適なものだけを選択する方法を学習します。 最後のステップとして、全文検索クエリのパフォーマンスを改善します。

前提条件

このガイドを開始する前に、次のものが必要です。

  • このUbuntu16.04 ガイドを使用した初期サーバーセットアップ(sudo非rootユーザーを含む)に従ってセットアップされた1つのUbuntu16.04サーバー。
  • Ubuntu 16.04にPostgreSQLをインストールして使用する方法ガイドに従って、PostgreSQLをインストールします。 このチュートリアルでは、 sammy そのガイドで設定されたデータベースとユーザー。

上記のチュートリアルに従わずにPostgreSQLサーバーをセットアップする場合は、 postgresql-contrib を使用したパッケージ sudo apt-get list postgresql-contrib.

ステップ1—サンプルデータの作成

まず、全文検索プラグインをテストするためのデータが必要になるので、いくつかのサンプルデータを作成しましょう。 すでにテキスト値を含む独自のテーブルがある場合は、手順2にスキップして、フォローしながら適切な置換を行うことができます。

それ以外の場合、最初のステップはサーバーからPostgreSQLデータベースに接続することです。 同じホストから接続しているため、デフォルトでは、パスワードを入力する必要はありません。

  1. sudo -u postgres psql sammy

これにより、操作しているデータベース名を示すインタラクティブなPostgreSQLセッションが確立されます。この場合は次のようになります。 sammy. あなたは見るべきです sammy=# データベースコマンドプロンプト。

次に、データベースにサンプルテーブルを作成します。 news. この表の各エントリは、タイトル、コンテンツ、作成者の名前、および一意の識別子を含むニュース記事を表します。

  1. CREATE TABLE news (
  2. id SERIAL PRIMARY KEY,
  3. title TEXT NOT NULL,
  4. content TEXT NOT NULL,
  5. author TEXT NOT NULL
  6. );

id 特別なタイプのテーブルのプライマリインデックスです SERIAL、テーブルの自動インクリメントカウンターを作成します。 これは、データベースインデックスに自動的に移動する一意の識別子です。 このインデックスについては、パフォーマンスの向上を確認するときに、ステップ3で詳しく説明します。

次に、を使用してテーブルにいくつかのサンプルデータを追加します INSERT 指図。 以下のコマンドのこのサンプルデータは、いくつかのサンプルニュース記事を表しています。

  1. INSERT INTO news (id, title, content, author) VALUES
  2. (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'),
  3. (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 checking out local parks.', 'Ethan'),
  4. (3, 'Machine Learning from scratch', 'Bare bones implementations of some of the foundational models and algorithms.', 'Jo');

データベースに検索するデータがいくつかあるので、いくつかのクエリを書いてみることができます。

ステップ2—ドキュメントの準備と検索

ここでの最初のステップは、データベーステーブルから複数のテキスト列を持つ1つのドキュメントを作成することです。 次に、結果の文字列を単語のベクトルに変換できます。これは、クエリで使用するものです。

注:このガイドでは、 psql 出力用途 expanded display 出力の各列を新しい行に表示するフォーマットにより、画面に長いテキストを簡単に収めることができます。 次のように有効にできます。

  1. \x
Output
Expanded display is on.

まず、PostgreSQL連結関数を使用してすべての列をまとめる必要があります || および変換関数 to_tsvector().

  1. SELECT title || '. ' || content as document, to_tsvector(title || '. ' || content) as metadata FROM news WHERE id = 1;

これにより、ドキュメント全体として最初のレコードと、検索に使用される変換されたバージョンが返されます。

Output
-[ RECORD 1 ]----------------------------------------------------- document | 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. metadata | '140':18 'current':8 'high':4 'high-spe':3 'ideal':29 'line':7 'mile':19 'none':25 'northwest':2 'option':14 'pacif':1 'rail':6 'seattl':21 'speed':5 'travel':16 'vancouv':23

変換されたバージョンでは単語が少ないことに気付くかもしれませんが、 metadata 上記の出力では、元の出力よりも document. 一部の単語は異なり、すべての単語にはセミコロンと数字が追加されています。 これは、関数が to_tsvector() 各単語を正規化して、同じ単語の異形を見つけられるようにしてから、結果をアルファベット順に並べ替えます。 数字は単語の位置です document. 正規化された単語が複数回出現する場合は、追加のコンマ区切りの位置が存在する可能性があります。

これで、この変換されたドキュメントを使用して、「探索」という用語を検索することにより、FTS機能を利用できます。

  1. SELECT * FROM news WHERE to_tsvector(title || '. ' || content) @@ to_tsquery('Explorations');

ここで使用した関数と演算子を調べてみましょう。

関数 to_tsquery() パラメータを変換します。これは、直接またはわずかに調整されたユーザー検索である可能性があり、テキスト検索条件に変換されます。これにより、次のように入力が削減されます。 to_tsvector() します。 さらに、この関数を使用すると、使用する言語と、すべての単語を結果に含める必要があるのか、それらの1つだけを含める必要があるのかを指定できます。

The @@ オペレーターは、 tsvector 一致します tsquery または別の tsvector. 戻ります true また false、これにより、の一部として簡単に使用できます WHERE 基準。

Output
-[ RECORD 1 ]----------------------------------------------------- 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 checking out local parks. author | Ethan

検索に使用した単語が「Explorations」であったにもかかわらず、クエリは「Exploring」という単語を含むドキュメントを返しました。 を使って LIKE ここでFTSの代わりに演算子を使用すると、空の結果が得られます。

FTS用のドキュメントを準備する方法とクエリを構造化する方法がわかったので、FTSのパフォーマンスを向上させる方法を見てみましょう。

ステップ3—FTSパフォーマンスの改善

FTSクエリを使用するたびにドキュメントを生成すると、大規模なデータセットや小規模なサーバーを使用する場合にパフォーマンスの問題になる可能性があります。 ここで実装するこれに対する1つの優れた解決策は、行を挿入するときに変換されたドキュメントを生成し、それを他のデータと一緒に保存することです。 このようにして、毎回生成するのではなく、クエリを使用して取得することができます。

まず、という追加の列を作成します document 既存のものに news テーブル。

  1. ALTER TABLE news ADD "document" tsvector;

次に、別のクエリを使用してデータをテーブルに挿入する必要があります。 ステップ2とは異なり、ここでは、変換されたドキュメントを準備して、新しいドキュメントに追加する必要もあります。 document このような列:

  1. INSERT INTO news (id, title, content, author, document)
  2. VALUES (4, 'Sleep deprivation curing depression', 'Clinicians have long known that there is a strong link between sleep, sunlight and mood.', 'Patel', to_tsvector('Sleep deprivation curing depression' || '. ' || 'Clinicians have long known that there is a strong link between sleep, sunlight and mood.'));

既存のテーブルに新しい列を追加するには、空の値を追加する必要があります document 最初は列。 次に、生成された値で更新する必要があります。

使用 UPDATE 不足しているデータを追加するコマンド。

  1. UPDATE news SET document = to_tsvector(title || '. ' || content) WHERE document IS NULL;

これらの行をテーブルに追加するとパフォーマンスが向上しますが、大規模なデータセットでは、データベースがテーブル全体をスキャンして検索条件に一致する行を見つける必要があるため、問題が発生する可能性があります。 これに対する簡単な解決策は、インデックスを使用することです。

データベースインデックスは、メインデータとは別にデータを格納するデータ構造であり、データ取得操作のパフォーマンスを向上させます。 テーブルの内容が変更されると更新されますが、追加の書き込みと比較的少ないストレージスペースが必要になります。 サイズが小さく、データ構造が調整されているため、メインの表スペースを使用して照会を選択するよりも、索引をより効率的に操作できます。

最終的に、インデックスは、特別なデータ構造とアルゴリズムを使用して検索することにより、データベースが行をより速く見つけるのに役立ちます。 PostgreSQLには、特定のタイプのクエリに適したいくつかのタイプのインデックスがあります。 このユースケースに最も関連するものは、GiSTインデックスとGINインデックスです。 それらの主な違いは、テーブルからドキュメントを取得する速度です。 GINは、新しいデータを追加するときのビルドには時間がかかりますが、クエリには高速です。 GISTはより高速にビルドされますが、追加のデータ読み取りが必要です。

GiSTはGINよりもデータの取得に約3倍遅いため、ここでGINインデックスを作成します。

  1. CREATE INDEX idx_fts_search ON news USING gin(document);

インデックス付きの使用 document コラム、私たち SELECT クエリももう少し簡単になりました。

  1. SELECT title, content FROM news WHERE document @@ to_tsquery('Travel | Cure');

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

Output
-[ RECORD 1 ]----------------------------------------------------- title | Sleep deprivation curing depression content | Clinicians have long known that there is a strong link between sleep, sunlight and mood. -[ RECORD 2 ]----------------------------------------------------- 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.

完了したら、データベースコンソールを終了できます。 \q.

結論

このガイドでは、メタデータドキュメントの準備と保存、パフォーマンスを向上させるためのインデックスの使用など、PostgreSQLで全文検索を使用する方法について説明しました。 PostgreSQLのFTSについて詳しく知りたい場合は、全文検索に関するPostgreSQLの公式ドキュメントをご覧ください。