Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

メルカリ カウルのマスタデータの更新

654 views

Published on

golang.tokyo#10で発表した資料です。
https://golangtokyo.connpass.com/event/70162/

Published in: Technology
  • Be the first to comment

メルカリ カウルのマスタデータの更新

  1. 1. The Go gopher was designed by Renée French. The gopher stickers was made by Takuya Ueda. Licensed under the Creative Commons 3.0 Attributions license. メルカリ カウルの マスタデータの更新 2017年11月14日(火) @golang.tokyo #10
  2. 2. 自己紹介 上田拓也 @tenntenn 所属 コミュニティ活動 & Go ビギナーズ Go Conference 上田拓也 @tenntenn 2
  3. 3. ソウゾウ エキスパートチーム 技術をアウトプットするところに技術は集まる ■ エキスパートチームとは? ● 50%以上の時間を技術コミュニティへの貢献に充てる ■ エキスパートチームの役割 ● 社内に新しい技術を取り取り込む ● 社外のコミュニティなどを通じて社会へ還元する ■ エキスパートチームの活動 ● カンファレンス・勉強会の開催/運営 ● 対外的な講演活動 ● 執筆、雑誌への寄稿、インタビュー ● 社内外での担当技術の普及推進 @tenntenn 担当:Go・GCP @mhidaka 担当:Android メンバー 3
  4. 4. アジェンダ ■ メルカリ カウルのマスタデータ ■ 大きなファイルを処理する ■ バイト列を変換する 4
  5. 5. メルカリ カウルのマスタデータ 5
  6. 6. Google App Engineを採用 6 https://goo.gl/ZzHDoW
  7. 7. メルカリ カウルのマスタデータ 7 ■ 製品のカタログ情報 ● 本、CD・DVD、ゲーム ● 外部のデータを利用している ■ 毎日の更新バッチにて更新している ● データ提供元から毎日データをバッチで取得している ● データの提供形式はデータの種類によって違う ○ JSONやTSVなど ■ Cloud SQL (MySQL)にて管理 ● スケールする必要のない低いマスタデータはRDBで管理 ● スケールする必要のあるデータはCloud Datastoreで管理
  8. 8. マスタデータ更新の例 8
  9. 9. 大きなファイルを分割して処理する 9
  10. 10. マスタデータの更新 10 ■ TSV形式 ● 1行がRDBの1レコードを表す ● 大きいものは1ファイルが50MB以上 ■ Google Cloud Storage(GCS)に保存 ● 1日1回データ提供元から取得したデータをGCSに保存 ● 1日あたり十数個のTSVがGCS上に置かれる ■ Google App Engine(GAE)のcronジョブで更新 ● 定期的にTSVを取得し、RDBへデータを更新する ※ すべてのマスタデータがこうなっているわけではない ID 製品名 発売日 発売元 001 ほげ 2017年11月14日 会社A 002 ふが 2017年11月13日 会社B
  11. 11. 大きなファイルを扱う問題点 ■ URL Fetchの制限 ● Google Cloud StorageにURL Fetch経由で接続 ● 32MB以上のファイルを一気に読めない ■ 分割して処理する必要がある ● どのように分割するのか? ● 一度メモリ上に確保して分割しても意味がない ● 固定長で分割していくしかない 11
  12. 12. 大きなファイルを処理する 12 ■ Task Queueを使う ● 更新順序に決まりがない ● 不要な外部キー制約を外す ● 冪等性を担保する ■ オフセットを指定して読み込む ● Google Clous StrageのRangeReaderの機能を使う ● 固定長に分割して処理する
  13. 13. Task Queueによる処理 13
  14. 14. TSVを分割する方法 14 ■ 固定長で分割する ● RDBにいれるデータなので1行のサイズの最大がおおよそ分かる ● 1レコードの最大サイズ+バッファで分割する ■ 1行ずつ処理する ● 固定長で分割するので行をまたぐ可能性がある ● 固定長に分割する際に若干被るように分割する ● 改行がくるまでバッファ分をはみ出て処理する ● 頭の部分は改行がくるまで読み飛ばす 001tほげt2017年11月14日t会社An 002tふがt2017年11月13日t会社Bn ...
  15. 15. バイト列を変換する 15
  16. 16. マスタデータの変換 16 ■ 変換の必要性 ● データ提供元の形式がUTF-8とは限らない ● アプリ上で表示できるものとは限らない ○ 外字などを利用している場合 ● データ提供元のデータを改変して保存するわけにはいかない ○ 実行時に動的に変換する必要がある
  17. 17. 文字コードの変換 17 ■ x/text/encoding/japaneseを使う ● SJISやEUP-JPなどの文字コードに対応 func main() { dec := japanese.ShiftJIS.NewDecoder() r := transform.NewReader(os.Stdin, dec) io.Copy(os.Stdout, r) } $ echo "ごーふぁー" | nkf --sjis | go run sjis.go ごーふぁー
  18. 18. Reader x/text/transfomを用いる ■ transform.Transformerインタフェース ● ReaderとWriterを提供している ● 既存のReaderとWriterをラップし、間で変換を行う ● x/transform/encoding.Encoderも実装している 18 Reader Transformer Writer Transformer Writer Read Write
  19. 19. Transformerを実装する ■ 実装はなかなか難しい ● 出力と入力で長さが違うかもしれない ● 出力と入力のバッファのサイズが足りないかもしれない ● EOFがくるかもしれない ● テストをしっかり行おう 19 type Transformer interface { Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) Reset() }
  20. 20. 詳しくはAdvent Calendarで!! 20
  21. 21. バイト列の置換 ■ Replacer ● https://godoc.org/github.com/tenntenn/text/transform ● Transformerを実装 ● 任意のバイト列を任意のバイト列に変換可能 21 func ExampleReplaceTable() { t := ReplaceStringTable{ "Hello", "Hi", "World", "Gophers", } r := transform.NewReader(strings.NewReader("Hello, World"), ReplaceAll(t)) io.Copy(os.Stdout, r) // Output: Hi, Gophers }
  22. 22. まとめ 22 ■ 大きなファイルを処理する ● うまく分割し、並列に処理してやる ● 途中で変更するのは大変なので先にやっておくと良い ■ バイト列を変換する ● x/text/transformパッケージを用いる ● transform.Transformerの実装は難しい ● テストをしっかり行おう
  23. 23. Thank you! twitter: @tenntenn Qiita: tenntenn connpass: tenntenn 23

×