/home/by-natures/dev*

データ界隈で働くエンジニアとしての技術的なメモと、たまに普通の日記。

2024/02/07 データエンジニアもくもく会 始めました

最近学びたいことは多いのにリズムが作れていないなと思い、データエンジニア向けのもくもく会を開いてみることにしました。

先日第2回が終わりました。私は初回は「SQLアンチパターン」の読み始め、2回目は業務で使いそうな Great Expectations(GX) のチュートリアル を行いました。私は新しい本やツールを学ぶのに少し腰が重いタイプなので、毎週決まった時間にもくもく会を開くことで、学び始めるきっかけを作るのにとても良いなと感じています。

初回は7、8名、2回目は6名ほど参加者がいらっしゃいました。みなさんの作業内容はそれぞれですが、「データエンジニア」という括りでもくもく会を開いているため、普通のもくもく会と違って他の人の作業内容も興味深く聞くことができます。業務での課題を真剣に解決する時間に使う方や、新しいツールを学ぶ方、社内勉強会の資料作りの時間にされている方、個人学習用のデータ基盤構築に励む方もいるなど、いろんなタスクに取り組んでいました。

しばらくは毎週月曜日(祝日の場合は火曜日)に開く予定ですので、ぜひ気軽に参加してください。

参加方法

開催日時

毎週月曜日 18:30 - 20:30

  • 18:30 より順次集まり、やることを Slack へ投稿
  • 20:00 まで各自もくもく。20:00 に Zoom にて、やったことの共有

運営というほど大きなイベントではありませんが、何か不明点があれば X の方でお問い合わせください。

2023/10/18 令和5年 データベーススペシャリスト受験 振り返り

10月頭に IPA のデータベーススペシャリストの試験を受けました。午後2で大きくつまづいたので振り返りをします。

午前2, 午後1は多分大丈夫

午前1は免除、午前2はマークシートですが23/25点でした。合格点は15/25点なので無事通過しているはずです。

午後1は大問3つから2つ選択で、予行練習では大問1と2を選ぶ予定でした。ただ解答欄を見ると大問1だけ問題数が多く、問題文も多かったことから、急遽大問2と3へ変更。午後1は午後2以上に時間との勝負だったので、良い判断だったと思います。自己採点では7割を超えているので恐らく通過しているはずです。

午後2で問題文を読み違える

午後2は大問2つから1つ選択で、予行練習通り大問2の概念データモデルの問題を選びました。

この大問2が思ったように点数が取れず、合格水準の60点ギリギリ届くか、採点が厳しいと届かないかもしれません。

問題を見たい方はこちらからどうぞ: IPA データベーススペシャリスト 令和5年 午後2

問題が短くて潔すぎる

問題文の指示と関係スキーマの相違

午後2大問2は決して難しい問題ではなく、問題量も2時間の割には多くないのですが、問題文の表現が過去数年分と違ったように感じます。

一番顕著なのは、店舗と支線ルートに関する以下の記述です:

②支線ルートは、TCごとの支線ルートコートで識別している。また、支線ルートには、車両番号、配送先店舗とその配送順を定めている。支線ルートの配送先店舗は8店舗前後にしている。支線ルート間での店舗の重複はない。

この段落ではエンティティ「支線ルート」についての説明がされていて、「支線ルート」の属性に「車両番号、配送先店舗とその配送順」があると読めます。一方で「支線ルートの配送先店舗は8店舗前後」という記述があり、「支線ルート」と「配送先店舗」は1対多の関係です。1対多であれば、多側に外部キーを持たせなければいけないので、回答としては以下のようになります(上記問題文の属性についてのみ言及。実際は支線LTなどが加わります):

  • 「支線ルート」には「車両番号」のみもたせる
  • 「店舗」には「支線ルート」への外部キーとして「支線ルートコード」を持たせ、「配送順」も「店舗」ごとの属性であることから、「店舗」側へ持たせる

実際に概念データモデルでも、TACやiTECの回答では「支線ルート」から「店舗」に1対多(→)が引かれており、「店舗」側から外部キーで「支線ルート」に参照を持たせなければいけません。

b(支線ルート)->店舗

指示書に関する表現も同様です:

(中略)積替指示書の明細は、配送先店舗ごとに作り、その内訳に店舗へ運ぶコンテナの配送指示番号を印刷する。

これは「積替指示明細」に関する説明です。この「内訳」は「積替指示明細」の内訳と読めます。しかし実は「積替指示明細」の属性ではなく、「DC出庫指示」に「積替指示番号」を記載するという意図を汲まなければなりません(「積替指示明細」→「DC出庫指示」(1対多)であるため)。

このような表現箇所がトランザクション部分でとても多く、時間制限や緊張もある中で問題文側に沿った回答をしてしまったので、かなり減点されている可能性があります。

以前の問題文を見てみる

令和3年の問題文を一部見てみます:

出荷指示ごとに、出荷指示番号を付与し、適用した締め契機、出荷指示対象の納入先を記録する。対象の受注番号に出荷指示番号を記録する。

これは「出荷指示」エンティティの説明ですが、合わせて「受注」エンティティにも「出荷指示番号」を追加する必要がある、と丁寧に説明があります。

令和2年は配送順についての問題があり、今回の令和5年と近いように見えます。ただ令和2年は関係スキーマの穴埋めが少なく、ある程度出題意図に沿った回答ができたので、空欄だらけの令和5年では本番でちょっとパニックになってしまいました。

反省:問題文の説明と、実際のリレーションや関係スキーマは異なると考える

直近で解いた問題がほとんど問題文に沿って考えればよかったものばかりだったので、問題文の指示と関係スキーマや概念データモデルの相違に混乱してしまいました。

概念データモデルの問題は「問題文」「概念データモデル」「関係スキーマ」の3つを統合して回答する必要がありますが、今回は「問題文」に寄り過ぎて回答してしまったため、来年再受験する場合は関係スキーマや概念データモデルの情報も踏まえて回答するようにしたいです。

2023/09/23 IPA データベーススペシャリスト試験勉強中

秋のデータベーススペシャリストの試験日が近づいてきたので最近は試験対策をしています。

新卒の頃から取りたかった IPA のネットワークスペシャリスト(NW)とデータベーススペシャリスト(DB)、この2つの高度試験に合格することが今年の目標です。実に10年越しですね…。新卒の頃の目標設定に掲げては、勉強する気力も湧かず試験当日も起きられず…というのを繰り返していたのですが、今年は勉強欲が結構高いので勢いで取り切ってしまおうと思っています。

DBの午後問題はテーブルの概念/外部設計に加え、データウェアハウスに関する出題もあって割と面白いです。仮想的でもいろんな業界のデータが題材になるので、いろんな業界のデータを見る機会がある今のポジションだと結構役立つかも、と感じています。

DB と比較すると NW は新しい知識がどんどん試験範囲に追加されていて、知識量がとにかく必要で試験対策が大変でした。HTTP/2, Wi-Fi6 などの試験範囲としては新しめのプロトコルもあれば、OSPF や BGP4 などの昔からあるルーティングプロトコルも基礎から理解する必要がありました。

一方 DB はあまり試験範囲が更新されず、テーブル設計や概念データモデルの作成など、文章題を解くのに近い感覚です。データ活用が広がる昨今ですが、あまり基礎的な部分での革新はないのかもしれない、とぼんやり思いながら試験対策しています。

試験が終わったら感想など綴ろうと思います。ではでは。

2023/09/03 MotherDuck の紹介と計算リソースについて

このブログで何度か DuckDB についてご紹介したのですが、DuckDB のクラウド版 MotherDuck のベータ版が2023年6月よりリクエストベースで利用可能になっています。

もくじ:

クラウド版 DuckDB, MotherDuck の利点

公式アナウンスで紹介されていることをご紹介します。

motherduck.com

クラウドとローカル環境のハイブリッド

DuckDB はローカル環境で余っている CPU やメモリリソースを活用することで、ローカル環境上でデータ分析を行うことを目指したシンプルなデータベースです。

そのため、DuckDB のクラウド版と聞くと DuckDB の理念から外れている気がしたのですが、MotherDuck はデータをクラウド環境下に保存することができる機能に加え、MotherDuck と DuckDB が協調することにより、適切な実行計画を自動的に立てることでクラウド上のデータとローカルのデータを合わせて分析することが可能です。

