Scalaによる スカラー UDF の記述

Scalaでスカラーユーザー定義関数(UDF)を記述できます。Scalaハンドラーコードは、 UDF が呼び出されたときに実行されます。このトピックでは、Scalaでハンドラーを記述し、 UDF を作成する方法について説明します。

UDF は、スカラー結果を返すユーザー定義関数です。つまり、複数の行ではなく単一の値を意味します。UDFsの一般的な情報については、 ユーザー定義関数の概要 をご参照ください。

UDF を作成するときは、次を実行します。

  1. UDF が呼び出されたときにSnowflakeが呼び出すメソッドを使用して、Scalaオブジェクトまたはクラスを作成します。

    詳細については、このトピック内の ハンドラーの実装 をご参照ください。

  2. CREATE FUNCTION コマンドを使用して、オブジェクトまたはクラスとメソッドをハンドラーとして指定して、 SQL に UDF を作成します。UDFを作成するときは、次のように指定します。

    • UDF入力パラメーターのデータ型。

    • UDF 戻り値のデータ型。

    • UDF が呼び出されたときにハンドラーとして実行するコード。

    • ハンドラーを記述する言語。

    CREATE FUNCTION 構文の詳細については、 CREATE FUNCTION を使用したUDFの作成 をご参照ください。

UDF の呼び出し で説明されているように、 UDF を呼び出すことができます。

ハンドラーの実装

ハンドラーメソッドを使用してオブジェクトまたはクラスを実装し、 UDF 引数値を処理して UDF の戻り値に変換します。

ハンドラーを記述するときは、次を実行します。

  • ハンドラーとして指定するパブリックメソッドを含むパブリッククラスを記述します。

    これは、 SQL で UDF が呼び出されたときにSnowflakeが呼び出すメソッドになります。

    同じオブジェクトまたはクラスで他の複数のメソッドを定義し、それぞれを別の UDF のハンドラーとして使用できます。たとえば、コンパイルされたハンドラーコードをステージ上に保持し、複数の関数から参照する場合は、これを実行するとよいでしょう。

    ステージされたハンドラーの詳細については、 ハンドラーコードのインラインまたはステージ上での保持 をご参照ください。

  • 必要に応じて、ハンドラーを初期化するために呼び出すSnowflakeの引数なしのコンストラクターを記述します。

注釈

各ハンドラーメソッドおよびそれが呼び出すメソッドでは、必ず、Snowflakeによって課された制約に従ってハンドラーを記述してください。これらの制約の詳細については、 Snowflakeが課す制約内でのハンドラーの設計 をご参照ください。

ハンドラーの例

次の例のコードには、文字列を受け取って返す MyHandler.echoVarchar ハンドラーメソッドが含まれています。UDF が受け取る値(VARCHAR)は、Snowflakeによってハンドラーメソッドのパラメーターの型(文字列)にマッピングされます。

CREATE OR REPLACE FUNCTION echo_varchar(x VARCHAR)
RETURNS VARCHAR
LANGUAGE SCALA
RUNTIME_VERSION = 2.12
HANDLER='MyHandler.echoVarchar'
AS
$$
class MyHandler {
  def echoVarchar(x : String): String = {
    return x
  }
}
$$;
Copy

UDF を呼び出す

SELECT echo_varchar('Hello');
Copy

ハンドラーの初期化

必要に応じて、引数なしのコンストラクターを追加してハンドラーを初期化できます。

コンストラクターがエラーをスローすると、エラーは例外メッセージとともにユーザーエラーとしてスローされます。

def this() = {
    // Initialize here.
}
Copy

関数の引数の処理

引数として UDF に渡されたデータを処理するには、 SQL コードで UDF が呼び出されたときにSnowflakeが呼び出すパブリックメソッドを実装します。CREATE FUNCTION コマンドを使用して UDF を作成する場合は、 HANDLER 句を使用してメソッドをハンドラーとして指定します。

ハンドラーメソッドを宣言するときは、次を実行します。

  • ハンドラーメソッドをパブリックとして宣言します。

    オプションで、引数なしのコンストラクターを含めてハンドラーを初期化できます。詳細については、このトピック内の ハンドラーの初期化 をご参照ください。

    クラスをステージングされたハンドラーとして JAR にパッケージ化する場合は、複数のハンドラーメソッドを宣言し、後で CREATE FUNCTION ステートメントの HANDLER 句を使用して、それぞれをハンドラーとして指定できます。ステージされたハンドラーの詳細については、 ハンドラーコードのインラインまたはステージ上での保持 をご参照ください。

  • ハンドラーメソッドのパラメーターを指定し、 UDF 宣言で指定された SQL 型にマップされる型を返します。

    詳細については、 SQL-Scalaデータ型マッピング をご参照ください。

  • 必要に応じて、ハンドラーメソッドから呼び出されるメソッドなど、ハンドラーメソッドの処理をサポートする追加のメソッドを宣言します。

    次の例のコードには、引数として受け取った配列の処理を支援する、非ハンドラーメソッド concatenate を呼び出す handleStrings ハンドラーメソッドが含まれています。

    CREATE OR REPLACE FUNCTION generate_greeting(greeting_words ARRAY)
    RETURNS VARCHAR
    LANGUAGE SCALA
    RUNTIME_VERSION = 2.12
    HANDLER='StringHandler.handleStrings'
    AS
    $$
    class StringHandler {
      def handleStrings(strings: Array[String]): String = {
        return concatenate(strings)
      }
      private def concatenate(strings: Array[String]): String = {
        var concatenated : String = ""
        for (newString <- strings)  {
            concatenated = concatenated + " " + newString
        }
        return concatenated
      }
    }
    $$;
    
    Copy

    次は、 generate_greeting 関数を呼び出します。

    SELECT generate_greeting(['Hello', 'world']);
    
    Copy

    次は、上記の値を使用して generate_greeting を呼び出した場合の出力を示しています。

    Hello world
    

ハンドラーメソッドのオーバーロード

パラメーター数が異なる限り、同じクラスまたはオブジェクト内のハンドラーメソッドをオーバーロードできます。

Scala UDFs の場合、Snowflakeはメソッド引数の ではなく、メソッド引数の のみを使用してハンドラーメソッドを区別します。一部の SQL データ型は複数のScalaまたはJavaデータ型にマップでき、したがって複数のハンドラーメソッド署名にマップできる可能性があるため、データ型に基づいて解決することは実用的ではありません。

たとえば、2つのScalaメソッドの名前と引数の数が同じで、データ型が異なる場合、これらのメソッドの1つをハンドラーとして使用して UDF を呼び出すと、次のようなエラーが生成されます。

Cannot determine which implementation of handler "handler name" to invoke since there are multiple
definitions with <number of args> arguments in function <user defined function name> with
handler <class name>.<handler name>
Copy

ウェアハウスが使用可能な場合は、 UDF の作成時にエラーが検出されます。それ以外の場合は、 UDF が呼び出されたときにエラーが発生します。