検索クエリ拡張

このページでは、全文検索の一部としてクエリ拡張を使用する方法について説明します。

関連性の高い結果を見つけられる可能性を高めるため、Spanner には、関連する語句、類義語、スペル修正を含むように検索クエリを拡張する高度な機能が用意されています。Spanner には、クエリの強化に次のオプションが用意されています。

拡張クエリ

拡張クエリを使用するには、SEARCH 関数で enhance_query=>true を設定します。Spanner は、関連する語句や類義語を含め、ステミングを適用し、スペル修正を行うことで、検索クエリを自動的に拡張します。たとえば、拡張クエリを使用する場合、検索クエリ hotl cal はアルバム Hotel California と一致します。

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'hotl cal', enhance_query=>true)

PostgreSQL

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'hotl cal', enhance_query=>true)

enhance_query は、トークン化に影響しないクエリ時オプションです。enhance_query の有無にかかわらず、同じ検索インデックスを使用できます。

Google は、クエリ拡張アルゴリズムの改善に継続的に取り組んでいます。そのため、enhance_query => true を含むクエリでは、時間の経過とともに結果が若干異なる場合があります。

enhance_query を使用すると、検索クエリの拡張と、その結果として得られたより大きなクエリの実行のオーバーヘッドにより、レイテンシが増加する可能性があります。

カスタム辞書

Spanner の全文検索でカスタム辞書を使用すると、データセット内の用語の同義語を定義できます。これは、類義語、頭字語、同義語などの語句のバリエーションをキャプチャして、検索結果の取得を改善するのに役立ちます。

カスタム辞書テーブルを作成する

カスタム辞書は、用語とその同義語の Key-Value ペアを含むユーザー作成のテーブルです。作成するには、CREATE TABLE ステートメントに fulltext_dictionary_table = true オプションを含めます。テーブルには次の 2 つの列が必要です。

  • Key: 類義語で展開される用語の null 不可の文字列列。
  • Value: キーの類義語の配列の null 不可の文字列配列の列。

テーブルには KeyValue 以外の列を含めることはできません。検索語句が辞書の Key と一致する場合、検索は、キーターム自体とともに Value 内の対応するすべての同義語を含むように拡張されます。次の例では、MyCustomDictionary という名前のカスタム辞書テーブルを作成します。また、作成時にこのテーブルにテーブル オプション fulltext_dictionary_table=true を設定する必要があります。

GoogleSQL

CREATE TABLE MyCustomDictionary (
  Key STRING(MAX) NOT NULL,
  Value ARRAY<STRING(MAX)> NOT NULL,
) PRIMARY KEY(Key),
OPTIONS (fulltext_dictionary_table = true);

PostgreSQL

CREATE TABLE mycustomdictionary (
  key character varying  NOT NULL,
  value character varying [] NOT NULL,
  PRIMARY KEY(key)
)  WITH ( type = 'fulltext_dictionary')

テーブルを作成したら、同義語を挿入します。

GoogleSQL

INSERT INTO MyCustomDictionary (Key, Value) VALUES
('album', ['vinyl', 'cassette']),
('edm', ['electronic dance music']);

PostgreSQL

INSERT INTO mycustomdictionary (key, value) VALUES
('album', ARRAY['vinyl', 'cassette']),
('edm', ARRAY['electronic dance music']);

テーブルにデータを入力する際は、次の点に注意してください。

  • キーは単語でなければなりません。
  • 値は単語または複数の単語から成るフレーズにできます。値に複数の単語が含まれている場合、クエリ拡張時にフレーズ検索として扱われます。
  • キーと値はすべて小文字にする必要があります。これにより、デフォルトのトークナイザーによって小文字に変換される検索トークンと一致します。

検索の拡張は、検索語句が Key と一致した場合にのみ行われます。検索語句が Value の類義語と一致し、Key と一致しない場合、検索は拡張されません。双方向マッピングが必要な場合(たとえば、vinyl または cassette の検索で album も見つかるようにする場合)、逆マッピングも辞書テーブルに挿入する必要があります。次の例は、albumvinylcassette の双方向マッピングを挿入する方法を示しています。

GoogleSQL

INSERT INTO MyCustomDictionary (Key, Value)
-- 1. Insert album -> vinyl, cassette
SELECT 'album', ['vinyl', 'cassette']
UNION ALL
-- 2. Insert vinyl -> album and cassette -> album
SELECT syn, ['album']
FROM UNNEST(['vinyl', 'cassette']) AS syn;

PostgreSQL

INSERT INTO mycustomdictionary (key, value)
-- 1. Insert album -> vinyl, cassette
SELECT 'album', ARRAY['vinyl', 'cassette']
UNION ALL
-- 2. Insert vinyl -> album and cassette -> album
SELECT syn, ARRAY['album']
FROM unnest(ARRAY['vinyl', 'cassette']) AS syn;

検索クエリでカスタム辞書を使用する

