4社のデータ基盤開発に携わって得たベストプラクティス

最近はデータサイエンティストとして働いているため、データエンジニア時代に得た知見を備忘録として残す。 データ流入量が1TB/日以下、DWHの利用者が1000人以下の現場を想定している。それ以上の大規模組織には以下の話は当てはまらない場合が多そう。 1. DWHにはBigQueryを使う 2023年時点だとDWHの選択肢はBigQuery,RedShift,Snowflakeの3択だと思う。 が、機能、コスト、運用の簡単さ、分析ツールのエコシステムの充実具合など、どの面を見てもBigQuery以外を選択する余地は今のところないように感じる。 詳細な比較に関してはいろいろな人が言っているので割愛するが、マルチクラウド構成にしてまでもBigQueryを選定する価値はある。 アプリケーションがAWSだからという理由でRedShiftやSnowflake on AWSを選定し、結局後から大変な手間をかけてBigQueryに移行したというのはよく聞く。 2. ETLよりELT コスト的な理想としてはETLで必要十分なデータマートを用意していければいいが、絶対といっていいほどうまくいかない。 分析のニーズは事業の変化に応じて変わっていくし、データソースとなるプロダクトも成長に伴って変化していく。 ETLの問題点は弾力性が無く、障害やカラム追加依頼などの度に過去データを入れ直したりと運用コストが高すぎる点にある。 ペタバイト単位のデータでもない限りはBigQueryに課金してELTにしたほうが良い。人的コストに比べれば圧倒的に安い。 3. データマートの前にまずはビューで提供する 前述の通りデータソースもデータマートの要求仕様も刻々と変わる。そのためデータマートを作る前にまずは変更コストの低いビューでリリースしたほうがいい。 クエリコスト的に厳しければマテリアライズドビューで中間テーブルを作り、データを圧縮できるか試す。 データマートは最終手段と捉えておいたほうが良い。 4. 分析で生データを直接触らない RDBから転送したデータをSQLで加工し、BIツールでダッシュボード化、というのはよくある使い方だ。 ではRDBにALTER TABLEがかかるとどうなるかというと、このテーブルを参照しているのはどいつなんだという影響調査が必要になる。 きちんと用途別にServiceAccountを使い分けていればINFORMATION_SCHEMAで大体の特定は可能だが、いずれにしろかなりの量のSQLの修正が必要になる。 適切なモデリングを行ったビューを用意しておき、そのビューだけを分析に使うという運用にするとビューが腐敗防止層として働いてくれる。 データソース側の仕様変更があってもビューで隠蔽すれば分析側に影響せず、圧倒的にトータルの運用コストが下がる。ビューの設計が適切であれば分析の難易度も格段に下がる。 生データを格納するデータセットのアクセス権はデータエンジニアだけが持っているというレベルでいいと思う。 5. データマート/ビューの規約を決める につながる話として、元データの仕様がバラバラであっても腐敗防止層があればインターフェースの仕様は統一できる。せっかくなのでテーブルの統一仕様を決めたほうが良い。 例として以下のようなルールを厳守するようにしておくと後々幸せになれる (日本企業の場合) JSTの時刻データはDATETIME型にする。それ以外のタイムゾーンはUTCに変換してTIMESTAMP型にする 6. データマート/ビューは最小限にする 分析を簡単にするという目的でビジネスロジックを盛り込んだデータマート/ビューを用意していくと、結局分析サイドは仕様を把握しきれずデータカタログやドキュメントをもっと整備してほしいという話になってくる。 こうなってくるといくら人手があっても足りないので、分析用に提供するデータマート/ビューはビジネスで取り扱うエンティティに対応したマスターデータ・トランザクションデータだけにしたほうが良い。 非正規化にはこだわらずにアトミックにしたほうがよい。多少クエリコストがかかろうとも結局それが分析側の学習コストを下げ、分析コードの可読性は上がり、トータルで見るとコスト抑制になる。 7. データ基盤を凝りすぎたアーキテクチャにしない データ基盤は社内システムであり、データエンジニアは間接部門に属する事が多い。 そのためふんだんにコストが投入されることは珍しく、基本的にはどこも常に人手不足だと思う。 更に大学にデータサイエンス学部などが創設されてデータサイエンティストは増え続ける一方だが、データエンジニアを目指す人はレアであり需要増に対して供給が全く足りていない。 新規開発時にはイメージされづらいが何年か経つと少数のデータエンジニアで大量の依頼を捌いていくことになり、分析PJは「データ連携待ち」「データエンジニア調査待ち」のステータスで溜まっていく。 なので組織のデータエンジニアのレベルが高かったとしても基盤はできるだけ学習コストが低い作りにして、業務委託などでスケールできるようにしておいたほうがよい。 最近はBigQuery周りの色々が進化しまくっているので、大体の場合は以下の構築パターンでいいんじゃないかと思う。 RDBデータ連携 Datastream スピードレイヤー Pub/Subに入れてBigQueryサブスクリプション(docs) バッチレイヤー GCS → Data Transfer データマート生成 SQLで完結するならDataflow しないものはワークフローエンジン行き ワークフローエンジンの選定に関しては一概に言えない。(大体の場合マネージドAirflowで良いとは思う) 8. データ品質の監視をする バッチジョブのエラーやマシンリソースの監視は大体どこもやっているだろうが、データの品質についての監視を行っている現場は意外と多くないのではと思う。 ちょっとMLOpsにはみ出た話ではあるが、重複・欠損・異常値などデータの中身を監視する仕組みを作ったほうがいい。 別部門が入力してきたデータをDWHに流すだけ、利用者に指摘されてから調査する、という後手後手の姿勢では無駄なリカバリ作業が増えるし、文化的にもどんどん社内下請けに成り下がってしまう。 9. コストの可視化は早めに始めたほうがいい Bizサイドが委託したアナリストが激重SQLをRedashのスケジュールで毎朝回し、しかもBizサイドはダッシュボードをあまり見ていない。使っていないなら止めろとデータエンジニアから連絡するも対応されない。 なんて光景をよく見てきた。...

