このページでは、テーブルにトークン化を追加する方法について説明します。トークン化は、検索インデックスで使用されるトークンを作成するために必要です。
トークン化とは、値をトークンに変換するプロセスです。ドキュメントのトークン化に使用する方法によって、ユーザーがドキュメントに対して実行できる検索の種類と効率が決まります。
Spanner には、自然言語テキスト、部分文字列、文字列テキスト、数値、ブール値のトークナイザーが用意されています。データベース スキーマは、列に必要な検索の種類に一致するトークナイザーを使用します。トークナイザーには次の特徴があります。
- 各トークナイザーは、文字列や数値などの入力と、追加オプションの名前付き引数を取得する SQL 関数です。
- トークナイザーは TOKENLISTを出力します。
たとえば、テキスト文字列 The quick brown fox jumps over the lazy dog は [the,quick,brown,fox,jumps,over,the,lazy,dog] にトークン化されます。HTML 文字列 The <b>apple</b> is <i>red</i> は [the,apple,is,red] にトークン化されます。
トークンには次の特徴があります。
- トークンは、TOKENLISTデータ型を使用する列に保存されます。
- 各トークンは、関連する属性のセットをオプションで指定して、バイトのシーケンスとして保存されます。たとえば、全文検索アプリケーションでは、トークンは通常、テキスト ドキュメントの単一の単語です。
- HTML 値をトークン化するときに、Spanner はドキュメント内のトークンの重要度を示す属性を生成します。Spanner は、これらの属性を使用してスコアリングを行い、より目立つ用語(見出しなど)を強調します
トークナイザー
Spanner は、次のトークナイザー関数をサポートしています。
- 全文トークナイザー( - TOKENIZE_FULLTEXT)は、自然言語クエリの単語全体のトークンを生成します。- 例 - 次の両方の関数 - GoogleSQL- TOKENIZE_FULLTEXT("Yellow apple") TOKENIZE_FULLTEXT("Yellow <b>apple</b>", content_type=>"text/html")- PostgreSQL- この例では - spanner.tokenize_fulltextを使用しています。- spanner.tokenize_fulltext("Yellow apple") spanner.tokenize_fulltext('Yellow <b>apple</b>', context_type=>'text/html')- 同じトークン( - [yellow,apple])を生成します。
- 部分文字列トークナイザー( - TOKENIZE_SUBSTRING)は、各単語の各 n-gram のトークンを生成します。テキスト内の単語の部分文字列を検索するために使用されます。- 例 - GoogleSQL- TOKENIZE_SUBSTRING('hello world', ngram_size_min=>4, ngram_size_max=>6)- PostgreSQL- この例では - spanner.tokenize_substringを使用しています。- spanner.tokenize_substring('hello world', ngram_size_min=>4, ngram_size_max=>6)- [ello,hell,hello,orld,worl,world]というトークンを生成します。
- n-gram トークナイザー( - TOKENIZE_NGRAMS)は、入力から n-gram を生成します(個別の単語に分割しません)。正規表現述語を高速化するために使用されます。- 例 - 次の関数: - GoogleSQL- TOKENIZE_NGRAMS("Big Time", ngram_size_min=>4, ngram_size_max=>4)- PostgreSQL- この例では - spanner.tokenize_ngramsを使用しています。- spanner.tokenize_ngrams('big time', ngram_size_min=>4, ngram_size_max=>4)- ["Big ","ig T","g Ti"," Tim", "Time"]というトークンを生成します。
- 完全一致トークナイザー( - TOKENと- TOKENIZE_BOOL)は、いずれかの列に特定の値を含む行を検索するために使用されます。たとえば、商品カタログにインデックスを付けるアプリでは、特定のブランドと色の商品を検索する場合があります。- 例 - 次の関数: - GoogleSQL- TOKEN("hello") TOKEN(["hello", "world"])- PostgreSQL- この例では - spanner.tokenを使用しています。- spanner.token('hello')- [hello]というトークンを生成します。- 次の関数: - GoogleSQL- TOKENIZE_BOOL(true)- PostgreSQL- この例では - spanner.tokenize_boolを使用しています。- spanner.tokenize_bool(true)- [y]というトークンを生成します。
- 数値トークナイザー( - TOKENIZE_NUMBER)は、数値比較検索を高速化する一連のトークンを生成するために使用されます。等価条件の場合、トークンは数値そのものです。範囲条件(- rating >= 3.5など)の場合、トークンのセットはより複雑になります。- 例 - 次の関数ステートメント: - GoogleSQL- TOKENIZE_NUMBER(42, comparison_type=>'equality') TOKENIZE_NUMBER(42, comparison_type=>'all', granularity=>10, min=>1, max=>100)- PostgreSQL- この例では - spanner.tokenize_numberを使用しています。- spanner.tokenize_number(42, comparison_type=>'equality') spanner.tokenize_number(42, comparison_type=>'all', granularity=>10, min=>1, max=>100)- "==42"、- "==42"、- "[1,75]"、- "[36, 45]"、- "[36,55]"、- "[36, 75]"の各トークンを生成します。
- JSON トークナイザーと JSONB トークナイザー( - TOKENIZE_JSONと- TOKENIZE_JSONB)は、JSON の包含とキーの存在述語(- doc[@key] IS NOT NULL(GoogleSQL)や- doc ? 'key'(PostgreSQL)など)を高速化する一連のトークンを生成するために使用されます。
トークン化関数は通常、生成された列式で使用されます。これらの列は HIDDEN として定義されているため、SELECT * クエリ結果には含まれません。
次の例では、全文トークナイザーと数値トークナイザーを使用して、音楽アルバムの名前と評価を格納するデータベースを作成します。DDL ステートメントは次の 2 つの処理を行います。
- データ列 AlbumTitleとRatingを定義します。
- AlbumTitle_Tokensと- AlbumRating_Tokensを定義します。これらの- TOKENLIST列は、Spanner がインデックスを付けられるように、データ列の値をトークン化します。- GoogleSQL- CREATE TABLE Albums ( AlbumId STRING(MAX) NOT NULL, AlbumTitle STRING(MAX), Rating FLOAT64, AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN, Rating_Tokens TOKENLIST AS (TOKENIZE_NUMBER(Rating)) HIDDEN ) PRIMARY KEY(AlbumId);- PostgreSQL- CREATE TABLE albums ( albumid character varying NOT NULL, albumtitle character varying, albumtitle_Tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN, PRIMARY KEY(albumid));
ベース値が変更されるたびに、AlbumTitle_Tokens と Rating_Tokens が自動的に更新されます。
プレーン テキストまたは HTML コンテンツをトークン化する
テキストのトークン化は、プレーン テキストと HTML のコンテンツ タイプをサポートしています。Spanner の TOKENIZE_FULLTEXT 関数を使用してトークンを作成します。次に、CREATE SEARCH INDEX DDL ステートメントを使用して検索インデックスを生成します。
たとえば、次の CREATE TABLE DDL ステートメントは、TOKENIZE_FULLTEXT 関数を使用して、Albums テーブルの AlbumTitles からトークンを作成します。CREATE SEARCH INDEX DDL ステートメントは、新しい AlbumTitles_Tokens を使用して検索インデックスを作成します。
GoogleSQL
CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  AlbumTitle STRING(MAX),
  AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN
) PRIMARY KEY(AlbumId);
CREATE SEARCH INDEX AlbumsIndex ON Albums(AlbumTitle_Tokens)
PostgreSQL
CREATE TABLE albums (
  albumid character varying NOT NULL,
  albumtitle character varying,
  albumtitle_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));