このハイブリッド実行ですが、公式ドキュメントのアーキテクチャに少し詳しく説明されています:

https://motherduck.com/docs/architecture-and-capabilities より

  • データがローカル上にある場合、ローカルの DuckDB へルーティングする
  • データが MotherDuck か S3 にある場合、MotherDuck へルーティングする
  • ローカルとMotherDuckのデータをジョインする場合、最適な方法を見つける

上の図だと MotherDuck 側の処理が終わったらローカルに転送し、MotherDuck とローカルのデータを結合しています。

MotherDuck はサーバレス実行モデルを採用とあり、ユーザがインスタンスを起動したり、ウェアハウスを設定する必要は全くありません。ユーザはクエリを書いて実行し、あとは MotherDuck が全て面倒を見てくれるとのこと。以下で紹介する GUI 上でも一応「設定」メニューはありますが、設定項目はほぼありません。

MotherDuck の計算リソースについて

では MotherDuck がどれほどの計算リソースを提供してくれるのかというと、調べた限りでは明確な記載はありませんでした。MotherDuck の Slack コミュニティで質問をすると、MotherDuck のマネージャーの方に回答をいただけました:

slack.motherduck.com より

概ね "12 cores and 16GB of RAM" との回答で、業務であればこれに近い水準のPCを使うことも多いのではないでしょうか。クラウド版だからといってリソースが膨大に使えるということではないようです。

MotherDuck 自体がまだベータ版ということもあり、将来的にはユーザ側でハードウェアリソースをスケールアップできる予定とも回答をいただけました。ただこれだけのリソースが割り当てられる保証はなく利用状況に応じて動的にリソース割り当てがされるようです。

ノートブックとGitスタイルのコラボレーション

GUI が付いてくるのはシンプルに魅力的ですね。ノートブックスタイルとあるように、セルごとにクエリと実行結果を追加できる形式です。Snowflake の SnowSight と似ていますがウェアハウスやロールの指定もなく、非常にシンプルです。

ただデータ共有機能があることとセキュリティ面もMotherDuckを使うことで強化されるとのことなので、管理面でロールの切り替えなどはもしかしたら今後実装されるかもしれません。計算リソースの設定についても計画があるとのことなので、徐々に GUI も機能拡張されると思われます。

"Git スタイル" という点について、データのスナップショットを切って他のユーザに共有できる機能があるようで、そのことを恐らく指していると思われます。

DuckDB が使える環境なら、MotherDuck が利用可能

公式アナウンスでは特に可視化について言及されており、DuckDB で集計した結果を MotherDuck に保存し、様々な BI ツールから MotherDuck に接続してダッシュボードを他のユーザと共有するといった使い方が考えられます。

注意点:DuckDB でしかできない機能もある

現状 DuckDB でしか使えない機能もあり、以下の機能を使っている場合は注意が必要です:

  • User Defined Functions (UDFs)
  • Custom extensions. Only the https/httpfs, CSV/Parquet reader, fts, json, icu, tpcds, and tpch extensions are preloaded into MotherDuck.
  • Sequences
  • Macros
  • Checkpointing
  • Stored Procedures

Architecture and capabilities | MotherDuck

2023/09/01 Streamlit 入力ウィジェットでの変数の扱い方

簡単に Web アプリケーションが作れて人気の Streamlit ですが、入力ウィジェットも豊富に揃っていて便利です。

一方であまり学ばずともそれっぽいモノが作れてしまうため、変数周りの扱いでつまづくことが多いのではないでしょうか(私のことです。。)。備忘録も兼ねて、誤った設定と正しい設定方法を見ていきます。

もくじ:

TL;DR

入力と出力はセッションステート変数を分ける、もしくは key 属性を極力活用すると読みやすくウィジェット間のやり取りが分かりやすいコードになります。

検証

OK: 初期引数を固定し、セッションステートで結果を受け取る

st.session_state["st_title"] = st.text_input(value="Titanic", label='Movie Title')
st.write(f"session state 'st_title: {st.session_state['st_title']}")

もしくは key を使って:

st.text_input(value="Titanic", label='Movie Title', key='st_title')
st.write(f"session state 'st_title: {st.session_state['st_title']}")

