Google Fusion Tables API v1.0 Tips
2013/3/18
@awwa500
Wataru Sato
1
自己紹介
• Wataru Sato
– 本業は通信キャリア研究所向けにソフトウェア作っています
– 個人的にはAndroid、AWS(SDB)、Fusion Tablesなどで遊んでいます• SmartTraining
• ググれカス plug-in for twicca
• 他
• @awwa500
2
きっかけ
• Fusion Tables APIが新しくなり、乗り換えてみました
• 乗り換えてみたはいいけど、ハマりまくってドブ板踏み抜き過ぎて疲れました
• 踏み抜いたドブ板の数を数えてみたら結構あったので、まとめてみました
3
Google Fusion Tablesとは
• Google Driveで使えるDBっぽいヤツ
• ユーザプライベートなデータを(たぶん)無料で利用できる
4
←コレ
Google Fusion Tablesとは
• データを手軽に可視化できる
5
Google Fusion Tables APIとは
• FTのデータにアクセスするためのAPI
• 2つのAPI
– SQL API
• 既にオワコン
• We will now shut down SQL API after January 14, 2013.
– API v1.0
• 今ならこれを使うしかない
• RESTful HTTP経由でSQL的なクエリ操作ができる
• 結果はJSON or CSVで受け取る
6
ライブラリ
• FTを使おうと思った時に公開されていたものが依存関係とか、使い方覚えるのが面倒だったので使っていません
• 最近チェックしたらスッキリしてきたかも– https://code.google.com/p/google-api-java-
client/wiki/APIs#Fusion_Tables_API
• もしかしたら、コレを使っていればドブ板踏み破る数は減っていたかも
• 是非使ってみて下さい7
基本
• Google APIs consoleでサービス有効化
• OAuth 2.0
• HTTPリクエスト
• レスポンスパース
• 詳しくは
– https://developers.google.com/fusiontables/docs/v1/using
8
OAuth2.0
• 通常は、普通にOAuth2すればいい• Androidの場合、AccountManager経由がセキュリティ的
に好ましい– 琴線探査:AndroidのAccountManager経由でGoogleの
OAuth2認証を行うには?(外部ライブラリ完全非依存版)• http://kinsentansa.blogspot.jp/2012/08/androidaccountmanagergoog
leoauth2.html
• AndroidでWebView経由で行うのは好ましくない– Shogo’s Blog:OAuthの認証にWebViewを使うのはやめよう
• http://shogo82148.github.com/blog/2012/11/24/no-more-webview/• この記事はTwitterのOauthに関して書かれているが、WebViewの脆弱性に関しては同じ事
9
テーブルアクセスの基本
• Create table時に返されるtableIdを使ってテーブル指定する必要がある
10
Create table
Client FT
tableId
SELECT * FROM <table_id>
レコードアクセスの基本
• Insert row時に生成されるROWIDを使って更新(update,delete)する必要がある
11
Insert row
Client FT
ROWID
UPDATE <table_id> SET <column_name> = <value> WHERE ROWID = <row_id>
レコードCRUD
CRUD 手法 詳細
Create Insert row 1クエリ1レコード挿入クエリを”;”で繋げて1リクエストに複数クエリ送信可戻り値でROWIDを得ることができる
Import rows POSTのBodyにCSVを突っ込んで大量レコード挿入可戻り値でROWIDを得ることができない
Select Select rows 作成したColumnの他、ROWIDを取得することができる
Update Update row ROWID指定するか、無指定で全レコード対象任意の条件を指定することはできない
Delete Delete row ROWID指定するか、無指定で全レコード対象任意の条件を指定することはできない
12
大量レコード挿入戦略~Insert row~
• Insert rowでは、1リクエストあたり500Insertまでいける、とドキュメントに書いてある
– https://developers.google.com/fusiontables/docs/v1/using#insertRow
– しかし、sqlパラメータはQueryString
– 実際にはURL長の制限を受ける
• ヾ(*`Д´*)ノ“
13
大量レコード挿入戦略~Import rows~
• Import rowsなら1リクエストで100MBまでのデータを挿入できる
• しかし、戻り値でROWIDは取得できない• ROWIDが欲しければ、Import rows後、Selectする必要がある
• しかし、500レコード以上をImport rowsした場合、すぐにSelectしてもROWIDが取得できない場合がある
• どうやらImport rows後のレコード反映は、500レコードずつ分割されて非同期で実行されている模様
14
大量レコード挿入戦略~Import rows~
• 大量レコードImport時の雰囲気
15
Import rows (over 500 rows)
Client FT
Insert rows(500)
BackEnd
Insert rows(500)Select
Insert rows(500)
Insert rows(500)
Insert rows(500)
全レコード取れない!反映に時間がかかる
NumRowsReceived=2500
大量レコード挿入戦略~Import rows~
• 期待したレコード数になるまでポーリング
16
Import rows (over 500 rows)
Client FT
Insert rows(500)
BackEnd
Insert rows(500)Select count()
Insert rows(500)
Insert rows(500)
Insert rows(500)
1000反映に時間がかかる
Select count()
2000Select count()
2500
Select
ROWID
NumRowsReceived=2500
大量レコード挿入戦略~Import rows~
• もしくはImport rows後すぐにはROWIDは取
りに行かない。必要になったタイミングで個別にROWIDをSelect後、更新操作を行う
17
• まとめ
– アクセス頻度に応じた作戦をとること
大量レコード挿入戦略~Import rows~
18
レコードアクセス頻度
方法
高い Import rows後、速やかに全ROWIDを取得してローカルに記憶しておき、即更新処理を可能にしておく
低い Import rows後、ROWIDは必要になったタイミングで個別にSelect後、目的の更新処理を実行する取得したROWIDはキャッシュしておくと少しは良い
• ROWID指定した場合
– レスポンスのaffectedRowsには影響を受けたレコード数が整数で返ってくる
• ROWID指定しない場合
– レスポンスのaffectedRowsに”all rows”という文字列が返ってくる
レコード更新(Update, Delete)時注意
19
_人人人人人人人人_>文字列が返ってくる< ̄^Y^Y^Y^Y^Y^Y^Y^Y ̄
• Insert rowした場合のROWID
– 割り当てられるROWIDは昇順とは限らない
• Order by無指定時のソート順
– ROWIDの昇順でソートされて返ってくる
• Order byにROWIDを指定すると503
– 指定してはいけない
• ROWID = 0でSelectすると503
– 指定してはいけない
ROWIDに関する注意
20
• そんな機能はない
• あるわけがない
• どうしてもやりたければ– A案)子テーブルに親テーブルレコードのROWIDを格納するColumnを設ける
– B案)親テーブルのレコード毎に子テーブルを分けて、親テーブルに子テーブルのtableIdを格納するColumnを設ける
• 無論、関連情報は自分で更新する、制約がはれるわけではない
テーブル間の外部参照
21
• A案)子テーブルに親テーブルレコードのROWIDを格納するColumnを設ける
テーブル間の外部参照
22
ROWID
1
2
ROWID PARENT_ROWID
1 1
2 1
3 2
4 2
親テーブル 子テーブル
• B案)親テーブルのレコード毎に子テーブ
ルを分けて、親テーブルに子テーブルのtableIdを格納するColumnを設ける
テーブル間の外部参照
23
ROWID CHILD_TABLE_ID
1 XXX
2 YYY ROWID
1
2
親テーブル
子テーブル(tableId=XXX)
ROWID
1
2
子テーブル(tableId=YYY)
大量なテーブル生成は大量なImportを必要とする503発生の原因になりやすいので注意する
タイムアウト
• クライアントタイムアウト値は最低でも60秒くらいは必要
– HttpClientなどを利用しているとタイムアウト値が短かったりするので長めに設定すること
24
HTTP 503との闘い
• HTTP 503:Service Unavailable
– 裏でナニかが起きた
– ナニ
• 高頻度のアクセスによるブロック
• Select rowでROWIDでorder by
• Select rowでROWID = 0
• Fusion Tables自体の不具合(たぶん)
• など
25
アクセス制限
• Google APIs console
• 制限はこれだけではない– 上限に関して明確には規定されていない
• 問合せても回答がもらえない
– 特にImport rowsで発生しやすい• 例)Import rowsをスリープなしで18回繰り返すと発生
– 復旧• まる1日制限されたり、数分で復旧したり、とにかくよくわからない
– 影響範囲• ユーザ単位
26
誰かに質問したい時は
• 技術的な質問はStackoverflowを使うこと
• Google GroupのFusion Tables APIグループは
技術以外に関するディスカッションの場という位置づけ
– 誤って質問を投げてしまうと、ディスカッションの途中で「Stackoverflowに行け!」と言われて議論はウヤムヤになる
27
Stackoverflowへ質問する時
• 503が発生した時の質問方法
• 以下の2点を質問内容に含めておくと回答が得られやすい– どういうリクエストを投げたのか?
– 具体的なレスポンスのBody(JSON)
• Try it!を使うとわりと便利– https://developers.google.com/fusiontables/docs/
v1/reference/query/sqlGet#try-it
• 「503起きた-!」だけでは何も伝わらない
28
Try it!
29