阿部寛のサイトを高速化する

ちまたで阿部寛のサイトが早いと話題になってます。

dev.toと阿部寛のホームページどっちが速いですか?
dev.toと阿部寛のホームページについてちゃんと計測させてくれ

阿部寛のサイトはベストを尽くしてるのか?
それを調べるために、阿部寛のサイトを高速化させてみたいと思います。

目指すべきスピード

最速はローカルのファイルへのアクセスだと思うのでこれを目指したいと思います。
file:///C:/abe_hiroshi/index.html

9baae75ad17a694cadc9a83081cd4df4.gif

ChromeのDeveloper Toolでレンダリング完了が「173ms」でした。
まぁここまでは無理だな…

阿部寛のサイトはどんなもん?

速度はwebpagetest.orgで測ってみます。

nama.png
レンダリング完了時間は「359ms」です。はえーな

S3でホスティングしてみる

サーバーを立てるほどでもないので、S3でWebホスティングしてそこにhtmlと画像を置いてみます。

s3_1.png
s3_2.png

レンダリング完了時間が「698ms」なんで、まだまだ遅いです。

CDN(CloudFront)でキャッシュする

続いてS3のオブジェクトをCloudFrontでキャッシュしてみる。

cf_1.png
cf_2.png

レンダリング完了時間が「379ms」になりました。
やはりCDNは効果絶大です。

Webpを使ってみる

dev.toではCloudinaryという画像ホスティングサイトを使用しており
画像をアップロードすると様々なフォーマットで利用できるようになります。

dev.toでも使用している「Webp」というJPG/PNGよりも圧縮に優れたフォーマットで
大幅なサイズ削減を実現してくれます。
サイズ削減できれば高速化できるはず。早速試してみます。

画像の返還作業は、Cloudinaryでこんな感じの画面で行えます。
webp.png

普通の画像サイズ
http://abehiroshi.s3-website-ap-northeast-1.amazonaws.com/image/abe-top2-4.jpg
64KB

cloudinaryでwebpに変更してみると
https://res.cloudinary.com/morix1500/image/upload/v1510926252/abe-top2-4_n99mu2.webp
18.9KB

cloudinaryのURLをhtmlに埋め込んで計測してみます。
webp_1.png
webp_2.png

はい、全部Aになりました。
しかし、レンダリング完了時間が「1.337s」と遅くなった…なぜでしょう?

このページではHTTP2が有効になってます。
同一ドメインでないと余計なコネクションが発生してしまうのではないかと推測し、
同一ドメインに画像を置いてみることにします。(間違えてたらご指摘おねがいします)

ということでCloudinaryから直接画像を読み込むのではなく、WebpをダウンロードしてS3に配置してみます。
webp_3.png

お、「328ms」になりました。
また読み込みバイト数も「70KB」から「18KB」になりました。
これはいい感じですね。

これで阿部寛サイトを超えることができました!

結論

以下の技術を使用すれば既存の阿部寛サイトを凌駕することが出来ました。
* S3でホスティング
* CDN(CloudFront)でキャッシュ
* HTTP2
* Webp

ここまでしないと超えられない既存サイト…恐ろしい。
Service Workerも使ってみたかったですが、それは今度の機会に。

では!

続きを読む

CloudFrontの署名付きURLをRubyで発行する

概要

画像コンテンツを扱うアプリのバックエンドをRails/EC2/S3/CloudFrontで作った。
コンテンツ保護のためCloudFrontの署名付きURLを使ったが、何やらAWSのSDKとやらが必要だったのでそのメモ。

前提

S3/CloudFrontの設定と署名用のキーペアの作成が終わっていること。
下記を参考にさせてもらったらバッチリできた。

CloudFront+S3で署名付きURLでプライベートコンテンツを配信する
https://dev.classmethod.jp/cloud/aws/cf-s3-deliveries-use-signurl/

しかし、肝心の署名付きURLの発行しようとしたらRubyのサンプルがなくて詰んだ。
泣きながら初心者なりに試行錯誤して見ると一応動いた。

やったこと

AWS SDK をGemで追加して

