Azure Machine LearningとAzure Storage／DocumentDBを連携させる

社内で「◯◯は俺に任せろ」「俺に◯◯させろ」という表現が使われ始めています。私はまだまだ駆け出しですが、「人工知能は俺に任せろ！」ぐらい言えるようになりたいものです。

> アクセシビリティやるぞ！夏祭り2 ～俺たちにテストさせろスペシャル～
> https://connpass.com/event/38351/

さて、Azure Data Factoryを利用して、Azureの世界の中でデータを動かす方法を下記の記事に記載しました。
[Azure Data Factoryを利用してAzure StorageのデータをDocumentDBにコピーする](
http://qiita.com/snomoto/items/50827178055ea870621f)
本記事においては、Azure Machine Learningでデータを利用する流れを記載します。Azureの他のリソースから投入する、、というよりも、Machine Learning側でインポートするというイメージになります。

Azure Machine Learningは他のAzure群とは少し違う世界観を持っており、別のドメインに飛ばされる上に料金体系も気をつけないとアクティベートしたワークスペースごとに日々請求されるようです。

<img width="512" alt="スクリーンショット 2016-12-13 13.01.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/48e33b25-31ac-0707-ffeb-5ed2ed9ed4ff.png">

# 前提
上記のqiita記事と同じ前提条件です。そしてまずはサラっと本記事を一通り読んで頂ければ良いかなと思います。
- Azure Machine Learningの課金ワークスペースを確保できること
- Azure Storageをアクティベート出来、何らかのデータを保存していること
- Azure DocumentDBをアクティベート出来、コレクションとデータベースを作成していること

# ログイン
Azure Portalから"Machine Learning Studio"を起動します。

なんかエラーが出ました。一つのブラウザの複数のタブでStudio or WorkSpaceを開くのはダメみたいです。

```
Microsoft Azure Machine Learning Studio
The Studio failed to load. Please refresh this page.
```

Experimentsとしてデータインポートのための空実験スペースを確保してみます。
<img width="512" alt="スクリーンショット 2016-12-13 13.43.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/cc046777-cb14-1fe8-9b77-504d4f06947f.png">

# データインポート

左側リストの「Data Input and Output」から、「Import Data」をドラッグ＆ドロップで配置します。
<img width="512" alt="スクリーンショット 2016-12-13 13.48.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/f823c68b-f453-fba0-b268-3b4a473a305e.png">

- 選べるデータ元としては以下の7つとなっています。(2016年12月時点、転記しただけです)

    * Web URL via HTTP
    * Hive Query
    * Azure SQL Database
    - Azure Table
    - Azure Blob Storage
    - Data Feed Provider
    - オンプレミス SQL Database (プレビュー版らしい)
    - Azure DocumentDB

## Azure Storageからインポート
Azure Blob Storageからは、以下のデータ形式のファイルをインポートできます。
- ARFF (https://ja.wikipedia.org/wiki/Weka)
- CSV
- TSV
- CSV with encoding
- Excel

上のスクリーンショットの続きとして「Azure Blob Storage」を選択し、それぞれ必要事項を入力していきます。
ストレージアカウント・アカウントキーについては以下のリンク先の記事のスクリーンショットを御確認ください
[Azure Storageへのアクセス方法](
http://qiita.com/snomoto/items/c2793866dee81b4718e9#azure-sdk-for-php%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)

必要事項を入力して、実行してみたのが以下のスクショです。
<img width="512" alt="スクリーンショット 2016-12-13 15.18.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/6ba46d9d-a101-8930-20ad-665ddc11302b.png">

なんの難しいこともなく、データをインポートできました。。

## Azure DocumentDBからインポート

基本的にはAzure Storageと同じで、コレクション・データベース名を入力します。
古いドキュメントには無い「SQL query parameters」という項目がありました。どうやら変数のバインド処理を行うもののようで、"value required"となっており何かをセットしなければなりません。
Microsoftにありがちな謎ドキュメントを辿ったところ、JSONを入力すれば良いことがわかりました。"select * from c"というSQL文に対して、以下の通り入力しました。（気付くのに時間がかかりました。。。）

```
{}
```

実行してみたのが、以下のスクショです。
<img width="512" alt="documentdbImport.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/c33ed80a-bbf4-9f37-20cc-1d876e535f23.png">

間違ったJSONを入れると、下記のようなエラー文言が出力されます。

```java:error
errorComponent=Module. taskStatusCode=400. 
{"Exception":{"ErrorId":"LibraryException","ErrorCode":"1000","ExceptionType":"ModuleException","Message":"Error 1000: DocumentDb library exception: The SQL script is invalid","Exception":
{"Library":"DocumentDb","ExceptionType":"LibraryException","Message":"The SQL script is invalid","Exception":
{"ExceptionType":"Exception",
 "Message":"Message: {\"Errors\":[\"Invalid query. Specified parameter name 'query' is invalid. Parameter names should be in the format of symbol '@' followed by a valid identifier.
```

### SELECT文で条件を追加してインポート

PDOのパラメータバインドを思い出しつつSELECT文を書いてみます。
Microsoft SQL Serverの書式なのか、LIKEでなく CONTAINSでいけました。
<img width="512" alt="スクリーンショット 2016-12-14 13.46.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/05eb271a-eace-fd49-dee1-067258cad041.png">

## オンライン上のデータをインポート
**2016年12月16日追記**
オープンなデータをインポート出来ることは当たり前として、自前／パートナーのデータをインポートすることを考えてみます。
Machine Learningのインポート設定からでは、各種認証には対応していないようですので、最低限のセキュリティとして、外部サーバ側でIPアドレスフィルタリングを利用することを考えてみます。

Machine LearningのIPアドレスの確認としては、一回何もない状態で何でも良いのでMachine Learningからアクセスしログを確認します。（もしかしてどこかに表示されている？）

```
13.xx.xx.xx - - [16/Dec/2016:05:25:41 +0000] "GET /data_set.csv HTTP/1.1" 200 1127413 "-" "-"
```

こちらを利用します。
サーバ側でIPアドレス制御するので、httpd.confファイルを書き換えます。
（確認するだけなので、皆様方におかれましては本番環境は[ちゃんとしたやり方](http://qiita.com/search?utf8=%E2%9C%93&sort=&q=apache+ip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E5%88%B6%E9%99%90)でやってくださいね！）


```java:httpd.confの最終行
<Directory "/var/www/html/data">
    Order  deny,allow
    deny   from ALL
    allow  from 13.xx.xx.xx

</Directory>


```

アクセス制御できています。。
<img width="384" alt="スクリーンショット 2016-12-16 17.15.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/f1b4ee6b-825c-d63f-c012-117ea52389cf.png">

Azure Machine Learningから読み込んでみます。
<img width="384" alt="スクリーンショット 2016-12-16 17.20.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/0856ee55-de95-9a63-2fcd-925ad87f3efa.png">

ものすごく当たり前のIPアドレス制御をやっただけになってしまいましたが、取り敢えず。
むしろ、単体で認証系が出来ないことがわかっただけでも良しとしたいと思います。



# おわりに
兎にも角にも、Azure Storage／DocumentDBからデータをインポートすることができました。
~~"Web URL via HTTP"というのは、ダイレクトにデータを取ってくるのでURLさえ設定すればOKみたいです。なんかコワいですね~~ （追記にてIPアドレスフィルタする流れを確認しました）
どこでデータを整形するかですが、投入前に下拵えが終わってればMachine Learning内部でいけそうですし、DocumentDBのSQLクエリで抽出するやり方もできそうですね。

# 付録
**2016年12月16日編集**
Machine Learningに持ち込むまでに、いくつかのポイントがあることがわかりました。

- Machine LearningにはCSV形式かTSV形式のデータの方が入れやすい。
- Machine LearningはAzure世界の中でも別枠ポジション。
    - DocumentDBからのデータインポートではSQL文を利用出来る。  
       →DocumentDBにはデータを雑多に入れれば良いとして課金はどこに付く？？

まだMachine Learningの全容が理解できてないのですが、Machine Learningを使った作業の進め方として、下図のようなデータフローを考えてみました。

＃1. Azure世界にデータがバラバラなタイミングでインジェストされる[（関連記事）](http://qiita.com/snomoto/items/a24b34ebb111706679e8)
＃2. Data Factoryによって、ある時点でのデータがDocumentDBに投入される[（関連記事）](http://qiita.com/snomoto/items/50827178055ea870621f)
＃3. 担当者はMachine Learningで必要なデータをインポートする（この記事で説明）
<img width="384" alt="スクリーンショット 2016-12-16 17.36.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/e3b1b56b-0ceb-a367-9046-c3064acf0a13.png">


＃4. 良い結果が得られたら、担当者はお宝データセットをエクスポートして保存する
<img width="384" alt="スクリーンショット 2016-12-16 11.42.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/7e0b3edb-bee6-b221-3664-f94c72391835.png">

＃ex. もしも元データを取っておきたいならば＃1で保存されたデータをアーカイブ化
<img width="384" alt="スクリーンショット 2016-12-16 11.42.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/147747/522ee203-02c7-7b81-e54f-e86223e6673d.png">