2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Databricksにおける高階関数のイントロダクション

Last updated at Posted at 2022-09-21

以下の高階関数(higher order function)のサンプルノートブックをウォークスルーします。

ネストされたデータを持つテーブルの作成

テーブルとは言っていますが、実際には一時ビューです。

SQL
CREATE
OR REPLACE TEMPORARY VIEW nested_data AS
SELECT
  id AS key,
  ARRAY(
    CAST(RAND(1) * 100 AS INT),
    CAST(RAND(2) * 100 AS INT),
    CAST(RAND(3) * 100 AS INT),
    CAST(RAND(4) * 100 AS INT),
    CAST(RAND(5) * 100 AS INT)
  ) AS values,
  ARRAY(
    ARRAY(
      CAST(RAND(1) * 100 AS INT),
      CAST(RAND(2) * 100 AS INT)
    ),
    ARRAY(
      CAST(RAND(3) * 100 AS INT),
      CAST(RAND(4) * 100 AS INT),
      CAST(RAND(5) * 100 AS INT)
    )
  ) AS nested_values
FROM
  range(5)
SQL
SELECT * FROM nested_data

以下の様にカラム内でデータがネストされています。
Screen Shot 2022-09-22 at 8.49.28.png

シンプルな例

基本的な変換処理でコンセプトの基礎を学びましょう。このケースでは、高階関数transformが配列valuesに対してイテレーションを行い、関連づけられたラムダ関数をそれぞれの要素に適用し、新たな配列を作成します。ラムダ関数element + 1は、それぞれの要素をどの様に操作するのかを指定します。このSQLは以下の様になります

SQL
SELECT
  key, 
  values,
  TRANSFORM(values, value -> value + 1) AS values_plus_one
FROM
  nested_data

配列の各要素が1だけ加算されています。
Screen Shot 2022-09-22 at 8.51.15.png

変換処理TRANSFORM(values, value -> value + 1)は2つのコンポーネントから構成されます:

  1. TRANSFORM(values..)は高階関数です。これは、入力として配列と匿名関数を受け取ります。内部的には、新規配列のセットアップ、それぞれの要素への匿名関数の適用、出力配列への結果の割り当てを行います。
  2. value -> value + 1は匿名関数です。この関数は、シンボル->で区切られた2つのコンポーネントから構成されます。
    • 引数のリスト。この場合は引数は1つのvalueです。(x, y) -> x + yのように、括弧で囲まれたカンマ区切りの引数リストを作成することで複数の引数もサポートしています。
    • 本体。新たな値を計算するために引数と外部の変数を使用できるエクスプレッションです。この場合、argumentの値に1を加算しています。

変数のキャプチャ

ラムダ関数では引数だけではなく、他の変数を使用することもできます。これはキャプチャと呼ばれます。トップレベルで定義されている変数や中間のラムダ関数で定義されている変数を使用することができます。例えば、以下の変換処理ではkey(トップレベル)変数を、配列valuesのそれぞれの要素に加算しています。

SQL
SELECT
  key,
  values,
  TRANSFORM(values, value -> value + key) AS values_plus_key
FROM
  nested_data

トップレベルの変数keyの値を配列の各要素に加算しています。
Screen Shot 2022-09-22 at 8.53.05.png

ネスト化

深くネストされたデータを変換したい場合、ネストされたラムダ関数を使用することができます。以下の例では、integerの配列の配列を変換し、ネストされた配列のそれぞれの要素に、key(トップレベル)カラムの値と中間配列のサイズを加算しています。

SQL
SELECT
  key,
  nested_values,
  TRANSFORM(nested_values, values -> TRANSFORM(values, value -> value + key + SIZE(values))) AS new_nested_values
FROM
  nested_data

Screen Shot 2022-09-22 at 8.54.30.png

サポートされる関数

transform(array<T>, function<T, U>): array<U>

入力であるarray<T>のそれぞれの要素にfunction<T, U>を適用することでarray<U>を変換します。

これは機能的にはmapと同じものとなります。(キーバリューエクスプレッションからmapを作成する)mapエクスプレッションとの混乱を避けるためにtransformと名付けられています。

以下のクエリーでは、それぞれの要素にkeyの値を加算することで配列valuesを変換しています。

SQL
SELECT   key,
         values,
         TRANSFORM(values, value -> value + key) transformed_values
FROM     nested_data

Screen Shot 2022-09-22 at 8.55.46.png

exists(array<T>, function<T, V, Boolean>): Boolean

入力のarray<T>の要素が述語function<T, Boolean>に合致するかどうかをテストします。

以下の例では、配列valuesに10で割った余りが1になる要素があるかどうかをチェックしています。

SQL
SELECT
  key,
  values,
  EXISTS(values, value -> value % 10 == 1) filtered_values
FROM
  nested_data

Screen Shot 2022-09-22 at 8.56.30.png

filter(array<T>, function<T, Boolean>): array<T>

入力array<T>から述語function<T, boolean>にマッチするもののみを追加することで出力array<T>にフィルタリングします。

以下の例では、value > 50を満たす要素のみからなるvalues配列にフィルタリングしています。

SQL
SELECT   key,
         values,
         FILTER(values, value -> value > 50) filtered_values
FROM     nested_data

Screen Shot 2022-09-22 at 8.57.11.png

aggregate(array<T>, B, function<B, T, B>, function<B, R>): R

function<B, T, B>を用いて、要素をバッファーBにマージし、最終的なバッファーに最後のfunction<B, R>を適用することで、array<T>の要素を単一の値Rにまとめます。Bの初期値はゼロエクスプレッションによって決定されます。最後の関数はオプションです。最終化の関数を指定しない場合、何も変化させない関数(id -> id)が使用されます。

これは、2つのラムダ関数を使う唯一の高階関数です。

以下の例では、values配列を単一の(sum)の値に合計(集計)しています。最終化関数(summed_values)のバージョンと、最終化関数なしのsummed_values_simpleバージョンを示しています。

注意 以下で使用しているREDUCE関数はAGGREGATE関数と同じものです。

SQL
SELECT   key,
         values,
         REDUCE(values, 0, (value, acc) -> value + acc, acc -> acc) summed_values,
         REDUCE(values, 0, (value, acc) -> value + acc) summed_values_simple
FROM     nested_data

Screen Shot 2022-09-22 at 8.57.56.png

さらに複雑な集計処理を行うこともできます。以下のコードでは、配列の要素のジオメトリックな平均値を計算しています。

SQL
SELECT   key,
         values,
         AGGREGATE(values,
           (1 AS product, 0 AS N),
           (buffer, value) -> (value * buffer.product, buffer.N + 1),
           buffer -> Power(buffer.product, 1.0 / buffer.N)) geomean
FROM     nested_data

Screen Shot 2022-09-22 at 8.58.26.png

Databricks 無料トライアル

Databricks 無料トライアル

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?