CREATE SEARCH INDEX albumsindex ON albums(albumtitle_tokens)
トークン化プロセスでは、次のルールが使用されます。
- トークン化には、ステミングやスペルミスの修正は含まれません。たとえば、「A cat was looking at a group of cats」という文では、トークン「cat」はトークン「cats」とは別にインデックスに登録されます。書き込み時にトークンを正規化する他の検索エンジンとは異なり、Spanner には、検索クエリを拡張してさまざまな形式の単語を含めるオプションがあります。詳細については、拡張クエリモードをご覧ください。
- 検索インデックスには、一般的な単語(「a」など)が含まれます。
- 全文検索では、大文字と小文字は区別されません。トークン化プロセスでは、すべてのトークンが小文字に変換されます。
トークン化プロセスでは、元のテキスト内の各トークンの位置を追跡します。これらの位置は、後でフレーズを照合するために使用されます。位置情報は、ドキュメント ID とともに検索インデックスに保存されます。
Google はトークン化アルゴリズムの改善に継続的に取り組んでいます。今後、文字列が現在とは異なる方法でトークン化される可能性があります。このようなケースは非常にまれです。たとえば、中国語、日本語、韓国語(CJK)の言語のセグメント化が改善された場合です。
content_type 引数は、コンテンツ形式でプレーン テキストと HTML のどちらを使用するかを指定します。次の設定を使用して content_type を設定します。
- テキスト トークン化の場合は、content_type引数をtext/plainに設定します。これはデフォルト設定です。
- HTML トークン化の場合は、content_type引数を"text/htmlに設定します。この引数を指定しないと、HTML タグは句読点として扱われます。HTML モードでは、Spanner はヒューリスティクスを使用して、ページ上のテキストの視認性を推測します。たとえば、テキストがヘッダーに含まれているかどうか、フォントサイズなどです。HTML でサポートされている属性には、small、medium、large、title、link などがあります。位置情報と同様に、属性は検索インデックス内のトークンとともに保存されます。トークン化では、HTML タグのトークンは作成されません。
トークン属性は、SEARCH 関数または SEARCH_SUBSTRING 関数の一致や結果には影響しません。ランキングにのみ使用されます。
次の例は、テキストをトークン化する方法を示しています。
GoogleSQL
CREATE TABLE T (
  ...
  Text STRING(MAX),
  Html STRING(MAX),
  Text_Tokens TOKENLIST
    AS (TOKENIZE_FULLTEXT(Text, content_type=>"text/plain")) HIDDEN,
  Html_Tokens TOKENLIST
    AS (TOKENIZE_FULLTEXT(Html, content_type=>"text/html")) HIDDEN
) PRIMARY KEY(...);
PostgreSQL
CREATE TABLE t (
  ...
  text character varying,
  html character varying,
  text_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(text, content_type=>"text/plain")) VIRTUAL HIDDEN,
  html_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(html, content_type=>'type/html')) VIRTUAL HIDDEN,
