Timee Product Team Blog

タイミー開発者ブログ

CircleCIからGitHub Actionsへ移行、テスト実行時間をp95で15分から6分に短縮!移行時の課題と解決策

エンジニアリング本部 プラットフォームエンジニアリングチームの徳富です。我々のチームでは、CIパイプラインの効率化と開発体験の向上を目指し、CircleCIからGitHub Actionsへの移行を進めてきました。移行によってテスト・静的解析(以降CIと記載する)の実行時間をp95で9分短縮しましたが、この移行にはいくつかの課題もありました。今回は移行の背景や移行時の苦労について紹介します。

本記事のまとめ

  • CircleCIからGitHub Actionsに移行し、CI実行時間をp95で9分短縮
  • 並列実行やテスト結果の連携における課題を解決し、効率化を実現
  • テスト結果のPR通知や分割テストの仕組みを工夫し、開発体験を向上

CircleCIからGitHub Actionsへ移行した背景

以前利用していたCircleCIのPerformanceプランでは、並列実行できるジョブ数が80に制限されていました。1回のCI実行に40の並列ジョブを使用していたため、同時にCIを実行できる開発者は最大2名まで。この状況では、今後開発者が増加するにつれて、CIの待ち時間が長くなるリスクを抱えていました。プランのアップグレードも検討しましたが、以下の理由からGitHub Actionsへの移行を決断しました。

理由1: 学習コストの削減と効率化

弊社では基本的にGitHub Actionsを利用していますが、RSpecテストと静的解析のみにCircleCIを使用していました。これをGitHub Actionsに統合することで、CircleCIとGitHub Actionsの両方を学ぶ必要がなくなり、開発者の学習コストが削減されます。また、以前はCircleCIでのCI完了後に、デプロイをGitHub Actionsで行うワークフローでした。CIの実行基盤をGitHub Actionsに移行することで、テストもデプロイもGitHub Actionsに統一できるようになります。これにより、デプロイフローがよりシンプルになり、メンテナンス性も向上しています。

理由2: セキュリティリスクと管理の効率化

CIプロバイダーをGitHub Actionsに一本化することで、複数のプロバイダーを管理する必要がなくなり、情報流出のリスクが低減し、一貫したセキュリティ対策を実施できます。さらに、管理するツールが減ることで管理業務が簡素化され、運用が効率的になります。

移行する上での課題となっていたポイント

  1. テスト実行時間ベースでテスト分割する仕組みがGitHub Actionsにない
  2. テストの失敗した情報をわかりやすく参照できるUIがない
  3. matrix strategyを使って並列実行をすると後続のjobに結果を送れない
  4. Flakyテストを一覧で参照できない

1. テスト実行時間ベースでテスト分割する仕組みがGitHub Actionsにない

CircleCIには、CircleCI CLI を使用してテストファイルを実行時間ベースで分割する機能がありましたが、GitHub Actionsには同様の機能がありませんでした。

そこで、代替としてmtsmfm/split-testライブラリを導入し、RSpecテストを均等に分割する仕組みを整えました。このライブラリは、過去のテスト実行時間をもとに、実行時間が均一になるようにテストファイルを分割します。そのためデフォルトブランチのテスト結果をS3に保存し、その結果を利用してテストを効率的に分割・実行するフローを構築しました。

2. テストの失敗した情報をわかりやすく参照できるUIがない

CircleCIには、テスト結果をわかりやすく表示する機能が標準で備わっており、開発者はテストの成否や詳細を簡単に確認できました。しかし、GitHub Actionsにはそのような標準機能がなく、開発者がテスト結果を確認するのに手間がかかってしまうという課題がありました。

そこで、SonicGarden / rspec-report-actionにパッチを適用し、テスト結果をPRにコメントする仕組みを導入しました。この改善により、CircleCIにログインせずにPR内で直接テスト結果を確認できるようになり、作業効率が向上しました。

3. matrix strategyを使って並列実行をすると後続のjobに結果を送れない

GitHub Actionsでは、matrix strategyを使うことで、並列実行ができます。しかし、この並列実行には問題があり、後続のジョブにテスト結果を渡せないという課題がありました。

最初は、各マトリックスで生成されたテスト結果をアーティファクトとしてアップロードし、後続のジョブでダウンロード・集計する方針を検討しました。しかし、25並列で実行していたため、アーティファクトのアップロード頻度が増加し、すぐにGitHub Actionsのレート制限に達してしまいました。

この問題に対処するため、テスト結果をGitHub Actionsのアーティファクトではなく、S3にアップロードする方法に切り替えました。これにより、レート制限の問題を回避でき、後続のジョブでテストの結果をPRに投稿する仕組みが無事に機能するようになりました。

4. Flakyテストを一覧で参照できない

CircleCIではテストインサイトを使ってFlakyテストを確認できましたが、GitHub Actionsにはそのような機能がありませんでした。当初はCodecovのTest Analyticsを使ってFlakyテストを確認していましたが、絞り込み機能が不十分で、ページの表示に時間がかかるという問題がありました。

そこで、現在はDatadog Test Visibilityを利用してFlakyテストを確認しています。Datadogを使用することで、テストのTrace情報などの詳細なデータを収集できるだけでなく、不安定なテストが検出された際にアラートを設定することも可能になりました。

完成したワークフローの一例

ここで、最終的に完成したワークフローの一部をご紹介します。GitHub Actionsへの移行を検討している方にとって、少しでも参考になれば幸いです。

name: ci

