ICOS上のファイルを簡単にSQL検索できる「SQL Query」を使ってみた

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/aa34513a-e516-228a-f70c-b6dc8e609f47.png)

(記事執筆時点 2018/08/24)
# はじめに

こんにちわ！石田です。IBM Cloudの新サービス「**SQL Query**」を触ってみたので、ご紹介します。クラウド上のオブジェクト・ストレージに置いてある様々なデータ・ファイルを簡単にSQLで検索できる仕組み、って意味ではAmazonさんのAthenaやGoogleさんのBigQueryに似ていますけど、データベースへのロードやスキーマの準備は不要で「**置いてあるファイルを、そのまま/即、ANSI準拠の標準SQLで検索できる**」簡単さがウリです。

# SQL Queryって何? ~1分で

- IBM Cloud Object Storage上のCSVなどのオープン・フォーマットのファイルを簡単にSQLで検索(SELECT)できるサービスです
- ICOS上にファイルが置いてあれば、すぐに検索できます。データベースへのロードやスキーマの定義などの準備は不要です
- 環境構築や準備も特にありません。カタログからサービスを選ぶだけ=1分で使い始められます
- DBのアーカイブやIoTのランディング・データ等へのアドホックな検索に向いています
- Webコンソールがありますが、REST APIやサーバーレスの仕組み[^1]からもアクセスできます
- 内部的にはSparkSQLを使っていますので並列処理できます
- 課金の単位は(他社様の類似サービス同様に) x円/TBスキャン・月です[^2]

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/a4e8b161-6b50-0442-c409-34871e9b7755.png)

:clock9: 1分終了です。

[^1]: IBM_Cloud_Functions
[^2]: Qiitaに「BigQueryで150万円溶かした人の話」がありましたが、スキャン量への課金という意味では同じ考え方ですのでご注意ください。もっともSQLQueryは「そのまま検索できる」ので、検索の準備のためにいちいちデータを移行したり移動することも少ないかとは思いますが。

# 何に使えるの? ~ユースケース

オブジェクト・ストレージは「コールド・データのコストの安い保管場所」的な意味合いが強いですが、アドホックな検索ができると色々な利用場面が考えられます。例えば

- DBの過去時系列等のアーカイブを置いておき、過去調査の必要が生じた都度、いちいち再度テーブルにロードせずに直接検索する
- IoTやストリーミングのランディング・データを置いておき、検索/集計/一次加工する
- 簡単なSQLを書ける現場部門の方なら、IT部門の支援なしで上記のことはできるでしょう

:triangular_flag_on_post: 私見ですが、SQL QueryはETLやBIなどの本格的でカチッと定例運用する分析システムの代わりになるものではなく、「基本、コールドデータだけど、たまに検索する必要が出るんだよね」というアドホックな検索に向いているものと思われます。あと「今はアーカイブはテープに保管して倉庫いれてるんで、いざ検索するときは出庫～リストア～ロードと、何かと手間がかかるんだよね」なんてシーンもあるでしょう。


# 何ができるの? ~機能

## 動き
【入力】ICOS上のバケットのファイルをテーブルと見立てます
【処理】標準SQLでSELECTします。内部的にはSparkSQLが動きます
【出力】SELECTした結果はICOS上で指定した任意のバケット上に書き出されます。(Webコンソールの場合は結果はパネルにも表示されます）

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/4ac19733-abab-20d6-009b-94c20ebc182f.png)

## サポートされている入力ファイルの形式

- CSV / JSON / Parquet / ORC
- :warning: CSVが一番お手軽でしょうが、現状は以下の制限があります
    - 先頭行に見出しヘダー必須
    - 区切り文字は「カンマ」のみ
- :warning: CSVの**見出しが日本語の場合はSELECTのカラム名を「 ‘ 」（バッククオート）で囲んでください。**

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/08dfe7a8-b075-7b1b-7db9-c5a99ba96567.png)

[^3]: これは仕様ではなく障害だと思うので近々直ると思います。しばらくご迷惑おかけしますがご容赦ください。

## 機能へのアクセス方法

一番簡単なのはWebコンソールですが、他にも以下のように色々な方法でサービスにアクセスできます。
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/c8128ccc-7f22-5eed-cfed-2f0418ee54dd.png)

:triangular_flag_on_post: AmazonさんのAthenaはJDBCでのアクセスもあるようですが、SQL Queryは現時点は未対応です。

## 追加機能