カスタム辞書を使用するには、SEARCH 関数の dictionary 引数で辞書テーブル名を指定します。

  • 検索語句がディクショナリのキーである場合、SEARCH はその値も検索します。album という用語は、vinyl または cassette を含むメッセージと一致します。

    GoogleSQL

    SELECT MessageId, Body
    FROM Messages
    WHERE SEARCH(Body_Tokens, 'album', dictionary=>'MyCustomDictionary');
    

    PostgreSQL

    SELECT messageid, body
    FROM messages
    WHERE spanner.search(body_tokens, 'album', dictionary=>'mycustomdictionary');
    
  • キー edm の辞書の値に electronic dance music などの複数の単語が含まれている場合、フレーズ検索として扱われます。つまり、一致と見なされるには、指定された順序で用語が隣接して表示される必要があります。たとえば、次のクエリは「electronic dance music」というフレーズを完全に含む結果を返しますが、「dance electronic music」とは一致しません。これは主に頭字語の展開に役立ち、次のように使用できます。

    GoogleSQL

    SELECT MessageId, Body
    FROM Messages
    WHERE SEARCH(Body_Tokens, 'edm', dictionary=>'MyCustomDictionary');
    

    PostgreSQL

    SELECT messageid, body
    FROM messages
    WHERE spanner.search(body_tokens, 'edm', dictionary=>'mycustomdictionary');
    

辞書検索の鮮度

デフォルトでは、カスタム辞書エントリは最大 15 秒の未更新で読み取られます。これにより、読み取りオペレーションのオーバーヘッドが削減されます。これは、最新のデータを読み取るよりも、多少の古いデータを含むデータを読み取る方が効率的であるためです。そのため、辞書エントリの変更が検索クエリに反映されるまでに最大 15 秒かかることがあります。この動作は、次の方法でオーバーライドできます。

  • fulltext_dictionary_staleness テーブル オプションを使用する。
  • fulltext_dictionary_staleness クエリヒントを使用して、よりきめ細かい制御を行う。

クエリヒントとテーブル オプションの両方が使用されている場合、クエリヒントがテーブル オプションをオーバーライドします。

fulltext_dictionary_staleness テーブル オプション

ディクショナリ テーブルに fulltext_dictionary_staleness オプションを設定できます。このディクショナリ テーブルを使用するすべてのクエリは、クエリヒントでオーバーライドされない限り、この古い値を使用します。

GoogleSQL

次の例は、fulltext_dictionary_staleness オプションを使用してテーブルを CREATE する方法を示しています。

CREATE TABLE MyCustomDictionary (
  Key STRING(MAX) NOT NULL,
  Value ARRAY<STRING(MAX)> NOT NULL,
) PRIMARY KEY(Key),
OPTIONS (
  fulltext_dictionary_table = true,
  fulltext_dictionary_staleness = '5s'
);

次の例は、ALTER テーブルを使用して fulltext_dictionary_staleness オプションを変更または設定する方法を示しています。

ALTER TABLE MyCustomDictionary SET OPTIONS (
  fulltext_dictionary_staleness = '60s'
);

PostgreSQL

次の例は、fulltext_dictionary_staleness オプションを使用してテーブルを CREATE する方法を示しています。

-- Create with 5s staleness
CREATE TABLE mycustomdictionary (
  key character varying NOT NULL,
  value character varying[]  NOT NULL,
  PRIMARY KEY(key)
) WITH (
  type = 'fulltext_dictionary',
  fulltext_dictionary_staleness = '5s'
);

PostgreSQL インターフェースは、fulltext_dictionary_staleness オプションを変更または設定するための ALTER テーブルをサポートしていません。

fulltext_dictionary_staleness クエリヒント

よりきめ細かい制御を行うには、fulltext_dictionary_staleness クエリヒントを使用して、個々のクエリに異なる鮮度を指定します。このヒントは、テーブルレベルの設定をオーバーライドします。

次の例では、ヒントを使用して、ステイルネスがゼロのディクショナリ テーブル ルックアップを実行します。これにより、最新の辞書エントリが読み取られます。このアプローチでは、最新のデータを読み取る方が、ある程度の古いデータを許容するよりも効率が低いため、クエリ レイテンシが増加する可能性があります。

GoogleSQL

@{fulltext_dictionary_staleness="0s"}
SELECT MessageId, Body
FROM Messages
WHERE SEARCH(Body_Tokens, 'Bill', dictionary=>'MyCustomDictionary');

PostgreSQL

/*@ fulltext_dictionary_staleness='0s' */
SELECT messageid, body
FROM messages
WHERE spanner.search(body_tokens, 'Bill', dictionary=>'mycustomdictionary');

カスタム辞書テーブルに関する既知の制限事項

  • カスタム ディクショナリ テーブルで Spanner のインポートとエクスポートを使用する場合、サポートは限定的です。
  • カスタム辞書テーブルはデフォルト スキーマに作成する必要があり、名前付きスキーマに作成することはできません。
  • カスタム ディクショナリ テーブルは、デフォルトの SEARCH クエリ言語のみをサポートしています。

カスタム辞書と拡張クエリの組み合わせ

SEARCH 関数で dictionaryenhance_query=>true の両方を設定すると、カスタム辞書の同義語を enhanced query と組み合わせることができます。クエリの範囲拡大では、一般的な類義語やスペル修正を使用してクエリを拡張できます。カスタム辞書では、独自の拡張を定義できます。たとえば、enhance_queryalbum を展開して record を含み、MyCustomDictionaryalbum['vinyl', 'cassette'] にマッピングする場合、次のクエリは albumrecordvinyl、または cassette を含むメッセージと一致します。

GoogleSQL

SELECT MessageId, Body
FROM Messages
WHERE SEARCH(Body_Tokens, 'album', enhance_query=>true, dictionary=>'MyCustomDictionary');

PostgreSQL

SELECT messageid, body
FROM messages
WHERE spanner.search(body_tokens, 'album', enhance_query=>true, dictionary=>'mycustomdictionary');

両方の拡張機能が有効になっている場合、元の検索語句に対して個別に動作し、一方の拡張機能で生成された語句が他方の入力として使用されることはありません。

次のステップ