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

PolarDB:テキスト検索の制御

最終更新日:Jun 03, 2024

全文検索を実装するには、ドキュメントからtsvectorを作成し、ユーザークエリからtsqueryを作成する関数が必要です。 また、有用な順序で結果を返す必要があるため、クエリとの関連性に関してドキュメントを比較する関数が必要です。 結果をうまく表示できることも重要です。

ドキュメントの解析

PolarDB PostgreSQLは、ドキュメントをtsvectorデータ型に変換するための関数to_tsvectorを提供します。

to_tsvector([ config regconfig, ] document text) はtsvectorを返します

to_tsvectorは、テキストドキュメントをトークンに構文解析し、トークンを語彙素に縮小し、語彙素とドキュメント内の位置を一覧表示するtsvectorを返します。 ドキュメントは、指定されたテキスト検索設定またはデフォルトのテキスト検索設定に従って処理されます。 簡単な例を次に示します。

SELECT to_tsvector (「english」、「マットの上に座っている太った猫-太ったネズミを食べた」);
                      to_tsvector
    -----------------------------------------------------
     'ate':9 'cat':3 'fat':2,11 'mat':7 'rat':12 'sat':4 

上記の例では、結果のtsvectoraon、またはitという単語が含まれていないことがわかります。ratsという単語はratになり、句読点記号-は無視されました。

to_tsvector関数は、ドキュメントテキストをトークンに分解し、各トークンに型を割り当てるパーサーを内部的に呼び出します。 トークンごとに、辞書のリストが参照され、リストは、トークンのタイプに応じて変化し得る。 トークンを認識する第1の辞書は、トークンを表す1つ以上の正規化された語彙素を発する。 たとえば、ラットという単語がラットの複数形であることを辞書の1つが認識したため、ラットラットになりました。 いくつかの単語は、ストップワードとして認識され、これは、それらがあまりに頻繁に出現して検索に有用ではないので、それらを無視させる。 この例では、これらはaon、およびitです。 リスト内のどの辞書もトークンを認識しない場合、それも無視される。 この例では、句読点記号-に発生しました。実際には、トークンのタイプ (スペース記号) に割り当てられた辞書がないためです。 パーサー、ディクショナリ、およびどのタイプのトークンをインデックスするかの選択は、選択されたテキスト検索構成によって決定される。 同じデータベースに多くの異なる構成を持つことが可能であり、事前定義された構成はさまざまな言語で利用できます。 この例では、英語のデフォルト設定英語を使用しました。

関数setweightを使用して、tsvectorのエントリに所与の重みでラベルを付けることができ、重みは、文字aBC、またはDのうちの1つである。 これは通常、タイトルと本文など、ドキュメントのさまざまな部分からのエントリをマークするために使用されます。 後に、この情報は、検索結果のランキングに使用することができる。

to_tsvector (NULL) はNULLを返すため、フィールドがnullになる場合は常にcoalesceを使用することをお勧めします。 構造化ドキュメントからtsvectorを作成するための推奨方法は次のとおりです。

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

ここでは、完成したtsvector内の各語彙素のソースにラベルを付けるためにseweightを使用し、次にtsvector連結演算子 | | を使用してラベルの付いたtsvector値をマージしました。

クエリの解析

PolarDB PostgreSQLは、クエリをtsqueryデータ型に変換するための関数to_tsqueryplainto_tsqueryphraseto_tsquerywebsearch_to_tsqueryを提供します。 to_tsqueryは、plainto_tsqueryまたはphraseto_tsqueryよりも多くの機能へのアクセスを提供しますが、その入力についてはあまり寛容ではありません。 websearch_to_tsqueryは、ウェブ検索エンジンで使用されているものと同様の代替構文を備えたto_tsqueryの簡略版です。

to_tsquery([ config regconfig, ] querytext text) はtsqueryを返します

