Power Automateでマスターデータを参照する(後編)

## 前回の続きです。
各店舗の在庫データと商品マスターをジョインして各店舗アイテム別の在庫金額を求めるには、Power Automateでは、どうしたらよいだろうということ前回は誰でも思いつきそうなやり方で実装してみました。

https://qiita.com/yamachan67/items/6caebab12aa19698a398

ただ、処理時間がかかりすぎるという課題が見つかりました。
今回は、それをどうすれば効率的な処理になるか試してみたいと思います。

### 何が悪かったのか

悪いというのは言いすぎかもしれません。『良くなかった』ぐらいですかね。
Power Automateに限らず、IO処理を出来るだけ減らすのはレスポンス改善をする上で定石と言えるでしょう。ましてやループさせながら、その中で１件づつ、別のマスターを読むのは美しい設計とは言えません。

では、どうすれば良いのでしょうか。

それは、可能な限り、物理的なIOを減らしてメモリー上で処理するしかないということです。もちろん、RDBMSのようにジョインをしてくれる機能があれば別ですが、それでも、実行計画を確認しながら効率の良い処理を選ぶ必要があります。

Power Automateの場合は、ジョインする機能がないので、なにか工夫する必要があります。

そこで、フローを作り直して、次のようにしてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/8d1ec81e-dba5-8ee5-76d6-56ec8b48edeb.png)

ぱっと見ただけでは理解しにくいかもしれません。
では、処理を順番に追いかけていきましょう。

### スコープ(マスター作成)
#### 商品マスターの一覧を取得する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/dd215084-d394-1c85-2a02-4ef76f13c3ce.png)
これは、普通に全件Readしているだけですね。
#### 選択(必要項目抽出)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/7733ebb9-b2b9-93be-6662-edab052fcf8f.png)
ここでは、取得した商品マスターを検索するキー項目と、マスターの中で使う項目だけを抽出しています。
キーは、ProductIDになりますので、項目名(**Key**)にこれをセットしています。
他のマスターを参照する時も、このようなカタチで、キー項目と必要項目だけを抽出しましょう。
#### 選択(KeyValue型へ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/711fafcd-2a39-2009-16a7-c2dfffafa80b.png)
また、選択アクションです。
開始には、一つ上のアクションの出力を指定しています。
そして、マップには次の式をセットしています。
```
concat('"Key:', item()?['Key'], '":', string(item()))
```
これではちょっと判りにくいかもしれません。

入力値と出力値を見てみましょう。
```
[
  {
    "Key": "J01",
    "ProductName": "Apple",
    "RetailPrice": "100"
  },
  {
    "Key": "P01",
    "ProductName": "Banana",
    "RetailPrice": "50"
  },  
  {
    "Key": "U01",
    "ProductName": "Cherry",
    "RetailPrice": "200"
  },
 　　　　　(中略)
  {
    "Key": "M01",
    "ProductName": "Indian Fig",
    "RetailPrice": "220"
  },
  {
    "Key": "I03",
    "ProductName": "Jackfruit",
    "RetailPrice": "250"
  }
] 
```
出力値(見にくいのでエスケープはとっています)
```
[
  "Key:J01":{"Key":"J01","ProductName":"Apple",     "RetailPrice":"100"}",
  "Key:P01":{"Key":"P01","ProductName":"Banana",    "RetailPrice":"50" }",
  "Key:U01":{"Key":"U01","ProductName":"Cherry",    "RetailPrice":"200"}",
 　　　　　(中略)
  "Key:M01":{"Key":"M01","ProductName":"Indian Fig","RetailPrice":"220"}",
  "Key:I03":{"Key":"I03","ProductName":"Jackfruit", "RetailPrice":"250"}"
]
```
#### 結合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/19bd1670-ad39-7006-9d8f-65760602edf8.png)
次に、配列にたまったデータを１件になるようにカンマでつなぎます。
処理結果はこんな感じですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/6836d3d9-8378-1ada-35aa-bdaf75f930ff.png)
#### 作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/5137d036-aa2f-0484-ac10-1d94335d1c13.png)
ここの式は次のようになっています。
```
json(concat('{', body('結合'), '}'))
```
一旦結合したものをカーリーブランケットで囲んでから、json関数を使ってオブジェクト化しています。
結果はこんな感じになっていると思います。
```
{
    "Key:J01": {
        "Key": "J01",
        "ProductName": "Apple",
        "RetailPrice": "100"
    },
    "Key:P01": {
        "Key": "P01",
        "ProductName": "Banana",
        "RetailPrice": "50"
    },
    "Key:U01": {
        "Key": "U01",
        "ProductName": "Cherry",
        "RetailPrice": "200"
    },
 　　　　　(中略)
   "Key:M01": {
        "Key": "M01",
        "ProductName": "Indian Fig",
        "RetailPrice": "220"
    },
    "Key:I03": {
        "Key": "I03",
        "ProductName": "Jackfruit",
        "RetailPrice": "250"
    }
}
```
これで、商品マスターをメモリー上にためて、キーを指定することで、必要な値を取り出す準備ができました。

### 在庫データと商品マスターのマッピング
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/9d1613aa-3b84-ab0f-ea03-f1b32d139e7f.png)
Store、ProductID,Quantityは、在庫データからとってきてます。
ここでは、それ以外の商品マスターから取得している式を見ていきましょう。
|ProductName|
|:----------|
|outputs('作成')?[concat('Key:', item()['ProductID'])]?['ProductName']|
|**RetailPrice**|
|outputs('作成')?[concat('Key:', item()['ProductID'])]?['RetailPrice']|
|**ProductName**|
|mul(int(item()?['Quantity']),int(outputs('作成')?[concat('Key:', item()['ProductID'])]?['RetailPrice']))|

### HTMLテーブルの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/f234223c-4e90-a7e1-b09c-baba3c305362.png)
最後にHTMLテーブルを作成して、求めていた結果の通り、在庫データと商品マスターがマリアージュされていることを確認してフローは完成です。

いかがでしょうか？
作成アクションの出力結果にたいして、Key:商品IDを指定することで、該当の項目の値が取得できることを理解していただけたでしょうか。

## まとめ
前回は、在庫データを全件Readし、その１件ごとに商品IDを用いて、商品マスターを検索していました。
これでは、単純にIOの数が増えるだけでなく、アクションを起動し、データを取得し、終了させるというオーバーヘッドが余分にかかってしまうため、どうしても時間が余計に必要になります。

後編では、まず、商品マスターを全件Readし、扱いやすいカタチでメモリー上に格納したうえで、在庫データも全件取得し、メモリー上でマッピングさせるカタチにフローを組み直したため、圧倒的な実行時間の差が生じました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272254/5aa70921-4d89-e350-32d5-91196f732388.png)
今回扱った在庫データは26件で実行時間はおよそ25秒でしたが、仮にこれが10倍、100倍になった時、この処理時間の差は圧倒的に違いが出てくるかと思います。


最初はなかなか判りにくいかもしれませんが、スコープごとコピーして、他のフローに転用したり、一つのフローの中にも複数のマスターをスコープとして固めて配置すれば、応用はすぐに出来るかと思います。

今回のテクニック、ぜひ、参考にしてみてください。