on:
  push:
    branches:
      - '**'
    tags-ignore:
      - '*'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  generate-matrix:
    runs-on: ubuntu-latest
    timeout-minutes: 1
    outputs:
      parallelism: ${{ steps.set-matrix.outputs.parallelism }}
      ids: ${{ steps.set-matrix.outputs.ids }}
    steps:
      - id: set-matrix
        run: |
          parallelism=25 # テストの並列数
          ids=$(seq 0 $((parallelism - 1)) | jq -s | jq -c)
          echo "parallelism=[$parallelism]"
          echo "ids=$ids"
          echo "parallelism=[$parallelism]" >> "$GITHUB_OUTPUT"
          echo "ids=$ids" >> "$GITHUB_OUTPUT"

  rspec:
    needs: [generate-matrix]
    runs-on: ubuntu-latest
    timeout-minutes: 20
    env:
      DD_CIVISIBILITY_AGENTLESS_ENABLED: true # Datadog Test Visibility用
      DD_API_KEY: ${{ secrets.DATADOG_API_KEY }} # Datadog Test Visibility用
      DD_ENV: ci # Datadog Test Visibility用
    strategy:
      fail-fast: false
      matrix:
        parallelism: ${{ fromJson(needs.generate-matrix.outputs.parallelism) }}
        id: ${{ fromJson(needs.generate-matrix.outputs.ids) }}

    services:
      # rspec実行に必要なコンテナを起動
   
    steps:
      - name: Generate token
        id: generate_token
        uses: actions/create-github-app-token@v1
        with:
          app-id: app idを指定
          private-key: キーを指定

      - name: Checkout
        uses: actions/checkout@v4
        with:
          token: ${{ steps.generate_token.outputs.token }}

      - name: Setup Ruby with caching
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.3
          bundler-cache: true

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: # S3にアクセスできる権限をもつロールを指定
          aws-region: # リージョン名

      # NOTE: デフォルトブランチで記録された各RSpecテストの実行時間データをダウンロード
      - name: Download rspec junit
        run: aws s3 cp s3://デフォルトブランチでのテスト結果(JUnit XML)が保存されているS3を指定 tmp/rspec_junit --recursive

      # NOTE: テストファイルを分割するためのツールをダウンロードし、後続ステップでテストファイルをダウンロードして分割する。
      #       これにより、マトリックスを使用して並列で実行されるRSpecテストが均等に分割され、
      #       すべてのテストジョブがほぼ同時に完了するようにする。
      - name: Split test file
        run: |
          curl -L --output split-test https://github.com/mtsmfm/split-test/releases/download/v1.0.0/split-test-x86_64-unknown-linux-gnu
          chmod +x split-test

      - name: RSpec
        run: |
          # テストファイルを分割しテストを実行する
          bundle exec rails db:create db:schema:load
          ./split-test --junit-xml-report-dir tmp/rspec_junit \
            --node-index ${{ matrix.id }} \
            --node-total ${{ matrix.parallelism }} \
            --tests-glob "spec/**/*_spec.rb" \
            --tests-glob "packs/*/spec/**/*_spec.rb" | xargs bundle exec rspec \
            --format progress \
            --format RspecJunitFormatter \
            --out report/rspec_junit/${{ matrix.id }}.xml \
            -f j -o report/results/${{ matrix.id }}.json \
            -f p

      # テストが完了したら、テスト結果をS3にアップロードし、後続のジョブで利用できるようにする
      - name: Upload test report
        if: always()
        run: |
          aws s3 cp report s3://テスト結果が保存されているS3を指定 --recursive

  rspec-status:
    runs-on: ubuntu-latest
    timeout-minutes: 1
    needs: [generate-matrix, rspec]
    if: ${{ !cancelled() && github.event_name == 'push' }}
    steps:
      - name: Check previous job status
        run: |
          if [ "${{ needs.rspec.result }}" == "success" ]; then
            echo "テスト成功"
          else
            echo "テスト失敗"
            exit 1
          fi

  upload-rspec-junit:
    runs-on: ubuntu-latest
    timeout-minutes: 2
    needs: [generate-matrix, rspec]
    if: github.ref == 'refs/heads/main' # デフォルトブランチを指定
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: # S3にアクセスできる権限をもつロールを指定
          aws-region: # リージョン名

      - name: Download rspec junit
        run: aws s3 cp s3://各マトリックスでのテスト結果が保存されているS3を指定 rspec_junit --recursive

      - name: Upload rspec junit
        run: aws s3 cp rspec_junit s3://各テストのJUnit XMLをアップロードするS3を指定 --recursive

  pr-comment:
    needs: [generate-matrix, rspec]
    if: ${{ !cancelled() }}
    runs-on: ubuntu-latest
    timeout-minutes: 2
    steps:
      - name: Generate token
        id: generate_token
        uses: actions/create-github-app-token@v1
        with:
          app-id: app idを指定
          private-key: キーを指定

      - name: Checkout
        uses: actions/checkout@v4
        with:
          token: ${{ steps.generate_token.outputs.token }}

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: # S3にアクセスできる権限をもつロールを指定
          aws-region: # リージョン名
     
      - name: Download RSpec reports
        run: aws s3 cp s3://各マトリックスでのテスト結果が保存されているS3を指定 report --recursive

      - name: RSpec Report
        if: steps.find_pr.outcome == 'success'
        uses: SonicGarden/rspec-report-actionアクションに一部パッチを適用したアクションを指定
        with:
          token: ${{ steps.generate_token.outputs.token }}
          json-path: report/results/*.json
          comment: "${{ github.event_name == 'push' }}" # PRにコメントするかどうか
          pull-request-id: ${{ fromJson(steps.find_pr.outputs.pr_json).number }}
          hideFooterLink: true

得られた成果

テスト時間の短縮による開発効率の向上

GitHub Actionsへの移行により、p95でテスト実行時間が9分短縮されました。並列実行の制限がなくなったことで、CI/CDのパフォーマンスが大幅に向上しました。この改善により、開発者の作業効率が向上し、より早くフィードバックを得られる環境が整いました。

  • CircleCIの時はp95で15分

  • GitHub Actionsに移行後はp95でテストが6分程度で終わるようになっているになっている

移行のまとめと今後の課題

CircleCIからGitHub Actionsへの移行により、テスト実行時間の大幅な短縮という大きな成果を得られました。しかし、移行に伴う課題も少なくなく、とくにテスト結果の連携テストの分割には工夫が必要でした。

今後は、GitHub Actionsの新機能やさらなる最適化手法を活用し、テストやデプロイのより一層の効率化を目指していきます。本記事が、同様の課題に直面している方々の参考になれば幸いです。

dbt coalesce 2024 1日目のセッションを徹底解説(okodoon視聴分)

こんにちは。okodoooonです🌵

ラスベガスに来てから、同行しているメンバーと手分けをしてセッションを聞いて、知見をまとめる作業に追われており、なかなかハードな日々を過ごしておりました。

今回は初日に聞いた5つのセッションがどれも知見に溢れるものだったので、そちら紹介していきたいと思います💪

スライドが公開されたり他メンバー担当分の記事が上がり次第リンクなど追って貼っていきます。(2日目以降のやつも頑張って書いております)

目次

Data alone is not enough(訳:データだけでは不十分である)

発表者:Preston Wong (Analytics Engineer @ Settle)

概要

データを提供できる組織や環境を作るのではなく、洞察を提供できる組織や環境を作るべきで、
理想の組織に改善されるために、Settleが取り組んでいるJTBDというフレームワークの紹介をしていました

セッション内容の紹介

以下のような画像とこちらブログの引用ともに

  • レポーティング業務はデータ組織にとってゲートウェイドラッグのようなものだ
  • これらのレポートは本当に意味のあるものなのか?変化を促しているのか?実際に使用されているのか?誰かがそれを見て、2秒で終わるために7時間も費やすのはなぜだろう?
  • 最近のデータイニシアチブは、情報へのアクセスを民主化することに重点を置きすぎており、ビジネスへの影響を促進することに十分に注力されていない。どんなに多くの情報があっても、それだけでは組織の変革を促すことはできない。

という強烈なメッセージを発信していました。

とても耳が痛いですね。

ビジネスインパクトをいかに生み出すか」という観点なしに、ただデータを出力し続けるチームになってしまうことへの懸念を紹介してくれました。

それらの懸念を紹介した後に「データチームがどのようにしてビジネスのデータが持つ潜在能力を最大限に引き出せるのかを考える必要がある」と続き、

レポーティング業務から抜け出せない理由はコンテキストを持っていないことが多いからと説明していました。

良い例として、Q3の新規アクティブ顧客数が安定して増加しており、最近の月では20%増加したことが挙げられます。データ担当者がこれに気づいたとしても、直接的な文脈を持っているとは限りません。このデータには、最近の企業買収があったことや、その顧客基盤を取得したことが含まれておらず、それが20%増加の理由です。この説明はデータ自体では行えず、他の誰かが説明する必要があります。つまり、なぜそうなったのかを答えるのは難しいのです。

Settleではデータチームを適切にステップアップさせていくためにデータ組織のJTBD(JobToBeDone)を設定しており、その運用によってレポーティング組織から適切に脱却しつつあると紹介しています。

  • JTBD of Modern Data Team
    • データの活用
    • メトリクス管理
    • プロアクティブなインサイト
    • 実験のドライブ
    • データとのインターフェース

紹介されていた各要素ごとの課題例のproblemとimpactがこちらです(ちょっと文量が多いので畳んでいます)。

データの活用(クリックすると展開)

  • データの活用
    • オペレーショナルデータを必要とするチームに提供すること
    • ex.
      • マーケティング部門からのリクエストで「ハブスポットで解約した顧客に自動メールを送信し、タッチポイントとアウトリーチを行いたい」
      • 解決したHow
        • 多様なソースからのデータを、主に内部データを含めて、dbtモデルに統合。このデータマーケットは、ビジネスの包括的な表現として機能し、意思決定に不可欠な業務属性、将来のフラグ、メトリクスおよびSSoTを提供。
        • リバースETLと組み合わせることで、各チームの好みや主要なSaaSツール(SalesforceやHubSpot、Intercomなど)にシームレスに同期されたSSoTを持つことが可能となり、効率的なデータ活用とリアルタイムのインサイトが実現可能。
      • インパクト
        • このワークフローを合理化し、データを取得して作業を行うのに何時間も費やす代わりに、数分で済むようになった。
        • このアプローチにより、彼らはツールセットを簡素化し、結果として効率的なセルフサービスモデルを実現。
        • マーケティングチームは最新の関連データに直接アクセスでき、タイムリーかつ正確に実行できるようになった。

メトリクス管理(クリックすると展開)

  • メトリクス管理
    • 共有された定義と重要な事実の基準を作成すること
    • ex.
      • もしファイナンスのステークホルダーに尋ねれば「アクティブカスタマー」とは、自分の銀行口座を接続した人だと言うでしょう。マーケティングに聞けば「アクティブカスタマー」は、完全なオンボーディングフローを完了した顧客だと言います。しかし、プロダクトに尋ねると「アクティブカスタマー」は、最近プラットフォーム上で活動があった顧客だと言います。では、どれが本当に正しいのでしょうか?
      • 解決したHow
        • セマンティックレイヤーを活用することで、これらのメトリクスを明確に定義し、文書化。
      • インパクト
        • Hexのようなツールや、ExcelやGoogle Sheetsを好むステークホルダーがアドホックレポートを作成する際にも使用可能に。
        • 指標に関する煩わしい問い合わせ対応が大幅に減少。

プロアクティブなインサイト(クリックすると展開)

  • プロアクティブなインサイト

    • プロアクティブ(=先手を取れる)ようなデータの提供 (= 先行指標を提供)
    • ex.
      • 顧客の解約が若干増えているが、どのデータが私たちが顧客を維持するためによりプロアクティブになる手助けをしてくれるか?
      • 解決したHow
        • 戦略的リーダーを特定、ビジネスユニットと密接に連携
        • 「アシュアランススコア」を開発
        • 顧客がサービスを解約する可能性を定量化し、チームが迅速に行動を起こすためのアラートを受け取れるようにする
      • インパクト
        • 。このデータ駆動型のアプローチにより、リスクのある顧客を早期に検出し、ターゲットを絞った介入措置を講じることが可能に。
        • 顧客のライフタイムバリューを向上させ、会社の長期的な成功と持続可能な成長において重要な役割を果たすことに成功。

実験のドライブ(クリックすると展開)

  • 実験のドライブ

    • プロアクティブなインサイトの発見と連携しながら、ビジネスに対して測定可能な影響を与えるための実験を推進すること
    • ex.
      • 現在使用している機能に問題が発生しました。リスクを高めたり、ビジネスへの影響を評価したりするために利用できるデータポイントはあるか?
      • 解決したHow
        • 組織内のステークホルダーと協力して、実験を展開
      • インパクト
        • 全体のスコアを向上させることができ、非常に洞察に富んだ重要な結果を得ることに成功

データのインターフェース(クリックすると展開)

  • データのインターフェース
    • ビジネス全体にわたるチームメンバーに必要な情報や結論を提供し、彼らがそれを活用できるようにすること
    • ex.
      • この収益はどこから来ているのか?モデルでどのように定義されているのか?この数字を週次レポートに使用しても良いのか?
      • 解決したHow

        • 彼らが自分自身で質問を探求し、答えを見つけるために必要なツールを提供できるようにする
        • description生成をAIに実行してもらいその内容をチェックするプロセスを実行する
        • dbtとmetabaseを接合して、metabase上でdbt exploreと同様のメタデータを閲覧可能とする
      • インパクト
        • 最終的にデータチームのレポーティング作業負担を軽減

JTBDのマトリクスは最終的にこのような形になります。

Settle社による所見

  • 生のデータ出力だけでは不十分であり、JTBDフレームワークは、ステークホルダーのコンテキスト、動機、および具体的なニーズを理解することが、データを実行可能なインサイトに変換し、ビジネスを推進するために重要である。
  • 私たちのステークホルダーを支援するために、データの活用を推進し、より効率的なセルフサービスモデルを実現するべきである。これにより、ステークホルダーは自身の専門分野で最も得意なことに集中でき、データの整理に関する煩わしさから解放される。

感想

  • 事業会社のデータ部署に勤めている僕としては、めちゃくちゃ刺さりました。
  • JTBDを弊社なりに構築しつつ、もっとアナリストやDSと協働して、意思決定に刺さる指標がビジネスに素早く届けられるような状態を構築しなきゃなあ。
  • なぜ早くデータを出せるようにするのか、なぜメタデータを拡充するのか、なぜこのようなインターフェースを構築するのか、などをしっかりとビジネスインパクトと紐づけた上で、今後意思決定をしていけるようになれる気がしています!

Breaking the mold: A smarter approach to data testing(型破り:データテストに対するより賢明なアプローチ)

発表者:Anton Heikinheimo (Senior Data Engineer @ Aiven) , Emiel Verkade (Senior Analytics Engineer @ Aiven)

概要

僕たちはdbt testを書きまくっているけれど、デリバリーが遅くなることの方がデータ品質において深刻なケースが多いよね。
warningの利用やWHERE句による代替で不要なテストを消してデータ品質を向上させていこう

セッション内容の紹介

朝にSlackを開いて、dbtパイプラインのfailedの通知を確認して、トリアージを決めて、ステークホルダーと合意形成して、解決策を実装・テストしてデプロイする。そんな朝がたくさんあるのはおかしい。dbtのデータテストのベストプラクティスに従っているはずなのに

そんな言葉から始まった本セッションでは、以下のようなMEMEでテストを書くこととデリバリー品質の向上が一致しないことに対する課題感を説明していました。

現状のdbtテストを単純に実装していくと、以下のような課題点があると説明しています。

  • テストが落ちるとその下流のビルドがすべて落ちるので、データの品質が落ちる。
  • 特定のモデルが更新される一方で、他のモデルが更新されないことがありロジックによっては致命的である。
  • buildコマンドではテストは落ちるが、run → testの順番なのでrunによって不正なテーブルが出力される。

データテストが何であるか、そして典型的なデータセットアップがどのようなものか を以下の図を用いて説明していました。

この図における右と左のアサーションテスト(正常な場合に予測されるものと一致していることを確認するテスト)の役割を整理すると、以下のように記述できます。

  • 左側のアサーションテスト
    • ソースデータに関する仮定をテストするのに役立ちます。
    • このデータは、外部および内部のソースから来る可能性があり、データコントラクトやQAフレームワークが組み込まれていないこともあります。
  • 右側のアサーションテスト
    • 私たちが適用したロジックに関する仮定をテストするためのもの。
    • すでにソースデータをテストし、それが期待に合致していることを確認していると仮定しているもの。
    • 入力データが検証された後、出力データをテストすることで、私たちはロジックの整合性を確認できる。つまり、dbtプロジェクトで行ったすべての変換が、期待した結果をもたらすことを確実にするためのテスト。

例えば左側のアサーションテストで落ちた場合は図中の Data と記載されたテーブルに悪いデータが留まり、左のアサーションテストが解決されるまで更新されない ショートサーキット が発生します。

ただし、テストの重要性が不明瞭で、モデルのテストに対して厳しい要件を持つことでプロセスを標準化しようとしたり、テスターなどのメトリクスを持つことで対処しようとしたりする場合、テストが品質に与える影響を無視しているとも言えます。

上流のプロダクトやSaasの変化や変更は加速しており、テストは「そのテスト作成時点のアサーションでしかない」という主張です。なのでよく落ちるテストに対しては削除することが合理的な場合があり、落ちるケースに対しては以下のような対応をしてしまうとのことでした!

<= before | after =>

このようにフィルターとして扱ってしまうことで、テストによるデータ鮮度の品質を落とさず、そもそも間違ったデータが渡らないようにしてしまおうという発想のものです。

テストはデータ基盤のしなやかさを構築するためのものでもあり、そのためにSettleのチームではテストのデフォルトの重要度を「警告」に変更したとのことでした。確かにこのようにすれば、上流の変化に“しなやかに”対応しつつデータ鮮度の品質は落とさずにいられますね。

また、このテストではなくフィルターを記載する取り組みをスケールさせるために、マクロを使用していると話していました。

<= before | after =>

↑こんな感じでマクロを呼び出せるようにして、外部キー制約やaccepted_valueなどをフィルターとして表現可能にしているとのことです!

最終的に以下のようにテストを減らしつつ、しなやかな構成に変更できたと締めくくられています!

感想

  • 弊社もdbt + Lookerで構築されたセマンティックレイヤーがかなりのオペレーションに活用されており、こちらのパイプラインの停止がビジネスの停滞に繋がりうるため、とても参考になる発表でした!
  • 外部に公開する数字とか請求金額とか絶対に間違えちゃいけないもの以外は、実は多少ずれていても意思決定に大きく影響しないものもありますもんね!
  • 主キー制約とかまでフィルターでやっちゃうのは執念が感じられて笑っちゃったのと、弊社だとSalesforceみたいなデータソースの自由入力や意図しないデータ入力にパイプライン全体が影響を受けていたりするので、すぐにでも実践を検討したいです!

How dbt transformed FinOps cost analysis at Workday(訳:dbtがWorkday社のFinOpsコスト分析をどのように変革したか)

発表者:Eric PuSpeaker (Senior Software Engineer @ Workday), Pattabhi Nanduri ( FinOps Data Engineer @ Workday )

概要

DBTとJinjaマクロを活用してAWSやGCPを中心としたプラットフォーム上でのコスト要因を把握
DBTマクロやテンプレートを用いることで、ユーザーの負担を軽減し、データモデルの構築から実装までを自動化
モデル定義を通じて、ドキュメンテーションの自動生成やテストの自動実行

  • Workday社でのビジネス上の課題
    • コストとコストドライバーの理解: AWSやGCPから発生するコストやその要因を把握。
    • コスト最適化の機会の特定: コスト削減のための最適化ポイントを特定。
    • コストの割り当て:アプリケーションサービス、顧客、テナントごとにコストを適切に割り当て。
    • コストの予測:未来のコストを見積もり、予測する。
    • レポートとセルフサービス機能: 自己サービス型のレポート作成、チーム開発、行レベルアクセスやオブジェクトレベルアクセスなど、SOXコンプライアンスに対応したアクセス制御。
  • 作成したダッシュボード(写真撮り忘れました)
    • 今日の作業全体が表示され、コンピューティング、ストレージ、データベースなど、さまざまな支出の詳細が表示されているもの。同様に、月ごとのコンピューティングトレンドも表示されているもの。
    • コンピュータに関連する支出の詳細が表示されているもの。現在の四半期での使用状況を見ることができ、プロセッサやインターネット利用料などがわかるもの。
  • ダッシュボードのDimension
    • 階層型の製品Dimension
      • 最初のレベルでAWS製品とGCP製品といった大分類で区切り、7つのレベルにブレークダウンする形で分割しているもの。
    • 階層型のプロジェクトDimension
      • マーケットや人、組織に関する情報が含まれる。人と組織の情報は、プラットフォームの所有者や責任者に関連している。

全体のデータ構造はこんな感じです。

ユーザーが早い段階で次元カラムとファクトカラムを明確に定義するようにして、カラムのタイプを一度だけ定義すれば、その情報がデータマートの最終段階まで引き継がれるようにしているとのことです。 モデルの概要を宣言するだけで、残りのコードが自動的に生成され、モデルが正しく効率的に動作するように設計されています。

こちら紹介されていたサンプルクエリ。

lightdashを活用しているので、その辺りのアクセス制御もマクロを活用して行っているとのこと。

  • 動的なユーザーフィルター
sql_filter: {account_project_id in [select account_project_id from cpus.flops.access_control_bridge where login_user=${lightdash.attributes.user_name}]}
  • ユーザーアクセスコントロール
- name: effective_discount_column
  data_type: numeric
  meta: 
    dimension: 
      required_attributes:
        is_opus_super_user: "true"
- name: aws_cur_table
  meta:
    required_attributes:
      is_opus_super_user: "true"
  • このような構成にしたメリット
    • ユーザーに多くの教育を必要としない。
      • パーティショニングが自動で切られてテストも自動で追加されるため気にしなくても良くなる。
    • 統一された生成方法なのでドキュメンテーションが自動的に生成される仕組みを導入できた。
    • 情報をリネージグラフと組み合わせて、実行計画を作成し、それをAirflowに送信、実行計画に基づいて、Airflowはクラスタの動的スケーリングを行い、各ステージのワークロードに応じた最適なリソースの割り当てが可能。

感想

  • クラウド料金を探索できるデータモデリングをする際のDimensionの切り方や、主要なコストはそれ単体をFactとして切り出して名前をつけてしまっているところなんかが地味に参考になりました!
  • マクロ化には賛否色々ありそうですが、テストが自動で設定されるようになっていたり、DBTが生成するドキュメントに自動的に反映するような仕組みになっていたりして、ここまでやりきってしまえるならメリットが大きそうだなあと思いました!

Surfing the LLM wave: We can't opt out and neither can you(訳:LLMの波に乗る:私たちも、あなたも避けることはできない)

発表者:Amanda Fioritto(Senior Analytics Engineer @ Hex), Erika Pullum(Analytics Engineer @ Hex Technologies)

概要

データ分析&BI統合ツールのHexにできたmagicと呼ばれるLLMによるサポート機能をHex社自身が使い倒して
LLMによるクエリ生成の精度をどうしたらどのくらい向上させることができるか試行錯誤したレポートです

セッション内容の紹介

Hex社にはドッグフーディングの文化があるので、リリースした magic というLLMによるクエリサポート機能を自社でどこまで活用できるか常に使用してきたそうで、社内のmagic機能に「パトリック」という名前をつけているそうです!

パトリックの精度は論文やLLMモデルの公式発表などによると90%であるとのこと。

パトリックをオンボーディングする時の仮説

⇒ 人間の同僚とそれほど違わないかもしれない。

⇒ 人間のステークホルダーにとってデータが役立つように工夫することが、パトリックが新しい役割で成功する手助けにもなるかもしれない。

⇒ データ組織の役割はステークホルダーにとって使いやすいデータ資産を作ることであり、現在ステークホルダーにはパトリックも含めている。

パトリックの評価の比較対象はspiderというtext-to-sqlのオープンソースとのことです。

パトリックの評価を比較可能にするために「前四半期に予約された会議の数はいくつですか?」という質問を投げることにしたが

  • dim_dates というテーブルがJOINできていなかった。
  • 会議の日を特定するカラムを指定できていない。

など人間のステークホルダーからもよく寄せられる質問のようなミスをした。

「MMセグメントにいる顧客数は何人ですか?」という質問にパトリックが答えられるためには「顧客」とは何か、「セグメント」とは何を意味するのか、「MM」が何を指すのかを理解する必要がある。

パトリックのチューニング方法

  • 「エンフォースメント」というツールを使ってDWH内のアクセス範囲を拡げる、または狭める。
  • ドキュメンテーションへのアクセスを許可してカンニングペーパーありの状態にする。

アクセス範囲のチューニングの実験結果

  • アクセス範囲を全snowflakeテーブルに拡大 ⇒ 正答率10%
  • アクセス範囲をHex社内のテーブルに限定 ⇒ 正答率38%
  • アクセス範囲をHex社内のテーブルに限定して、よく使われるテーブルにフラグをつける ⇒ 正答率46%

ドキュメンテーションの実験をする際に、ドキュメントの品質にも差をつけた。

  • 低品質: segment_typeEnterpriseMid-Marketなどの値を含むことができる。
  • 高品質: 低品質なものに加えて同義語も提供します。例えば、「Small Midsize(中小企業)」は「SMB」とも呼ばれるし、「Mid-Market」は別の呼び方もある。

ドキュメントの品質によるチューニングの実験結果

  • 低品質のドキュメント ⇒ 正答率33%
  • 高品質のドキュメント ⇒ 正答率51%

セマンティックレイヤーを使った場合の実験結果

  • 正答率75~88%

実験結果を受けてHex社の見解

  • MMをMidMarketと変換できるような人なら、パトリックのサポートをうまく活用し、自分たちの作業を進められるかもしれません。
  • データチームにとって、これらのツールがどのように、そしてなぜ機能するのか、またそれが質問に答えようとする人たちにとって役立っているのかを理解することが重要です。
  • データウェアハウスの整理やモデルのドキュメント化やコンテキストの整理は必要です。
    • 重要なテーブルをマーキングする作業と高品質のドキュメント整備がそこまで差異がなかったのは驚異的でした。
  • LLMをうまくクエリビルダーとしてワークさせたいならセマンティックレイヤーの導入が必要そう。

感想

  • LLMをクエリビルダーとして使う想像は誰もがしたと思いますが、(僕も去年試行錯誤しましたhttps://speakerdeck.com/okodoon/slackkarazi-you-yan-yu-deshe-nei-zhi-biao-wowen-ihe-waserarerubotwozuo-ritaka-tuta)実際にこれをすると何%改善するのかというところまで定量的に示してくれている実例は滅多にないので素晴らしい発表だと思いました!
  • セマンティックレイヤーを作っていくことで、社内のクエリコスト低下だけでなくLLM活用まで見据えられそうなことが明確に示唆されたので、セマンティックレイヤー整備を引き続き頑張ります!
  • LLMをステークホルダーと捉えてマシンリーダブルなデータ基盤に寄せていくって発想は今後のデータ基盤にきっと求められていく要素なんだろうなあと思いました!

Semantic layers: The next data revolution or just overrated hype? (訳:セマンティックレイヤー:次のデータ革命か、それとも過大評価された流行か?)

発表者:Katie Hindson(Head of Product and Data @ Lightdash)

概要

dbtによってトランスフォーメーションが容易になったが課題が多く、数字の不整合の解消、指標の統一、LLMの活用といった課題を解決するためにセマンティックレイヤーが有用であると思われる。
ユニバーサルなセマンティックレイヤーを参照できるツール(Lightdash)がセマンティックレイヤーの活用方針としては望ましい

セッション内容の紹介

セマンティックレイヤー不在における課題点を以下のようなスライドで紹介しています。

  • クエリごとに同じ指標を出しているはずなのにバラバラになってしまう。
  • 指標の定義が社内で噛み合わない(アクティブユーザーのアクティブって何?「使用」の定義は?)
  • LLMをデータ基盤で活用するためには同じ質問に対して同じ答えが得られることが重要。

そして、今日のセマンティックレイヤーは以下のようにスタンドアロン型かバンドル型かに分類されるとの主張をしていました。

  • スタンドアロン型
    • ex. ATSCALE, Minerva, cube, dbt Semantic Layer
    • インテグレーションが不足しており、ビジネスユースケース足り得ない。
  • バンドル型
    • ex. Lightdash, MicroStrategy, Looker, SAP
    • BIツールに統合されたセマンティックレイヤー。他のモダンデータスタックとのインテグレーションが不足している。

セマンティックレイヤーの使用体験として必要なもの

  • メトリクスファーストの探索(テーブルを意識しないで指標名だけで思考が完結するような体験)。
  • データカタログでメトリクスの意味が確認できること。
  • データカタログから、簡単にメトリクスの探索ができること。

これらの体験を満たしているセマンティックレイヤーとして、Airbnb社が内製しているMinervaがとても優れていると述べていました。(Minervaに関するAirbnb社の記事はこちら

セマンティックレイヤーのユニバーサル性として必要なもの

  • スタック全体に適用できるほど汎用的
  • 必要なすべてのツールと統合可能

今後セマンティックレイヤーがデータ基盤の中心となるため、あらゆるデータスタックと接続可能な状態を構築する必要があるとのことでした!

感想

  • 結構ポジショントークみが強く「ユニバーサルって言葉をLightdashにだけ使うのは言葉として強すぎるのでは?」という指摘をQAで受けていて少し面白かったです。
  • Looker上にセマンティックレイヤーを構築している弊社としては、データカタログからの滑らかな探索体験みたいなところは実現が難しそうで、Lightdashも全然候補になってくるなと思いました!
  • Gemini on Lookerを超えるセマンティックレイヤー✖️LLMの体験を創出できるのか、これからもWatchし続けていきたいです。

【イベントレポート】タイミーのレコメンドにおける ABテストの運用

イベント概要

2024年9月18日に「GENBA #4 〜データサイエンティストの現場〜」と題してタイミー、ビットキー、AbemaTVの3社でデータサイエンスに関する合同勉強会を開催しました。 今回はそちらの勉強会からタイミーのデータサイエンティストである小関さん(@ozeshun_)の発表をイベントレポート形式でお伝えします。

続きを読む

Vertex AI Pipelinesを効率的に開発するための取り組み(part2)

こんにちは、タイミーのデータエンジニアリング部 データサイエンス(以下DS)グループ所属のYukitomoです。

DSグループではMLパイプラインとしてVertex AI Pipelinesを利用しており、その開発環境の継続的な効率化を進めていますが、今回はここ最近の変更点を紹介したいと思います!

Vertex AI PipelinesについてはGoogle Cloudの公式ページや、前回の記事を参照ください。

モノレポ環境に移行

当初はパイプライン毎にレポジトリを用意していました。しかしながら新規でパイプラインを起こす度にレポジトリの作成から行うのは、

  • ちょっとした“作業”ではあるのですが気軽に行うには少し腰が重い
  • cookie cutter を使って初期状態を揃えたり前回の記事のような標準化を行っても、異なるレポジトリを異なる開発者によりメンテナンスを行うと、それぞれが独自の進化をしたり属人化したりしがち

といった問題を抱えていました。そこで、モノレポ化して1箇所に集積し、

  • CI/CDや、パイプラインビルド等の付随スクリプトを共用化、付随スクリプトのような非本質的な機能開発を効率化
  • フォルダ構成やファイルの命名規則などを統一、“隣のプロジェクト”を参照しやすくすることで、ベストプラクティスを共有化、パイプラインの機能そのものの開発を効率化

することを目指しました。同一レポジトリ傘下に収めることで従来よりも敷居が下がり、共通知化を進められていると感じています。

コンテナイメージの共通化

パイプラインを1箇所のレポジトリに集めた段階でパイプラインのコンポーネントは200個以上あり、パイプラインのコンポーネントそれぞれが独自にDockerfileやpyproject.tomlを持っていました。脆弱性対応や機能追加のための依存モジュールのアップデートはそれぞれのpyproject.tomlを更新することになりますが、ファイルの数が多いと更新に手間がかかってしまいます。そこで、同一パイプラインのコンポーネント間ではコンテナイメージを共用できるような形にアーキテクチャを改めました。

おおまかな方針は以下のとおりです。

  1. コンポーネントの入出力を定義するyamlファイル(component.yaml)はそれぞれ名前を変え、1つのフォルダにまとめる。
  2. コンポーネントの中のロジックを記述するpython コードも1箇所にまとめ、全体をコンテナイメージに複製。
  3. 単一コンテナだけでは処理しきれない場合を考慮し、複数のコンテナイメージを格納できるようコンテナイメージ用のフォルダは階層化。

従来のアーキテクチャ

% tree PIPELINE_X

./PIPELINE_X
├── components
│   ├── component_A         # コンポーネント毎にフォルダを用意し、
│   │   ├── Dockerfile      # Dockerfile/pyproject.tomlはそれぞれ独立に配置
│   │   ├── component.yaml
│   │   ├── pyproject.toml
│   │   └── src
│   │       └── ...
│   ├── component_B
│   │   ├── Dockerfile
│   │   ├── component.yaml
│   │   ├── pyproject.toml
│   │   ├── src
│   │       └── ...
│   └── component_C
│       ├── Dockerfile
│       ├── component.yaml
│       ├── pyproject.toml
│       ├── src
│           └── ...
└── pipelines
    └── main.py 

新しいアーキテクチャ

% tree ./PIPELINE_X

./PIPELINE_X
├── components
│   ├── definitions           # 1. component.yamlは1箇所に集約
│   │   ├── component_a.yaml
│   │   ├── component_b.yaml
│   │   └── component_c.yaml
│   └── src                   # 2. src以下全てをコンテナイメージに複製.
│       ├── component_a.py    # component_*.yamlの設定で動作するpython fileを指定
│       ├── component_b.py    # DockerfileのCMDを指定するイメージ
│       └── component_c.py
│
├── containers                # 3. 単一コンテナでは難しい場合に備え
│   └── main                  # 複数のコンテナを利用できるようフォルダを階層化
│       ├── Dockerfile
│       └── pyproject.toml
└── pipelines
    └── main.py

コンテナ数を減らすことで、dependabotの運用は格段に楽になりました。コンテナが減ることで警告の数も下がり、警告の数が下がることで更新の初動も取りやすくなるという好循環のおかげで、2024年10月現在、dependapotからの警告は画面のスクロールが不要な範囲にはおさまるようになってきました。

また、コンテナを集約する段階で気がついたのですが、いくつかのDockerfileの中で利用するpoetryのバージョンが古いままだったり、マルチステージのビルドが正しく行われていなかったりするものも少なからずありました。Dockerfileに限らずコードライティング全般に言えることですが、記述量は可能な限り少なくする方が、このような小さな不具合の発生は抑制でき、安定したコードを供給できます。

CDにおけるビルドキャッシュの利用

タイミーDSグループにおいて、CI/CD環境はGitHub Actions、クラウド環境はGoogle Cloudを利用しています。指定されたトリガー条件が発生した時にコンテナイメージをビルドするのですが、GitHub Actionsの場合、ジョブ単位でVMが異なるため、連続するGitHub Actionsの実行の場合でもdockerのビルドは一からやり直しになってしまいます。 そこで、こちらこちらの内容を参考に、ビルド結果をVMの外部、Artifact Registryにキャッシュ、次回実行時に再利用することでCI/CD の処理を高速化させました。なお、以下の設定ではbuildcacheは通常のコンテナ用Artifact Registry(下のコードで言うと${IMAGE_NAME})とは異なるRegistry( ${IMAGE_NAME}-buildcache )に保存しています。

GitHub Actions内での記述より抜粋

docker buildx create --name container --driver=docker-container

docker buildx build \
  --builder=container \
  :
  --cache-from=type=registry,ref=${IMAGE_NAME}-buildcache \
  --cache-to=type=registry,ref=${IMAGE_NAME}-buildcache,mode=max \
  -t ${IMAGE_NAME}:${IMAGE_TAG} \
  --load .
              
docker push ${IMAGE_NAME}:${IMAGE_TAG}

# -cache-from/-cache-toに指定するrefの値にsuffix '-buildcache'を付加し
# 本来のイメージとキャッシュイメージの置き場所を分離しています。

パイプライン命名規則の工夫

MLパイプラインを開発していると、

  • あるパイプラインを少しだけ変えたパイプラインを実現したい
  • Gitの別ブランチで管理すればいいんだけれど、比較しながらコード書きたい

といったケースはよくあると思います。簡単にこれを実現しようと cp -r でパイプラインを丸ごとコピーしたとしても、従来のアーキテクチャでは様々な設定(パイプラインの名前、参照するコンテナイメージの名前、バージョン情報)を書き換える必要があります。そのため、煩わしい作業が発生していました。また、それらの設定方法も統一が取れておらず、“微妙に”パイプライン毎に異なっていました。そこで、それらのバージョン情報以外の情報を全てパイプラインが保存されているフォルダのパス情報から取得するよう統一し、cp -r だけですぐにパイプラインの亜種が作成できるようにしました。

従来のアーキテクチャ

# 1. パイプラインの名前はパイプラインのpyproject.toml内のname属性や環境変数(dotenv)を利用
# 2. コンテナイメージの名前は コンテナイメージのpyproject.toml内のname属性を利用
# 3. Version情報:
#    パイプライン    -> パイプラインのpyproject.toml内のversionを利用
#    コンテナイメージ -> コンテナイメージのpyproject.toml内のversionを利用
 
. PIPELINE_X
├── components
:
│
├── containers
│   └── main
│       ├── Dockerfile
│       └── pyproject.toml    # 2 [tool.poetry].name    -> パイプラインの名前# 3 [tool.poetry].version -> パイプラインのversion
├── pipelines
│   └── main.py
├── .env.* (prod/stg/dev..)   # 1 パイプラインの名前は .envからやpyproject.tomlなど
└── pyproject.toml            #   各種のやり方が存在。
                              # 3 [tool.poetry].version -> コンテナイメージのversion

# Compile されたpipeline config抜粋
{
  :
  "deploymentSpec": {
    "executors": {
      "exec-comp_a": {
        "container": {
        :
          "image": "${GAR_REGISTRY_PREFIX}/blahblahblah:vX.Y.Z"
          # 2. コンテナイメージの名前"blahblahblah"はコンテナイメージのpyproject.tomlより
          # 3. コンテナイメージのVersion "vX.Y.Z"はコンテナイメージのpyproject.tomlより
        }..}..}..},
      :
  "pipelineInfo": {
    "name": "arbitrary_string"
    # 1. パイプラインの名前は
  },

# 注: ${GAR_REGISTRY_PREFIX} は Artifact Registry のアドレス

新しいアーキテクチャ

# 1. パイプラインの名前はRepository内のフォルダ位置を利用 (= ${SERVICE}-${PIPELINE} )
# 2. コンテナイメージの名前は "${パイプラインの名前}"-"${コンテナのフォルダ名}"
# 3. Version情報:
#    パイプライン    -> パイプラインのpyproject.toml内のversionを利用
#    コンテナイメージ -> パイプラインのversionを利用

SERVICE/**/vertex_ai_pipelines/PIPELINE_X  # 1 
├── components
:
│
├── containers
│   └── main                             # 2
│       ├── Dockerfile
│       └── pyproject.toml
├── pipelines
│   └── main.py
├── pyproject.toml
└── .env.* (prod/stg/dev..) 

