Athenaのmigrationやpartitionするathena-adminを作った

awsnode.jsproductprestoetl

https://github.com/sambaiz/athena-admin

AthenaはS3をデータソースとするマネージドなデータ分析基盤。Prestoベースで標準SQLを実行できる。

料金はスキャンしたデータ量にかかり、$5/TB。1MB切り上げで、10MB以下のクエリは10MBになる。 データ量に対してかなり安く使えるものの、フルスキャンしてしまうとBigQueryと同様にお金が溶けてしまうので、大抵はパーティションを切ることになるのだが都度locationを指定して ADD PARTITION を実行するのは大変。さらにスキーマを変更するのにも ALTER TABLE ADD COLUMNS などはないのでテーブルを作り直すことになるが、当然パーティションも全部作り直すことになる。

ではどうしようもないかというと MSCK REPAIR TABLE というのがあって、 これはS3のObjectのdt=YYYY-MM-DDのようなkey=valueのprefixを認識してパーティションを作るもの。作り直す際もこれ1クエリで終わる。それなら最初からそういう風に置けばよいのではというところだが、勝手にYYYY/MM/DD/HHのprefixを付けてしまうFirehoseのようなのもある。

今回作ったathena-adminは以下のような定義ファイルから、 パーティションのkey=valueのprefixが付くように置き換えたり、変更があったらmigrationする。 このファイルを書き換えるだけで基本的にどうにかなるし、バージョン管理すればテーブル定義の変更を追うことができる。

{
  "general": {
    "athenaRegion": "ap-northeast-1",
    "databaseName": "aaaa",
    "saveDefinitionLocation": "s3://saveDefinitionBucket/aaaa.json"
  },
  "tables": {
    "sample_data": {
      "columns": {
        "user_id": "int",
        "value": {
          "score": "int",
          "category": "string"
        } /* "struct<score:int,category:string>" のように書くこともできる */
      },
      "srcLocation": "s3://src/location/",
      "partition": {
        "prePartitionLocation": "s3://pre/partition/", /* optional */
        "regexp": "(\\d{4})/(\\d{2})/(\\d{2})/", /* optional */
        "keys": [
          {
            "name": "dt",
            "type": "string",
            "format": "{1}-{2}-{3}", /* optional */
          }
        ]
      }
    }
  }
}

使い方はこんな感じ。使い方によっては migrate() だけ呼ぶこともあると思う。replaceObjects() にはmatchedHandlerというのを渡すこともできて、UTCからJSTに変換するといったこともできる。

$ npm install athena-admin
const AthenaAdmin = require('athena-admin').AthenaAdmin;
const dbDef = require('./sampledatabase.json');
const admin = new AthenaAdmin(dbDef);
await admin.replaceObjects();
await admin.migrate();
await admin.partition();

追記 (2019-01-01): AWS Glueを使っても同じことができる AWS GlueでCSVを加工しParquetに変換してパーティションを切りAthenaで参照する - sambaiz-net