- [GeoSpatial Analytics](https://console.bluemix.net/docs/services/sql-query/geospatial.html#geospatial-analytics)が含まれており、位置情報を使った検索ができます
- 標準のANSI SQLのSELECT以外に [SparkSQLのFunctions](https://console.bluemix.net/docs/services/sql-query/sqlref.html#sql-function-reference)が利用できます

# やってみた
今回はお手軽にWebコンソールでやってみます。

## 1. サービス・インスタンスの作成
カタログから「SQL Query」を選んでお好きなサービス名を指定して「作成」ボタン。

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/3ff4696d-d9ca-fa37-3418-c6918daafb8e.png)

インスタンスができたら「Open UI」でWebコンソールを開きます。
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/125a1df4-f050-6890-42e9-f29197dc9d89.png)

## 2. Webコンソールの起動
以下がWebコンソールです。これで検索の準備ができました。
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/6ce32cb9-f086-622e-e34a-64814ee2c216.png)

| # | 説明|
|:--|:--|
| 1 | サンプルQuery.データも用意されています|
| 2 | APIリファレンスとドキュメントへのリンク |
| 3 | ここにSELECT文を書きます |
| 4 | 実行結果ファイルはここで指定したICOSバケットに保管されます |
| 5 | 実行ボタン |
| 6 | SELECT実行結果の表示領域 |

## 3. 検索前のICOSの状態
検索前のICOSのバケットの状態を確認しておきます。

#### 【入力(検索対象)】
ロケーション **us-geo**のバケット名　**sql-in-e051466-us**に**Customer.csv**というCSVファイルを置きました。中身は以下のようなテスト用の日本語CSVデータです。(UTF-8）今回はこのファイルを検索対象にします。

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/8862e704-a424-f0f1-4275-07316bb102fb.png)

:triangular_flag_on_post: SQLQueryではICOSのインスタンス名( ICOS-e051466)は意識不要です。ロケーションとバケット名でユニークになるので。

#### 【出力】
ロケーション **us-geo**のバケット名　**sql-out-e051466-us**を用意しておきます。中身は空です。
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/fd7b7738-f14b-673e-a78a-9f533fe7834f.png)

## 5. SELECTする

#### やってみる
WebUIで以下のSELECT文を入力し「Run」ボタンを押すと、数秒で結果が表示されます。きちんとカラムの選択、条件の適用、並べ替え等が効いているのがわかります。

```sql
SELECT CUSTOMERID,NAME_KANJI,AREA,TELNO,MARRIAGE,GENDER,BIRTHDAY
FROM cos://us-geo/sql-in-e051466-us/Customer.csv
WHERE AREA ="北海道"
ORDER BY CUSTOMERID DESC;
```
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/c7bbb6e2-9e43-1de4-943d-b93ee6fbca8a.png)

#### FROM 句の書き方
基本、標準のSELECTなので迷うことは無いのですが、一点だけ。FROM句で検索対象のファイルを指定するところは独自なのでご説明します。
ファイルを表す書き方は[ドキュメント](https://console.bluemix.net/docs/services/sql-query/sql-query.html#table-unique-resource-identifier)にありますが、以下のURIの形式です。

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/46a591b5-3a25-9a59-b625-a61d977c752e.png)


- endpointは"s3-api.us-geo.objectstorage.softlayer.net"などの正式の長い名前でもいいですが、**”us-geo”**などの[alias](https://console.bluemix.net/docs/services/sql-query/sql-query.html#endpoints)が使えます
- バケット名とオブジェクト名はそのまま書けばいいです（楽！）

- :triangular_flag_on_post: CSV以外の形式ではSTORED AS でファイルの形式を指定する必要があります。(STORED AS JSON, STORED AS ORC, or STORED AS PARQUET)　(CSVはデフォルトなので割愛可能)
`SELECT *FROM cos://us-geo/sql-in-e051466-us/Customer.json STORED AS JSON`
- SQLの表現についてはパネル右上のサンプルボタンを押すと様々なSELECTの例があるのでご参照ください。JOIN,UNION,HAVINGなど標準のSQL(SELECT)でできることは、できます。
- 検索対象のファイルは正確に言うとRDBでいうテーブルのパーティションのイメージであり、よって**複数を連結できます**。つまり`SELECT *FROM cos://us-geo/sql-in-e051466-us/Customer*.csv`とファイル名に*(ワイルドカード)を使え、その場合は名前が条件に一致する複数のファイルを一つのテーブルとして扱え、一度に検索できます。これは便利ですね！

#### 結果のファイル

以下のようにSELECT実行毎に出力で指定したバケット上にjobidの名前がついた３つのファイルができます。＃１、＃２のファイルは空で＃３のファイルにはSELECTの結果が入っています。
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/afec6cb9-38ec-54a5-d222-70308354e83b.png)

