見出し画像

【DataWeave】ループ処理の入れ子を避けて効率的・性能がいいコードを書く方法


はじめに

こんにちは。CREFILでコンサルタントをしている片野です。
今回は、ループ処理の入れ子による性能の低下の回避方法をお伝えします。
ループ処理を複数回使用して処理時間がかかってしまったり、メモリを使いすぎてしまったことはないでしょうか?
最近そんな場面があったので、その時に学んだループ処理の回避について共有しようと思います!
また、今回のブログではDataWeaveというMuleSoftのAnypoint Platformの一部として提供されるデータ変換言語を使用します。


ループの入れ子処理とは

ループ処理の入れ子とは、プログラム内で1つのループが別のループの中に配置されるプログラムの制御構造を指します。

具体的に記載してみると以下のようになります。
(処理の目的は「社員情報に該当社員のプロジェクト情報を合体させる」です。)

%dw 2.0
output application/json
---
// 入れ子になっているプログラミング
employees map (value) ->
  value
  ++
  {
    "projects": (projects filter ($.no == value.no)).projects[0]
  }

プログラムの処理内容は、
社員情報を持っている配列の変数[employees]にprojectsという項目を追加し、projectsの値はプロジェクト情報を持っている配列の変数[projects]から二つの変数の項目「no」が一致するものを探しています。

上記の処理を行うためにループ処理(map)の中でループ処理(filter)を行い、外側のループ処理が実行されるたびに内側のループ処理が毎回実行されます。

単純に100万人の社員情報があるとすると、100万(社員情報)×100万(プロジェクト情報)回処理が行われてしまう、というわけです。
少ないデータ量であればさほど問題はありませんが、特に大規模なデータセットを処理する際にパフォーマンスの低下やコードの複雑さを引き起こす可能性があります。

補足

上記の処理をinputデータありで確認されたい方は、「PlayGround」で、以下のzipファイルをImportしていただければ、より動きがわかりやすいかなと思うので、よければぜひ確認してみてください!
PlayGround使用方法の参考ブログ:https://note.com/crefil/n/n83dcc8329972


入れ子処理を避ける対応策

入れ子処理を避ける手段として「groupBy」を紹介します!
groupByとは、指定された条件によって配列の項目をグループ化してオブジェクトを返します。
groupByによって作成された変数はDBでいうところのINDEXがはられた状態になるので、変数内で該当データを探す際の処理が早くなります!

具体的に記載してみると以下のようになります。
(処理の目的は上記と同様で「社員情報に該当社員のプロジェクト情報を合体させる」です。)

%dw 2.0
output application/json

var prGroupBy = projects groupBy (item) -> item.no

---
// 入れ子を避けているプログラム
employees map (value) ->
  value
  ++
  {
    "projects": prGroupBy[value.no].projects[0]
  }

今回使用しているgroupByでは、配列の変数を、項目の値ごとにグループ化しています。

プログラムの処理内容は
項目「no」でグループ化された変数[prGroupBy]を作成し、変数[employees]のループ処理中に該当するデータを変数[prGroupBy]から検索しています。
入れ子処理の時とは違い、ループ内の処理ごとに変数[projects]をすべて確認しなくなります。

この処理でしたら、社員情報が100万件、プロジェクト情報が100万件あっても処理回数は100万回になります。

補足

groupByを使用した処理も「PlayGround」で確認できるようにzipファイルを添付しますので、よければ確認してみてください!

さいごに

今回、ループの入れ子処理の回避方法を紹介しました。
よければ参考にしていただけたら嬉しいです。

最後まで読んでいただき、ありがとうございました。
よければ、「♡」していただければ幸いです!

この記事が参加している募集