# フルテキスト検索

注意

このガイドは、DBバージョン1.5.0以降にのみ適用されます。

従来のデータベースのテキスト検索機能は、LIKEILIKEなどの演算子を使用することが基本でした。しかし、これらの方法は、いくつかの制限により、現代の情報検索システムのニーズに対応できません。

  • 言語サポートの不足: 伝統的な方法では、言語の微妙なニュアンスに対応するのが難しく、単語の派生(例:「satisfies」と「satisfy」)を認識できず、検索結果が不完全または不正確になることがあります。ORを使用して手動でバリエーションを検索することは可能ですが、手間がかかりエラーが発生しやすいです。
  • 結果のランキングの欠如: 検索結果のランキングを行わないため、数千件の一致するデータを処理するのは効率的ではありません。
  • パフォーマンスの問題: インデックスのサポートがないため、各検索ごとにすべてのドキュメントを処理する必要があり、パフォーマンスが低下します。

これらの課題に対処するため、MyScaleはTantivy (opens new window)ライブラリをベースにした新しいインデックスタイプであるFTSインデックス(フルテキスト検索インデックス)を導入しました。FTSインデックスはBM25インデックスアルゴリズムをサポートしており、効率的かつ関連性の高い検索結果を可能にします。この統合により、MyScaleのフルテキスト検索機能が強化され、全体的なパフォーマンスが向上します。

# チュートリアルの概要

このチュートリアルでは、FTSインデックスを使用した3つのタイプの検索実験を実施する方法について説明します。

MyScaleのFTSインデックスのイラスト

開始する前に、MyScaleクラスターが設定されていることを確認してください。セットアップ手順については、クイックスタートガイド (opens new window)を参照してください。

# データセットの概要

ウィキペディアの要約データセット (opens new window)を使用します。このデータセットには560万以上のレコードが含まれており、Parquet形式で利用できます。このデータセットは、ローカルのダウンロードを必要とせずに、S3から直接MyScaleにインポートされます。

以下の表は、このデータセットの内容を簡単に説明しています。

id body title url
... ... ... ...
77 Jake Rodkin is an American .... and Puzzle Agent. Jake Rodkin https://en.wikipedia.org/wiki/Jake_Rodkin (opens new window)
78 Friedlandpreis der Heimkehrer is ... of Germany. Friedlandpreis der Heimkehrer https://en.wikipedia.org/wiki/Friedlandpreis_der_Heimkehrer (opens new window)
... ... ... ...

# テーブルの作成とデータの挿入

次のSQLコマンドを使用して、en_wiki_abstractテーブルをMyScaleに作成します。

CREATE TABLE default.en_wiki_abstract(
    `id` UInt64,
    `body` String,
    `title` String,
    `url` String,
)
ENGINE = MergeTree
ORDER BY id;

次に、S3からデータセットをインポートします。データのインポートが完了するまでお待ちください。

INSERT INTO default.en_wiki_abstract SELECT * FROM s3('https://myscale-datasets.s3.ap-southeast-1.amazonaws.com/wiki_abstract_5m.parquet','Parquet');

テーブルに5,648,453行のデータが含まれていることを確認します。

SELECT count(*) FROM default.en_wiki_abstract;

出力:

count()
5648453

検索パフォーマンスを向上させるために、テーブルを最適化して単一のデータパートに統合することができます。このステップはオプションです。

OPTIMIZE TABLE default.en_wiki_abstract FINAL;

次のSQLステートメントを実行して、このテーブルのデータが1つのパートに圧縮されたかどうかを確認します。

SELECT COUNT(*) FROM system.parts
WHERE table = 'en_wiki_abstract' AND active = 1;

データが1つに圧縮されている場合、このSQLステートメントは次の結果セットを返します。

count()
1

# FTSインデックスのパラメータの理解

MyScaleは、さまざまなシナリオに適した複数のトークナイザーをサポートしています。FTSインデックスを作成するときに、トークナイザーのJSON構成でカスタマイズできます。

TIP

FTSインデックスのパラメータには、有効なJSON文字列を指定してください。