好きな映画タイトルを入れたときに、セッションステート変数 st_title がどう変わるかを見てみます:

予想通り、Titanic -> Avatar -> Green Mile と入力したものが、そのままセッションステート変数に反映されていることが分かります。

NG: 入力と出力に同じセッションステート変数を利用(key 未使用)

他のウィジェットの結果を用いたりするなど、初期値自体にセッションステートを与えたい場合もあるかもしれません。同じセッションステート変数を使い回してみます:

if 'st_title' not in st.session_state:
    st.session_state["st_title"] = "Titanic"

st.session_state["st_title"] = st.text_input(value=st.session_state["st_title"], label='Movie Title')
st.write(f"session state 'st_title: {st.session_state['st_title']}")

これは予想を裏切り、挙動が不安定になります。映画タイトルを入れて Enter キーを押すと、入力が前の値に戻ってしまったり、消えてしまっています。

OK?: 入力と出力に同じセッションステート変数を利用(key 使用)

同じセッションステート変数でもウィジェットの key 属性を通じて設定すると、うまく動きました。

if 'st_title' not in st.session_state:
    st.session_state["st_title"] = "Titanic"

st.text_input(value=st.session_state["st_title"], label='Movie Title', key='st_title')
st.write(f"session state 'st_title: {st.session_state['st_title']}")

この短いコードでは正しく動きましたが、アプリケーションを複雑にしていったときにもお勧めできるかは分からないため、「OK?」としました。該当のセッションステート変数の更新箇所が複数に渡るためコードも読みづらくなると思いますし、明確な意図がなければ避けた方が良さそうです。

OK: 入力と出力に違うセッションステート変数を利用

初期値と出力にどちらもセッションステートを使いたい場合は、変数名を変えれば正しく動きます。

if 'st_title_init' not in st.session_state:
    st.session_state["st_title_init"] = "Titanic"

st.text_input(value=st.session_state.st_title_init,
              label='Movie Title',
              key='st_title_edited')

st.write(f"session state 'st_title_edited: {st.session_state['st_title_edited']}")

複数個組み合わせて数珠繋ぎにもできます:

import streamlit as st

if 'st_title_init' not in st.session_state:
    st.session_state["st_title_init"] = "Titanic"

st.text_input(value=st.session_state["st_title_init"], label='Movie Title1', key='st_title_edited1')
st.text_input(value=st.session_state["st_title_edited1"], label='Movie Title2', key='st_title_edited2')
st.text_input(value=st.session_state["st_title_edited2"], label='Movie Title3', key='st_title_edited3')

st.write(f"session state 'st_title_init: {st.session_state['st_title_init']}")
st.write(f"session state 'st_title_edited1: {st.session_state['st_title_edited1']}")
st.write(f"session state 'st_title_edited1: {st.session_state['st_title_edited2']}")
st.write(f"session state 'st_title_edited1: {st.session_state['st_title_edited3']}")

こんな直接的にウィジェットを繋げることはないと思いますが、例えば「入力された日付を別のテキストエリアに反映させたい」など、異なるウィジェットを組み合わせて少し複雑なアプリケーションを作ろうと思ったときに、結果的にウィジェットがセッションステートを通じて繋がることはあるかと思います。

セッションステート変数の数は増えてしまいますが、入力と出力に同じ変数を利用しないことで、その変数がどのウィジェットで更新されたものか分かるようにもなるためデバッグもしやすくなると思います。

まとめ

入力と出力はセッションステート変数を分ける、もしくは key 属性を極力活用すると読みやすくウィジェット間のやり取りが分かりやすいコードになります。

以下のコールバックのことを考えると、基本的には key 属性を利用する方法がよさそうです。

(参考)コールバックで新しい値を参照する方法

コールバック関数内で新しい値を参照するには、「key を通じて設定されたセッションステートにコールバック内でアクセスする」ことで唯一成功しました。なお args, kwargs を使っても、古い値が渡ってしまうため使えません。

公式ドキュメントでも key を通じてコールバックから新しい値を参照しているため、これが正しい方法のようです。

if 'st_title_init' not in st.session_state:
    st.session_state["st_title_init"] = "Titanic"

def callback():
    st.write(f"Callback: session state 'st_title_edited: {st.session_state['st_title_edited']}")