Gemfile
gem 'aws-sdk-cloudfront'

キーペアのIDとダウンロードした秘密鍵を指定し、署名付きURLを発行する。

url_signer.rb
signer = Aws::CloudFront::UrlSigner.new
  key_pair_id:      "APKA9ONS7QCOWEXAMPLE", # 鍵ID
  private_key_path: "tmp/pk-cloudfront.pem" # 鍵ファイル
)
# 5分間有効な署名付きURLを発行
signed_url = signer.signed_url(
  "https://d111111abcdef8.cloudfront.net/images/image.jpg",
  expires: Time.now.getutc + 5.minute
)

# 発行された署名付きURL
# signed_url = https://d111111abcdef8.cloudfront.net/images/image.jpg?Expires=123456789&Signature=nitfHRCrtziwO2HwPfWw~yYDhUF5EwRunQA-j19DzZrvDh6hQ73lDx~-ar3UocvvRQVw6EkC~GdpGQyyOSKQim-TxAnW7d8F5Kkai9HVx0FIu-5jcQb0UEmatEXAMPLE3ReXySpLSMj0yCd3ZAB4UcBCAqEijkytL6f3fVYNGQI6&Key-Pair-Id=APKA9ONS7QCOWEXAMPLE

これだけだ。

発行したURLでアクセスするとちゃんとコンテンツにアクセスできたし、有効期間(5分)が過ぎた後はちゃんとアクセスが拒否された。
ちなみにexpiresではなくpolicyも指定できるので、もっと複雑な条件も指定できるらしい。

参考

続きを読む

[S3]クロスアカウント時のアップロード時の権限エラー[はまった]

コンニチハ、千葉です。 S3のクロスアカウント環境を構築したのですが、クロスアカウント上でアップロードしたファイルをダウンロードしたとろこと権限エラー(Access Denied)になってはまったので記しておきます。 事 […] 続きを読む

カテゴリー 未分類 | タグ

terraform管理下にないインフラをterraformingしようとする場合に遭遇しやすい(?)Plan error : Resource ‘data.terraform_remote_state.not_immutable’ does not have attribute ‘vpc-xxx-yyy’ for variable ‘data.terraform_remote_state.not_immutable.vpc-xxx-yyy’

TL;DR

terraform管理下にないインフラをterraformingしようとする場合、
いわゆるStagingなどと呼ばれる環境で本番稼働環境を再現してから、本番環境に適用したいと思うわけです。
VPCやSubnetのような、壊すと大変なnot immutableなりソースはterraform importを駆使して、現行環境を壊さないよう、そーーーっとterraform管理下に引き込みます。(いずれQiita書く)
そしていざimmutableなりソースを–targetオプションを使いながら、ひとつひとつ本番環境に適用する際に遭遇しがちな下記エラー

$ terraform plan -out=apply.plan --target=module.compute.hoge.fuga

..(snip)..

Error: Error running plan: 1 error(s) occurred:

* module.compute.var.vpc-xxx-yyy: Resource 'data.terraform_remote_state.not_immutable' does not have attribute 'vpc-xxx-yyy' for variable 'data.terraform_remote_state.not_immutable.vpc-xxx-yyy'

を(強引に)解決するお話。

issueもあがっております。
https://github.com/hashicorp/terraform/issues/12316

環境

$ terraform version
Terraform v0.10.8

ディレクトリ構成

Terraform Best Practices in 2017

immutableなリソースから、VPCなどのnot immutableなリソースのremote stateを参照しています。