以下のように、この出力をFROMで指定して再利用することもできます。

```sql
 SELECT * 
 FROM cos://us-geo/sql-out-e051466-us/jobid=b7580d94-c9f9-46c2-a7a8-49e9cb52a9d5 
 ORDER BY CUSTOMERID;
```
 
 ![image](https://qiita-image-store.s3.amazonaws.com/0/108535/08b0b633-2517-0371-703d-a9951c9b154c.png)

:warning: 当該出力ファイル群は自動的に消されません=増え続けます。定期的に運用するなら消しこみを考える必要があります
:warning: 前述の#1,#2のファイルは空ですが、「検索結果を再利用するなら」消してはいけないそうです。（使わないならもちろん消して結構です）
 
# 性能面の考慮点　～ビッグデータをSELECTするなら

:newspaper: ブログ記事[How to Layout Big Data in IBM Cloud Object Storage for Spark SQL](https://www.ibm.com/blogs/bluemix/2018/06/big-data-layout/)に考慮点が記載されています。いくつか抜粋すると

- ファイルは128MBくらいで分割しましょう
- Parquet形式など格納効率のいい(カラムナ）形式を使いましょう
- CSV or JSONをgzipで圧縮**しない**
- (時系列で分割するなど)Hive style のpartitioningを行いましょう

などなど。

# REST API

詳しくは[REST APIのリファレンス](https://console.bluemix.net/apidocs/sql-query?language=curl)に記載がありますが、SQL Queryはジョブを起動する非同期型のサービスです。ゆえに

1) ジョブを起動する(POST)→jobidが戻る
2) 一定間隔でジョブの状況(Status)を確認する(GET)
3) StatusがCompleteになったら、出力のバケットから結果をダウンロードする

の段階を踏みます。（=SELECTの結果を同期的に直にプログラムに戻すことはできません）

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/70d86f6e-8c96-beec-7e68-425d8f51484e.png)

# 最後に
以上です。あれこれ触ってて、「**要はICOS-SparkSQL連携のラッパーだよな、これ..**」とも思いましたが、実際に自分で環境を用意してICOS上のファイルをSparkSQLで並列に検索できるようにするのはインフラやプログラミングの知識が必要です。できないとは申しませんが、何もないところから１分でCSVやJSONファイルをSELECT検索できるのは便利でいいんじゃない、と思いました。GAしたら皆様もぜひ使ってみてくださいませ。

# 参考文献
## :blue_book: ドキュメント
[IBM Cloud SQL Query](https://console.bluemix.net/docs/services/sql-query/sql-query.html#overview) - 量が少ないので全部読めます。

## :newspaper: ネット/ブログ記事
[製品紹介ページ](https://www.ibm.com/cloud/sql-query)
[FAQ](https://www.ibm.com/cloud/sql-query/faq)

IBMソリューション・ブログ 

- :jp:  [IBM Cloud SQL Query の発表](https://www.ibm.com/blogs/solutions/jp-ja/introducing-ibm-cloud-sql-query/) - お披露目記事
- [Query and Analyze Call Logs with IBM Cloud SQL Query](https://www.ibm.com/blogs/bluemix/2018/09/query-and-analyze-call-logs-with-ibm-cloud-sql-query/) - Aspera & ややこしいSQLもかける、って例
- [Geospatial Without Projections in IBM Cloud SQL Query](https://www.ibm.com/blogs/bluemix/2018/09/geospatial-without-projections-in-ibm-cloud-sql-query/) - 地理情報機能の紹介シリーズ#1

Medium - [Analyzing Data with IBM Cloud SQL Query](https://medium.com/ibm-watson-data-lab/analyzing-data-with-ibm-cloud-sql-query-bc53566a59f5)

## :tv: 動画やデモ
YouTube: [IBM Cloud SQL Query - Learning Center](https://www.youtube.com/watch?v=dEFZ4fZr5VE&list=PLzpeuWUENMK2R9CqhF0eJDSxfPBi6JeXA)
- 動画が5本あります