to_tsqueryは、querytextからtsquery値を作成します。これは、tsquery演算子 & (AND) 、| (OR) 、! (NOT) 、および <-> (FOLLOWED BY) 、場合によっては括弧を使用してグループ化されます。 つまり、to_tsqueryへの入力は、すでにtsquery入力の一般的なルールに従っている必要があります。 違いは、基本的なtsquery入力は額面のトークンを受け取りますが、to_tsqueryは指定された設定またはデフォルトの設定を使用して各トークンを語彙に正規化し、設定に従ってストップワードであるトークンを破棄することです。 設定例:

SELECT to_tsquery('english '、'The & Fat & Rats');
      to_tsquery
    ---------------
     「脂肪」&「ラット」 

基本的なtsquery入力と同様に、各語彙素に重みを付けて、それらの重みのtsvector語彙素のみに一致するように制限できます。 設定例:

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

また、* を語彙素に添付してプレフィックスマッチングを指定することもできます。

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

このような語彙素は、所与の文字列で始まるtsvector内の任意の単語と一致する。

to_tsqueryは、単一引用語句も受け入れることができます。 これは主に、構成がそのようなフレーズをトリガするシソーラス辞書を含む場合に有用である。 以下の例では、シソーラスに超新星星: snというルールが含まれています。

SELECT to_tsquery(''超新星の星'' & !crab);
      to_tsquery
    ---------------
     'sn' & ! 'crab' 

引用符がない場合、to_tsqueryは、AND、OR、またはFOLLOWED by演算子で区切られていないトークンの構文エラーを生成します。

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

plainto_tsqueryは、未フォーマットのテキストquerytexttsquery値に変換します。 テキストは解析され、to_tsvectorのように正規化され、& (and) tsquery演算子が生き残った単語の間に挿入されます。

例:

SELECT plainto_tsquery('english '、'The Fat Rats');
     plainto_tsquery
    -----------------
     「脂肪」&「ラット」 

plainto_tsqueryは、入力でtsquery演算子、重みラベル、またはプレフィックス一致ラベルを認識しません。

SELECT plainto_tsquery('english' 、'The Fat & Rats:C');
       plainto_tsquery
    ---------------------
     「脂肪」&「ラット」&「c」 

ここでは、すべての入力句読点が破棄されました。

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

phraseto_tsqueryplainto_tsqueryとよく似ていますが、& (AND) 演算子ではなく、生き残った単語の間に <-> (FOLLOWED BY) 演算子を挿入します。 また、ストップワードは単純に破棄されるのではなく、<-> 演算子ではなく <> 演算子を挿入することによって考慮されます。 この関数は、FOLLOWED BY演算子がすべての語彙素の存在だけでなく語彙素の順序をチェックするため、正確な語彙素シーケンスを検索するときに役立ちます。

例:

SELECT phraseto_tsquery('english '、'The Fat Rats');
     phraseto_tsquery
    ------------------
     'fat' <-> 'rat' 

plainto_tsqueryと同様に、phraseto_tsquery関数は、入力内のtsquery演算子、重みラベル、またはプレフィックス一致ラベルを認識しません。

SELECT phraseto_tsquery('english' 、'The Fat & Rats:C');
          phraseto_tsquery
    -----------------------------
     'fat' <-> 'rat' <-> 'c' 
websearch_to_tsquery([ config regconfig, ] querytext text) はtsqueryを返します

websearch_to_tsqueryは、単純なフォーマットされていないテキストが有効なクエリである代替構文を使用して、querytextからtsquery値を作成します。 plainto_tsqueryphraseto_tsqueryとは異なり、特定の演算子も認識します。 さらに、この関数は構文エラーを発生させないため、ユーザーが指定した生の入力を検索に使用できます。