backend.tf
data "terraform_remote_state" "not_immutable" {
  backend = "s3"
  config {
    bucket = "bucket_name"
    key    = "env:/${terraform.env}/tfstate/not_immutable/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

対処方法

必要なresource定義を、手で書く or Stagingなどのterraform化検証環境のtfstateからコピペして、リソースIDを本番環境のものに書き換える

まずは最新のtfstateをremoteからpull。

$ terraform state pull > ./terraform.tfstate.d/$(terraform workspace show)/terraform.tfstate

./terraform.tfstate.d/$(terraform workspace show)/terraform.tfstate
に必要なリソースを追記。

terraform.tfstateより抜粋
            "resources": {
                "data.terraform_remote_state.not_immutable": {
                    "type": "terraform_remote_state",
                    "depends_on": [],
                    "primary": {
                        "id": "2017-11-15 02:25:07.174946468 +0000 UTC",
                        "attributes": {
                            "backend": "s3",
            ..(snip)..
                            "config.%": "3",
                            "config.bucket": "bucket_name",
                            "config.key": "env:/prod/tfstate/not_immutable/terraform.tfstate",
                            "config.region": "ap-northeast-1",
                            "environment": "default",
                            "id": "2017-11-15 02:25:07.174946468 +0000 UTC",
                            "vpc-xxx-yyy.%": "5",
### 今回はここから
                            "vpc-xxx-yyy.subnet-private-a": "subnet-pra",
                            "vpc-xxx-yyy.subnet-private-c": "subnet-prc",
                            "vpc-xxx-yyy.subnet-public-a": "subnet-pua",
                            "vpc-xxx-yyy.subnet-public-c": "subnet-puc",
                            "vpc-xxx-yyy.vpc_id": "vpc-xxx-yyy-id"
### ここまでのresource idを本番環境のものに書き換えました。
                        },
                        "meta": {},
                        "tainted": false
                    },
                    "deposed": [],
                    "provider": ""
                }
            },

tfstateをremoteへpush。

$ terraform state push ./terraform.tfstate.d/$(terraform workspace show)/terraform.tfstate

そして再度terraform plan。

$ terraform plan -out=apply.plan --target=module.compute.hoge.fuga

..(snip)..

Plan: X to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

This plan was saved to: apply.plan

To perform exactly these actions, run the following command to apply:
    terraform apply "apply.plan"

エラーは消えました。
めでたしめでたし。

続きを読む

RddshiftからS3へUNLOADする

S3へ書き出したDynamoDBデータをRedshiftへコピーする [Copyコマンドについて]の逆をする。

UNLOADコマンドを使用する際の個人的な確認用まとめ

構文(抜粋)

UNLOAD ('select-statement')
TO 's3://object-path/name-prefix'
authorization
[ option [ ... ] ]

where option is

{ MANIFEST
| DELIMITER [ AS ] 'delimiter-char' 
| FIXEDWIDTH [ AS ] 'fixedwidth-spec' }  
| ENCRYPTED
| BZIP2  
| GZIP     
| ADDQUOTES 
| NULL [ AS ] 'null-string'
| ESCAPE
| ALLOWOVERWRITE
| PARALLEL [ { ON | TRUE } | { OFF | FALSE } ]
[ MAXFILESIZE [AS] max-size [ MB | GB ] ]

相変わらずわかりにくい構文っすよね。。。

簡単なサンプル

sample
UNLOAD ('SELECT * FROM test;')
TO 's3://mybucket_name/target_dir/'
CREDENTIALS 'aws_access_key_id=<キー>;aws_secret_access_key=<シークレットキー>'
MANIFEST
DELIMITER AS 't'
GZIP
ALLOWOVERWRITE

UNLOAD (‘select-statement’)

SQL文を書く。途中で '' を使用したい場合はちゃんとエスケープすること ''

TO ‘s3://object-path/name-prefix’

出力先のS3を指定する。
object-path 配下に name-prefixXXXXXXXXXXXX で作成される。

CREDENTIALS

COPYにも書いたけどIAMなりクレデンシャルキーなり指定する

オプション指定

一覧
MANIFEST
DELIMITER [ AS ] 'delimiter-char' 
FIXEDWIDTH [ AS ] 'fixedwidth-spec' }  
ENCRYPTED
BZIP2  
GZIP     
ADDQUOTES 
NULL [ AS ] 'null-string'
ESCAPE
ALLOWOVERWRITE
PARALLEL [ { ON | TRUE } | { OFF | FALSE } ]
MAXFILESIZE [AS] max-size [ MB | GB ] ]

幾つかかいつまんで

MANIFEST

UNLOAD プロセスによって作成されたデータファイルを明示的にリストするマニフェストファイルを作成します。

