すべてのプロダクト
Search
ドキュメントセンター

PolarDB:テキスト検索の制御

最終更新日:Mar 29, 2026

PolarDB における全文検索には、以下の 3 つの構成要素が必要です:ドキュメントを検索可能な tsvector 値に変換すること、ユーザークエリを tsquery 値に変換すること、および検索結果の順位付けまたはハイライト表示を行うことです。本ページでは、各ステップを実現する関数について説明します。

ドキュメントの解析

to_tsvector は、テキストドキュメントを tsvector — すなわち、語幹化された語形(lexeme)とそのドキュメント内位置を含む、並べ替え済みの語彙リスト — に変換します。

to_tsvector([ config regconfig, ] document text) returns tsvector

パーサの動作手順は以下のとおりです:

  1. ドキュメントをトークンに分割し、それぞれにタイプ(単語、数字、句読点など)を割り当てます。

  2. テキスト検索構成で指定された辞書チェーンを参照し、各トークンを照合します。

  3. トークンを認識する最初の辞書が、1つ以上の正規化された形素を出力します。たとえば、ratsrat になります。これは、辞書が rats を複数形として認識するためです。

  4. a」「on」「it」などのストップワードとして認識されたトークンは破棄されます。これらは出現頻度が高すぎて検索に有用でないためです。

  5. 辞書に一致するエントリがないトークンも破棄されます(例:句読点 - など)。

SELECT to_tsvector('english', 'a fat  cat sat on a mat - it ate a fat rats');
                      to_tsvector
-----------------------------------------------------
 'ate':9 'cat':3 'fat':2,11 'mat':7 'rat':12 'sat':4

config 引数は、インデックス作成に使用するテキスト検索構成 — すなわち、パーサ、辞書、トークンタイプの組み合わせ — を指定します。省略した場合は、データベースのデフォルト構成が使用されます。

ドキュメントフィールドへの重みの割り当て

setweight を使用して、lexeme に重み(ABC、または D)を付与します。通常、これはドキュメントのセクション(タイトル、キーワード、概要、本文)の重要度を反映させるために用いられます。順位付け関数は、これらの重みをスコア算出時に利用します。

to_tsvector(NULL)NULL を返すため、NULL 許容カラムには coalesce をラップします:

UPDATE tt SET ti =
    setweight(to_tsvector(coalesce(title,'')), 'A')    ||
    setweight(to_tsvector(coalesce(keyword,'')), 'B')  ||
    setweight(to_tsvector(coalesce(abstract,'')), 'C') ||
    setweight(to_tsvector(coalesce(body,'')), 'D');

|| 演算子は、ラベル付きの tsvector 値を連結し、単一のインデックス対象表現に統合します。

順位付け関数で使用されるデフォルトの重みは以下のとおりです:

重みラベルデフォルト値
A1.0
B0.4
C0.2
D0.1

クエリの解析

ユーザー入力を tsquery に変換する関数は 4 つあります。入力ソースに応じて適切な関数を選択してください。

関数入力形式挿入される演算子エラーを発生させない使用するケース
to_tsquery明示的な演算子が必要入力通りいいえ完全制御を伴うプログラムによるクエリ構築
plainto_tsqueryプレーンテキスト&(AND)をすべての語間に挿入いいえシンプルなキーワード検索
phraseto_tsqueryプレーンテキスト<->(FOLLOWED BY)を語間に挿入いいえ正確なフレーズ検索
websearch_to_tsqueryWeb 検索構文構文から解釈はい検索ボックスからの生のユーザー入力を処理する場合

to_tsquery

to_tsquery([ config regconfig, ] querytext text) returns tsquery

to_tsquery は、各トークンを lexeme に正規化し、ストップワードを破棄します。この動作は to_tsvector と同様です。入力には、あらかじめ tsquery 演算子 — &(AND)、|(OR)、!(NOT)、<->(FOLLOWED BY)— を使用する必要があります。括弧によるグループ化もサポートされています。有効な演算子で区切られていないトークンは、構文エラーを引き起こします。