st.text_input(value=st.session_state.st_title_init,
              on_change=callback,
              label='Movie Title',
              key='st_title_edited')

2023/08/23 トランザクション対応の列志向データフォーマット比較(Iceberg,Hudi,DeltaLake)

先日読んだ Snowflake の記事に Iceberg 連携の話があったので、自分の学習も兼ねてデータレイクに使われる新しいデータフォーマットについていくつか記事を紹介します:

先日の記事: bynatures.hatenadiary.jp

"AWSにおける Hudi/Iceberg/Delta Lake の使いどころと違いについて"

https://pages.awscloud.com/rs/112-TZM-766/images/AWS-Black-Belt_2023_Datalake-Format-On-AWS_0516_v1.pdf

AWS のソリューションアーキテクト、Chie Hayashida さんによる各種データフォーマット比較です。

CSV, JSON, AVRO, Parquet, ORC などのファイルフォーマットや様々なユースケースを紹介しながら、新たなデータレイクフォーマットの必要性と、Apache Hudi, Iceberg, Delta Lake の3つのフォーマットを紹介しています。資料の最後には、これらのフォーマットをいつ使うべきかもまとめられていたり、AWS のどのサービスで利用可能かもまとめられており、貴重な資料です。

"Delta vs Iceberg vs hudi : Reassessing Performance"

databeans-blogs.medium.com

Delta Lake, Iceberg, Hudi のパフォーマンス比較記事。データウェアハウス用のベンチマーク指標 TPC-DS を用いて検証をしています。

大きく分けてデータロード、クエリ実行時間の2パートに分かれていますが、Hudi のデータロード(ベンチマーク用の 3.0 TB Parquet ファイルを読み込む時間)が Delta Lake, Iceberg に比べて遅くなっている点が目立ちます。クエリ実行は Delta Lake が早く、クエリ実行時間が短いものは Hudi が早かったケースが多いようです。

ロード、クエリ実行時間共に Delta Lake フォーマットの性能の良さが目立つ検証内容でした。Delta Lake は Databricks 社にとっても重要な技術であり、今後も注力して改善や機能追加が行われるのではないかと思います。

"Comparison of Data Lake Table Formats (Apache Iceberg, Apache Hudi and Delta Lake)"

www.dremio.com

Dremio 社の技術ブログで、Iceberg, Hudi, Delta Lake の3フォーマットの紹介/比較を行っています。3つのフォーマットを ACID特性、パーティション変更、スキーマ変更、タイムトラベル、管理体制、どんなツールで利用可能かなどが詳細に比較されています。ざっと調べた限り、このブログが一番細かく比較されていて、定期的に情報も更新されているようです。

パーティションの変更は唯一 Iceberge がもつ機能で、既存のテーブルに対して、タイムスタンプ ts による年ごとのパーティションが区切られている場合、月ごとのパーティションを追加するのは Iceberg が提供する SQL を実行するだけで行えます。パーティションを切る場合、多くは時刻や日付によって行われるでしょうし、この粒度をテーブル作成後に変更できるのはとても便利そうです。

管理体制については Delta Lake がほぼ Databricks 社によって更新されていることが目につきます。Delta Lake はオープンソース版と Databricks 社が独自に開発を続けるバージョン(フォーク)の2つがありますが、Iceberg は Netflix, Apple, AWS などを中心に様々な企業が開発に加わっており、これと比べると開発の盛り上がりは欠けている印象を受けました。しかし Delta Lake フォーマットは Databricks 社製品としても重要な製品であるため、今後も Databricks 社によって開発は続けられるだろうと思います。

このブログを投稿した Dremio という会社は、セルフサービス SQL 分析を実現するオープン・データレイクハウスを提供しています。様々なデータソースを統合し(レイクハウス)、統合されたデータに対して SQL を中心としたインタフェースでデータ分析ができるサービスのようです。…と書きましたが、機能が豊富で正直よく分かっていません。ドキュメントを見る限りはデータ自体は移動せず、クラウドサービスやオンプレミスのデータソースをまとめ上げる複数データレイク上でのクエリエンジン+αのように見えます(詳しい方がいたら教えてください)。上記ブログは Dremio が上記テーブルフォーマットのどれが利用可能か(Iceberg と Delta Lakeに対応)を紹介することが目的のようです。