November 3, 2023

Ubuntu desktop 23.04 環境構築メモ

GPUを使う開発は自作PC+Linuxに限る、ということでゲーム用Windowsと開発用Ubuntuのデュアルブートにした。 OS関係 Windowsをnvme0, Ubuntuをsata0に入れてfirst boot driveをsata0に設定、GNU GRUBでOSを選択する。 こうしておくとブートローダーを吹っ飛ばしてもsata0を外せばきれいなWindowsが起動する。(はず) ハードウェアクロックをローカルタイムにする 1 sudo hwclock -D --systohc --localtime この設定をしないとWindows側の時刻がずれる 日本語ディレクトリを英語化 1 LANG=C xdg-user-dirs-gtk-update GPU関係 GPUドライバのインストール 1 $ sudo ubuntu-drivers autoinstall CUDAセットアップ https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=22.04&target_type=deb_network 1 2 3 4 $ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb $ sudo dpkg -i cuda-keyring_1.0-1_all.deb $ sudo apt update $ sudo apt install cuda ~/.bashrc 1 2 3 ... export PATH="/usr/local/cuda/bin:$PATH" export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH" 動作確認 1 2 3 4 5 6 $ nvcc -V nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2023 NVIDIA Corporation Built on Mon_Apr__3_17:16:06_PDT_2023 Cuda compilation tools, release 12....

June 20, 2023

AutoMLライブラリ MLJARを使う

MLJARとは MLJARは、自動機械学習(AutoML)フレームワークであり、データの前処理、特徴量生成、モデルの選択、ハイパーパラメータの最適化、アンサンブル学習など、機械学習の一連の流れを自動化することができます。 auto-sklearn、H2O、AutoGluonといった競合に対して高いスコアを誇り、更にモデルの解釈性を高めるための機能も備えています。 触ってみたところ雑にデータを突っ込むだけで分析コンペでもある程度戦えるモデルができてしまいました。 ChatGPTに使い方を聞いても微妙に間違っていたりするのでここにまとめておきます。 インストール 1 pip install mljar-supervised 学習 1 2 3 4 5 6 7 8 9 10 11 import pandas as pd from supervised.automl import AutoML train_df = pd.read_csv("train.csv") X = train_df.drop('target', axis=1) y = train_df['target'] automl = AutoML(ml_task="classification", eval_metric="accuracy", mode="Compete") automl.fit(X_train, y_train) print("score:", automl.score(X, y)) ml_task タスクの種類 auto binary_classification multiclass_classification regression のいずれか eval_metric 評価指標 binary_classification:logloss, auc, f1, average_precision, accuracy multiclass_classification: logloss,f1,accuracy regression: rmse, mse, mae, r2,mape,sperman,pearson mode Explain 解釈性を重視したモデルを選択する Perform バランス重視 Compete 分析コンペ向け Optuna 学習時間を度外視したスコア特化 モデルの解釈 1 automl....

April 26, 2023

JSONLファイルからBigQueryスキーマJSONを生成する