PRIMARY KEY(...));
language_tag 引数による言語検出の絞り込み
トークン化では、デフォルトで入力言語が自動的に検出されます。入力言語が判明している場合は、language_tag 引数を使用してこの動作を絞り込むことができます。
GoogleSQL
AlbumTitle_Tokens TOKENLIST
  AS (TOKENIZE_FULLTEXT(AlbumTitle, language_tag=>"en-us")) HIDDEN
PostgreSQL
albumtitle_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle, language_tag=>'en-us')) VIRTUAL HIDDEN
ほとんどのアプリでは、language_tag 引数を指定せず、自動言語検出に依存しています。中国語、韓国語、日本語などのアジア言語のセグメント化では、トークン化言語を設定する必要はありません。
次の例は、language_tag がトークン化に影響するケースを示しています。
| トークン化関数 | 生成されたトークン | 
|---|---|
| TOKENIZE_FULLTEXT("A tout pourquoi il y a un parce que") | [a, tout, pourquoi, il, ya, un, parce, que] | 
| TOKENIZE_FULLTEXT("A tout pourquoi il y a un parce que", \ language_tag=>"fr") | [a, tout, pourquoi, il, y, a, un, parce, que] | 
| TOKENIZE_FULLTEXT("旅 行") | 2 つのトークン: [旅, 行] | 
| TOKENIZE_FULLTEXT("旅 行", language_tag=>"zh") | 1 つのトークン: [旅行] | 
次のステップ
- 検索インデックスについて確認する。
- 数値インデックスについて確認する。
- インデックスのパーティショニングについて確認する。