
AkimasaKajitaniです。
今回は、ThoughtSpotの関数である「テキストの類似度計算」に関連する2つの関数similar_toとsimilarityについてご紹介します。
この関数何が違うのでしょうか?
名前自体も、ドキュメントの記載も似たように感じに見えるこの関数ですが、一体何が違うのでしょうか?まずはドキュメントを見てみましょう。
まず、similar_toです。原文は英語で、Google翻訳で翻訳しています。
ドキュメントのテキスト文字列と検索テキスト文字列を受け入れます。ドキュメントに対する検索文字列の関連性スコア (0 ~ 100) が 20 以上の場合は true を返します。関連性は、編集距離、クエリ内の単語数、およびドキュメント内に存在するクエリ内の単語の長さに基づきます。
次は、similarityです。こちらも原文は英語で、Google翻訳で翻訳しています。
ドキュメントのテキスト文字列と検索テキスト文字列を受け入れます。ドキュメントに対する検索文字列の関連性スコア (0 ~ 100) を返します。関連性は、編集距離、クエリ内の単語数、およびドキュメント内に存在するクエリ内の単語の長さに基づきます。2 つの文字列が完全に一致する場合は、100 を返します。
「ドキュメントのテキスト文字列と検索テキスト文字列を受け入れます」の部分は同じですが、いずれの関数も、引数として2つの文字列(テキストの項目)を指定する必要があります。実際に使った感じを含めて表にしてみましょう。
関数名 | 戻り値 | 戻り値の意味 |
---|---|---|
similar_to | True/False | 2つの文章の一致度を計算し、20(100点満点)を超えればTrue、それ以外はFalse |
similarity | 0~100の整数値 | 2つの文字列の類似度を計算し、全く異なる場合は0、一致した場合は100。 |
よく見るとぜんぜん違う関数なんですね。
ここで、もう一つポイントは、similar_to関数は文章に対しての類似度で、単語を指定した場合は、完全一致のときだけTrueとなり、それ以外はFalseとなります。つまり、空白区切りで文章を区切り、単語がどれくらい一致しているか、というのを見ているようです。
それに対して、similarity関数は文字を1文字1文字比較しているようなので、「ThoughtSpot」と「ThoughSpotとは」を比較すると、似ているという判定になります。逆に、similat_to関数はFalseが帰ってきます。
さらに似たような関数で、spells_likeという関数もあります。これも文字列レベルで見ているのでTrue/Falseで判定結果が帰ってきますが、「ThoughtSpot」と「ThoughtSpotとはなにか?」ではFalseが帰ってきます。これは余計な部分が多いためスコアが下がってしまうからのようです。(つまり、「ThoughtSpot」以外に「とはなにか?」という言葉がくっついてきているので、割合的に異なる部分はそこそこあるので似ていないと判定されているようです)。
Snowflakeで利用する場合の注意点
接続しているDWHがSnowflakeの場合、注意点があります。
similar_to関数
similart_to関数を使う場合、結果がどうしてもドキュメント通りではないため、実際のSQLを確認しましたが、結論から行くとドキュメント通りではないようです。
実際にSnowflakeに発行されているSQLは以下の通りで、どうやらLIKE関数を使って判定を行っているようです。
SELECT
min(('what''s thoughtspot' LIKE 'what is thoughtspot')) "ca_1",
"ta_1"."CATEGORY" "ca_2"
FROM "DM"."DATAMART"."TECHBLOG_REPORT" "ta_1"
GROUP BY "ca_2"
LIMIT 1000
LIKE関数は、Snowflkeのドキュメントによると 、一致を判定する関数で、「一致度が20」などは見ておらず、単に一致するかどうかを見ているだけです。LIKE関数はパターン一致が使えるので、例えば以下のような比較が可能です。
この結果としては「True」が帰ってきます。
いずれにしても、ThoughtSpotのドキュメント通りに動作しないので、Snowflakeの関数のLIKE関数の説明を見て運用してください。
similarity関数
similarity関数を使うと以下のようなエラーメッセージが出ます。
「StringMatchScore は Snowflake でサポートされていません。」
どうやらSnowflakeに存在しない関数を内部的に使っているようです。これでは困るので、代替の手段を探してみると似たような機能を持つSnowflakeの関数「JAROWINKLER_SIMILARITY」というのがあります。このようなDWH特有の関数があるのであれば、SQLパススルー関数を使うことでThoughtSpotから利用することができます。
実際に使ってみましょう。今回、類似度を計算したい項目として、「SC_Keyword」と「Mastercategory」という項目があるとします(つまりGoogleのサーチコンソールで取得できる検索キーワードと、その検索されたページのカテゴリ名を比較したい、とイメージで捉えてもらえれば)。これの類似度を図るためには、以下のような計算式が利用できます。
sql_int_op ( "JAROWINKLER_SIMILARITY( {0} , {1} )", SC_Keyword , Mastercategory )
ここでは、戻り値が整数値なので、sql_int_opという関数を使っています。基本的にSQLパススルー関数は、戻り値のデータ型に応じた関数を使う必要があります。ちなみに、このままだと計算結果が合計されるのですが、今回使っている数値は合計する意味がないので、平均を取りましょう。そのため最終的には以下のような関数になります。
average(sql_int_op ( "JAROWINKLER_SIMILARITY( {0} , {1} )", SC_Keyword , Mastercategory ) )
例えば、「thoughtspot」と「thoughtspot spotiq」というワードだと、92というスコアが帰ってきます。spells_like関数の場合は無情にもFalseが帰ってきます(このケースだとContains関数も仕事をします)。
その他のテキストの類似度を測る関数
edit_distance関数やedit_distance_with_cap関数も類似度を測れる関数となっています。これらはレーベンシュタイン距離を計算する関数だと思われます。一方で、SnowflakeのJAROWINKLER_SIMILARITY関数はジャロ・ウィンクラー距離を計算する関数で、それぞれ特徴が異なるため、実際のデータにあった関数を使うようにしてください(英語環境だとsounds_like関数なども利用可能です)。
キーワードの「次と類似する」とはどう違うの?
キーワードにも「次と類似する」(英語だとsimitar to)というものがあります。これはsimilart_toと同じ動きをするようです。ですので、単語レベルで少し食い違いがある場合は似ているという判断がされません。
「jean jacket men’s」に対して「次と類似する」で、「jacket」と比較すると、jacketという単語が「jean jacket men’s」に含まれているのでヒットします。逆に、比較する単語を「ja」などと単語の一部にするとヒットしません。つまり、単語単位で比較しているようなのですが、日本語は単語が空白区切りで区切られていないため、ちょっと使いにくい機能と言えるかと思います。
今回ご紹介したような文字列の類似度を測ることは、データの名寄せに有効ですが万能なものはないので、適材適所で使うようにしてください。
※2025/03/10時点の情報です(バージョン10.6.0.cl-255)