【検証】Google Apps Script × Fusion Tables ～"Table:importRows"との闘い編～

[前回は、「データ10,00件Insert」という観点から「Query:sql」と「Table:importRows」比べました](http://qiita.com/47monbazooka/items/4c013549bf5b9f661c69)。今回は、「Table:importRows」を極めることを目的として、結論から言えば挫折したというお話です（笑）。

※できているっちゃできているんですが :dizzy_face: 

## 前回のおさらい

### 「Query:sql」と「Table:importRows」の違い

+ Query:sql⇒大量データ投入には向いてない（用途として成立しない）
+ Table:importRows⇒少なくともGASからの動作は不安定

### Query:sql

APIの仕様通り30件/分の制約があるため、件数が多いデータを挿入するのには不向き。

```
Exception: Rate Limit Exceeded
```

こちらは原因も明確なので、10,000件のデータ投入には向いていない用途であると断言できます。

### Table:importRows

15MB程度のデータ挿入でレスポンスが返ってこない。

```
Exception: Empty response
```

また、繰り返し実行していると、内部エラーが発生する。

```
Exception: Internal error when processing import.  Please try again.
```

こちらは詳細な発生原因は掴めていません。とにかく事実として起こりましたとしか言いようがないのが実態です。

## 今回やること

前回の実験では、500字×10,000件のデータ挿入でレスポンスが返って来なくなり、250字×10,000件ではレスポンスが返って来ました。今回の実験では、500字×10,000件のデータ挿入が問題なく行えるようにします。

+ 「try again」と言われるなら「try again」してやんよ
+ 300件ずつデータを挿入するようにして、レスポンスが返って来ない事態を回避する

### コードを書いてみた

[前回のコード](http://qiita.com/47monbazooka/items/4c013549bf5b9f661c69#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88)を修正しています。

```GAS:sample.gs
function importRowsTestA() {
  Logger.log("importRowsTestA Start");
  var tableName = "importRowsTestAZ";
  var tableId = createTable(tableName); 
  var rowsData = "";
  for(var i=1;i<=10000;i++){
    var isDone = false;
    rowsData += i+","+shimono()+"\n" ;
    if(i%300==0 || i==10000){
      Logger.log(i);
      do{
        try{
          var rowsBlob = Utilities.newBlob(rowsData, "application/octet-stream");
          FusionTables.Table.importRows(tableId, rowsBlob);
          rowsData = "";
          rowsBlob = "";
          isDone = true;
          Logger.log("importRows:OK");
        }catch(e){
          Logger.log(e);
          if(e.message.lastIndexOf("try again")>0){
            isDone = false;
          }else{
            Logger.log("異常終了");
            return;
          }
        }
      }while(isDone==false);
    }
  }
  Logger.log("importRowsTestA End");
}

function createTable(tableName) {
  var resource = {
  "name": tableName,
  "isExportable": false,
  "kind": "fusiontables#table",
  "columns": [
    {
      "name": "id",
      "type": "NUMBER",
      "kind": "fusiontables#column"
    },
    {
      "name": "name",
      "type": "STRING",
      "kind": "fusiontables#column"
    },
    ],
  };
  return FusionTables.Table.insert(resource).tableId;
}

var shimono = function(){
  var tmp ='';
  for(var i=0;i<100;i++){
    tmp+="下野由貴💛";
  }
  return tmp;
};
```

例によって生成する文字列は「[下野由貴](http://www.hkt48.jp/profile/yuki_shimono.html)💛」の繰り返し。

### 実行してみた

```
[15-08-06 11:35:59:364 JST] importRowsTestA Start
[15-08-06 11:36:01:019 JST] 300.0
[15-08-06 11:36:01:733 JST] importRows:OK
[15-08-06 11:36:01:949 JST] 600.0
[15-08-06 11:36:02:381 JST] Exception: Internal error when processing import.  Please try again.
[15-08-06 11:36:02:809 JST] Exception: Internal error when processing import.  Please try again.
[15-08-06 11:36:03:256 JST] Exception: Internal error when processing import.  Please try again.
[15-08-06 11:36:03:975 JST] importRows:OK
（中略）
[15-08-06 11:37:06:097 JST] 10000.0
[15-08-06 11:37:06:531 JST] Exception: Internal error when processing import.  Please try again.
[15-08-06 11:37:06:881 JST] Exception: Internal error when processing import.  Please try again.
[15-08-06 11:37:07:379 JST] Exception: Internal error when processing import.  Please try again.
[15-08-06 11:37:07:718 JST] Exception: Internal error when processing import.  Please try again.
[15-08-06 11:37:08:092 JST] Exception: Internal error when processing import.  Please try again.
[15-08-06 11:37:08:576 JST] importRows:OK
[15-08-06 11:37:08:576 JST] importRowsTestA End
```

うむ！狙い通り！

・・・どうみても異常系のログですが、僕としてはこれで良いんだ・・・良いんだよね？（弱気）

## 良いわけがない！

ところが、何度か実行してみると、非常に不安定です。ていうか意味わかんないし（逆ギレ）。

今度はQuota Exceededというエラーが頻発します。

[Fusions Tables APIのQuota](https://developers.google.com/fusiontables/docs/v2/using#quota)

ちなみに他のテーブルを作成してそこにデータを挿入しようとしても発生します。

おそらくユーザ単位にQuotaに触れていると想定されますが…明らかに余裕があるはずなのにナゼ！？

### 2度目の実行

```
（略）
[15-08-06 11:48:41:011 JST] 9600.0
[15-08-06 11:48:41:375 JST] Exception: Quota Exceeded
[15-08-06 11:48:41:376 JST] 異常終了
```

### 3度目の実行

```
[15-08-06 11:54:04:660 JST] importRowsTestA Start
[15-08-06 11:54:06:013 JST] 300.0
[15-08-06 11:54:06:718 JST] importRows:OK
[15-08-06 11:54:06:868 JST] 600.0
[15-08-06 11:54:07:201 JST] Exception: Quota Exceeded
[15-08-06 11:54:07:202 JST] 異常終了
```

これが最大の謎。日単位のリクエスト数でQuotaを定めているのであれば、ものすごい矛盾。

### 4度目の実行

```
[15-08-06 11:55:59:732 JST] importRowsTestA Start
[15-08-06 11:56:01:551 JST] 300.0
[15-08-06 11:56:02:099 JST] Exception: Quota Exceeded
[15-08-06 11:56:02:100 JST] 異常終了
```

どうも、[前回のInternal Errorにしても、レスポンスが返って来ない件にしても](http://qiita.com/47monbazooka/items/4c013549bf5b9f661c69#%E5%AE%9F%E8%A1%8C%E7%B5%90%E6%9E%9C%E3%81%AE%E8%A3%9C%E8%B6%B3)、見えない敵と戦ってる感ハンパないっす :cold_sweat: 

## 結論

ぶっちゃけ、ゴリゴリとプログラムするより、以下の手法が一番スマートなのかも知れません。

1. スプレッドシートに挿入対象のデータを作成する
2. そのスプレッドシートをFusion Tablesに変換する（ブラウザ上で）

GASで、スプレッドシートをFusion Tablesに変換することが…できるのかは存じ上げませんが、次回のテーマはそれで。

※ただ、それができたところで実用的かどうかは知りません（笑）