-- 例 1: 追加のパラメータを指定せずに、デフォルトのトークナイザーを使用して単一のテキスト列にインデックスを作成します。
ALTER TABLE [table_name] ADD INDEX [index_name] [column_name]
TYPE fts;
-- 例 2: デフォルトのトークナイザーを明示的に定義して、単一のテキスト列にインデックスを作成します。
ALTER TABLE [table_name] ADD INDEX [index_name] [column_name]
TYPE fts('{"<column_name>":{"tokenizer":{"type":"default"}}}');
-- 例 3: ICUトークナイザーを使用して、単一のテキスト列にインデックスを作成します。
ALTER TABLE [table_name] ADD INDEX [index_name] [column_name]
TYPE fts('{"<column_name>":{"tokenizer":{"type":"icu"}}}');
-- 例 4: ステムトークナイザーを使用し、フィルタリングのためにストップワードを適用してインデックスを作成します。
ALTER TABLE [table_name] ADD INDEX [index_name] [column_name]
TYPE fts('{"<column_name>":{"tokenizer":{"type":"stem", "stop_word_filters":["english"]}}}');
-- 例 5: 複数のテキスト列にインデックスを作成します。各列はデフォルトでデフォルトのトークナイザーを使用します。
ALTER TABLE [table_name] ADD INDEX [index_name] ([column_name_0], [column_name_1], ...)
TYPE fts;
-- 例 6: インデックス内の各テキスト列に対して、異なるトークナイザータイプを指定します。
ALTER TABLE [table_name] ADD INDEX [index_name] ([column_name_0], [column_name_1], ...)
TYPE fts('{"<column_name_0>":{"tokenizer":{"type":"icu"}}, "<column_name_1>":{"tokenizer":{"type":"whitespace"}}}');

以下の表は、FTSインデックスでサポートされているトークナイザの種類を示しています。

トークナイザの種類 説明
default デフォルトのトークナイザで、非アルファベット文字でテキストを分割し、大文字小文字を区別しません
raw テキストにトークナイズを行わず、テキスト全体を1つのトークンとして扱います
simple テキストを非アルファベット文字で分割します
stem ステミングトークナイザで、複数の言語をサポートし、単語をステム形式に変換し、単語の時制を無視することができます
whitespace スペース、タブ、改行などのホワイトスペース文字でテキストを分割します
ngram 指定されたn-gramの長さに基づいてテキストを分割します
chinese 中国語のテキストをトークナイズし、内部的にはjiebaトークナイゼーションライブラリを使用します
icu ICU トークナイザーは多言語テキストの処理に優れています。多言語のテキストのトークン化に苦労している場合、ICU トークナイザーが最適な解決策です。

# 一般的なトークナイザのパラメータ

defaultrawトークナイザはstore_docパラメータのみをサポートしており、他のトークナイザは以下の一般的なパラメータに加えて、さらに多くのパラメータをサポートしています。

パラメータ名 デフォルト値 説明
store_doc boolean false オリジナルのドキュメントを保存するかどうか。現在は推奨されていません。
length_limit number 40 トークン化されたトークンの最大長
case_sensitive boolean false トークナイズが大文字と小文字を区別するかどうか

上記の一般的なパラメータに加えて、ほとんどのトークナイザはさらに追加のパラメータをサポートしています。

# simplestemwhitespaceicu トークナイザ

パラメータ名 デフォルト値 説明
stop_word_filters string[] [] ストップワードフィルターで、トークナイズ時にどの言語のストップワードを破棄するかを指定します。有効な言語は["danish", "dutch", "english", "finnish", "french", "german", "hungarian", "italian", "norwegian", "portuguese", "russian", "spanish", "swedish"]です。

# stemicu トークナイザ

パラメータ名 デフォルト値 説明
stem_languages string[] [] ステミングに使用する言語。英語の場合、トークナイズ時に単語の時制を無視することができます。ステムトークナイザでサポートされている言語は["arabic", "danish", "dutch", "english", "finnish", "french", "german", "greek", "hungarian", "italian", "norwegian", "portuguese", "romanian", "russian", "spanish", "swedish", "tamil", "turkish"]です。

# ngramトークナイザ

パラメータ名 デフォルト値 説明
min_gram number 2 最小のグラム数
max_gram number 3 最大のグラム数
prefix_only boolean false 単語の接頭辞からのn-gramのみを抽出するかどうか

# chineseトークナイザ

