Oracle Analytics CloudとFunctionsの連携 - OACからデータセットを定期的にObject Storageに書き出す方法

# 資料の紹介
OACでは、セキュリティ上の懸念とファイル・システムへのアクセスの制限により、カスタム関数を直接実行することはできません。 OCI Functions統合により、OACのデータフローからカスタム・スクリプトを実行することが可能になります。

この記事では、OACにFunctionsを登録します。データ・フローで定期的にFunctionsを呼び出し、OACのデータ・セットをObject Storageに書き出す方法を紹介します。
現在では、保存するデータ・セットはCSVフォーマットしかサポートしておりません。

# ソースコードの紹介
Functionsには以下の３つのファイルがあります。
* func.yaml
名前、バージョン、エントリポイント、メモリなどのFunctionsに必要なパラメータを定義します。このファイルはFunctionsを作成するとき、自動的に生成されます。特に修正する必要がありません。
* requirements.txt
Functionsで使用されるライブラリのリストを含めます。
* func.py
関数ロジックは、func.pyのハンドラー関数で記述されています。

func.pyの一部（functionsの定義）
```:func.py
funcDefinition = {
    "status": {
        "returnCode": 0,
        "errorMessage": ""
    },
    "funcDescription": {
        "outputs": [　　//OACの出力結果を定義、保存が成功であることを出力結果とする
            {"name": "save_result", "dataType": "varchar(100)"}
        ],
        "parameters": [　//入力パラメータの指定、保存するデータ・セットの名前を入力
            {"name": "title", "displayName": "Title Column",
             "description": "Specify Title for Dataset", "required": True,
             "value": {"type": "string"}}
        ],
        "bucketName": "bucket-ivy-FAAS",  //入力と出力ファイルを格納するバケットの指定
        "isOutputJoinableWithInput": False  //処理結果を入力データと結合しないことを指定
    }
}
```
func.pyの一部（ファイルの読み込み、処理、出力）
```:func.py
//データフローが実行されると、OACは、カスタム・スクリプトノードの適用の前に入力CSVファイルを作成、バケット・ストレージにアップロード
//ここで、入力CSVファイルを読み込む
input_csv_path = read_from_objectstore(bucketName, fileName)
dat = pd.read_csv(input_csv_path, sep=",", quotechar="\"", encoding="utf-8", parse_dates=True, infer_datetime_format=True)

//保存先のバケットを指定
//入力CSVファイルのrow_id列を削除
//入力CSVファイルを指定したバケット・ストレージに格納
bucketName1 = "bucket-ivy01-FAAS"
dt = datetime.datetime.now()
s = dt.strftime("%Y-%m-%d %H:%M:%S")
output_dat1 = dat.drop(["row_id"], axis=1)
outputFile1 = body.get("output").get("fileName") + body.get("output").get("fileExtension")
output_csv_path1 = "/tmp/" + outputFile1
output_dat1.to_csv(output_csv_path1, index=False )
dstitle = args.get("title")
tt_outputFile = dstitle+s+ ".csv"
write_to_objectstore(bucketName1, tt_outputFile, output_csv_path1)

//出力CSVファイルを作成し、バケット・パケットにアップロード
dat2 = dat.head(1)
output_dat = pd.DataFrame(np.vectorize(save_result)(dat2["row_id"]), columns =['save_result'])
outputFile = body.get("output").get("fileName") + body.get("output").get("fileExtension")
output_csv_path  = "/tmp/"+outputFile
output_dat.to_csv(output_csv_path, index=False)
write_to_objectstore(bucketName, outputFile, output_csv_path)
```


# バケットの作成

Functionsが必要とするバケットを作成します。
* OCIコンソールのバケット作成画面で、「バケットの作成」をクリック
* Functions用のバケット名を指定し、「作成」をクリック
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/c732d779-0653-3c9d-9733-ab20a791a0f8.png)

OACデータセットを保存するバケットを作成します。OACのデータセットは、Functionsの入力として使用するために、バケット・ストレージにアップロードされます。 また、Functionsによって処理された出力CSVファイルもバケット・ストレージにアップロードされます。
* OCIコンソールのバケット作成画面で、「バケットの作成」をクリック
* OACデータセット用のバケット名を指定し、「作成」をクリック
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/c2477d03-df3c-a0e1-f9e1-d7ef03f864b2.png)


# リポジトリの作成
Functionsのソースコードを格納するリポジトリを作成します。