2023/08/23 トランザクション対応の列志向データフォーマット比較

先日読んだ Snowflake の記事に Iceberg 連携の話があったので、自分の学習も兼ねてデータレイクに使われる新しいデータフォーマットについていくつか記事を紹介します:

先日の記事: bynatures.hatenadiary.jp

"AWSにおける Hudi/Iceberg/Delta Lake の使いどころと違いについて"

https://pages.awscloud.com/rs/112-TZM-766/images/AWS-Black-Belt_2023_Datalake-Format-On-AWS_0516_v1.pdf

AWS のソリューションアーキテクト、Chie Hayashida さんによる各種データフォーマット比較です。

CSV, JSON, AVRO, Parquet, ORC などのファイルフォーマットや様々なユースケースを紹介しながら、新たなデータレイクフォーマットの必要性と、Apache Hudi, Iceberg, Delta Lake の3つのフォーマットを紹介しています。資料の最後には、これらのフォーマットをいつ使うべきかもまとめられていたり、AWS のどのサービスで利用可能かもまとめられており、貴重な資料です。

"Delta vs Iceberg vs hudi : Reassessing Performance"

databeans-blogs.medium.com

Delta Lake, Iceberg, Hudi のパフォーマンス比較記事。データウェアハウス用のベンチマーク指標 TPC-DS を用いて検証をしています。

大きく分けてデータロード、クエリ実行時間の2パートに分かれていますが、Hudi のデータロード(ベンチマーク用の 3.0 TB Parquet ファイルを読み込む時間)が Delta Lake, Iceberg に比べて遅くなっている点が目立ちます。クエリ実行は Delta Lake が早く、クエリ実行時間が短いものは Hudi が早かったケースが多いようです。

ロード、クエリ実行時間共に Delta Lake フォーマットの性能の良さが目立つ検証内容でした。Delta Lake は Databricks 社にとっても重要な技術であり、今後も注力して改善や機能追加が行われるのではないかと思います。

"Comparison of Data Lake Table Formats (Apache Iceberg, Apache Hudi and Delta Lake)"

www.dremio.com

Dremio 社の技術ブログで、Iceberg, Hudi, Delta Lake の3フォーマットの紹介/比較を行っています。3つのフォーマットを ACID特性、パーティション変更、スキーマ変更、タイムトラベル、管理体制、どんなツールで利用可能かなどが詳細に比較されています。ざっと調べた限り、このブログが一番細かく比較されていて、定期的に情報も更新されているようです。

パーティションの変更は唯一 Iceberge がもつ機能で、既存のテーブルに対して、タイムスタンプ ts による年ごとのパーティションが区切られている場合、月ごとのパーティションを追加するのは Iceberg が提供する SQL を実行するだけで行えます。パーティションを切る場合、多くは時刻や日付によって行われるでしょうし、この粒度をテーブル作成後に変更できるのはとても便利そうです。

管理体制については Delta Lake がほぼ Databricks 社によって更新されていることが目につきます。Delta Lake はオープンソース版と Databricks 社が独自に開発を続けるバージョン(フォーク)の2つがありますが、Iceberg は Netflix, Apple, AWS などを中心に様々な企業が開発に加わっており、これと比べると開発の盛り上がりは欠けている印象を受けました。しかし Delta Lake フォーマットは Databricks 社製品としても重要な製品であるため、今後も Databricks 社によって開発は続けられるだろうと思います。

このブログを投稿した Dremio という会社は、セルフサービス SQL 分析を実現するオープン・データレイクハウスを提供しています。様々なデータソースを統合し(レイクハウス)、統合されたデータに対して SQL を中心としたインタフェースでデータ分析ができるサービスのようです。…と書きましたが、機能が豊富で正直よく分かっていません。ドキュメントを見る限りはデータ自体は移動せず、クラウドサービスやオンプレミスのデータソースをまとめ上げる複数データレイク上でのクエリエンジン+αのように見えます(詳しい方がいたら教えてください)。上記ブログは Dremio が上記テーブルフォーマットのどれが利用可能か(Iceberg と Delta Lakeに対応)を紹介することが目的のようです。