SELECT to_tsquery('english', 'The & Fat & Rats');
  to_tsquery
---------------
 'fat' & 'rat'

特定のラベル付き lexeme のみにマッチングを制限するには、重みラベルを付与します:

SELECT to_tsquery('english', 'Fat | Rats:AB');
    to_tsquery
------------------
 'fat' | 'rat':AB

プレフィックスマッチングを行うには、lexeme 末尾に * を付加します。これにより、tsvector 内で該当文字列で始まるすべての単語がマッチします:

SELECT to_tsquery('supern:*A & star:A*B');
        to_tsquery
--------------------------
 'supern':*A & 'star':*AB

テキスト検索構成にシソーラス辞書が含まれている場合、to_tsquery はシングルクォートで囲まれたフレーズを受け入れます。この例では、シソーラスが supernovae starssn にマッピングしています:

SELECT to_tsquery('''supernovae stars'' & !crab');
  to_tsquery
---------------
 'sn' & !'crab'

plainto_tsquery

plainto_tsquery([ config regconfig, ] querytext text) returns tsquery

plainto_tsquery は、整形されていないテキストを入力として受け入れ、正規化後に残存するすべての語間に & を挿入します。tsquery 演算子、重みラベル、プレフィックスマッチングラベルは入力内で認識されず、すべての句読点はプレーンテキストとして扱われ、破棄されます。

SELECT plainto_tsquery('english', 'The Fat Rats');
 plainto_tsquery
-----------------
 'fat' & 'rat'
SELECT plainto_tsquery('english', 'The Fat & Rats:C');
   plainto_tsquery
---------------------
 'fat' & 'rat' & 'c'

phraseto_tsquery

phraseto_tsquery([ config regconfig, ] querytext text) returns tsquery

phraseto_tsqueryplainto_tsquery と同様に動作しますが、残存する語間に <->(FOLLOWED BY)演算子を挿入し、語順を強制します。ストップワードは単に破棄されるのではなく、位置精度を保つため、<> 演算子(<-> ではない)を挿入して考慮されます。

SELECT phraseto_tsquery('english', 'The Fat Rats');
 phraseto_tsquery
------------------
 'fat' <-> 'rat'
SELECT phraseto_tsquery('english', 'The Fat & Rats:C');
      phraseto_tsquery
-----------------------------
 'fat' <-> 'rat' <-> 'c'

websearch_to_tsquery

websearch_to_tsquery([ config regconfig, ] querytext text) returns tsquery

websearch_to_tsquery は Web 検索構文を入力として受け入れ、構文エラーを発生させません。そのため、検索ボックスからの生のユーザー入力を直接渡す安全な関数です。検索ボックスからの入力を受け付ける場合、本関数の使用を推奨します。サポートされる構文は以下のとおりです:

  • クォートなしのテキスト& で区切られた語(plainto_tsquery と同様)に変換されます

  • 「クォート付きテキスト」<-> で区切られた語(phraseto_tsquery と同様)に変換されます

  • OR| に変換されます

  • -(ダッシュ)!(NOT)に変換されます

その他の句読点は無視されます。入力内の演算子、重みラベル、プレフィックスマッチングラベルは認識されません。

SELECT websearch_to_tsquery('english', 'The fat rats');
 websearch_to_tsquery
----------------------
 'fat' & 'rat'
SELECT websearch_to_tsquery('english', '"supernovae stars" -crab');
       websearch_to_tsquery
----------------------------------
 'supernova' <-> 'star' & !'crab'
SELECT websearch_to_tsquery('english', '"sad cat" or "fat rat"');
       websearch_to_tsquery
-----------------------------------
 'sad' <-> 'cat' | 'fat' <-> 'rat'
SELECT websearch_to_tsquery('english', 'signal -"segmentation fault"');
         websearch_to_tsquery
---------------------------------------
 'signal' & !( 'segment' <-> 'fault' )
SELECT websearch_to_tsquery('english', '""" )( dummy \\ query <->');
 websearch_to_tsquery
----------------------
 'dummi' & 'queri'

検索結果の順位付け

ts_rank および ts_rank_cd は、ドキュメントがクエリにどの程度適合するかをスコアリングします。両関数とも、語彙的および構造的情報(すなわち、クエリ語がドキュメントに出現する頻度、および出現箇所の重要度)を考慮します。スコアはアプリケーション依存であり、普遍的なスケールはありません。

ts_rank([ weights float4[], ] vector tsvector, query tsquery [, normalization integer ]) returns float4

マッチする lexeme の出現頻度に基づいてベクターを順位付けします。

ts_rank_cd([ weights float4[], ] vector tsvector, query tsquery [, normalization integer ]) returns float4

さらに、マッチする lexeme 間の近接性(カバーデンシティ)も考慮します。位置情報が必要であり、tsvector に非ストリップの lexeme が含まれていない場合はゼロを返します。

weights 引数

float4[] 配列を渡すことで、各重みラベルの影響度を調整できます:

{D-weight, C-weight, B-weight, A-weight}

デフォルト値:{0.1, 0.2, 0.4, 1.0}

重みラベル A(通常はドキュメントのタイトル)が付与された lexeme は、重みラベル D(本文)が付与された lexeme より最大 10 倍の寄与度を持ちます。

normalization オプション

デフォルトでは、長いドキュメントほど単純に単語数が多くなるため、スコアが高くなります。normalization 整数オプションは、ドキュメント長による補正を行います。これはビットマスクであり、| で値を組み合わせます:

効果
0(デフォルト)長さ補正なし
1ランクを 1 + log(ドキュメント長) で割る
2スコアをドキュメント長で除算
4スコアを範囲間の調和平均距離で除算(ts_rank_cd のみ)
8スコアを固有語数で除算
16スコアを 1 + log(固有語数)で除算
32ランクを (ランク + 1) で除算 (すべてのランクを 0〜1 の範囲にスケーリング)

複数のフラグが設定されている場合、変換は上記の順序で適用されます。

32 の正規化(rank/(rank+1))はスコアを 0–1 の範囲にスケーリングしますが、結果の順序付けには影響しません。これは単なる表示上の変換です。

例:上位 10 件のマッチ

SELECT title, ts_rank_cd(textsearch, query) AS rank
FROM apod, to_tsquery('neutrino|(dark & matter)') query
WHERE query @@ textsearch
ORDER BY rank DESC
LIMIT 10;
                         title                     |   rank
-----------------------------------------------+----------
 Neutrinos in the Sun                          |      3.1
 The Sudbury Neutrino Detector                 |      2.4
 A MACHO View of Galactic Dark Matter          |  2.01317
 Hot Gas and Dark Matter                       |  1.91171
 The Virgo Cluster: Hot Plasma and Dark Matter |  1.90953
 Rafting for Solar Neutrinos                   |      1.9
 NGC 4650A: Strange Galaxy and Dark Matter     |  1.85774
 Hot Gas and Dark Matter                       |   1.6123
 Ice Fishing for Cosmic Neutrinos              |      1.6
 Weak Lensing Distorts the Universe            | 0.818218

normalization=32 を指定した場合:

SELECT title, ts_rank_cd(textsearch, query, 32 /* rank/(rank+1) */ ) AS rank
FROM apod, to_tsquery('neutrino|(dark & matter)') query
WHERE  query @@ textsearch
ORDER BY rank DESC
LIMIT 10;
                         title                     |        rank
-----------------------------------------------+-------------------
 Neutrinos in the Sun                          | 0.756097569485493
 The Sudbury Neutrino Detector                 | 0.705882361190954
 A MACHO View of Galactic Dark Matter          | 0.668123210574724
 Hot Gas and Dark Matter                       |  0.65655958650282
 The Virgo Cluster: Hot Plasma and Dark Matter | 0.656301290640973
 Rafting for Solar Neutrinos                   | 0.655172410958162
 NGC 4650A: Strange Galaxy and Dark Matter     | 0.650072921219637
 Hot Gas and Dark Matter                       | 0.617195790024749
 Ice Fishing for Cosmic Neutrinos              | 0.615384618911517
 Weak Lensing Distorts the Universe            | 0.450010798361481
順位付け処理は、マッチした各ドキュメントの tsvector を参照する必要があるため、I/O バウンドとなり、処理が遅くなる可能性があります。実用的なクエリでは多数のマッチが発生することが多いため、残念ながらこれを回避することはほぼ不可能です。

検索結果のハイライト表示

ts_headline は、元のドキュメントからクエリ語をマークアップした抜粋を返します。

ts_headline([ config regconfig, ] document text, query tsquery [, options text ]) returns text

ts_headline は、ドキュメントとクエリを引数として受け取り、クエリ語をハイライト表示したドキュメントの抜粋を返します。具体的には、関数はクエリを用いて関連するテキスト断片を選択し、クエリに含まれるすべての語をハイライト表示します(クエリの制約条件に合致しない語位置であっても)。順位付け関数とは異なり、ts_headlinetsvector のサマリーではなく、元のドキュメントテキスト上で動作します。このため精度は高いものの処理が遅く、結果セットを事前にフィルタリングした後に呼び出す必要があります。

config を省略した場合は、default_text_search_config 設定が使用されます。

オプション

カンマ区切りの option=value の文字列を渡します:

オプションデフォルト説明
MaxWords整数35見出しの最大語数
MinWords整数15見出しの最小語数
ShortWord整数3この長さ以下である語は、見出しの境界で除外されます(ただし、クエリ語である場合は除く)
HighlightAllブール値falseドキュメント全体を見出しとして使用し、MaxWordsMinWords、および ShortWord
MaxFragments整数0表示するフラグメントの最大数。0 の場合は非フラグメントモード、正の値の場合はフラグメントモードが有効になります
StartSel文字列<b>ハイライト表示されるクエリ語の開始デリミタ
StopSel文字列</b>ハイライト表示されるクエリ語の終了デリミタ
FragmentDelimiter文字列...MaxFragments > 0 の場合のフラグメント間の区切り文字

オプション名は大文字小文字を区別しません。スペースまたはカンマを含む文字列値は二重引用符で囲んでください。

非フラグメントモード(デフォルト、MaxFragments=0):見出し長の制限内で最も多くのクエリ語を含む単一の最適な抜粋を選択します。

フラグメントモードMaxFragments > 0):すべてのクエリマッチを検出し、それぞれを最大 MaxWords 語のフラグメントに分割し、クエリ語の多いフラグメントを優先します。マッチがドキュメントの大規模な範囲にまたがる場合に特に有用です。

いずれのモードでも、クエリ語が見つからない場合は、ドキュメントの先頭 MinWords 語が返されます。

SELECT ts_headline('english',
  'The most common type of search
is to find all documents containing given query terms
and return them in order of their similarity to the
query.',
  to_tsquery('english', 'query & similarity'));
                        ts_headline
------------------------------------------------------------
 指定された クエリ 語を含み、              +
 それらをクエリとの 類似度 の順に返す。+
 クエリ。
SELECT ts_headline('english',
  'Search terms may occur
many times in a document,
requiring ranking of the search matches to decide which
occurrences to display in the result.',
  to_tsquery('english', 'search & term'),
  'MaxFragments=10, MaxWords=7, MinWords=3, StartSel=<<, StopSel=>>');
                        ts_headline
------------------------------------------------------------
 <<Search>> <<terms>> may occur                            +
 many times ... ranking of the <<search>> matches to decide