PostgreSQL 全文検索


PostgreSQL の全文検索機能はどのように機能しますか?



最近のプロジェクトでは、私のチームと私は、機能豊富なデータベース管理システムである PostgreSQL を使用しています.私たちが利用した機能の 1 つは全文検索です.これは、PostgreSQL の組み込みテキスト検索を使用してネイティブに実装できます.

この全文検索は、基本的なテキスト マッチングとは少し異なります. PostgreSQL のネイティブ機能を使用すると、JavaScript のネイティブ Array.filter() メソッドなどを使用する場合よりも、より緩やかなテキスト マッチングを実現できます.これが機能するのは、検索可能なテキストが、同じ単語の異なる活用形で単語の語根を大まかに一致させることができるように実際に処理されるためです.

上記のように、PostgreSQL は検索可能な用語を「語彙素」にトークン化します.ウィキペディアによると:

"[In computer science, a] lexeme is a sequence of characters in the source program that matches the pattern for a token and is identified by the lexical analyzer as an instance of that token."



PostgreSQL では、単語をトークン語彙素に分解するこのプロセスを単語の「ベクトル化」と呼んでいます.このタスクを実行するための PostgreSQL のネイティブ機能は TSVector と呼ばれます (TS は「テキスト検索」の略です).

英単語を含む任意のテーブルから TSVector を作成して追加できます (英語以外の単語については、後で言語を指定する必要があります).

ALTER TABLE "Items" ADD COLUMN "Items_search" TSVECTOR


上記では、TSVector タイプの列であるテーブル「Items」に新しい列を追加しています.これで、列を作成しただけで、トークン化された検索語を入力する必要があります.以下のコマンドでそれを行います.

UPDATE "Items" SET "Items_search" = to_tsvector('english', ' /* words || joined || like || this */ ');


上記のコマンドでは、組み込みの to_tsvector() 関数を使用して、言語と、検索可能にする必要がある "Items"テーブル内の単語を渡しています.この例では、単語は論理 OR ( '||' ) で区切られて明示的に綴られていますが、実際の状況では、これはプログラムで行われます.次に、PostgreSQL GIN インデクサーを使用して、さらに処理とトークン化を行います.

CREATE INDEX "Items_search" ON "Items" USING gin('Items_search');


GIN インデクサーは重み付けされていない語彙素のみを格納します. PostgreSQL には、特定の状況で GIN インデックス作成よりも優れたパフォーマンスを発揮する、GiST などの他のインデクサー メソッドがあります. PostgreSQL ドキュメントから:

"As a rule of thumb, GIN indexes are best for static data because lookups are faster. For dynamic data, GiST indexes are faster to update. Specifically, GiST indexes are very good for dynamic data and fast if the number of unique words (lexemes) is under 100,000, while GIN indexes will handle 100,000+ lexemes better but are slower to update."



「Items」テーブルに「Items_search」という検索可能な列ができました.これで、TSQuery と呼ばれる別の PostgreSQL メソッドを使用して、加重全文検索を実行できるようになりました.これは、PostgreSQL の基本的なテキスト マッチング演算子: @@ を使用して行われます.

SELECT * FROM "Items"
WHERE "Items_search" @@ plainto_tsquery('english', '/* text to search */');


この場合も、コメントアウトされたサンプル引数があります.実際のシナリオでは、この検索はプログラムで実装されます.

これで、PostgreSQL データベースで機能する検索機能が得られました.これは非常に便利で、実装がそれほど難しくなく、Elasticsearch のようなものよりもオーバーヘッドが少なくて済みます.私たちのチームが最近のプロジェクトで PostgreSQL を利用するという決定を下したことを振り返ってみると、PostgreSQL には他の DMS よりも「すぐに使える」多くの機能があることを理解するようになりました.この PostgreSQL 機能について楽しく学べたことを願っています.次のブログでは、もう 1 つのネイティブ PSQL 機能であるリスナー/通知イベント ハンドラーの実装についてお話しします.またね.

https://www.postgresql.org/docs/9.1/textsearch-indexes.html

https://en.wikipedia.org/wiki/Lexical_analysis

https://www.postgresql.org/docs/9.5/textsearch-intro.html#TEXTSEARCH-DOCUMENT