DELIMITER

パイプ文字 (|)、カンマ (,)、タブ (t) など、出力ファイル内のフィールドを分離する単一の ASCII 文字。デフォルトの区切り文字はパイプ文字です。

BZIP2/GZIP

出力時に圧縮して出力する

ADDQUOTES

アンロードされた各データフィールドは引用符で囲まれるため、Amazon Redshift は区切り文字自体を含んでいるデータ値をアンロードすることができます。

出力データに区切り文字が含まれている場合、カラム毎に ”” で囲んで出力してくれる機能
読み込み時の使い方に寄る。

NULL AS ‘null-string’

NULL文字の置き換え

ALLOWOVERWRITE

デフォルトでは、UNLOAD によってファイルの上書きが発生する可能性がある場合、その UNLOAD 操作は失敗します。ALLOWOVERWRITE が指定された場合、UNLOAD によって、マニフェストファイルを含めた既存のファイルが上書きされます。

ファイルが存在すると上書き禁止でエラー終了する。
これを指定すると上書きする。

MAXFILESIZE AS 最大サイズ [ MB | GB ]

Amazon S3 で作成された UNLOAD ファイルの最大サイズ。5 MB ~ 6.2 GB の十進値を指定します。AS キーワードはオプションです。デフォルト単位は MB です。MAXFILESIZE を指定しない場合、デフォルトの最大ファイルサイズは 6.2 GB です。

マニフェストファイルが使用されている場合、このサイズは MAXFILESIZE に影響されません。

LIMIT

SELECT クエリは、外部の SELECT で LIMIT 句を使用することはできません。その代わり、ネスティングされた LIMIT 句を使用してください。

sample
SELECT 
 * 
FROM 
 test 
WHERE id IN (
  SELECT 
   id
  FROM 
   test
  LIMIT 100
);

こんな感じにしろとのこと。

参考

UNLOAD

続きを読む

Apexを使ってgoでAWS Lambda functionを作ってみる

はじめに

AWS Lambdaの管理ツールであるApexを使ってgoを実行する
LambdaFunctionの作り方と使い方のメモ。
割とapex.run に載ってる内容ではありますがが。

AWS Lambdaとは

いわゆるサーバーレスアーキテクチャの一種でFaas(Function as a Service)
公式

  • コードをアップするとAWSInfra上でサーバー用意したり、プロビジョニングしなくても実行する事ができるコンピューティングサービス。

    • 現状はjs,java,c#,pythonなどをサポートしてる(近々goもやるらしい)
    • apexだとNodeでgoを実行してくれるのでgoもいける
  • AWS内の他サービスで定義されたトリガーに紐付けてpubsubみたいな事もできる

    • s3,dynamoの変更通知を受け取ってゴニョゴニョしてあげたり、code deployのデプロイ完了のトリガーを使ってなにがし、みたいに。

簡単に言うとLambdaでサポートしてる言語なら、デプロイとか実行環境整備したりとか不要でEC2インスタンスわざわざ立てなくても
実行できるし、他のAWSサービスと連携しやすいよって感じ。

ウェブサーバーやバッチサーバーみたいなIaasを必要とするようなものではなく、イベントに引っ掛けて
ちょっとした処理をするくらいのものに使うのがいい感じ

インストール

apexのインストール

curl https://raw.githubusercontent.com/apex/apex/master/install.sh | sh

awscliのインストール

aws使うなら入れてる人が大半だと思いますが
apexの動作にaws credentialが必要なので…

公式の引用

curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo pip install awscli

sixの依存関係errorが出る場合は

 sudo pip install --ignore-installed awscli

あたりで無視しちゃうと早いです。

credentialの設定

公式の引用。
regionは自分の使ってるもので。

$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE #
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-2
Default output format [None]: json

プロジェクト作成

apex cliで雛形作成ができるのでサクッと作ってしまいましょう。