* OCIコンソールで「開発者サービス」→「コンテナ・レジストリ」をクリック
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/ddf565e5-941e-6a9c-4124-0ad5fa2b14ba.png)


* 一覧画面で「リポジトリの作成」をクリック
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/6b305f53-6cfa-d3e1-4006-607ae5465205.png)
* リポジトリ名を入力し、「リポジトリの作成」をクリック
リポジトリ名は「アプリケーション名/ファンクション名」で作成してください。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/be5db7e4-d8e1-6a89-9fe0-58537dbfc4cf.png)

# 認証トークンの作成
後ほど、Cloud Shellに登録し、Functionsをデプロイします。ここで、Cloud Shellに登録するユーザーの認証トークンを生成します。
* OCIコンソールの右上の「プロファイル」メニューを開き、「ユーザー設定」をクリック
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/0fc5ff95-30a4-a190-5bc0-29d74776063b.png)
* ユーザーの詳細画面で、「認証トークン」→「トークンの生成」をクリック
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/846bef88-e1de-1a9d-bc7a-19895d717e0f.png)
* 説明を入力、「トークンの生成」をクリック
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/a9be01dc-0d06-b809-f329-d027f08676a3.png)
* 生成したトークンをコピーし、「閉じる」をクリック
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/90b9015a-4daf-3f1a-8930-f0d64ac7f3f0.png)

