Databricksジョブでfor eachタスクがサポートされました！

これも心待ちにしていた機能。マニュアルはこちらです。

https://docs.databricks.com/ja/jobs/for-each.html

# for eachタスクとは

For eachタスクは、コレクション(テーブル名のリストなど)に対して繰り返しの処理を行い、動的なパラメーターの値で複数回処理を実行することができ、データドリブンなワークフローを構築することができます。
![capture.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/976c2424-486b-c4d4-3e4e-7f385cbec822.gif)


# for eachタスクの作成

ループする処理を記述するノートブックを作成します。

```py:sample notebook
print("I'm a task!")
```

ノートブックを指定してジョブの**タスクを作成**します。一度タスクを保存しないとループ処理に変更できません。
![Screenshot 2024-08-21 at 10.09.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/a191238f-80fd-b5e6-dec0-b93da0fd0edb.png)

保存するとタスクの上のメニューにループマークが表示されます。こちらをクリックすることでタスクをループ処理に変更することができます。
![Screenshot 2024-08-21 at 10.10.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/8fb8efcd-0aa7-6be5-31ba-75bbd1178377.png)
![Screenshot 2024-08-21 at 10.10.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/3dc5360c-6e32-ef6d-2fff-14c57608c552.png)

最低限、ここで入力する必要があるのは**入力**です。入力パラメーターをJSONの配列形式で指定します。以下の配列を指定してタスクを保存します。

```
[1,2,3]
```

![Screenshot 2024-08-21 at 11.14.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ad8d05ac-c0b7-5fca-0c63-5d1e78ee75d7.png)


これでジョブを実行してみます。すると、ループの過程を確認することができます。
![Screenshot 2024-08-21 at 10.17.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b5ee2398-b568-1043-3405-ec852602b4e8.png)
![Screenshot 2024-08-21 at 10.18.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0dda4e78-8b61-71b7-b032-85a9dedb023b.png)

# 入力パラメーターの引き渡し

上の例では同じタスクをループしただけでした。ループの場合、イテレーションごとに異なるパラメーターを入力して処理することが一般的です。それでは、その方法を試してみます。

ノートブックのロジックを変更します。従来からタスクでのパラメーター受け取りで用いている[dbutils.widgets.get](https://docs.databricks.com/ja/dev-tools/databricks-utils.html#dbutils-widgets-get)を使います。

```py:sample notebook
print(dbutils.widgets.get("input_parameter"))
```

タスクを表示し、ループのボックスの中にある**ループされるタスク**をクリックします。**パラメータ**を追加します。
![Screenshot 2024-08-21 at 10.23.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b30896a2-c60e-4082-dfb4-02bf742d0f37.png)

ループで指定されているインプットは`{{input}}`で動的に参照することができます。キーはノートブックで参照しているキー`input_parameter`にそろえてタスクを保存します。
![Screenshot 2024-08-21 at 10.25.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e195d317-87e6-bbc5-8400-24eea29462c8.png)

再度ジョブを実行します。すると、ループごとに異なるインプットが渡されていることを確認できます。
![Screenshot 2024-08-21 at 10.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/aa08bb76-6d15-d4f4-5b11-e9ef7fc4775e.png)
![Screenshot 2024-08-21 at 10.27.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/308ee8a7-7be3-c3c3-0d8e-c9a42cb78d24.png)
![Screenshot 2024-08-21 at 10.28.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0d1bc8be-de9e-76ac-425a-9f73539eaa45.png)

# 動的な入力パラメーターの引き渡し

上の例ではインプットの配列は静的なものでしたが、これを動的に生成される配列にしたいケースもあるかと思います。ここでは、タスクバリューを用いて動的に生成された配列をループのインプットにします。

```py:create input
job_task = []
# ランダムな国名のキーと値を作成するためにrandomモジュールを使用
import random

# オブジェクトを格納するためのリスト
job_task = []

# 国名のリスト
country_names = ["USA", "Canada", "Mexico", "Brazil", "Argentina", "Chile", "France", "Germany", "Spain", "Italy", "China", "Japan", "India", "Australia", "South Africa"]

# ランダムな国名のキーと値を持つ100個のオブジェクトの作成
for _ in range(100):
    country_key = random.randint(1000, 9999)
    country_name = random.choice(country_names)
    obj = {"country_key": country_key, "country_name": country_name}
    job_task.append(obj)

# dbutilsを用いてタスクバリューを設定
dbutils.jobs.taskValues.set(key = "countries", value = job_task)
```

上記ノートブックをポイントするタスク`create_input`を作成し、最初に作ったタスクがこのタスクに依存するように設定します。そして、**入力**をタスクバリューの動的参照`{{tasks.create_input.values.countries}}`に設定します。

そして、値を参照する方のノートブックも変更を加えます。

```py:sample notebook
country_key = dbutils.widgets.get("country_key")
country_name = dbutils.widgets.get("country_name")

print("country_key:" + country_key, "country_name:" + country_name)
```

ループされるタスクのパラメータも入力の形式にそろえます。

| キー | バリュー |
|:--|:--|
| country_key  | `{{input.country_key}}`  |
| country_name  |  `{{input.country_name}}` |

![Screenshot 2024-08-21 at 10.44.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/3b8767ec-bb33-8651-e91d-397b829aefdb.png)

これでジョブを実行します。すると、最初のタスクで国のキーと名前のペアを格納するリストが生成されます。
![Screenshot 2024-08-21 at 10.41.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/a56bc16f-ab3a-fcb3-8242-bd9f93a2a7f7.png)

そして、後段のタスクにリストが引き渡され、それに従ってループ処理が行われます。
![Screenshot 2024-08-21 at 10.46.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/089881c3-95fe-9a09-edf2-0d25443603f8.png)
![Screenshot 2024-08-21 at 10.46.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d26c762a-51e6-ae21-bb09-90aa77f172b0.png)

各イテレーションに値も引き渡されています。
![Screenshot 2024-08-21 at 10.46.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/299084db-0f3e-84ab-a654-2d2b8871206a.png)

# 同時実行

ループのイテレーション間に依存関係がある場合は逐次実行すべきですが、そうでなければ同時実行することも可能です。
![Screenshot 2024-08-21 at 11.09.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/353b3aef-28e0-20d0-2507-beb1c02f2a48.png)

同時実行度を上げればループ全体の処理を高速化できます。
![Screenshot 2024-08-21 at 11.11.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/00ed9fb5-80aa-ae2a-0114-a5e582a66bbc.png)

これまで以上に柔軟にジョブを組めるようになりましたので、是非ご活用ください！

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)