fourside.github.io

郵便番号検索APIを作った

2020/09/08 11:00:00 +00:00

$ curl -s https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/addresses/1000001 | jq .
[
  {
    "zipcode": "1000001",
    "address1": "東京都",
    "address2": "千代田区",
    "address3": "千代田",
    "kana1": "とうきょうと",
    "kana2": "ちよだく",
    "kana3": "ちよだ"
  }
]
  • 元になるデータは zipcloud の加工済み csv ファイル を使った。ありがたく使わせてもらっています
    • zipcloud でも WebAPI を公開してるのだけどなるべく自前でホストしたいと思って実装した

構成

  • いわゆるサーバレス
  • aws-cdk
    • Lambda Function
    • API Gateway
    • DynamoDB
  • ちょこちょこ考えなきゃいけないところがあったのでメモしていきます

DynamoDB のテーブル設計

  • 「データをどう使うか」から設計を始める
  • 郵便番号をキーに検索するので、パーティションキーは郵便番号にする
  • ただし郵便番号はユニークではない。ひとつの郵便番号に複数の住所が紐付くパターンがある
  • ソートキーが必要になるが、ふさわしい CSV のカラムはない
    • 住所1や住所2だと重複するし、住所3だと空文字になる
    • 住所1、住所2、住所3を連結して、ソートキーとした
    • それでさえ重複するケースがあるので、データ投入時にパーティションキー + ソートキーでユニークにする必要がある
      • 例: 0741273 北海道 深川市 音江町

データ投入

  • cdk deploy にからめて実行できればと考えたけど、何度も実行する必要はないのでコマンドを分けた
  • データ量は、ざっくり13万件弱
  • BatchWriteItem
    • 一度に複数レコードを書き込める API を使う
    • ただし25件が上限で、超えると次のエラーメッセージ
      • Member must have length less than or equal to 25, Member must have length greater than or equal to 1
      • 上記ドキュメントにもちゃんと書いてあったね…
      • 13万件 / 25件 で、5200回のリクエストを発行することになる
  • DynamoDBのテーブルの Billing mode をプロビジョニング済み(cdkでのデフォルト)にすると途中で失敗する
    • ProvisionedThroughputExceededException: The level of configured provisioned throughput for the table was exceeded. Consider increasing your provisioning level with the UpdateTable API.
    • オンデマンドにすること
  • DynamoDBに空文字は登録できないので、null に置き換えること
  • 元データは Shift_JIS なので、UTF-8 に変更すること

misc

  • Node.js でのファイルシステムのアクセスで、Stream API を使ってみた
    • 一度にメモリに読み込むより省メモリでよいかと思ったけど、結局読み込んでからユニークにする処理を入れたりで、あんまり意味がなかった…
  • 元々のモチベーションとして、決済機能を補助するものとして作っていて、今回はそのリファインしたもの
    • amplify 内の Lambda Function で実装していて、src ディレクトリ内をごっそりデプロイする形だったので、Lambda から csv を直接読むような形にしていた
      • csv は未ソートだし、ファイルサイズは大きいしで、HTTPリクエスト時にファイル内検索するのはレスポンスが遅くなりすぎる
      • よって csv を事前にソートし、さらに郵便番号の頭2桁をキーにファイル分割するようにした
      • 今考えるとちょっと雑だったかな…

fourside

Written by fourside