中国語のトークナイザでは、cang-jie (opens new window)が基礎となる実装として使用されます。

パラメータ名 デフォルト値 説明
jieba string "default" "default"はjieba辞書を使用することを意味し、"empty"はトークナイズのために組み込みのjieba辞書を使用しないことを意味します。有効な値は"default"または"empty"です。
mode string "search" 中国語のトークナイズモード。有効な値は "all"、"default"、"search"、または "unicode" です。各モードの違いについては、cang-jie/options.rs (opens new window)を参照してください。
hmm boolean false HMMを有効にするかどうか

# icu トークナイザー

パラメータ名 タイプ デフォルト値 説明
mode 文字列 "word" 有効な値は "word""sentence""line""grapheme""word" です。 "word" モードは多言語環境で最適に動作します。

ICU トークナイザーの機能の詳細については、icu_segmenter (opens new window) を参照してください。

上記は、MyScale FTSインデックスのトークナイザのパラメータについての詳細な説明です。FTSインデックスを作成する際には、最適なトークナイザタイプを選択し、パラメータを設定して検索パフォーマンスと結果を向上させることができます。

# FTSインデックスの作成

適切なトークナイザーを使用して、FTS(全文検索)インデックスをカスタマイズし、検索パフォーマンスを最適化します。たとえば、英語のストップワードを使用した stem トークナイザーを採用すると、単語の語幹に焦点を当てることで検索の精度を向上させることができます。

単一列インデックスと複数列インデックスは、テキスト検索機能において重要な役割を果たします。単一列インデックスは、特定のフィールド内での効率的な検索を容易にし、複数列インデックスは複数のフィールドにまたがる包括的な検索を可能にし、全体的な検索パフォーマンスを向上させます。単一列インデックスでテキスト検索を実行するには、TextSearch 関数を使用できます。複数列インデックスの場合、full_text_search 関数により、すべてのインデックス化された列に対して効果的な検索が可能です。

# 単一列テキストインデックスの作成

単一列テキストインデックスを作成するには、次の SQL 文を使用します。

ALTER TABLE default.en_wiki_abstract
ADD INDEX body_idx body
TYPE fts('{"body":{"tokenizer":{"type":"stem", "stop_word_filters":["english"]}}}');

この例では、body 列に FTS インデックスを作成します。FTS インデックス(ClickHouse のスキップインデックスに似ています)は、新しく挿入されたデータにのみ適用されることに注意してください。そのため、単にインデックスを追加しても既存のデータには影響しません。既存のレコードをインデックス化するには、次の文を実行します。

ALTER TABLE default.en_wiki_abstract MATERIALIZE INDEX body_idx;

# 複数列テキストインデックスの作成

複数のテキスト列にインデックスを作成して、さまざまなフィールドでの検索機能を向上させることもできます。たとえば:

ALTER TABLE default.en_wiki_abstract
ADD INDEX multi_col_idx (body, title)
TYPE fts('{"body":{"tokenizer":{"type":"stem", "stop_word_filters":["english"]}}, "title":{"tokenizer":{"type":"default"}}}');

この場合、body 列と title 列の両方に FTS インデックスを定義し、それぞれの列に異なるトークナイザーを使用しています。もちろん、単一列インデックスの作成時と同様に、MATERIALIZE 文を実行する必要があります。

ALTER TABLE default.en_wiki_abstract MATERIALIZE INDEX multi_col_idx;

# ドキュメントのBM25ランキングを使用した検索

注意

最初のTextSearch()の実行は遅くなる場合があります。これはFTSインデックスの読み込みが必要なためです。

以下の例では、TextSearch()関数の使用方法を示しています。この例では、"non-profit institute in Washington"に最も関連性の高いトップ10のドキュメントを返します。関連性の指標は、TextSearch()関数が返すBM25スコアです。スコアが高いほど関連性が高いです。

SELECT
    id,
    title,
    body,
    TextSearch(body, 'non-profit institute in Washington') AS score
FROM default.en_wiki_abstract
ORDER BY score DESC
LIMIT 5;

結果から、body列の各行のテキストが検索フレーズ"non-profit institute in Washington"に関連していることがわかります。