script.sh 1 2 3 4 5 6 7 8 #!/bin/bash set -eu PROJECT_ID=myproject DATASET_NAME=temp TABLE_NAME=$(basename $1 | sed 's/\.[^\.]*$//') bq load --autodetect --source_format=NEWLINE_DELIMITED_JSON ${PROJECT_ID}:${DATASET_NAME}.${TABLE_NAME} $1 bq show --schema --format=prettyjson ${PROJECT_ID}:${DATASET_NAME}.${TABLE_NAME} > ${TABLE_NAME}.json bq rm -f -t ${PROJECT_ID}:${DATASET_NAME}.${TABLE_NAME} 1 $ ./script.sh /path/to/mydata.jsonl 以下のファイルが出力される ./mydata.json 1 2 3 4 5 6 7 8 [ { "mode": "NULLABLE", "name": "id", "type": "INTEGER" } ... ] もっといい方法ありそう

January 17, 2023

Pythonデータ分析チートシート

データのロード CSVファイルのロード 1 2 import pandas as pd pd.read_csv('./data.csv') BigQueryクエリ結果のロード 1 2 3 4 5 6 7 8 9 10 import pydata_google_auth import pydata_google_auth.cache from google.cloud.bigquery import Client credentials = pydata_google_auth.get_user_credentials( scopes = ['https://www.googleapis.com/auth/bigquery'], ) client = Client(project="myprojectname", credentials=credentials) job = client.query("SELECT * FROM mytable;") df = job.to_dataframe() データ仕様の把握 データの中身を見る 1 2 df.head() # 先頭 df.tail() # 末端 スキーマ情報を見る 1 df.info() 1 2 3 4 5 6 7 8 9 <class 'pandas....

December 28, 2022

NextCloudのパーミッションエラー回避

こんな感じでNextCloudをk8sにデプロイするとします。 nextcloud.yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 apiVersion: apps/v1 kind: Deployment metadata: name: nextcloud namespace: default spec: replicas: 1 selector: matchLabels: app: nextcloud template: metadata: labels: app: nextcloud spec: containers: - name: nextcloud image: nextcloud env: - name: NEXTCLOUD_DATA_DIR value: /data ports: - containerPort: 80 protocol: TCP volumeMounts: - name: myvolume subPath: config mountPath: /var/www/html - name: myvolume subPath: data mountPath: /data volumes: - name: myvolume persistentVolumeClaim: claimName: myvolume securityContext: fsGroup: 33 --- apiVersion: v1 kind: Service metadata: name: nextcloud namespace: default spec: ports: - name: http port: 80 protocol: TCP selector: app: nextcloud clusterIP: None すると初回ログイン後に以下のようなエラーが出てきます。...

November 29, 2022

BigQueryのデータを元にパーソナライズされたメールを送信する

BigQueryに格納されている行動ログを元にマーケティングオートメーションを構築、SendGridでメールを発射したいケースは多々あるかと思います。 MAツールはかなり高価なものが多いため、シュッと自前構築するためのサンプルコードを掲載します。 送信したメールの効果測定・分析方法についても少し触れます。 1. SendGridテンプレートの作成 公式ドキュメントを参考に、Dyamic templateを作成します。 詳細は割愛しますが、今回は以下のようなメールを送りたいとします。 1 2 3 4 5 6 7 foobar様への今週のおすすめ商品です! 1. ほげほげ (1000円) 2. ふがふが (1500円) 購入はこちらから! https://example.com テンプレートはこんな感じで記述します。 1 2 3 4 5 6 7 8 {{customer_name}}様への今週のおすすめ商品です! {{#each products}} {{this.number}}. {{this.product_name}} ({{this.price}}円) {{/each}} 購入はこちらから! https://example.com このテンプレートに対して、送信対象ごとに以下のようなデータを埋め込む事が目標になります。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { "customer_name": "foobar", "products": [ { "number": 1, "product_name": "ほげほげ", "price": 1000 }, { "number": 1, "product_name": "ふがふが", "price": 1500 }, ] } 2....

November 8, 2022

Kinesis Data FirehoseからMongoDB Cloudにデータを流してみる