# Compile されたpipeline configの一部を抜粋
{
  :
  "deploymentSpec": {
    "executors": {
      "exec-comp_a": {
        "container": {
        :
          "image": "${GAR_REGISTRY_PREFIX}/${SERVICE}-${PIPELINE_X}-main:vX.Y.Z"
        }..}..}..},
      :
  "pipelineInfo": {
    "name": "${SERVICE}-${PIPELINE_X}"
  },
  :
  
# 注: ${GAR_REGISTRY_PREFIX} は Artifact Registry のアドレス

ちょっとした変更ではあるのですが、新しいパイプラインを構築する際の初動を早くすること、また簡単にできることにより、新しい方式を試そうという心理的な敷居を下げることができていると考えています。

今回紹介した取り組み以外にも、Vertex AI Pipelinesに限らず効率化するための具体的なアイデアはいくつかあるのですが、プロダクションを動かしながら変更しており、障害の発生を抑えるためにも、一度に大きな変更は与えずステップを踏みながらMLOps基盤を理想の姿に近づける活動を続けています。

We’re Hiring!


タイミーのデータエンジニアリング部・データアナリティクス部では、ともに働くメンバーを募集しています!!

現在募集中のポジションはこちらです!

「話を聞きたい」と思われた方は、是非一度カジュアル面談でお話ししましょう!

PyCon JP 2024参加レポート

みなさんこんにちは。タイミーのデータエンジニアリング部 データサイエンスグループ所属の菊地と小関です。

2024年9月27日(金)、28日(土)に開催されたPyCon JP 2024に参加してきました。今回はPyCon JP 2024の雰囲気と、特に興味深かった&勉強になったトークセッションをいくつかピックアップしてお届けしようと思います!

PyCon JPとは

PyConJPは1年に1度開催されていて、今年はTOC有明コンベンションホールにて9月27日(金)、28日(土)の2日間にわたって開催されました。

概要については、PyCon JP 2024の「What is PyCon JP」をそのまま引用させていただきます。

PyCon JP は、Python ユーザーが集まり、Python や Python を使ったソフトウェアについて情報交換、交流をするためのカンファレンスです。 
PyCon JP の開催を通じて、Python の使い手が一堂に集まり、Python にまつわる様々な分野の知識や情報を交換し、新たな友達やコミュニティとのつながり、仕事やビジネスチャンスを増やせる場所とすることが目標です。

当日のタイムテーブルはこちらを参照いただければと思います。

PyCon JPの雰囲気

今年の参加者数は600名超で、日本国内のみならず、海外からの参加者も多く、非常に活気がありました。昼食についても様々な文化圏の方に配慮して用意されていた印象です。

また、企業ブースも多数出展しており、トークセッションで気になった企業様の発表内容を更に詳しく伺うことができました。スタンプラリーや書籍販売、Pythonに関する求人が掲載されている等、ビジネスチャンスを増やせるよう、非常に配慮された設計だったと感じています。

個人(菊地)的には、企業ブースにいたGrooveX社の「LOVOT」がとてもかわいかったです(写真を撮っていないのが心残りです…)。

特に興味深かった、勉強になったトークセッション

まず、小関が興味深かった&勉強になったトークセッションを紹介します。

FastAPIでのasync defとdefの使い分け

speakerdeck.com

このセッションでは、タイトル通りのFastAPIにおける実装方法の使い分けを、Pythonにおける並列処理・並行処理・非同期処理の性質を説明した上で解説しており、非常にわかりやすかったです。

要点は以下の通りでした。

  • マルチスレッド、非同期処理ともにI/Oバウンドな処理の場合に高速化が期待できるが、マルチスレッドはスレッドが増えるとスレッド切り替え分だけ処理速度が低下してしまう
    • つまり、スレッドが多くなるような処理だと非同期処理の方が処理速度が速くなる場合がある
  • Fast APIにおけるdefasync defの違いと使い分け
    • def
      • 並行処理 (マルチスレッド)
      • 同期処理を行いたい場合はこちらを使う
    • async def
      • 非同期処理
      • マルチスレッドだとスレッドの切り替え時間がかさむぐらいのリクエスト量をさばきたい時に有効

低コストで実現する社内文書RAG機能を搭載したAIチャットボット開発

speakerdeck.com

このセッションでは、RAG機能を用いたAIチャットボットの開発について、主に開発前の実装スコープの決め方や実装方法の詳細の観点からお話しされていました。

開発前にpros & consを言語化して、目的にあったHowとして今回のRAG + Chat botを選択した過程がわかりやすくまとまっていたり、システムのアーキテクチャ自体も丁寧に説明されていたりしたので、今すぐにでも社内で試せそうな感じでした。

弊社だとNotionのドキュメント量が膨大なので、indexingするドキュメントの選定基準をどう決めたのかが特に気になりました。Notionのページ階層が綺麗にまとまっている組織だとindexingする対象を選択する時の手助けになるのかなとも思いました。

LlamaIndexは未履修なので、近々個人で触ってみようと思います!

次に、菊地が興味深かった&勉強になったトークセッションをピックアップして紹介します。

PandasAI:生成AIがデータ分析業務にもたらすパラダイムシフト

speakerdeck.com

このセッションでは、機械学習・生成AI・データ分析の基礎の基礎を説明した後に、PandasAIについて紹介しています。

PandasAIとは、自然言語でデータ分析をしたり可視化を行ったりできるデータ分析のためのAIエージェントで、OSSとして公開されています。OpenAIのAPIキーがあれば使用できるとのことです。

また、SaaSとしても提供しており、登録・課金を行えばAPIキーがなくとも使用できるそうです。

データコネクタとしては、CSVやParquet, XLSX等はもちろん、PostgreSQL, MySQL, BigQuery, Databricks, Snowflakeといった各種クラウドサービスのデータソースへ接続できます。

内部の処理としては、自然言語をPythonコードやクエリに変換してデータを操作し、結果をユーザーへ返却しており、悪意のあるコードの実行に対する制御もできるそうです(ホワイトリストとして特定のモジュールのみ実行可能にする等)。

OSSとして提供されているので一度試してみたいなと思っているのですが、弊社でも導入しているLookerやその他BIツールに搭載されているAI機能とどのように差別化していくのかは気になりました。

データサイエンスのフルサイクル開発を実現する機械学習パイプライン

speakerdeck.com

このセッションでは、まずCARTA MARKETING FIRM社におけるデータサイエンティスト像「フルサイクルデータサイエンティスト」について紹介し、類似概念「フルスタック」との違いを説明しています。

その上で、理想状態とのギャップを課題として整理し、データサイエンティストがより本質的な価値創出ができる状態に向けて、これまでのデータ分析基盤の歴史(luigi → Amazon SageMaker → Prefect)が紹介されています。

タイミーのデータサイエンティストも「フルサイクルデータサイエンティスト」に近い働き方をしている点や、ML基盤の歴史が似通っていたり、チームの規模感や構成が近いなど、多くの共通点がありました。「わかる〜」と心の中でうなずきながら、セッションを聴かせていただいておりました。

あえてApache AirflowではなくPrefectを選定した経緯などは、機会があればぜひ伺ってみたいなと思いました。

終わりに

いかがでしたか?PyCon JP 2024の雰囲気が少しでも伝わっていますと幸いです。次回は広島開催とのことで、ぜひ来年も参加させていただきたいなと思っています。

ちなみに、タイミーには「TDE10」という、プロダクト開発やデータ職種メンバーを対象とした成長支援制度があります。今回は「世界中で開催されているすべての技術カンファレンスに無制限で参加できる『KaigiPass』」を利用してPyConJPに参加しました。

今後もこのような機会があれば、積極的に技術カンファレンスに参加していきたいと考えておりますし、外部登壇も積極的に行っていきたいです。

We’re hiring!!!

現在、タイミーでは、データサイエンスやエンジニアリングの分野で、共に成長し、革新を推し進めてくれる新たなチームメンバーを積極的に探しています!

また、気軽な雰囲気でのカジュアル面談も随時行っておりますので、ぜひお気軽にエントリーしてください。↓

product-recruit.timee.co.jp hrmos.co hrmos.co hrmos.co hrmos.co

新規プロジェクトでのルールベース手法の活用

こんにちは、株式会社タイミーでデータサイエンティストをしている貝出です。直近はカスタマーサポートの業務改善に向けたモデルやシステムの開発を行っております。

新規プロジェクトを始めるにあたって、予測や検知の機能といった複雑な課題に取り組む必要がある際、機械学習モデルを使うことを検討される方も多いと思います。しかし、Google の定めた Rules of Machine Learning: Best Practices for ML Engineering でも記載されているように、必ずしも最初から機械学習モデルを使うことが最適とは限りません。データの不足や問題の不明確さから、機械学習が効果的に機能しない場合もあります。

その一方で、ルールベースなどのシンプルなアプローチを用いることで、早期にプロダクトやサービスを開発し、ユーザーの反応を得られます。この段階でデータサイエンティストや機械学習エンジニアが関与することで、後々の機械学習モデルの導入をスムーズに進めることが可能です。

本記事では、新規プロジェクトでのルールベースの活用方法と、その段階でデータサイエンティストができることについて書きたいと思います。

新規プロジェクトにおける早期フィードバックと早期成果

構築・計測・学習のフィードバックループ

新しいプロダクトやサービスを開発する際には、できるだけ早く最小限の機能を持つ製品(MVP:Minimum Viable Product)を作成し、ユーザーからのフィードバックを得ることが重要です。これは、エリック・リースの『リーン・スタートアップ』で提唱されている手法で、迅速なサイクルで仮説検証を行うことで、無駄を最小限に抑えながら製品を改善していく考え方です。

早期にユーザーの反応を得ることで、問題設定や解決策が適切かを迅速に判断できます。もしユーザーに使われなかったり、期待した効果が得られなかったりする場合は、素早く方向転換(ピボット)することが可能です。このように、早期フィードバックはプロジェクトの成功確率を高める重要な要素となります。

具体的な成果物を早く提供することで、ステークホルダーからの信頼を得やすくなり、追加のリソース確保やプロジェクトの優先順位向上にもつながります。

機械学習モデル構築の課題

機械学習モデル(今回は教師あり学習の場合に限定します)を構築する際には、データの質と量が極めて重要です。しかし、新規プロジェクトでは利用可能なデータが限られていたり、ラベリングルールが明確でなかったりすることも多く、高性能なモデルを開発するのが困難である場合があります。

例えば、数千から数万件のラベル付きデータが必要な場合、データの収集とラベリングには数週間から数ヶ月、さらにはそれ以上の時間と多大なコストがかかることがあります。また、専門知識が必要なラベリング作業では、ラベルの一貫性を保つために教育や管理も必要です。

データが少ない場合、モデルは訓練データに過度に適合し、未知のデータに対しては性能が低下する「過適合(オーバーフィッティング)」が起こりやすくなります。逆に、データのパターンを十分に学習できず、訓練データでも性能が低い「過小適合(アンダーフィッティング)」の状態になることもあります。

このような状況では、データの追加収集やラベリングにかかる時間とコストを考慮し、新規プロジェクトではまずシンプルなルールベースの方法を検討することが有効です。

ルールベースと機械学習ベースの違い

ルールベースと機械学習ベースのアプローチの違いを簡単に整理します。

ルールベース 機械学習ベース
定義 人間が設定したルールで動作 データからパターンを学習
メリット ・簡易性
・迅速な開発
・解釈性
・高い精度
・適応性
・高度なパターン認識
デメリット ・柔軟性の欠如
・拡張性の限界
・開発コスト
・解釈の難しさ

ルールベース

  • 定義:人間が設定したルールや条件に基づいて動作する
  • メリット
    • 簡易性:実装が比較的容易で、結果が理解しやすい
    • 迅速な開発:短期間での開発・デプロイが可能
    • 解釈性:なぜその結果になったのか説明しやすい
  • デメリット
    • 柔軟性の欠如:複雑なパターンや例外への対応が難しい
    • 拡張性の限界:ルールが増えると管理が煩雑になる

機械学習ベース

  • 定義:データからパターンを学習し、予測や分類を行う
  • メリット
    • 高い精度:大量のデータから複雑なパターンを学習可能
    • 適応性:新しいデータや状況にも柔軟に対応
  • デメリット
    • 開発コスト:データ収集やモデル構築に時間とリソースが必要
    • 解釈の難しさ:モデルがブラックボックス化しやすく、結果の説明が難しい場合がある

事例:スパムメールのフィルタリング

  • ルールベースの場合:特定のキーワードや送信元をブロックリストで管理。実装が簡単で明確な基準で判定可能。
  • 機械学習モデルの場合:メールの内容を解析し、ナイーブベイズや深層学習モデルでスパムを分類。大量のデータで高精度を実現。

ルールベースモデルの活用

迅速な実装とデプロイ

ルールベースモデルはシンプルなため、短期間で実装・デプロイが可能です。これにより、ユーザーからのフィードバックを早期に得られ、製品の改善に活かせます。

ルールベースモデルにおけるデータサイエンティストの役割

データサイエンティストは、ルールベースのアプローチでも以下のような重要な役割を果たせます。

  • データ分析によるルール策定支援:データの傾向やパターンを分析し、効果的なルールの策定をサポートする
  • 性能評価とモニタリング:モデルの性能を定期的に評価し、改善点を提案する
  • エラー分析とルール改善:誤判定の原因を特定し、ルールの精度向上に貢献する
  • 将来の機械学習モデルへの布石:データの蓄積とラベリング戦略を立案し、スムーズな機械学習モデルの導入を支援する

段階的な開発プロセス

段階的な開発プロセスの一例として、以下のような進め方が考えられます。

段階的な開発プロセスのイメージ

  1. ルールベースでの MVP 開発
    • シンプルなルールを用いて基本機能を実装
    • 迅速なデプロイを目指す
  2. フィードバックの収集
    • ユーザーや領域専門家(ドメインエキスパート)から意見を収集
    • ルールの有効性や不足点を把握
  3. 評価と改善の繰り返し
    • 性能指標を用いてモデルを評価
    • エラー分析を行い、ルールを最適化
  4. 機械学習モデルの導入検討
    • ルールベースの限界が見えた段階で機械学習の導入を検討
    • データの蓄積状況やビジネス価値を総合的に判断

まとめ

ルールベースと機械学習モデルの双方にメリットとデメリットがあります。新規プロジェクトにおいて、データが十分に揃っていない初期段階では、ルールベースなどのシンプルなアプローチを活用することで迅速に価値を提供し、フィードバックを得られます。

データサイエンティストが早期から関与し、評価やエラー分析、データ品質の向上に努めることで、プロダクトの質を高めつつ、将来的な機械学習モデルの導入をスムーズに進めることが可能となります。

ビジネス価値が確認できた段階で機械学習モデルを導入することで、より高度な機能や精度の向上を実現できます。この段階的なアプローチは、リソースの有効活用とプロジェクトの成功に寄与することが期待されます。

おわりに

今回はルールベースのアプローチの活用を中心に紹介しましたが、技術的にルールベースでは実現が難しいケースもあります。例えば、画像内の文字を機械が読み取れる形式に変換する光学文字認識(OCR)は、ルールベースでの実装が困難です。そのようなケースでは、ルールベースではなく、既存の機械学習モデルや Google の Cloud Vision API などの SaaS を最初のアプローチとして利用することになるかもしれません。

新規プロジェクトでは、限られたリソースや時間の中でいかに迅速にユーザーに価値を提供するかが重要です。シンプルなアプローチから始めて、段階的に機械学習モデルを導入することで、プロジェクトのリスクを最小限に抑えつつ、より高度な機能を実現できます。

私はタイミーにおけるデータサイエンティストとして、このプロセスに積極的に関与し、ビジネスと技術の橋渡し役を目指しています。

現在、タイミーでは、データサイエンスやエンジニアリングの分野で、共に成長し、革新を推し進めてくれる新たなチームメンバーを積極的に探しています!

product-recruit.timee.co.jp

また、気軽な雰囲気でのカジュアル面談も随時行っておりますので、ぜひお気軽にエントリーしてください。↓

hrmos.co

hrmos.co

dbt Coalesce 2024 のKeynote「Innovating with dbt」現地レポート

2024年10月7日から10日(現地時間)にかけて、dbt Coalesce 2024がラスベガスで開催されています。

私たち株式会社タイミーからは、4名が現地参加しました (※)。 今回は、カンファレンスの最初のKeynoteについてご紹介したいと思います。

このKeynoteでは、dbtのビジョンや今後の新機能リリースに関する熱いトピックが多く取り上げられ、非常に刺激的な内容となりました。

以下がアジェンダです。


ここからはKeynoteのレポートをお届けします。

発表内容とその他を切り分けるため弊社メンバーの今回の発表に対するコメントや確認した内容はこのマークアップスタイルで表記します。

イントロ

2024年のdbt Coalesceには、世界中から2000人以上の参加者がラスベガスに集まり、オンラインでは8000人もの方が参加していました。分析エンジニアやデータエンジニアはもちろん、アナリスト、CDO、財務、マーケティング、プロダクト担当者など、さまざまな役割を持つ人々が一堂に会し、dbtのコミュニティの成長を感じました。

既に5万以上のチームが本番環境でdbtを利用しており、毎日1350万回もの実行が行われ、過去1年間で49億ものモデルが構築されているそうです。

データ変換の課題が解決されつつある一方で、品質やオーナーシップ、そしてステークホルダーのリテラシーといった新たな課題が浮上しています。特に、データシステムをソフトウェアシステムと同様に扱う必要性がますます強調されていることが印象的でした。

dbtは、ソフトウェアエンジニアリングのベストプラクティスを取り入れた「ADLC(Analytics Development Lifecycle)」という新しい概念を提案し、分析の全過程をカバーするエンドツーエンドのワークフローを提供しています。このアプローチが、今後どのようにデータ活用を進化させていくのか、とても楽しみです。

画像はhttps://www.getdbt.com/resources/guides/the-analytics-development-lifecycleより抜粋

新機能の紹介

今回の Keynote では dbt Cloud の新機能として dbt Copilot、 Advanced CI、ビジュアルエディティング、クロスプラットフォーム連携などが紹介されました。

dbt Cloud はオーケストレーションやオブザーバビリティ、カタログやセマンティクスの機能を持った Data Control Plane と説明されていました。

今回発表された新機能も Data Control Plane の一部とのことで、抜粋しながら紹介していきたいと思います。

画像はhttps://www.getdbt.com/blog/coalesce-2024-product-announcementsより抜粋

dbt Copilot

LLMはコード作成に優れており、データワークを大幅に簡素化できる可能性がある。dbt Copilotは、モデル、テスト、メトリクス、ドキュメントなどを支援してくれます。

ログ分析による根本原因分析、クエリプロファイルの分析と改善の提案によるコスト削減、ビジネス上の質問などを行うための自然言語インターフェースの提供など、さまざまな機能を持つチャット画面も追加されます。

  • OpenAIのAccesskeyを登録することで利用が可能になるそうです。

dbt開発に慣れ親しんでいないメンバーがこれを使ってすぐに開発者になることは難しそうですが、これまでdbt開発をしていたメンバーがアシスタントとして並走してもらう形で活用することで、開発スピードが向上させられそうです。

Visual Editing Experience

  • NoCodeでブロックを繋げるだけでdbtモデルを作成可能となる機能が発表されました。

ドラッグ&ドロップ・インターフェースをベースとして、元データからブロックを繋げるだけで変換、計算、フィルターなど少し風雑なモデルも作ることができます。ビジュアル編集モデルはSQLに変換されgitによって管理されます。作ったモデルはdbt上の基本機能であるテストとドキュメントに接続できるため、dbt上と同じ信頼性を担保できます。ベータ期間に申し込むのはこちらから。

DataMesh的な思想で開発を分散可能になりうる部分は素晴らしいと感じましたが、ビジネスメンバーに機能を譲渡する前にしっかりガードレールを敷くような開発を行わないとカオスが発生しうると感じたため、機能利用可能時にはその辺りは深くチェックしたいです!
弊社はSQLに慣れ親しんでいないビジネスメンバーが大きなボリュームを占めているので、この機能がしっかりしたガードレールの元でハマることがあれば開発スピードを大きく高めることができそうです!

Advanced CI

これまでのdbt Cloudではslim CIの概念に則って、変更差分とその影響範囲をテストして開発速度を向上させてきましたが、「CIでテストが通ってビルドが通ること」と「期待した変更が正しくされたこと」が一致しないケースも多々あり、今回の advanced CIはそちらを解決する機能として紹介されていました。

そのPRで変更対象となったモデルの実行結果と、直近の本番ビルドの実行結果と比較して「作成されるモデルがこのPRでどのように変化したのか」を確認できるような新しいCIです!

以下の内容を本番とCIの差分として確認できます。

  • 追加、変更、または削除された行または列
  • 列内の値の変更
  • 列のデータ型または列の順序の変更
  • 主キーの変更または重複
  • データモデル全体と比較して、変更、追加、または削除された行の割合

紹介されている画面

  • dbt Cloud上のCI Job詳細画面

  • PullRequest上に投稿されるdbt Cloudからのコメント画面

こちらの機能によって以下のメリットがあると説明されています。

  • 不正なデータを本番環境にデプロイされることを防止できることによるデータ品質の向上
  • 行レベルの変更を確認可能となることで、行レベルテストなどが不要になることによる開発者の速度向上
  • 本番環境の手前で消化活動が可能なため、事後対応が減ることによるコスト効率の向上


早速ちょっとやってみました。(色々な事情ありが成功版と中身をお見せできず、すみません)CI環境のJobで Run compare changes のオプションをONにします。
この機能をONにしないとCI Jobの画面で以下のような表示になります。

pull request上にadvaced CIのコメントがしっかりされました!

(advanced CIに対するコメント)
全てのケースを網羅するテストを書くことは難しいため、コードやデータの変更を自動的に確認できるようになるこのCIは、「これこそ顧客が求めていた機能だ」と感じました。
ただ、本番環境のビルドに関してもCIを意識しなければならないため、ビルド戦略は少し複雑になるかもしれません。それでもビルドの信頼性の向上によって、より安定したリリースプロセスに近づくはずです。

Data health tileの埋め込み

自動公開とそれに対応するData health tileにより、信頼できるデータセットを保証できます。

Tableauワークブックやiframeで埋め込めるData health tileで信頼性を可視化することが可能です。

こちらTableauとの連携が主にフィーチャーされていましたが、こちらLookerStudioにも埋め込み可能なことを確認しました。

このようにdbt Cloud exploreからexposureを選択してiframeを取得

iframe内のtokenパラメータにdbtのBearerトークンを渡した状態で、LookerStudioに埋め込むことで以下のようにLookerStudio上に表示されることを確認できました!

dbtセマンティックレイヤーのコネクタ追加

Tableau(updated)、Sigma、Power BIなど、さまざまなBIツールとの統合が強化されました。

クロスプラットフォームのためのdbt Mesh

これまでの dbt では、複数のデータプラットフォームをまたいだプロジェクトの構成が困難でした。例えば、あるプロジェクトで Databricks を利用していて、後続のプロジェクトで Snowflake を使っていたとしても、後続のプロジェクトから source として Databricks のプロジェクトのテーブルを参照することはできませんでした。

今回の Keynote でクロスプラットフォーム dbt Mesh の機能が発表されて、プラットフォームをまたいだプロジェクトの構成が現実味を帯びてきました。

実現に至ったのは、 Apache Iceberg に対応したデータプラットフォームが増えたことがきっかけでした。

Apache Iceberg とは Open Table Format と呼ばれる、主にデータレイクハウスでの利用が想定されたオープンなテーブルフォーマットです。Apache Iceberg 自体の詳細の説明は割愛しますが、データレイクハウスにおいて Iceberg 形式でテーブルを作成することで、他のデータプラットフォームから読み取りが可能になる仕組みです。

2024年10月に入って dbt が Apache Iceberg のサポートを開始したことで、クロスプラットフォームでの連携が可能になりました。

弊社では BigQuery を利用しており Iceberg 互換でデータを保持することはできないため、残念ながら今の環境で試すことはできませんが、企業間のデータ連携などを見据えると触っておきたい機能だと思いました。

さらに Apache Iceberg 形式への対応に加えて、 Amazon Athena や Azure Synapse Analytics といったアダプターが新しくサポートされました。

プラットフォーム間の連携が容易になるとのことで、柔軟な形式でデータを保持できるデータレイクハウスの強みがこういった形で出てくるのは印象深いです。さらにアダプターの追加によって dbt とデータレイクハウスの相性がますます良くなったように感じました。

まとめ

dbt Coalesce 2024のKeynote「Innovating with dbt」は、dbtのビジョンと共に新規機能がいち早く聞ける非常に刺激的な内容でした。特に、advanced CIやdbt Copilotによってさらに効率的に分析・開発が推進できそうですし、ビジュアルエディティングによって開発に関われるデータ関係者の幅が広がりそうで可能性を感じました。 セッション内で繰り返し強調されるOne dbt というワードの名の通り、dbtがカバーできる新しい領域が沢山できたと思える内容でした。

タイミーでも、こういった新機能を活用することでdbt開発の効率化や品質向上を図り、データ基盤の信頼性とアジリティをさらに高めていきたいです。

※今回私たちは、タイミーのKaigi Pass制度を利用してdbt Coalesce 2024に参加できました。

References

One dbt: the biggest features we announced at Coalesce 2024
https://www.getdbt.com/blog/coalesce-2024-product-announcements

About dbt Copilot
https://docs.getdbt.com/docs/cloud/dbt-copilot

Build with speed and confidence
https://www.getdbt.com/product/develop

Advanced CI
https://docs.getdbt.com/docs/deploy/advanced-ci

Data health tile
https://docs.getdbt.com/docs/collaborate/data-tile