次の構文がサポートされています。

  • unquoted text: 引用符内にないテキストは、plainto_tsqueryによって処理されたかのように、& 演算子で区切られた用語に変換されます。

  • "quoted text": 引用符内のテキストは、phraseto_tsqueryによって処理されるかのように、<-> 演算子で区切られた用語に変換されます。

  • OR: "or" という単語は | 演算子に変換されます。

  • -: ダッシュはに変換されます! 演算子のみ使用できます。

他の句読点は無視される。 したがって、plainto_tsqueryphraseto_tsqueryと同様に、websearch_to_tsquery関数は、入力内のtsquery演算子、重みラベル、またはプレフィックス一致ラベルを認識しません。

例:

SELECT websearch_to_tsquery('english '、'The fat rats');
     websearch_to_tsquery
    ----------------------
     「脂肪」&「ラット」
    (1行)

    SELECT websearch_to_tsquery('english '、' "supernovae stars" -crab);
           websearch_to_tsquery
    ----------------------------------
     「超新星」 <-> 「スター」&! 'crab'
    (1行)

    SELECT websearch_to_tsquery('english' 、'"sad cat" または "fat rat"');
           websearch_to_tsquery
    -----------------------------------
     'sad' <-> 'cat' | 'fat' <-> 'rat'
    (1行)

    SELECT websearch_to_tsquery('english' 、'signal -"セグメンテーションフォールト" ');
             websearch_to_tsquery
    ---------------------------------------
     '信号' & ! ('segment' <-> 'fault')
    (1行)

    SELECT websearch_to_tsquery('english', '"" " )(ダミー \\ query <->');
     websearch_to_tsquery
    ----------------------
     「ダミー」&「ケリ」
    (1行) 

ランキング検索结果

PostgreSQLには、語彙、近接、構造情報を考慮した2つの事前定義されたランキング関数が用意されています。つまり、クエリ用語がドキュメントに表示される頻度、ドキュメント内の用語がどの程度近くにあるか、そして、それらが発生する文書の部分がどれほど重要か。 しかし、関連性の概念は曖昧であり、非常にアプリケーション固有である。 異なるアプリケーションは、ランク付けのための追加情報、例えば文書修正時間を必要とし得る。 組み込みランキング関数は単なる例である。 独自のランキング関数を作成したり、特定のニーズに合わせて結果を追加の要素と組み合わせたりすることができます。

現在利用可能な2つのランキング機能は次のとおりです。

  • 一致する語彙素の頻度に基づいてベクトルをランク付けします。

    ts_rank([ weights float4[], ] ベクトルtsvector, query tsquery [, normalization integer ]) returns float4
  • 指定されたドキュメントベクトルとクエリのカバー密度ランキング。

    ts_rank_cd([ weights float4[], ] ベクトルtsvector, query tsquery [, normalization integer ]) returns float4

    この関数は、指定されたドキュメントベクトルとクエリのカバー密度のランキングを計算します。 カバー密度は、マッチングする語彙素の互いに対する近接性が考慮されることを除いて、ts_rankランキングと同様である。

    この関数は、その計算を実行するために語彙素位置情報を必要とする。 したがって、tsvector内の「ストリップされた」語彙素は無視されます。 入力にストリップされていない語彙素がない場合、結果はゼロになります。

これらの関数の両方で、引数オプションの重みは、単語インスタンスのラベル付け方法に応じて、単語インスタンスを多かれ少なかれ重み付けする機能を提供します。 重み配列は、単語の各カテゴリの重みを次の順序で指定します。

{D-重、C-重、B-重、A-重}

重みが指定されていない場合は、次のデフォルトが使用されます。

{0.1、0.2、0.4、1.0}

通常、重みは、タイトルまたは最初の要約のような、ドキュメントの特別な領域からの単語をマークするために使用され、したがって、それらは、ドキュメント本体内の単語よりも高いまたは低い重要度で扱うことができる。

より長い文書は、クエリ用語を含む可能性がより高いので、文書サイズを考慮に入れることが合理的であり、例えば、検索ワードの5つのインスタンスを有する百語文書は、おそらく、5つのインスタンスを有する千語文書よりも関連性が高い。 どちらのランキング関数も、ドキュメントの長さがランクに影響するかどうか、およびどのように影響するかを指定する整数正規化オプションを使用します。 integerオプションは複数の動作を制御するため、ビットマスクです。| (2 | 4など) を使用して1つ以上の動作を指定できます。

  • 0 (デフォルト) はドキュメントの長さを無視します

  • 1はランクを1 + ドキュメントの長さの対数で割ります

  • 2ランクをドキュメントの長さで割る

  • 4は、ランクをエクステント間の平均高調波距離で除算します (これはts_rank_cdによってのみ実装されます) 。

  • 8ランクをドキュメント内の一意の単語の数で割る

  • 16は、ランクを1 + ドキュメント内の一意の単語の数の対数で除算します。

  • 32はランクを1で割ります

2つ以上のフラグビットが指定される場合、変換はリストされた順序で適用される。

ランキング関数はグローバルな情報を使用しないため、場合によっては必要に応じて1% または100% に公平な正規化を生成することは不可能であることに注意することが重要です。 正規化オプション32 (rank/(rank + 1)) を適用して、すべてのランクを0から1の範囲にスケールすることができるが、もちろんこれは単なる外観上の変更であり、検索結果の順序付けには影響しない。

最高ランクの10試合のみを選択する例を次に示します。

SELECTタイトル、ts_rank_cd(textsearch, query) AS rank
    FROM apod, to_tsquery('neutrino |(dark & matter)') クエリ
    WHEREクエリ @ @ textsearch
    ランクDESCによる注文
    LIMIT 10;
                         タイトル | ランク
    -----------------------------------------------+----------
     太陽のニュートリノ | 3.1
     サドベリーニュートリノ検出器 | 2.4
     銀河暗黒物質のMACHOビュー | 2.01317
     高温ガスと暗黒物質 | 1.91171
     おとめ座クラスター: ホットプラズマと暗黒物質 | 1.90953
     ソーラーニュートリノのラフティング | 1.9
     NGC 4650A: 奇妙な銀河と暗黒物質 | 1.85774
     高温ガスと暗黒物質 | 1.6123
     宇宙のニュートリノのための氷釣り | 1.6
     弱いレンズは宇宙を歪める | 0.818218 

これは、正規化されたランキングを使用する同じ例です。

SELECTタイトル, ts_rank_cd(textsearch, query, 32 /* rank/(rank + 1) */ ) AS rank
    FROM apod, to_tsquery('neutrino |(dark & matter)') クエリ
    WHEREクエリ @ @ textsearch
    ランクDESCによる注文
    LIMIT 10;
                         タイトル | ランク
    -----------------------------------------------+-------------------
     太陽のニュートリノ | 0.756097569485493
     サドベリーニュートリノ検出器 | 0.705882361190954
     銀河暗黒物質のMACHOビュー | 0.668123210574724
     高温ガスと暗黒物質 | 0.65655958650282
     おとめ座クラスター: ホットプラズマと暗黒物質 | 0.656301290640973
     ソーラーニュートリノのラフティング | 0.655172410958162
     NGC 4650A: 奇妙な銀河と暗黒物質 | 0.650072921219637
     高温ガスと暗黒物質 | 0.617195790024749
     宇宙のニュートリノのための氷釣り | 0.615384618911517
     弱いレンズは宇宙を歪める | 0.450010798361481 

ランク付けは、各一致ドキュメントのtsvectorを調べる必要があるため、高価になる可能性があります。 残念ながら、実際のクエリはしばしば多数の一致をもたらすため、回避することはほとんど不可能です。

ハイライト結果

検索結果を提示するには、各ドキュメントの一部と、それがクエリにどのように関連しているかを示すことが理想的です。 通常、検索エンジンは、マークされた検索用語を持つドキュメントの断片を表示します。PostgreSQLは、この機能を実装する関数ts_headlineを提供します。

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

ts_headlineはクエリとともにドキュメントを受け取り、クエリの用語が強調表示されているドキュメントからの抜粋を返します。 具体的には、関数はクエリを使用して関連するテキスト断片を選択し、クエリに表示されるすべての単語を、それらの単語の位置がクエリの制限に一致しない場合でも、強調表示します。 ドキュメントの解析に使用する設定は、configで指定できます。configが省略されている場合、default_text_search_config設定が使用されます。

options文字列を指定する場合は、1つ以上のoption=valueペアのコンマ区切りリストで構成する必要があります。 使用可能なオプションは次のとおりです。

  • MaxWordsMinWords (整数): これらの数値は、出力する最長見出しと最短見出しを決定します。 デフォルト値は35と15です。

  • ShortWord (整数): この長さ以下の単語は、クエリ用語でない限り、見出しの先頭と末尾で削除されます。 デフォルト値の3は、一般的な英語の記事を削除します。

  • HighlightAll (boolean): trueの場合、ドキュメント全体が見出しとして使用され、前の3つのパラメータは無視されます。 デフォルトはfalseです。

  • MaxFragments (整数): 表示するテキスト断片の最大数。 ゼロのデフォルト値は、非フラグメントベースのヘッドライン生成方法を選択する。 ゼロより大きい値は、フラグメントベースの見出し生成を選択する (以下を参照) 。

  • StartSel, StopSel (strings): ドキュメントに現れるクエリ単語を他の抜粋単語と区別するために区切るための文字列。 デフォルト値は「 <b> 」と「 </b> 」で、HTML出力に適しています。

  • FragmentDelimiter (文字列): 複数のフラグメントが表示される場合、フラグメントはこの文字列で区切られます。 デフォルトは“...".

これらのオプション名は、大文字と小文字を区別しないで認識されます。 文字列値にスペースまたはコンマが含まれている場合は、二重引用符が必要です。

非フラグメントベースの見出し生成では、ts_headlineは、所与のクエリに対する一致を見つけ、表示する単一のものを選択し、許容される見出しの長さ内により多くのクエリ単語を有する一致を優先する。 フラグメントベースのヘッドライン生成では、ts_headlineは、クエリの一致を見つけ、各一致をMaxWordsワード以下の「フラグメント」に分割し、より多くのクエリワードを有するフラグメントを優先し、可能な場合、周囲のワードを含むようにフラグメントを「ストレッチ」する。 したがって、フラグメントベースのモードは、クエリの一致がドキュメントの大きなセクションにまたがる場合や、複数の一致を表示することが望ましい場合に便利です。 どちらのモードでも、クエリの一致が識別できない場合、ドキュメント内の最初のMinWordsワードの単一のフラグメントが表示されます。

設定例:

SELECT ts_headline('english' 、
  '検索の最も一般的なタイプ
指定されたクエリ用語を含むすべてのドキュメントを見つけることです
との類似性の順にそれらを返します。query.',
  to_tsquery('english '、'query & similarity'));
                        ts_headline
------------------------------------------------------------
 与えられた <b> クエリ </b> 用語を含む +
 + への <b> 類似 </b> の順にそれらを返します
 <b> クエリ </b>

SELECT ts_headline('english' 、
  '検索条件が発生する可能性があります
ドキュメントで何度も、どちらを決定するために検索マッチのランキングが必要
結果に表示するオカレンス。'、
  to_tsquery('english' 、'search & term') 、
  'MaxFragments=10、MaxWords=7、MinWords=3、StartSel =<<、StopSel =>> ');
                        ts_headline
------------------------------------------------------------
 <<検索>> <<terms>> が発生する可能性があります +
 何度も... 決定する 
<<search>> マッチのランキング

ts_headlineは、tsvectorの要約ではなく元のドキュメントを使用するため、遅くなる可能性があり、注意して使用する必要があります。