$ mkdir your_lambda_function_dir
$ cd your_lambda_function_dir
$ apex init

             _    ____  _______  __
            /   |  _ | ____ / /
           / _  | |_) |  _|    /
          / ___ |  __/| |___ /  
         /_/   __|   |_____/_/_

  Enter the name of your project. It should be machine-friendly, as this
  is used to prefix your functions in Lambda.

    Project name: xxx_notify

  Enter an optional description of your project.

    Project description: notification for xxx

  [+] creating IAM xxxx_function role
  [+] creating IAM xxxxx policy
  [+] attaching policy to lambda_function role.
  [+] creating ./project.json
  [+] creating ./functions

  Setup complete, deploy those functions!

    $ apex deploy

テンプレートな構成を作ってくれます。
terraform使ってない場合はIAMを求められるので、作るor指定が必要。

 tree
.
├── functions
│   └── hello
│       └── index.js
└── project.json

goでコードを書く

特にgoを使うための細かな設定などは不要です。apexできる子。
今回は受け取ったsnsのbodyをsqsに投稿するサンプルを。

  • .apexignoreでdeployしないファイルを指定する(バイナリをあげれば良いので*.goは無視)
cat .apexignore
*.go
  • snsで受け取ったbodyをsqsに送るコードを書く
import (
    "bytes"
    "encoding/json"
    "strings"

    apex "github.com/apex/go-apex"
    apexSns "github.com/apex/go-apex/sns"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
    "github.com/aws/aws-sdk-go/service/sqs"
)

func main() {
    apexSns.HandleFunc(func(event *apexSns.Event, ctx *apex.Context) error {
        body := event.Records[0].SNS.Message
        //bodyをsqsに送るよ
        awscli := sqs.New(sess, &aws.Config{Region: aws.String("ap-northeast-1")})
        queueUrl := "your_sqs_queue_url"
        params := &sqs.SendMessageInput{
            QueueUrl:    &queueUrl,
            MessageBody: &body,
        }
        _, err = awscli.SendMessage(params)
        return err
    })
}

こんな感じ。
apexでのgo実行は、プロセス立ち上げてnodeでgoのバイナリを実行してるだけなので
importとかはローカルで解決してれば大丈夫です。

aws-sdk-goがいい感じにIAMの権限を使ってくれるので
403とか出る場合はlambdaを実行するIAMのロールにsqsのアクセス権を与えてあげてください。

イメージ湧きづらい場合は
公式をみると良いです。

deployと実行

  • deploy
apex deploy function_name
  • 実行
apex invoke function_name
  • logを見る