# アプリケーションの作成
Functionsのアプリケーションを作成します。
* OCIコンソールで「開発者サービス」→「アプリケーション」をクリック
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/5fb2404c-dbfe-e204-a23b-d5fae340911e.png)
* アプリケーションの一覧画面で、「アプリケーションの作成」をクリック
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/acb88c85-a13e-da08-1f3e-2ab9a6aed424.png)
* アプリケーション名を入力、VCNとサブネットを選択、「作成」をクリック
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/dfbc80d5-33fc-ebaa-7795-d1f1287e5df5.png)
# アプリケーションのデプロイ
Cloud Shellでアプリケーションの環境を構築し、デプロイします。
* アプリケーションの詳細画面で、「スタート・ガイド」を選択
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/f7733227-6a90-b5c1-220b-73ea19265098.png)
* 「Cloud Shellの起動」をクリック
* Step②、③のコマンドをコピーし、Cloud Shellウィンドウに貼り付けて、実行
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/e7cfac52-e943-8f17-4eaa-4f18e08077b1.png)
* Step④の[repo-name-prefix]をFunctionsのアプリケーション名に変更して、Cloud Shellウィンドウに貼り付けて、実行
* Step⑥のコマンドをコピーし、Cloud Shellウィンドウに貼り付けて、実行
パスワードは前で生成したトークンを使用
* Step⑦のコマンドをコピーし、Cloud Shellウィンドウに貼り付けて、実行
![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/be24f772-4021-c61f-1499-bc211a2a2647.png)
* Cloud Shellウィンドウで以下のコマンドを実行し、環境を設定
```
fn init --runtime python <Functions名>
```
* 「アップロード」をクリック、ソースコードfunc.pyとrequirements.txtをアップロード 
[func.pyのダウンロード](https://github.com/jiangqiandlut/Functions/blob/main/func.py "func.pyのダウンロード")
[requirements.txtのダウンロード](https://github.com/jiangqiandlut/Functions/blob/main/requirements.txt "requirements.txtのダウンロード")
![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/19db86f9-3574-5410-1be0-8cb99e64758f.png)

* Cloud Shellウィンドウでコマンドを実行し、ソースコードをFunctionsのフォルダに移動
* Functionsのディレクトリに切り替え、アプリケーションをデプロイ

```
mv func.py requirements.txt ./<Functions名>
cd  <Functions名>
fn -v deploy --app <アプリケーション名>
```
# OACタグの追加
FunctionsがOACで利用するために、OACタグを追加する必要があります。
* Functions名をクリック、Functionsの詳細画面に移動
* Functionsの詳細画面で「タグの追加」をクリック


![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/6e27f024-1f08-67b4-4828-c3cb9ec76219.png)

* タグ・ネームスペースで「なし（フリーフォーム・タグの追加）」を選択
* タグ・キーに「oac-compatible」、タグ値に「true」を入力
* 「タグの追加」をクリック
![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/5ef49d10-385d-df08-eaa2-b3d552d6c7e0.png)

# OCIリソース接続の作成
OCI リソースへの接続情報を確認します。
* OCIコンソールの右上のユーザーのプロファイル・メニューをクリック
* 「テナンシ」をクリックし、テナンシOCIDをコピー
* 「ユーザー設定」をクリックし、ユーザーのOCIDをコピー
![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/e1f21824-5886-5f90-6c4a-5f2f8a0d7a6d.png)
* テナンシOCIDをコピー
![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/cf33643a-0a25-d4dc-c484-eb642b7a19c3.png)
* ユーザーのOCIDをコピー
![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/b19a46b2-d5c0-21cc-ddf7-5de81ac41f4c.png)

OACでOCI リソースへの接続を作成します。
* OACコンソールで「作成」→「接続」をクリック
* 接続タイプ「OCI Resource」を選択
![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/d2f4bd48-6def-2f48-46fa-bec6f1b8ef95.png)
* 接続名を入力
* Functions所属のリージョンを選択
* Functions所属のテナンシOCIDを入力
* FunctionsにアクセスするユーザーのOCIDを入力
* APIキーの「生成」をクリック、コピー
![24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/c202b241-8bfe-6644-e3ec-5160c8003b8b.png)

OACで生成したAPIキーを追加します。
* ユーザーのプロファイル・メニューをクリック、「ユーザー設定」をクリック
* 「APIキー」を選択、「APIキーの追加」をクリック
![25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/8d68621e-cad9-9682-6e02-c8a9a122825d.png)
* 「公開キーの貼り付け」を選択
* OACで生成したAPIキーを貼り付け
* 「追加」をクリック
![27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/37332123-e4f4-6663-e8b6-1329e8f738e4.png)

# Functionsの登録

作成したFunctionsをスクリプトとして、OACに登録します。
* OCIリソースへの接続作成画面で、「保存」をクリック
![28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/f8f2fec0-9d50-4608-d94a-49f3bd1d950d.png)
* メニュー・アイコン→「モデル/関数の登録」→「OCI関数」をクリック
* 作成したOCIリソースへの接続を選択
![29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/82172d62-1e9a-88f8-625e-24c2493c6149.png)

* 作成したアプリケーションを選択
![31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/ed7a9e7a-f512-9715-de41-6df6bb1e910d.png)

* 作成したFunctionsを選択
![32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/2964899b-952f-0548-a792-6aa243a80474.png)

* Functionsの情報が右側に表示され、「登録」をクリック
![33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/bfab78da-bc26-0dba-124a-8a67772fef43.png)

登録したFunctionsの詳細を確認します。

* 「機械学習」→「スクリプト」を選択
* 登録したFunctionsのアクション・メニューをクリック、「検査」を選択
![34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/98c53d0f-73d7-a360-5c2d-a7fbe29975b1.png)

* Functionsの詳細情報が正しいことを確認
![36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/3b7b55b3-af16-726a-06ce-00a0ebfe3c7c.png)
# データ・フローの作成
Functionsを呼び出すOACデータ・フローを作成します。
* OACの「作成」をクリック
* 「データ・フロー」をクリック
![37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/4c81d552-d05a-7f4e-7e7f-bb3685a6a5e5.png)

* 保存するデータ・セットを追加
* 「カスタム・スクリプトの適用」を追加
![38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/00213a2a-c5d2-6d06-70c3-59259d1b6346.png)

* 登録したFunctionsを選択
* 「OK」をクリック
![39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/5f77faee-288f-3a01-9b31-ba78d0345285.png)

* 保存するデータ・セットの名前を入力
![40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/326c3cd0-df3e-949b-8c2d-39e701a0e978.png)

* 「データの保存」を追加
* 結果データ・セットの名前を入力
* 保存結果を確認
![41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/b4c278f1-e92f-4adb-aee0-4c74d74b962e.png)

* データ・フローの「別名保存」をクリック
* データ・フローの名前を入力、「OK」をクリック
![43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/d274180e-001f-6064-5b67-bb777f350f82.png)

* データ・フローのアクション・メニューをクリック、「新規スケジュール」を選択
* 必要な情報を入力、「OK」をクリック
![44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/3580526f-a03d-4c92-15ec-ce3456e8f24b.png)

# 保存結果の確認

Object Storageで格納したデータ・セットを確認します。
![45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851448/4a8e0b59-697d-0fe8-fedf-514565fa0c81.png)