Amazon Kinesis Data Firehose が MongoDB Cloud へのデータ配信のサポートを開始 したそうなので試してみましたが、色々と「ん?」と思う点があったので書き残します。 MongoDB Atlas でClusterを作成 MongoDB Atlas、MongoDB Realmという単語が登場しますが、AtlasはDBaaSとしてのMongoDBそのもの、RealmはAtlasを操作するためのインターフェースとなるサービスのようです。 まずはAtlasでCluster, Database, Collectionを作成します。 Get Started with Atlas MongoDB Realm Functionsを実装 てっきりGUIポチポチで連携完了するものかとおもってましたが、FirehoseからのWebhookエンドポイントとなるサーバーレス関数を自前で実装する必要があります。 だったらKinesis Data Streams + Lambdaでよくね…? MongoDB Realm Functions リリースノートのリンク先のサンプルコードの冒頭はこんな感じ。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 exports = function(payload, response) { /* Using Buffer in Realm causes a severe performance hit this function is ~6 times faster */ const decodeBase64 = (s) => { var e={},i,b=0,c,x,l=0,a,r='',w=String....

February 2, 2022

2021年 エンジニア的に買ってよかったもの

仕事(エンジニア/フルリモート)に役立ったかどうか、という観点で備忘的にまとめてみました。 自宅サーバー (自作) サーバーとして使っていたRaspberry piが成仏し、現在どこも在庫が皆無なため代わりにファンレスPCを組みました。スペック的にも物理的な拡張性にも余裕があるためより一層遊べるようになり、結果として大正解。 サブスクのクラウドサービスをセルフホステッドにどんどん切り替えていってるので、スキルアップと家計の両面に大いに貢献しています。 消費電力は25W/hくらい、電気代は月500円弱。 動かしているアプリケーションに関してはまた別記事で書きたい。 パーツ 型番 M/B BIOSTAR J4105NH CPU オンボード MEM CFD W4U2400PS-4GC17 (4GB x 2) PSU DC-DCコンバータ + 120W ACアダプタ ストレージ 余っているSSD/HDDいっぱい。合計10TBくらい ケース 100均の書類ケースに適当にネジ止め 自作キーボード YD60MQ 何個かキーボードを作ってみて得た結論として、 特殊すぎる配列はメリットに対して切り替えコストが割に合わない 右手でマウスを持ったまま左手で右側のキーを押す事があるため、自分の場合は左右分割だと効率が下がる という事から、結局HHKB配列の YMDK YD60MQ に落ち着きました。 Cherry MX銀軸が自分にかなりマッチしており、HHKBを使っていたときより指の疲労が低減しました。 LG ウルトラワイドモニター 35WN75C-B 買ったというか、転職サイトから貰った。 4kモニタは既に持っていてこちらの方が解像度は低かった(3440×1440)けど、大きい正方形のウィンドウ2つを横に並べても視野に収まるのが予想以上に便利でメインモニタに昇格しました。 曲面のため光の映り込みが少ないのも便利。 つっぱり棚 サバゲーやる人が銃を飾るのによく使っているアレです。 棚が小物類で散らかりまくってカオスだったので、いっそ全てを壁に引っ掛けるスタイルにしました。 ヘッドホンとかメガネとか、100均のS字フックでなんでも引っ掛けています。 適当に積む事が物理的にできなくなりました。負債を貯めないように頑張るのではなく、負債が貯まらない仕組みができました。 Mi Band 6 安くて小型軽量、更にめちゃくちゃ電池が持つスマートウォッチです。 Apple Watchをあまり着けなくなった過去がありますが、こいつは1週間以上電池が持つので基本つけっぱなしです。 運動量と睡眠の可視化、Slackの通知などに使っています。 パネルヒーター ファンヒーターより気持ちいい暖かさで消費電力も少ない。 暖房を普段より弱くして頭寒足熱状態にすると集中しやすい。 底面にもパネルがあるタイプがお勧め。 コーヒーメーカー 誰でもわかるレベルでインスタントコーヒーより美味しく、エナジードリンク依存を脱却できました。 手動ミル + ペーパーフィルター + コーヒーメーカー(ドリップのみ) のスタックで運用しています。...

January 9, 2022

Kubernetesに写真サーバーを構築する

2021年6月1日からGoogle Photoの容量が無制限ではなくなり、無料枠は15GBに制限されてしまいました。 完全に音楽サーバーを構築した話の二番煎じですが、自宅k8sに写真サーバーを構築してそちらに移行する事にしました。 デプロイ self-hostedな写真サーバーで最もメジャーなプロダクトはPiwigoの模様。 サクっとyamlを書いてデプロイします。 deployment.yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 apiVersion: apps/v1 kind: Deployment metadata: name: piwigo spec: replicas: 1 selector: matchLabels: app: piwigo template: metadata: labels: app: piwigo spec: containers: - name: piwigo image: lscr....

January 4, 2022