apex logs function_name -f
/aws/lambda/*** 2017-11-15T06:05:30.238Z    fb0b2dbb-c9ca-11e7-afc4-6762e3c5815e    {"errorMessage":"hoge"} // handlerFuncで返したerrがprintされる
/aws/lambda/*** END RequestId: fb0b2dbb-c9ca-11e7-afc4-6762e3c5815e
/aws/lambda/*** REPORT RequestId: fb0b2dbb-c9ca-11e7-afc4-6762e3c5815e  Duration: 936.31 ms Billed Duration: 1000 ms    Memory Size: 128 MB M

[応用] vpc内のリソースにアクセスする

公式のやり方でもいいし、
package json に以下を追加する感じでもおkです

{
  "vpc": {
    "securityGroups": ["xxx"],
    "subnets": ["aaaa", "bbbb"]
  }
}

続きを読む

boto3が~/.aws/credentialsのaws_session_tokenを見ないで毎回`Enter MFA code:`と聞いてくるのをなんとかする方法

はじめに

AWSのroleを使っていてMFAが設定してあり、boto3を使いつつLocal環境開発時の鬱陶しさ軽減の話です。

※ よく見ると ISSUE: https://github.com/boto/botocore/issues/1126 になっていますね。いずれ修正されるのでしょう。

Version

  • boto3==1.4.4
  • botocore==1.5.7

ちょっと古いです。

内容

Pythonのboto3ライブラリは、AWS操作の鉄板ライブラリです。
認証の時にCredentialを色々な箇所から自動的に取得してくれますが、
~/.aws/configrole_arnmfa_serial があると、~/.aws/credentials にキーを設定してあってもその前にAssumeRoleProviderが発動し、Enter MFA code: というプロンプトを表示してMFAの入力を求められてしまいます。

ソースコード を見ると、

  • EnvProvider
  • AssumeRoleProvider
  • SharedCredentialProvider

の順にCredentialをチェックして、AssumeRoleProvider の時にこのプロンプトを表示します。
別途事前にassume-roleを実行していてファイル~/.aws/credentialsに書いてある場合はこの手順はスキップしたいです。

以下のようにするととりあえずできます。

sample.py
from botocore.session import get_session
from boto3.session import Session

bc_session = get_session()
session = Session(botocore_session=bc_session, profile_name="<your profile name>")
cred_resolver = bc_session.get_component('credential_provider')  # type: CredentialResolver

# set assume-role after shared-credentials-file
assume_role = cred_resolver.get_provider("assume-role")
cred_resolver.remove("assume-role")
cred_resolver.insert_after('shared-credentials-file', assume_role)

#
s3 = session.resource("s3")

# for testing
for bucket in s3.buckets.all():
    print(bucket.name)

ちなみにprofile_name の部分は、環境変数AWS_PROFILE で指定してあれば省略可能です。

さいごに

小技でした。

続きを読む

S3へ書き出したDynamoDBデータをRedshiftへコピーする [Copyコマンドについて]

S3へ書き出したDynamoDBのデータをRedshifへ取り込む際、指定方法がいろいろあったりして自分でも忘れやすいのでメモ

ここで打つコマンドはRedshfitコマンドであり、psqlコマンドとは異なる。

構文(抜粋)

COPY table-name 
[ column-list ]
FROM data_source
authorization
[ [ FORMAT ] [ AS ] data_format ] 
[ parameter [ argument ] [, ... ] ]

table-name

テーブルはすでにデータベースに存在する必要があります。テーブルは一時テーブルまたは永続的テーブルです。COPY コマンドは、新しい入力データをテーブルの既存の行に追加します。

FROM data_source

ターゲットテーブルにロードするソースデータの場所

  • S3

    • FROM ‘s3://mybucket_name/target_dir/’
  • DynamoDB

    • FROM ‘dynamodb://table-name’
  • EMR

    • FROM ‘emr://emr_cluster_id/hdfs_filepath’

CREDENTIALの指定

S3やDynamoDBから引っ張ってくるときはクレデンシャルの指定が必要

  • AWS_CLIのキーを使用: 'aws_access_key_id=<キー>;aws_secret_access_key=<シークレットキー>'
  • IAM_Roleを使用: 'arn:aws:iam::<aws-account-id>:role/<role-name>'

オプション

列のマッピングオプション

  • 列リスト

    • COPY tablenem の後に、列をリストで列挙する方法

ソースデータフィールドを特定のターゲット列にロードするには、列名のカンマ区切りリストを指定します。COPY ステートメントで列は任意の順序に指定できますが、Amazon S3 バケットなどにあるフラットファイルからロードする場合、ソースデータの順序に一致する必要があります。Amazon DynamoDB テーブルからロードする場合、順序は関係ありません

COPY sample (id, name, age)
  • JSONPaths ファイル

    • ソースデータの列情報をJSONファイルで記述し、S3に置いておく方法

データファイルを JSON または Avro 形式でロードする場合、COPY は Avro スキーマのフィールド名をターゲットテーブルまたは列リストの列名と一致させることで、JSON または Avro ソースデータのデータ要素をターゲットテーブルに自動的にマッピングします。

基本的にこっちを使っている。

JSONPath式

jsonpaths.json
{
    "jsonpaths": [ // 個々の記述は固定
        "$['venuename']", // 各列情報を"$['列名']で記載
        "$['venuecity']",
        "$['venuestate']",
        "$['venueseats']"
    ]
}

S3に書き出したDynamoDBの場合、 "$['カラム名']['型']", の形式で記載する。
項目の個数はCOPY先のテーブルに合わせなければならない

余談:
jsonpaths.jsonで指定したカラム数が7でCOPY先のテーブルのカラム数が8といったカラム数に差がある場合、下記のようなエラーがでる。

err
 error:  Number of jsonpaths and the number of columns should match. JSONPath size: 7, Number of columns in table or column list: 8

DynamoDBには確実に存在しないカラムであっても、Redshift側のテーブルにカラムが存在する場合、jsonpaths.jsonにそのカラムを指定し、COPY先のテーブルとカラム設定をあわせておけば
COPYを実行することが出来る。その際、DynamoDBに存在しないカラムのデータについては NULL で取り込む。指定した値で取り込むといった事がオプション指定で可能である。

取り込むテーブルとJSONのカラム数合わせろ、そこだけ確認しろ、自分。

データ形式パラメータ

  • FORMAT AS json

    • jsonpathsファイルを指定する方法

      • FORMAT AS json ‘s3://mybucket_name/target_dir/jsonpaths.json’
  • DELIMITER [AS] [‘delimiter_char’]

    • csv,tsv形式等を任意の区切り文字を指定して取り込む

      • DELIMITER AS ‘\t’
  • FIXEDWIDTH ‘fixedwidth_spec’

    • 固定長の場合に使用(ワタシは使用したこと無い。)

      • FIXEDWIDTH ‘colLabel1:colWidth1,colLabel:colWidth2, …’
  • BZIP2/GZIP/LZOP

    • 取り込むデータがどんな圧縮をされているかを指定する。gzip圧縮されていてもそのまま取り込むことが出来る。

データ変換パラメータ

テーブルをロードする際に、COPY は暗黙的にソースデータの文字列をターゲット列のデータ型に変換しようとします。デフォルトの動作とは異なる変換を指定する必要がある場合、またはデフォルトの変換がエラーになった場合、次のパラメータを指定してデータ変換を管理できます。

ここは使ったことがあるのと無いのがある。

一覧
ACCEPTANYDATE
ACCEPTINVCHARS
BLANKSASNULL
DATEFORMAT
EMPTYASNULL
ENCODING
ESCAPE
EXPLICIT_IDS
FILLRECORD
IGNOREBLANKLINES
IGNOREHEADER
NULL AS
REMOVEQUOTES
ROUNDEC
TIMEFORMAT
TRIMBLANKS
TRUNCATECOLUMNS

幾つか使うやつの抜粋

  • BLANKSASNUL

NULL など、空白文字のみから構成される空のフィールドをロードします。このオプションは CHAR と VARCHAR の列にのみ適用されます。INT など、他のデータ型の空のフィールドは常に NULL でロードされます。

  • EMPTYASNULL

Amazon Redshift で CHAR と VARCHAR の空のフィールドを NULL としてロードすることを指定します。INT など、他のデータ型の空のフィールドは常に NULL でロードされます。

  • IGNOREHEADER [ AS ] number_rows

指定された number_rows をファイルヘッダーとして扱い、ロードされせん。

  • NULL AS ‘null_string’

null_string に一致するフィールドを NULL としてロードします。

マニュフェストファイル

Datapipeline等を使用する場合、マニュフェストファイルが生成されます。
それを使用して取り込む場合に指定する。

  • manifest

manifest を指定する場合は、FORMAT でマニュフェストファイルを指定する。

サンプル

S3からCOPY

sample
COPY table
FROM 's3://mybucket_name/target_dir/' 
CREDENTIALS 'aws_access_key_id=<キー>;aws_secret_access_key=<シークレットキー>'
FORMAT AS json 's3://mybucket_name/target_dir/jsonpaths.json'
GZIP;

DynamoDBからCOPY

sample
COPY table 
FROM 'dynamodb://table_name' 
CREDENTIALS 'aws_access_key_id=<キー>;aws_secret_access_key=<シークレットキー>'
readratio 0.7;

readratio は確保されたキャパシティに対して使用する割合

マニュフェストファイルを使用した取り込み

COPY table
FROM 's3://mybucket_name/target_dir/manifest'
CREDENTIALS 'aws_access_key_id=<キー>;aws_secret_access_key=<シークレットキー>'
FORMAT AS json 's3://mybucket_name/target_dir/jsonpaths.json'
manifest;

資料

COPY

続きを読む