id title body score
3400768 Drug Strategies Drug Strategies is a non-profit research institute located in Washington D.C. 24.457561
872513 Earth Policy Institute Earth Policy Institute was an independent non-profit environmental organization based in Washington, D.C. 22.730673
895248 Arab American Institute Founded in 1985, the Arab American Institute is a non-profit membership organization based in Washington D.C. 21.955559
1950599 Environmental Law Institute The Environmental Law Institute (ELI) is a non-profit, non-partisan organization, headquartered in Washington, D.C. 21.231567
2351478 Public Knowledge Public Knowledge is a non-profit Washington, D.C. 20.742344

DBバージョンv1.8以上では、TextSearch()関数を使用して、複数列のFTSインデックスを使用してテキスト列を検索できます。使用方法は、単一列のFTSインデックスを使用する場合と同じです。

# 自然言語クエリの活用

MyScaleは、フルテキスト検索(FTS)インデックスのためにTantivyライブラリを使用しており、複雑な自然言語クエリをサポートしています。詳細については、Tantivyのドキュメント (opens new window)を参照してください。

以下は、ANDORを使用した複数の条件の組み合わせクエリの例です。ニューヨーク、アフリカ、またはパリに関連する人類学のトピックを検索したい場合、SQLクエリは次のようになります。

SELECT
    id,
    title,
    body,
    TextSearch(body, 'Anthropological AND ("New York City" OR African OR Paris)") AS score
FROM default.en_wiki_abstract
ORDER BY score DESC
LIMIT 5;

検索結果から、各行のテキストが"Anthropological"(大文字小文字を区別しない)に関連しており、同時に"African"または"Paris"のいずれかを含んでいることがわかります。

id title body score
2826913 African Anthropologist African Anthropologist is the journal of the Pan African Anthropological Association (PAAA). 20.131313
3905943 Tunnel People Tunnel People is an anthropological-journalistic account describing an underground homeless community in New York City. It is written by war photographer and anthropologist Teun Voeten and was published by PM Press in 2010. 13.759308
3790627 Les Accords de Bella Les Accords de Bella is a 2007 anthropological documentary film directed by David Constantin. It was selected by the African Film Festival of Cordoba - FCAT. 12.769518
4488199 Naparay Naparay, in African anthropological study, is a non-linear conception of human life held by some West African peoples such as the Yoruba. Similar to reincarnation, naparay holds that lives are cyclic and attributes of previous lives may carry over to a new life. 11.682068
1725559 Gradhiva Gradhiva is an anthropological and museological journal, founded in 1986 by the poet and social scientist Michel Leiris and by the anthropologist Jean Jamin. It is since 2005 published by the Musée du Quai Branly in Paris. 11.135916

# TextSearchパラメータの説明

注意

パラメータは、DBバージョンv1.6.3以降でのみ利用可能です。

以下は、TextSearch()のパラメータの詳細な説明です。

パラメータ デフォルト値 候補の値 説明
enable_nlq true true, false このパラメータは、自然言語クエリの解析を有効にするかどうかを決定します。trueに設定すると、FTSはユーザーの入力を自然言語クエリとして解釈します。falseに設定すると、FTSは標準のtermsクエリを使用してユーザーの入力を解析します。
operator OR OR, AND このパラメータは、各クエリの条件(トークナイズされたトークンごと)を組み合わせるための論理演算子を指定します。ORを選択すると、いずれかの条件に一致する結果が返されます。ANDを選択すると、すべての条件に一致する結果が返されます。

NOTE

分散テーブルのTextSearchは、DBバージョンv1.7.0以上でのみ利用可能です。分散テーブルのTextSearchでは、ローカルテーブルに対応するFTSインデックスを作成するだけで十分です。

以下に TextSearch() クエリ設定の詳細な説明を示します:

Settings Default Value Candidate Values Description
dfs_query_then_fetch false true, false 分散テーブルの場合、この設定は、まずすべてのシャードから統計を収集する分散クエリを実行し、その後、収集された統計に基づいた正確な全文検索 (FTS) を行うかどうかを決定します。

# 使用例

SELECT
    id,
    title,
    body,
    TextSearch('enable_nlq=true', 'operator=OR')(body, 'mammoth AND Europe') AS score
FROM default.wiki_abstract_text
ORDER BY score DESC
LIMIT 5

結果に基づいて、各行には"mammoth"と"Europe"の両方が含まれており、自然言語クエリを有効にするロジックに一致していることがわかります。

注意:検索結果は2つだけです。SQLクエリで制限を5に設定していますが、テーブル内のエントリのうち条件を満たすのは2つだけです。

id title body score
3171491 Leymus racemosus Leymus racemosus is a species of perennial wild rye known by the common name mammoth wild rye. It is native to southeastern and eastern Europe, Middle Asia, Caucasus, Siberia, China, Mongolia, New Zealand, and parts of North America. 10.067189
2719784 Venus of Hohle Fels The Venus of Hohle Fels (also known as the Venus of Schelklingen; in German variously ) is an Upper Paleolithic Venus figurine made of mammoth ivory that was unearthed in 2008 in Hohle Fels, a cave near Schelklingen, Germany. It is dated to between 35,000 and 40,000 years ago, belonging to the early Aurignacian, at the very beginning of the Upper Paleolithic, which is associated with the earliest presence of Cro-Magnon in Europe. 6.9371195
SELECT
    id,
    title,
    body,
    TextSearch('enable_nlq=false', 'operator=OR')(body, 'Atlantic AND Europe') AS score
FROM default.wiki_abstract_text
ORDER BY score DESC
LIMIT 5

自然言語クエリを無効にした場合、結果はもはや"Atlantic"と"Europe"の両方が同時に表示されることを保証しません。オペレータのデフォルト値がORであるため、"Atlantic"、"AND"、または"Europe"のいずれかを含む行が検索結果に含まれます。

id title body score
3046233 And And or AND may refer to: 13.748591
5050203 A N D (Tricot album) And}} 13.047318
357499 Andromeda I And 1}} 12.335348
678064 Omicron Andromedae And 1}} 12.335348
3716928 Platycheirus ramsaerensis Platycheirus ramsaerensis is a species of hoverfly. It is found along the parts of northern Europe that face the Atlantic. 11.937536

Note

注意 テーブル関数 full_text_search() はDBバージョンv1.7.0以上でのみ利用可能です。

テーブル関数 full_text_search() は、MyScaleの複数のテキスト列を持つFTSインデックスでテキスト検索を行うために使用されます。full_text_search() テーブル関数の基本構文は次のとおりです:

full_text_search(table_name, index_name, query [,with_score] [,enable_nlq] [,operator])
  • table_name はFTSインデックスを含むテーブルを指します。
  • index_name は検索対象の複数のテキスト列を含むFTSインデックスを指します。
  • query はTantivyクエリ言語に準拠した検索文字列を指します。
  • with_score はbm25スコア列を返すかどうかを示します(デフォルトは0)。
  • enable_nlq は自然言語クエリ解析を有効にするかどうかを示します(デフォルトは1)。
  • operator は各クエリ用語(トークン化されたもの)を組み合わせるために使用する論理演算子を指します(デフォルトは 'OR')。

次の例は、full_text_search() 関数の使用方法を示しています。この例では、body列に "non-profit institute in Washington" またはtitle列に "Institute" が含まれている、最も関連性の高い上位5件のドキュメントを返します。関連性を測定する指標は、full_text_search() 関数によって返されるBM25スコアで、スコアが高いほど関連性が高くなります。

SELECT
    id,
    title,
    body,
    bm25_score
FROM full_text_search('default.en_wiki_abstract', 'multi_col_idx', 'body:non-profit institute in Washington or title:Institute', 1)
ORDER BY bm25_score DESC
LIMIT 5;

結果から、body列の各行のテキストが "non-profit institute in Washington" に関連しているか、またはtitle列のテキストが "Institute" に関連していることがわかります。

id title body bm25_score
849009 Washington Institute Washington Institute may mean 38.110603
872513 Earth Policy Institute Earth Policy Institute was an independent non-profit environmental organization based in Washington, D.C. 35.545998
895248 Arab American Institute Founded in 1985, the Arab American Institute is a non-profit membership organization based in Washington D.C. 34.77088
1730029 Washington Cancer Institute The Washington Cancer Institute (WCI) is Washington, D.C. 34.445385
1950599 Environmental Law Institute The Environmental Law Institute (ELI) is a non-profit, non-partisan organization, headquartered in Washington, D.C. 34.046894

# 組み込み文字列関数の高速化

FTSインデックスは、equalsnotEqualslikenotLikehasTokenhasTokenOrNullinnotInstartsWithendsWithhasmapContainsmultiSearchAnyなどのClickHouseの組み込み文字列関数を高速化するためにも使用できます。

これらの文字列関数を実行する際にFTSインデックスを有効にするかどうかを制御するために、enable_fts_index_for_string_functionsというクエリ設定が提供されています。デフォルト値は0で、これはこれらの組み込みClickHouse関数を実行する際にFTSインデックスが使用されないことを意味します。ユーザーは手動で1に設定してFTSを有効にすることができます。クエリ設定の使用方法についての詳細は、ClickHouse Query-level Settings (opens new window)を参照してください。

# enable_fts_index_for_string_functionsのデフォルト値が0に設定されている理由

効率性の考慮:

検索される文字列がテーブル全体で比較的まれにしか出現しない場合、FTSを使用することで大幅な高速化が可能です。しかし、Whathisなどの一般的な単語のように、検索される文字列がテーブル内で非常に頻繁に出現する場合、FTSインデックスを使用することで通常の関数のクエリ速度が実際に遅くなることがあります。これはほとんどのグラニュールを読み取る必要があるためです。

検索結果の正確性:

FTSインデックスはテーブル内のテキストをトークン化し、トークナイザーの種類によってトークン化の動作が異なります。例えば、rawトークナイザーは元のテキストを1つのトークンとして扱い、whitespaceトークナイザーはスペースに基づいて元のテキストを複数のトークンに分割します。以下は、"WhiteHouse is very beautiful."に対するこれら2つのトークナイザーのトークン化結果です:

  • tokenizer(raw): token<"WhiteHouse is very beautiful.">
  • tokenizer(whitespace): token<"WhiteHouse">, token<"is">, token<"very">, token<"beautiful">

トークナイザーの動作は文字列一致関数の正確性に影響を与える可能性があります。rawトークナイザーを使用する場合、%WhiteHouse%beautiful%のようなlikeクエリを実行すると、FTSはlikeクエリをTantivyのRegexQueryに変換し、すべてのトークンを検索します。この場合、token<"WhiteHouse is very beautiful.">を正しく一致させることができます。

しかし、whitespaceトークナイザーを使用する場合、FTSはlikeクエリ%WhiteHouse%beautiful%を正規表現マッチに変換し、既存のトークンと一致しないため、テキストセグメントがヒットとしてマークされず、検索結果が不正確になります。

したがって、likenotLikestartsWithendsWithなどRegexQueryに変換される文字列関数では、enable_fts_index_for_string_functionsを1に設定すると、rawトークナイザーのみが正確な結果を提供できます。

# 使用説明

例1: 単純なキーワード検索を実行する

単語'Tsinghua'を検索します。

SELECT count(*)
FROM default.en_wiki_abstract
WHERE hasToken(body, 'Tsinghua') 
SETTINGS enable_fts_index_for_string_functions=1;

出力:

count()
81

例2: 複数のキーワード検索を実行する

"Eiffel Tower"を含み、"Paris"を含まない記事を見つけます。

SELECT count(*)
FROM default.en_wiki_abstract
WHERE (NOT hasToken(body, 'Paris')) AND multiSearchAny(body, ['Eiffel', 'Tower']) 
SETTINGS enable_fts_index_for_string_functions=1;

出力:

count()
2828

例3: 複雑な条件組み合わせクエリを実行する

異なる名前、場所、学科などの用語を組み合わせます。

SELECT count(*)
FROM default.en_wiki_abstract
WHERE (NOT multiSearchAny(body, ['Montessori', 'postulated', 'Rooney'])) AND (hasToken(body, 'Patsy') OR hasToken(body, 'Anthropological')) 
SETTINGS enable_fts_index_for_string_functions=1;

出力:

count()
204

# 結論

このガイドでは、MyScaleを使用して高度なテキスト検索機能を活用する方法について説明しました。FTSインデックスの設定から自然言語クエリの実行まで、構造化されていないテキストデータを効率的に管理および検索することができます。これにより、MyScaleの堅牢なテキスト処理機能が活かされます。

Last Updated: Tue Oct 08 2024 07:35:58 GMT+0000