GKE CronJobとcloud-sdk-goでElasticCloudのスケーリングを自動化しコスト削減した

はじめに

こんにちは、検索エンジニアの安達(id:kotaroooo0)です。 10Xで検索基盤・検索機能の開発運用をしています。 最近は推薦システムの開発もちょっとやり始めました。

負荷に合わせてElasticsearch(ElasticCloud)をスケーリングする機能を作りコスト削減したので、その取り組みについて経緯と内容を紹介します。

前提

背景と課題

10Xでは小売チェーン向けECプラットフォームStailerにおいて、検索機能の開発運用にElasticsearchを利用してしています。 Elasticsearchクラスタの基盤にはElasticCloudを採用していますが、ディスク利用量に応じたオートスケール機能しかなく、メモリ利用量やCPU利用量に基づくオートスケーリングはできません。 そのため、負荷が少ない時間帯でもピークタイムのリクエストを処理できるクラスタを稼働させる必要がありました。

また、日に日に負荷が増え続けている影響で、最近インスタンスサイズをスケールアップしないと安定した運用ができなくなりました。 これによりコストが約2倍になり、何らかの対応が必要になりました。

対応方針

リソース利用率に合わせてElasticsearchをスケーリングすることで解決しました。 他の打ち手の候補として、データ更新の時間をずらす、データ更新の速度を落とす、インデックスのデータ構造・設定の変更がありましたが、調整によるリードタイムや工数が大きかったり、効果の不確実性が高かったため見送りました。

StailerのElasticsearchに関する特性

StailarのElasticsearchはCPU boundです。 検索リクエストのピークタイムが8:00 - 12:00、更新リクエストのピークタイムが9:30 - 12:00で重なっており、結果的に CPU利用率 のピークタイムは 9:30 - 12:00になっています。 細かいデータ更新は常にあるものの、スーパーやドラッグストアの在庫データを一括で更新するバッチが日次かつ定時で動いており、更新リクエストのピークタイムは固定です。

以下はCPU利用率のメトリクスです。 縦はCPU利用率、横は時刻です。

検索・更新リクエストのピークタイムが被る9:45~あたりからCPU利用率が急上昇します。

要件

スケールイン・アウトではなくスケールアップ・ダウン

ノード数を増減させるスケールイン・アウトではなく、ノードスペックを増減させるスケールアップ・ダウンを採用しました。

理由

  • ElasticCloudは2(+1 TieBreaker) or 3台構成しかできない(低可用性なら1台でも可)
    • シャード・レプリカ構成上、ノード数を2~3と変動させるとややこしい
      • 負荷・ディスク占有が不均一になる可能性がある
      • シャードの再編成が走りデータ通信量が大きくなりコストがかかる

リソース負荷トリガーではなくスケジュールトリガー

スケジュールトリガーを採用しました。

理由

  • スケジュールトリガーの方が開発工数が小さい
  • StailerのElasticsearchの特性
    • 更新リクエストのピークタイムは固定、検索リクエストのピークタイムもほぼ一定のため
    • データ更新バッチが走り始めると一気にCPU負荷が高騰するため、CPU負荷が高騰に合わせてスケールアップするより事前にスケールアップしておいた方が好ましい
      • ElasticCloudのスケールアップは1台ずつクラスタから切り離されスケールアップされていく
        • 通常3ノードでリクエストを捌くところ一時的に2ノードでリクエストを捌く必要がある
          • そのため、高負荷時にスケールアップするとさらに負荷が高騰するリスクがある

設計

cloud-sdk-goを利用したGoスクリプトをDocker ImageにしGKE CronJobで実行し、定期的なスケールアップ/ダウンを実施しました。

アーキテクチャ図は以下です。

他の選択肢とPros/Consは以下です。 #2を採用しました。

# スケール方法 定期実行方法 Pros Cons 選択候補になった理由
1 Terraform + GitHub ActionsでPull Requestマージ GitHub Actions • 宣言的に管理
• Extensionsもコード管理できコンソールでの手作業が減る
・現状ElasticCloudのTerraform管理していないし、PR自動作成&マージは工数大
・GutHub ActionsのSLAに不安あり
クラスタのスケールアップ・ダウン方法はTerraformが一番良いと考えた。Pull Request作成&マージはGitHub Actionsが親和性が高い。
2 cloud-sdk-go GKE CronJob ・既存で多くCronをGKEで動かしており運用しやすく可用性も安心
・Go(プログラミング言語)で操作できる
・Go用のDocker ImageのBuild/Deployを実装する必要あり クラスタのスケールアップ・ダウン方法はTerraformの次点でcloud-sdk-goと考えた。GitHub Actionsと親和性がない方法にするのであれば別の定期実行方法にしたい。
3 cloud-sdk-go Cloud Functions + Cloud Scheduler ・CloudSchedulerはマネージドであり可用性が高い
・モニタリング・監視もしやすい
・Go(プログラミング言語)で操作できる
Cloud FunctionはGoランタム対応
・CloudSchedulerはこれまで利用されておらず、管理対象が増える
・処理時間の要件上、Cloud FunctionsをHTTP経由でフックするしかなくその場合デプロイが複雑
・長時間Functionsを動かす必要がありGoogleが期待するFunctionsの用途からずれていそう
同上

スケールアップが失敗すると、検索機能に障害が発生する可能性が高く、高い可用性が必要です。 しかしGitHub ActionsでのCronはこれまでの実績的に信頼が低いため、#1は選びませんでした。

また、当初Cloud Scheduler → Pub/Sub → Cloud Functionsも選択肢に入れていましたが、timeoutが最大10分なので選択肢から棄却しました。 スケーリングは10分以上かかってしまうので、成功確認できず失敗した時の検知やリトライの仕組みを別途作る必要がありました。

cloud-sdk-goでの処理

処理の流れは以下です。

注意すべき点は2点あります。

  • ノードのスケールダウン時はディスク容量も小さくなるので、スケールダウン後のディスク容量がパンパンになりすぎないかチェックする必要があります。ElasticCloudではディスクがパンパンになるとインデックスが自動でクローズしノードが機能しなくなることがありました。同様にスケールアップするときもディスク容量に一定の空きが必要です。おそらくシャードのコピーが走るためかと思います。
  • スケールプロセスでは既存のElasticsearchクラスタの設定をGET -> 設定の中のメモリ部分を書き換え -> 書き換えた設定をPUTという処理が必要になります。ここが複雑であるため、生APIを使ったシェルスクリプトでなく、cloud-sdk-goを使うと嬉しい点です。

モニタリング

スケールアップが失敗すると、弱いスペックのノードのまま高負荷状態を迎えることになります。 これによりElasticsearchがパンクし検索機能が動かなくなり、大きなユーザー影響につながるかもしれません。

CronJobでリトライを設定しJobの失敗はリトライするようにし、複数回失敗した場合にはDatadogで検知しSlack + PagerDutyで通知するようにしました。 実際に、リリースしてから3日後にElasticCloudの偶発的な問題によりスケールアップが失敗しリトライが走ることがありました。 リトライを設定しておいて良かったです。

おわりに

本施策により、本番Elasticsearchクラスタのコストを40%程度削減できました。 以下のグラフは、縦軸がElasticsearchクラスタごとのコスト、横軸が時間です。

緑の折れ線が対象のElasticsearchクラスタです。 元々のコストが左の区間、その後スケールアップしコスト増加したのが中央の区間、本施策導入後が右の区間です。 中央の区間で一時的にコストが下がっているのは、別の施策を試してみたが上手くいかなかったので戻した痕跡です。

また、本施策導入後もサービス品質を落とさずに運用できています。

余談ですが、Elasticsearch 7.17から8.12へアップデートも最近実施したのですがパフォーマンスが向上しさらにインスタンスサイズをスケールダウンできコスト削減できました。 おまけにレイテンシーも良くなりました。

ディメンショナルモデリング勉強会を実施しました

データ基盤チームに所属しているデータエンジニアの吉田(id:syou6162)です。10X社内のデータマネジメントの仕事をしています。

最近、社内でディメンショナルモデリング勉強会を行なったですが、なぜ勉強会を行なったのか、どのように行なったのか、勉強会を行なった結果何が得られたかについてまとめます。

ディメンショナルモデリング勉強会開催の背景

前回のエントリにまとめた通り、10Xのデータマネジメントの課題の中でも「データウェアハウジングとビジネスインテリジェンス」は優先度が高いです。意思決定を支えるデータをデータユーザーに提供するため、以前からファクトテーブルやディメンションテーブルといったディメンショナルモデリングでモデリングされたテーブルを提供していました。

しかし、チームの半期の振り返り会でディメンショナルモデリングに対するメンバー間の理解度にばらつきがあるという課題が出ました。より具体的に書いてみると

  • ディメンショナルモデリングに慣れていないメンバー(例: 著者である吉田)がレビューすると、表面的な内容しかレビューができていない
  • ディメンショナルモデリングに慣れていないメンバーがファクトテーブルやディメンションテーブルを書くと、勘どころをを押さえきれておらず、Pull Requestのマージまで時間がかかる
    • 勘どころがなぜ重要なのかを理解しきれておらず、レビューで再度同じ指摘を受けてしまう
  • ディメンショナルモデリングに対する理解度が低いため、データ品質も低くなっている場合があった
    • 例: ファクトテーブルとディメンションテーブルのJOINで必要な外部キーが提供できていない、外部キーは提供されているが命名規則がバラバラ、本来は露出する必要のないナチュラルキーが露出しているなど、データユーザーに対する認知負荷が高くなっていた
    • 例: 外部キーの作り方に一貫性がなく、conformedになっていない外部キーも一部存在した

といった課題が存在しました。これらの課題を解決するための方法の一つとして、ディメンショナルモデリング勉強会を行なってみることにしました。

勉強会の進め方やスコープ

勉強会の初期の予定ではKimball GroupのDimensional Modeling Techniquesの読み合わせを行なう予定でした。Kimball Groupはこの分野では本家的な存在であり、ディメンショナルモデリングの知見に対するカバレッジも高いです。しかし、勉強会を少しやってみて思ったこととしては「よいリファレンスやポインタになっており、すでに知識がある人の辞書としては使いやすい。しかし、経験がない人にとっては、具体例が少なく理解が難しい」ということでした。

そこで、ぺいさんの書かれた記事をベースに勉強会を行なう形に切り替えました。具体的には以下のエントリを参照しながら進めました。

内容としてはStar Schema: The Complete Referenceがベースになっているエントリではあるので、より広く詳細に知りたい方は書籍を読むのがよいと思います。

上述のぺいさんのエントリは典型的なディメンショナルモデリングの本で扱われる内容の1/3~1/2のスコープに留まります。しかし、ディメンショナルモデリングを実務で行なう上ではこのスコープでも一定カバレッジとしては担保できており「広めにやって急ぎ足になるより、基礎を十分固めてチーム内の理解度を高めていきたい」と考えた結果、このスコープで勉強会を行なうことにしました。

なお、Slowly Changing Dimensionsもディメンショナルモデリングにおいて欠かせないトピックの一つです。10Xではデータ基盤の基礎の部分にData Vaultを採用しており、履歴データの管理はData Vaultで担保できている側面も大きかったため、今回の勉強会のスコープからは除外しました。

勉強会の参加者

参加の対象者は社内のDWHやデータマートを作るアナリティクスエンジニアを主に対象にしましたが、DWHやデータマートを使うことが多いアナリスト、(ディメンショナルモデリングを直接使うわけではないが)商品マスタを業務で作るデータエンジニアなどが参加してくれました。毎回5~10人程度が参加し、オンライン(Google Meet)で開催しました。

通常業務もあるため、勉強会の参加者には予習を求めないスタイルで行ないましたが「ファシリテーターがきちんと道案内しないと、議論が深まらない」と感じました。そのため、アナリティクスエンジニアであり、ディメンショナルモデリングにも造形が深い@tenajimaと私*1が事前に読み合わせを行ないました。読み合わせでは、内容の確認もしつつ

  • この事例は自社のリポジトリや分析事例でいうと、どこに該当するだろうか?
  • 自社でも同様の課題感や問題になった事例はあるだろうか?

というような自社事例をこれでもかと豊富に扱うことを心掛けました。以前から社内でファクトテーブルやディメンションテーブルを提供こそしていましたが、きちんとしたディメンショナルモデリングにはまだまだできていません。そのため「現在のモデリングにどういった課題感があるかを再認識してもらいたい」という意図で、自社事例を多く扱うスタイルにしました。

勉強会で学んだ内容

Four-Step Dimensional Design Process

ディメンショナルモデリングを実践する上である意味一番重要とも言えるパートです。Dimensional Design Processは以下の4つの過程で定義されています。

  • 1: Select the business process
  • 2: Declare the grain
  • 3: Identify the dimensions
  • 4: Identify the facts.

1のSelect the business processは特に重要で、業務システムと分析システムはそれぞれシステムの目的が異なります。業務システムから出てくるデータをなんとなくファクトテーブルとディメンションテーブルに切り分けただけでは、成果物がデータユーザーにとっても使いにくいものになってしまいますし、後からの保守運用も難しくなってしまいます。

勉強会ではStailerでは「そもそもどういったビジネスプロセスがあるのか」を含め、tenajimaから以下の内容を説明してもらいました。

  • (あまり整理されていない状態ながらも)過去のDWHで作られていたテーブルにどのようなビジネスプロセスが含まれているか、それをどう整理したか
    • 特に販促関連はスプレッドシートからアドホックなクエリで分析されることも多く、どういったビジネスプロセスがあるか分からなかったため、スプレッドシートを読み解きながら識者にヒアリングを行なった
      • 開発チームが作成したクリティカルユーザージャーニー(CUJ)なども参考にした
    • データ基盤チームは特に見なければいけない領域が広く、一つのドメインはそれに内包されるビジネスプロセスへの理解は浅くなりがちなため、ドメインエキスパートからどのようにヒアリングを行ない、ビジネスプロセスとして整理をしていっているかは特に参考になりました
  • 異なるビジネスプロセスは異なるファクトテーブルに分割する
    • 参考にしたエントリでは注文と出荷が単一のファクトテーブルにすることに弊害が説明されていましたが、自社でも同様の問題が起きていました
    • 特に注文に関するテーブルはデータソースになるテーブルが単一のテーブルになっていたことから、ファクトテーブルも単一のテーブルになっており、配達が完了したものやキャンセルがあったものなど複数のビジネスプロセスが混じっていました
    • そのため、特定のビジネスプロセスの集計をしたい場合にはクエリでフィルタの条件を書く必要があったり、特定のビジネスプロセス以外では全てNULLになるカラムが存在する、などデータユーザーにとっても認知負荷が高い状態になっていました
    • また、単一のファクトテーブルが複数のビジネスプロセスを含んでいたため、開発者としてもクエリが難しくなりがちでメンテナンス性にも問題があるテーブルになっていました
    • それを解決するために、どのようなビジネスプロセスおよびファクトテーブルに分割していったかの説明がされました

今回の勉強会では触れませんでしたが、GitLabのこちらの資料も分かりやすくまとまっていますね。

2のDeclare the grainについても、社内の実例を踏まえてtenajimaから説明してもらいました。社内の例では、注文に対するレコード内で、注文された商品の情報がBigQueryのARRAYSTRUCTの形でデータソースには入っており

  • レコードを粒度を変えずにまとめた形で保持するのか
  • UNNESTを使って、粒度をさらに細かくしたものに分割するのか

について、それぞれのメリット / デメリットについて議論しました。ディメンショナルモデリングでは基本的に粒度は最小粒度で宣言することが推奨されます。しかし、最小粒度である注文された商品一つ一つに対して配送料が定まるわけではなく、注文の合計金額や注文に対して適用されたクーポンの有無など複合的に決まるケースもあります*2。こういった事例を通じて、基本的には粒度は最小粒度で宣言するものの、どの粒度にどういった情報を付与するのがよいか、といった議論を深めていきました。

キーの設計について

ディメンショナルモデリングでは、ナチュラルキーだけでなくサロゲートキーを適切に作る / 使うことが重要になります。データ分析の文脈で、お客様情報のステータスや店舗名の変更といった履歴の管理を行なう必要がある際、サロゲートキーは重要な役割を果たします。また、前述したように10Xではデータ基盤の基礎の部分にData Vaultを採用しており、ここではハッシュキーが登場します。

3つのキー(ナチュラルキー / サロゲートキー / ハッシュキー)を適切に利用できていればよいのですが、残念ながらそうなっていませんでした。ファクトテーブルやディメンショナルテーブルにハッシュキーが露出する必要は本来ないのですが、データマートをData Vaultとファクトテーブルを組合せて作っているケースが存在しており、妥協の結果、ファクトテーブルやディメンショナルテーブルにハッシュキーが露出してしまっているケースがありました。その結果、データユーザーにとっては本来見る必要のないキーが存在することになり、JOINのミスや認知負荷が高い状態になっていました。

勉強会の中ではどのレイヤーでどの種類のキーがインプット / アウトップトになり、どの種類のキーが露出してはいけない(隠蔽する必要があるか)について改めて整理しました。

複数スタースキーマを適切に利用し、ファントラップを避ける

Dimensional Design Processを適切に行なった結果、単一のファクトテーブルではなく複数のファクトテーブルが存在するのはよくあることです(複数スタースキーマ)。複数プロセスをまたいだ分析をする場合、複数のファクトテーブルをまとめて分析する必要が出てきます。10Xではファネル分析などでこういったケースが実際によく現われます。複数のファクトテーブル同士をJOINし、その後GROUP BYして分析する、というのが素直なやり方の一つですが、このやり方には2つの罠が存在します。

1つ目の罠がファントラップです。ファクトテーブル同士をJOINで1:Nの関係になっている場合、レコードが重複し集計値が意図せず増えるケースが起こり得ます(=ファントラップ。書籍によってはfanoutと呼ばれることも)。また、ファネルのように複数個のファクトテーブルをJOINする場合、どこでファントラップが起きているかをデバッグするのは大変でもあります。

2つ目の罠はコスト面です。GA4をデータソースにしたファクトテーブルなどの場合、1つ1つのファクトが大きくなる傾向にあります。巨大なテーブル同士をJOINするとBigQueryのスロットを大量に消費してコストがかかったり、後述する適切なクエリを書けば10分以内に終わるはずの処理が1時間経っても終わらず可用性の面でも問題がある、といった例を具体的なPull Requestを見ながら議論しました。

こうした罠を避けるための方法としては、ドリルアクロスと呼ばれる方法があります。単一のファクトで集計をそれぞれ行ない、粒度を合わせて細かいテーブルになった段階で初めてJOINを行なうというものです。私自身、この方法はBigQueryのベストプラックティスでも紹介されている内容だったため把握はしていましたが、ディメンショナルモデリングの文脈でこうした名前が付いているのを初めて知りました。また、ファクトテーブルやディメンショナルテーブルを使って分析を行なうアナリストも参加してくれていたので、こういった問題を言語化したり「ドリルアクロス」という共通の名前で認識合わせすることもできました。また、ドリルアクロスする場合としない場合の可読性の善し悪しを議論できたのもよかったと思います。

コンフォームドディメンション

入力となるデータソースの種類が増加するにつれ、ファクトテーブルやディメンショナルテーブルは一定の割合で増加するものだと思います。そうなってきた場合にディメンションの間の互換性が問題になってきます。キーの構成方法に微妙に違いがあったり、ディメンションの入力となる値が異なる、などのケースです。こういったディメンションに一貫性がないケースが頻発すると、JOINが意図通りにできなかったり、意図した結果を得るためにアドホックなクエリを書く必要が出てくるとった問題が出てきます。こうした問題はディメンショナルモデリングの旨みをかき消してしまうこともあるため、そうならないように(=コンフォームド)にしていく必要があります。

勉強会では既存のモデリングの中でコンフォームドになっていなかったケースなどを共有し、どうやったらコンフォームドディメンションであることを担保 / 確認*3しやすくなるか、といったことを議論しました。特にStailerではデータの種類が今後増えてくることも想定されるため、今の時点でこういった議論ができたのは有益だったなと思います。

まとめ: 勉強会で得られたもの

このエントリでは、ディメンショナルモデリング勉強会を行なった背景やそのやり方、どのような内容を議論したかについてまとめました。一参加者として、以下の点でこの勉強会をやってよかったなと思いました。

  • 課題感を感じていたメンバー間の知識のギャップをある程度埋める(ベースラインを引き上げる)ことができた
  • 勉強会をきっかけに「今のファクトテーブルって何でこうなってるんでしたっけ?」といったそもそも論の議論をすることができた
    • 歴史的経緯でこうなってしまっており、ToBeの姿とはずれているため、将来的にこうしたいと思っている、といった認識合わせをすることができた
  • 複数の職種で議論する際の共通言語ができた
    • 浸透しきったかというとまだまだですが、ありがちな問題に実は名前が付いていることが知れたり、今後の業務の中で参考にできるポインタがアナリティクスエンジニアやアナリストの間で握れたのもよかった
  • 新メンバーのオンボーディングがやりやすくなった
    • 組織体制の変更に伴ない4月から新しくチームメンバーが増えたが、ペアプロを行なう際に「これはこの間の勉強会で話していたXXXですね」といった形で参照するポインタができるようになった
    • 勉強会の様子は録画しており、後からでも議論の内容が復習しやすいようにしていたのもよかった

ディメンショナルモデリング自体はもう数十年前に提唱されたものですが、最近のモダンデータスタックだけでなくこういった基礎も定期的にチーム内の勉強会で継続的にやっていこうと思います。

*1:ディメンショナルモデリングの知識がまだ薄い想定参加者のつもりで質問

*2:もちろん、商品の体積や重量などを考慮して配送料を商品毎に按分したい、というケースもあると思います

*3:dbtのテストなどを通じて

データマネジメント成熟度アセスメントを実施しました(2024年版)

データ基盤チームに所属しているデータエンジニアの吉田(id:syou6162)です。10X社内のデータマネジメントの仕事をしています。

10X社内では2022年10月にデータマネジメント成熟度アセスメントを実施していましたが、それから約一年半が経過し、データマネジメント上の課題が進捗 / 変化した箇所が出てきました。そこで、最近の成果を振り返りつつ今後のデータマネジメントの方針を改めて見直すため、データマネジメント成熟度アセスメントを再度行なうことにしました。本エントリではその内容についてまとめます。

前回のデータマネジメント成熟度アセスメントへの取り組み

  • データマネジメント成熟度アセスメントとは何か?
  • 2022年10月実施した際のアセスメントの結果
  • アセスメントを実業務にどのように生かしているか

については過去の資料にまとめているので、そちらを参照してください。

「そもそもデータマネジメントとは?その重要性はどういうものがあるの?」という方はDMBOKデータマネジメントが30分でわかる本を読むことをオススメします。前回および今回の成熟度アセスメントもこれらの本をベース / 参考にしながら行なっています。

今回のデータマネジメント成熟度アセスメントのやり方

前回(2022年10月)のデータマネジメント成熟度アセスメントでは、私(吉田)が入社直後だったということもあり、オンボーディングを兼ねてほぼ全職種にヒアリングしました。これ自体は当時の10Xのデータマネジメントの成熟度に対する解像度を飛躍的に高めることに寄与しました。しかし、これを毎回行なうには工数がかかり過ぎるため、今回(2024年3月)は以下のようにコンパクトに実施しました。

  • データマネジメントの11項目に渡って、吉田が成熟度アセスメントの叩き台を作成
    • 各項目につき、notionで1ページ程度のサマリー。以下の3つについて記載する
      • 1: 現在でのレベル感
      • 2: 今後の優先度
      • 3: 各項目のDMBOKでの簡単な概要
        • データマネジメント成熟度アセスメントを初めて行なうメンバーもいるため
  • 叩き台を元に、参加メンバーに各項目の「現在でのレベル感」と「今後の優先度」を入力してもらう
    • レベル感や優先度にギャップがあれば詳細を深掘りし、認識を合わせていく
    • 各項目10~12分程度でサクサク進めていく
      • 初回であればこのペースは難しいと思いますが、成熟度アセスメントをすでに一度実施していると大分やりやすくなっていると感じた
  • 参加メンバーは部内メンバーの3名とデータマネジメントに興味を持つアナリスト2名(任意参加)で実施

成熟度アセスメントの各項目の記入およびディスカッションで2時間、全体のまとめで1時間の合計3時間で実施しました。

成熟度アセスメントの実際の結果

全項目を記載すると膨大な量になってしまうため「前回実施時との差分が大きかった項目」や「優先度が高かったにも関わらずあまり進まなかった項目」についてダイジェストを記載します。

データマネジメント成熟度アセスメントの実施結果の全体像

前回実施時との差分が大きかった項目

データセキュリティ

データセキュリティは確実な進捗がありました。前回実施時点では、データに対する権限は広すぎる & 強すぎる権限付与が行なわれていたり、権限付与も手動によるオペレーションで行なわれていました(前回のレベル感1.5)。しかし、Stailerの利用拡大に伴ないパートナー数も増加しており、パートナー毎の権限管理の強化の必要性が増していました(前回の優先度5)。

これを改善するために、以下の取り組みを実施しました。

  • 誰がどのデータにアクセスしてよいかのポリシーを整備
  • IaCによるコード管理、レビューの必須化、機械による権限付与
    • Conftestによる必要な項目の入力必須化の基盤構築をSREが行なってくれたため、特にBigQueryに関してリソースに関してdescriptionやownerなどのlabelsの情報の入力必須化の実施
    • 新規の権限付与はTerraformで行なうことを徹底
    • terraform importを使って、既存の権限付与もIaCで管理に取り込む*1
  • データエンジニア / アナリティクスエンジニア向けのTerraformを使った権限管理の勉強会の開催し、Terraformに対する敷居を下げる
  • 個人データをより安全に取り扱えるようにするため、仮名加工化の実施
    • 法務担当や外部の法律事務所の先生のアドバイスをもらいながら進行

これらの結果、状況をかなり改善することができました(レベル感3.5)。前回よりは優先度を下げるもののとはいえ、データセキュリティは事業の根幹を支える項目でもあるため、引き続き既存の仕組みの整備などを含めて一定のリソースをかけていく必要があるというディスカッションをしました(優先度3.5)。

データ品質

データ品質は前回の成熟度アセスメントの優先度が4と、積極的に取り組みたい項目の一つでした。その理由としては

  • データに関する問い合わせが特に多く、対応工数がかかっていた
  • DWHやデータマートにテストやdescriptionが書かれていないことも多く、問い合わせに対する調査コストが大きくなりがち
    • 何が担保できているかが明らかではない状況
    • メンテナンスがきちんとできていない古いデータパイプラインによって生成されるデータが参照され続けていることも多かった
    • DWHでは管理されていないBIによるカスタムクエリも多数存在

などがありました(レベル感1.5)。

こういった状況を解決するために、以下の取り組みを行ないました。

  • 古いデータパイプラインの撤退
    • メンテナンスがきちんとできていないパイプラインが2系統存在していたため、データ利用者とのコミュニケーションを取りながら撤退を進めた
    • これは非常に根気が必要で、アナリティクスエンジニアである@tenajimaが粘り強く取り組んでくれた成果
  • カスタムクエリの撲滅
    • BIでカスタムクエリを書けることは自由度を上げるが、データの品質を下げる要因になりやすい傾向があった
    • Tableauの導入に伴ない、担保できる品質によってBIを使い分ける方針を決定し、カスタムクエリを基本的に使わない方針を採用
    • 具体的にはTableauはcertificateされた公式のダッシュボード、Looker StudioやConnected Sheetはアドホックな分析(こちらはカスタムクエリを許容する)という形
  • データ品質の定義や可視化
    • データ品質向上に向けた全体像や指標の定義を部長である@kazk1018が行ない、その実装を吉田が行なった
    • 特に可視化の詳細についてはTokyo dbt Meetup #8で発表した資料を公開しているので、そちらを参照してください
    • 可視化の結果を元にどこに何のテストを書くべきかというToBeの策定に繋げることもできた

以上のように、一定の進捗があったため優先度は少し下げつつ(優先度3.5)、データ品質の可視化結果を参照しながら必要な品質とのギャップを埋めるためのDWH構築(特にDimentional Modelingの拡充)やデータ品質改善のライフサイクルを回していくことを今後は進めていく予定です(レベル感3)。

メタデータ

一番進捗した項目はメタデータでした。前回はメタデータはほぼ何もできておらず(レベル感1)、進んでやる予定もない(優先度1.5)状況でしたが、前述したデータセキュリティの進捗に伴ない、データディスカバリーが課題となってきました。そのため、データカタログ(Dataplexの導入)とメタデータ管理の強化(dbt-osmosisの導入)を行ないました。この内容の詳細については、Findy Toolsに寄稿した記事Data Engineering Study #22で発表した以下の資料を参照してください。

特にdbt-osmosisによる効果は大きく、カラムのdescriptionがほぼ入っていない状況(1割未満)からデータカタログが機能できる状況(5~8割)までカラムのdescriptionに持っていけたのは大きかったです。メタデータの拡充(メタデータの伝播)を自動化できた点も大きく、メタデータの所在をSSoTにしつつ、カバレッジを上げる環境を作ることができました。dbt-osmosisの導入 / 運用にあたり、不足していた機能もあったので、多数Pull Requestを送って取り入れていただきました。

また、メタデータはデータカタログだけでなく、データマネジメント全体を支えてくれる大きな武器にできているなと思います。単純なメタデータ整備に留まらず、アクティブメタデータに代表されるようなメタデータ管理の体制や活用への発展に繋げることができています。詳細については、datatech-jpで発表した以下の資料を参照してください。

大きく進捗を果たすことができたため、今後の優先度は一定下げつつ(優先度1.5)、よりデータ利用者に分かりやすいdescriptionをどう書くかやデータレイク側のメタデータを開発チームとどのように連携するか(Data Contractの導入検討)、TableauなどBIツール側へのメタデータ / データカタログの提供などより高度な項目について考えていきたいと思います(レベル感4)。

優先度が高かったにも関わらずあまり進まなかった項目

大きく進捗した項目があった一方、想定通りには進んでいない項目もありました。一番顕著な項目はデータアーキテクチャです(前回優先度が4.5であるにも関わらず、今回のレベル感が2。前回のレベル感は1.5)。これは主に著者である吉田がサボっていたからなのですが、入社してしばらく時間が経過すると頭の中に社内全体のデータアーキテクチャが入ってしまい、部内のメンバーも同じレベルの解像度を持っているため、データアーキテクチャを描き切らなくてもあまり課題になることがなかった、という背景がありました。

しかし、広告データの取り込み、CRMの導入(data activationを含む)、新BI(Tableau)の導入などに伴ない、データアーキテクチャは前回より複雑になっており、部内以外のメンバー(法務 / コーポレートIT / セキュリティチーム)とデータに関するディスカッションをするときに毎回口頭で説明する必要があるなど課題となってきています。また、チームに新規に所属したメンバーのキャッチアップコストが高くなってしまっているという課題にもなっています。

全ての項目を詳細に描き切るのは非常に骨が折れるため、今後は大まかな図から徐々に整える形でデータアーキテクチャを整備していく予定です(優先度2)。

まとめ

このエントリでは10Xで定期的に行なっているデータマネジメント成熟度アセスメントについて紹介しました。成熟度アセスメントの実施は初回こそ工数はかかりますが、一定型ができてくるとやりやすくなり、データマネジメン全体の見通しもよくなるため、データに対して課題がある人は是非試してみてください。

*1:これは結構大変で、SREに負けないくらいterraformを書いた一年でした

Elementaryアップデートの試行錯誤

はじめまして、データエンジニア業務委託のjcです。今回は、Elementaryアップデートに関する試行錯誤の話を共有したいと思います。Elementaryの運用にお困りの方、これからElementaryを導入しようとする方の参考になれば嬉しい限りです。

Elementaryとは

Elementaryはdbtのモニタリングツールの一つであり、データ品質を可視化するためのダッシュボード作成・Slackへのアラート通知機能を提供しています。

先日、データエンジニアの吉田さんがTokyo dbt Meetup #8で「Elementaryを用いたデータ品質の可視化とデータ基盤の運用改善」を題として発表を行いました。Elementaryの活用例に興味のある方はぜひ併せて確認してみてください。

speakerdeck.com

Elementaryアップデートへの道程

Elementaryの初リリースは2022年1月であり、現在(2024年3月17日時点)はまだstable版に至っておらず、後方互換性が担保されてないアップデートもしばしばあります。先日0.9.4から0.13.2にアップデートするのに苦労したため、その際に遭遇したエラーとその対処法を紹介します。

  • dbt_columnsを生成する際に too many subqueries or query is too complex エラーが発生
  • elementaryのon-run-endを実行する際に too many subqueries or query is too complex エラーが再び発生
  • dbt_run_resultsを生成する際に The query is too large. The maximum standard SQL query length is 1024.00K characters, including comments and white space characters. エラーが発生

※DWHはBigQueryを利用しており、RedshiftとSnowflakeは検証していません。

dbt_columnsを生成する際に too many subqueries or query is too complex エラーが発生

まずはelementaryを0.13.2に上げた後、モデルを実行したらdbt_columnsを生成する際に too many subqueries or query is too complex エラーが発生しました。 (ここではdbt_columnsの説明を割愛します。ご興味のある方は前述した吉田さんの発表資料にご参照ください)

Maximum number of resources referenced per query are 1,000 resources

Quotas and limits  |  BigQuery  |  Google Cloud

調査した結果、BigQueryのサブクエリの上限(1,000)に引っかかっていることがわかりました。

Elementaryのドキュメントに記載されていませんが、ソースコードを参照することで、Artifact(成果物)のアップロードには以下の2つのモードがあることが判明しました。

  • chunk: 長いクエリをdbt_artifacts_chunk_sizeで指定されたchuck_sizeに分割して処理する
  • max_query_size: 設定したクエリ文字列数の上限までギリギリ使い、不足があれば新しいクエリに分割する

デフォルトは max_query_size モードになっており、文字列数の上限も適切に設定されているようですが、このモードではBigQueryのサブクエリ数の上限を考慮していません。つまり、レコードが短い場合、同じ文字列数の上限でも、一度insertするレコードが増えるためBigQueryの制限にひっかかることがあります。

ログから、エラーメッセージが出る直前、1000以上のレコードをunion allしてからinsertするクエリを確認できました。

2024-02-13 04:39:14.190704 (MainThread): 04:39:14  On master: /* {"app": "dbt", "dbt_version": "1.7.7", "profile_name": "user", "target_name": "prod", "connection_name": "master"} */
insert into `my-project`.`elementary`.`dbt_columns__tmp_20240213043537835414`
         (full_table_name,database_name,schema_name,table_name,column_name,data_type) values
    (NULL,'hoge','hoge','hoge',NULL,'STRING'),
    (NULL,'hoge','hoge','hoge',NULL,'STRING'),
    ...
2024-02-13 04:39:18.028758 (MainThread): 04:39:18  
BigQuery adapter: Retry attempt 1 of 1 after error: BadRequest('Resources exceeded during query execution: Not enough resources for query planning - too many subqueries or query is too complex.; reason: resourcesExceeded, message: Resources exceeded during query execution: Not enough resources for query planning - too many subqueries or query is too complex.')   

そのため、max_query_sizeモードをやめてchuckモードに変更しました。

dbt_project.yml からElementaryに変数を渡すことで設定を変更できます。

vars:
    elementary:
    "insert_rows_method": "chunk"
    "dbt_artifacts_chunk_size": 500

chuckモードに変更し、さらに dbt_artifacts_chunk_size を500に変更することにより、too many subqueries or query is too complex エラーが解消されました。

Elementaryのon-run-endを実行する際に too many subqueries or query is too complex エラーが再び発生

chuckモードに変更することで上記エラーを解消しましたが、elementaryのon-run-endを実行する際に too many subqueries or query is too complex エラーが再び起きました。

ソースコードを調査したところ、on-run-endを実行する際にinsert_rows関数にchunk_sizeを明示的に渡しておらず、デフォルトの5,000を使っていることが判明しました。このバグを修正するためにelementaryにpull requestを送りました。

fix: add arg chunk_size when calling `insert_rows` by aibazhang · Pull Request #669 · elementary-data/dbt-data-reliability · GitHub

4日後マージされ、0.14.1でリリースされました

Release 0.14.1 · elementary-data/dbt-data-reliability · GitHub

dbt_run_resultsを生成する際に The query is too large. The maximum standard SQL query length is 1024.00K characters, including comments and white space characters. エラーが発生

Elementaryを0.14.1に上げると上記エラーを解消しましたが、dbt_run_resultsを生成する際に The query is too large. The maximum standard SQL query length is 1024.00K characters, including comments and white space characters. エラーが発生しました。

テーブルdbt_run_resultsにはクエリのコンパイル結果を保存するcompiled_codeという項目があります。10Xでは、dbtのマクロやjinjaテンプレートを多用しているため、クエリのコンパイル結果が長くなりがちです。このような場合、クエリのコンパイル結果が長くなると、BigQueryのクエリ文字列数の上限1024Kを超えてしまいます。

この問題はchuckモードにおいて起きます。dbt_artifacts_chunk_sizeで指定されたchuck_sizeに分割して処理できるが、max_query_size モードのように文字列の制約はありません。

このバグを改修するために、Elementaryにクエリ文字列の長さを制限するPRを出しました。

support query_max_size for insert_rows_method `chunk` by aibazhang · Pull Request #679 · elementary-data/dbt-data-reliability · GitHub

現時点はまだレビューされておらず、マージされるまで時間かかるでしょう。

その間、一時的な対策としてchuck_sizeを小さ目な値(例えば100)に設定して、クエリの長さを制限しています。このエラーを一時的に回避できますが、実行するクエリ数自体が増えるため、モデルの実行速度が落ちる可能性があります。この修正により、最新のElementary v0.14.1でも動作するようになりました。

おまけ:一気にバージョンを上げることにならないように、dbtのpackages.ymlをRenovateに対応させる

Renovateという依存管理のツールを使用して、dbt関連のパッケージを一気にバージョンを上げることにならないように自動的にアップデートすることができます。Renovateの設定方法自体の説明は割愛します。

Renovateは、Npm、Pypi、Helmなど複数のデータソースに対応していますが、現時点ではdbtのデータソースが直接サポートされていないので、データソースをカスタマイズする機能を利用します。

Custom - Renovate Docs

ドキュメントの例を参考にして、dbthubのAPIから最新バージョンの情報をparseするcustomDatasourceと、リポジトリ内のpackages.ymlにあるバージョン情報をマッチさせるcustomManagerを作ってみました。

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:base"
  ],
  "customManagers": [
    {
      "customType": "regex",
      "fileMatch": ["packages\\.yml$"],
      "datasourceTemplate": "custom.dbt_hub",
      "matchStrings": [
        "- package: (?<depName>.+)\n    version: (?<currentValue>.+)"
      ],
      "versioningTemplate": "semver"
    }
  ],
  "customDatasources": {
    "dbt_hub": {
      "defaultRegistryUrlTemplate": "https://hub.getdbt.com/api/v1/{{packageName}}.json",
      "transformTemplates": [
        "{\"releases\":[{\"version\": $string(latest)}], \"homepage\": \"https://hub.getdbt.com/{{packageName}}/latest/\"}"
      ]
    }
  }
}

mainブランチにマージしたあと数秒経つと、バージョン更新のPRが自動的に作成されることを確認できました。

Update dependency elementary-data/elementary to v0.14.1 by renovate[bot] · Pull Request #11 · aibazhang/renovate-tutorial · GitHub

まとめ

本記事では

  • Elementaryアップデート時に遭遇したエラーとその解消法
  • dbtのパッケージを小刻み更新するためにRenovoteを活用する方法

について紹介しました。皆さんのElementaryのアップデートにご参考になれば幸いです。

WACATEに乗ってどこまでも

はじめまして、ソントプです。

私は現在、品質管理部のテストエンジニア(TE)としてお届けチームに配属され、以降はQA業務に従事しています。

今回、初めてQA向け社外イベント:WACATE2023 冬(開催日:2023/12/23(土)、24(日))に参加してきましたので感想を交えながら主に

  • 参加して得たもの
  • 業務に活かせたこと、活かせそうなこと

について書いてみました。

  • WACATEってそもそも何?
  • 興味あるけど参加したことないな…

という方の参考にもなれば幸いです。

参加した経緯と動機

IT業界に飛び込んだのが8年前になるのですが、その頃からWACATEの名前自体は聞くことがありました。ただ当時の私は業界のいろはもよく分かっておらずひたすらテスト実行する毎日だったので、当然テスト設計をやれるほどのスキルもなかったですしむしろ「何それ?ウマイの??」状態でした。

その後、運良くテスト設計未経験でも入れる現場があり、業界に転職して2〜3年経ってようやくテスト設計するチャンスを得ます。その後もテスト設計者としていくつかの現場を渡り歩き、今に至ります。

テスト設計力に関して自己分析すると、ある程度の基礎は身についているもののテスト設計技法の使い分けや現場での適切な運用がまだまだできていない、というのが率直なところです。

なので遥か先にいるチームメンバーに少しでも追いつくためにも、テストエンジニアとして生き残っていくためにも、テスト設計力の向上は不可欠だと思いました。そこで手始めに自分が知っていて、かつ知っている人が運営サイドにいる社外イベントにとにかく飛び込んでみよう!というのがWACATE2023 冬に参加した動機になります。

そもそもWACATEとは?

そもそも「WACATE(ワカテ)」をご存知ない方向けにこちらも軽く紹介しておきます。

宿泊型(1泊2日)のワークショップで『Workshop for Accelerating CApable Testing Engineers』の頭文字をとって「WACATE」と呼ばれています。

WACATEでは35歳以下を「若手」と定義していますが36歳以上の若手じゃない人も参加可能となっています。よく「若手じゃないと参加できないの?」と間違えられがちみたいなのですがそんなことはなく、むしろ若手じゃない人も大歓迎!とのこと(by WACATE実行委員長)

WACATE2023 冬のプログラムはこちら↓

wacate.jp

WACATE公式サイト_ホームはこちら↓

wacate.jp

WACATEで得たもの

1. 実務に活かせる知見・経験が得られた

1 - 1. すぐに実務で活かせたこと

参加している時、ずっと考えていたことがあります。

それは「実務ですぐに活かせることってないかな?」です。

積極的にワークに取り組んでいても、それを実務に活かせるように持って帰らなければ参加した意味がありません。ワークしながら内容の理解にも努めながらメモも取りつつ、すぐに活かせることないかなー?と頭の片隅でずっと考えていました。

そしてやってきました2日目のこちらのセッション!

「テストの目的って何?私がテスト設計でやってしまった3つの失敗」

発表内容は登壇者の高橋さんの実際の失敗談3つをふりかえりつつ

  • その都度何を考えていたのか
  • どう乗り越えていったのか
  • 最終的に高橋さんがたどり着いた「テストの目的の重要性」

についてお話ししてくださりました。

うっかりするとテストの目的を定めずにテスト設計をしたり、あるいは無意識にテストの目的に沿って取り組んでいて日頃意識していない方もいるのではないでしょうか?

私は両方やりがちなので改めて、テスト設計の成果物の中にテストの目的を盛り込むようにしました。テスト分析の段階でテストの目的をしっかり定義することで、その後のテスト設計の方向性がより定めやすくなります。

正直、テストの目的を明確に定めなくてもテスト業務が滞りなく進められるのであればそれでもいいのかもしれません。ただ個人的には、チーム単位で見た時に皆が同じ方向を向いて進んでいくためにもテストの目的は必要不可欠だと感じています。

1 - 2. これから実務で活かせそうなこと

「すぐに活かせること」と同様にずっと考えていたことがもう1つあります。

それは「すぐではなくても後々の実務で活かせそうなことはないかな?」です。

こちらも参加中はずっと頭の片隅においてました。正直言ってWACATEに参加していた2日間はずっと脳みそフル回転で大変だったのはいい思い出です。

そんな状態でやってきてくれました同じく2日目のこちらのセッション

「JSTQB FL 最後の幻のテスト技法「ユースケーステスト」を学ぶ」

セッション内容はこんな感じでした。

  1. ユースケーステストとはどんなものなのかの説明
  2. 提示された仕様をもとに実際にユースケーステストのワークに取り組む
  3. ワークの回答例や解説

個人的にはユースケーステストがどんなものなのかは以前から知ってはいましたし、なんならメンバーが成果物としてあげてきたものをリーダーという立場でレビューしたこともあったりします。ですが自分で使ったことはなかったので、今回ワークという形で実践し体験できたことで自分の中での解像度が爆上がりしました。

具体的にどこら辺の解像度が上がったのかと言いますと、一番はユースケーステストの作成方法が理解できたことです。

  1. ユースケース図
  2. ユースケース記述
  3. ユースケーステスト

この順番でそれぞれワークを体験したことで理解度が飛躍的に高まりましたし、自力での作成力も身についたと思います。

ただあくまでテスト技法の一つなのでテスト設計の度に使うわけではないですが、今後のテスト業務において必要になった時に役立つセッションだったと思っています。

2. 日々の業務をテスト理論の中で捉え直すことができ、理解が深まった

すでにやってることあったんだ!

WACATE2023 冬で一番印象に残っているセッションは

「テスト活動にまつわるお悩みを解消するカギはどこに?〜テストのモニタリングとコントロールに貢献できるテストエンジニアになろう」

です!!

このセッションではタイトルの通り、テストのモニタリングとコントロールについてグループワークを行いました。

セッション内容はこんな感じでした。

  1. まず実践(グループワーク)
  2. ふりかえり&共有で気付きを得る
  3. 登壇者の解説で学びを得る

このセッションを通じて

日々のテスト業務の中で何かしらの課題が出てきた時にそれらを解決すべく対策を打つ

…という、日頃から当たり前のようにやっていたことそのものがまさしく、テストのモニタリングとコントロールだった、ということに気付かせてもらいました。この「ハッとした気付き」が一番印象に残っている理由になります。(下手したら昨年一の驚きだったかもしれない)

「モニタリング」と「コントロール」という単語は意識せずとも日々の業務で

  • 自分のタスクの進捗が遅れそうな時にどんな対策を打てば良いのだろう?
  • 自分のタスクはどうやったら目的を達成できるだろう?

というところを意識しながらこれからも取り組んでいきたいと、改めて思いました。

3. 横のつながりが増えた

そこかしこで始まる名刺交換

WACATEは参加者同士の交流の場でもあります。

最初こそソワソワしていた感じもありましたが、最初に自己紹介、次にグループワークを経てすぐに打ち解けた後はみな積極的に交流を図っていました。気付けば私の名刺も17枚ほど減っており、よくもまぁこんなに交換できたなと自分で自分に感心してしまいました。

こうして「横」のつながりが増えたこともまた、WACATEに参加したことで得られた財産となっています。

まとめ

まずは、最後までお読みいただきありがとうございます。感謝です。

拙いながらも人生初ブログを書き上げられてまずは一安心しております。

WACATEは知ってても参加を迷ってる人にとって、一つの体験談として参考になるような、あるいは参加の後押しになるような内容になっていれば幸いです。

過去WACATEに参加した人にとっては、今回はこんなことやってたのね〜といった感想文のように見てもらえれば嬉しいです。

そしてWACATE同期(同じWACATE2023 冬参加者)から何かしら反応あればめちゃくちゃ喜びます!!!

LLMとデータ駆動でサービスデスク業務の改善サイクルをまわしていく

10Xでコーポレートエンジニアをやっているハリールです。

このブログでは、社内サービスデスク・ヘルプデスクの運用において、問い合わせの受け付けから始まるデータの流れ、そのデータの蓄積方法、そしてそのデータを活用して改善サイクルをどのように回していくかについて、試行錯誤を重ねてきた経験、LLM活用方法、構成、実用的なTipsなどをまとめています。

前提条件

以下のサービスを使って構成しています。 各SaaSの基本的な利用・操作について記載はないためある程度理解している前提での記述となっています。

  • Slack
  • Jira Service Management
  • Zapier
  • OpenAI
  • Looker Studio

全体構成

全体構成としては

  • 問い合わせのI/Fは日常最も利用するチャットツール(Slack)を利用し、ツールのスイッチングコストをかけない。
  • チャットツールで投げた問い合わせはチケット管理ツール(Jira Service Management)に双方向同期し、情報の欠落・重複データを防止。
  • チケット管理ツールにデータが投入されると内容を元に要約・タグ・分類などを自動生成することで属人的な作業を減らし、精度の高いデータを蓄積。
  • 蓄積されたデータをBIツール(Looker Studio)に連携・可視化。定期的な振り返りを実施し改善サイクルを回していく。

といった流れとなります。

SlackとJira Service Managementとの連携

基本的な設定は以下に公式ドキュメントがあります。 www.atlassian.com 上記設定によってSlackの投稿をJira Service Managementに蓄積する構成が実現できます。 それを踏まえた上でのTipsをまとめていきます。

Tips1. プロジェクトタイプ

Jira Service Managementで利用できるプロジェクトは以前までは企業管理型のみでしたが、現在はチーム管理型も作成できるようになっています。 現在10Xではチーム管理型で運用していますが特に大きな課題はありません。それぞれのプロジェクトの特性や相違点については以下を参照ください。 support.atlassian.com

Tips2. Slackチャンネル情報の登録

Slackのメッセージから同期されているJiraチケットへ遷移したい場合、SlackにJiraチケットへのリンクがあるので問題ないのですが、その逆にJiraチケットからSlackメッセージに遷移したい場合には以下の設定を行うことで実現できます。

設定方法はチケットの属性に requesterChannelLink といった名前で文字列型のカスタムフィールドを設定するだけです。 これでJira Service Managementが自動でSlack投稿へのリンクを挿入してくれます。

カスタムフィールド設定
自動で設定される値

requesterChannelLink にはリクエストを受け付けた発言へのリンクが、slackCreationChannel にはチャンネル名が自動で設定されます。 なお、他にどのような属性が指定可能かについては以前まではHalpやAtlassianのドキュメントに記載がありましたが、現在記述がなくなっており、今後この機能がなくなったり、非推奨となる可能性がありますのでその点ご了承ください。

Tips3. Emoji ショートカットAutomation

Jira Service Managementのチャットはその前身であるHalp時代から絵文字リアクションによる操作が特徴でした。 Slack上でチケットの投稿に対して、 👀 をリアクションして担当になったり、完了を意味するリアクションでチケットを完了させることができます。

なお、現在もその設定はありますが、2024年6月4日までにJira Automationに移行させる必要がありますのでご注意ください。 移行の手間はあるものの、利用可能なアクションの範囲が拡大し、様々な操作をリアクションベースのトリガーで実行できるようになったことは、歓迎できる点だと思います。

詳細は以下を参照ください。

support.atlassian.com

チケット属性をLLMで自動生成

チケットが作成されると以下の情報を自動生成しています。

  • 要約/説明
  • タグ
  • 分類

生成はJira(Automation)からZapierを経由してOpenAIを呼び出しています。それぞれの詳細を記します。

AutomationからZapierコール

まずは、対象プロジェクトに課題が作成されるとZapierにWebリクエスト(WebHook)を送信するAutomationを用意します。

Webリクエストの本文はカスタムデータとし、後続処理で必要なデータを設定します。更新時のチケットを特定するためのkeyと、生成元となるsummaryを設定しています。 なお、reporter(報告者)はZapierから再度Jiraチケット更新する際の必須項目となるため設定しています。

これで自動生成の準備ができました。

余談. データに改行が含まれる場合の注意点

上記のカスタムデータは問題ありませんが、例えばカスタムデータで渡すデータに改行が含まれる場合、上記の記載方法では正常にZapierを呼び出すことができません。さらにいうとJira Automation上の検証は成功するがZapierは呼び出されないためなかなか原因に気付きにくいです。 その場合の対応については以下を参照ください。

zenn.dev

要約/説明

続いてユーザーからの問い合わせ内容を元に、要約と説明を生成します。なお、SlackとJira Service Managementの連携では問い合わせの元の文章は自動的に最初のコメントに記録されるため、今回のように加工したとしても元の情報が失われることはありません。 以前までは長文の場合のみコメントに記録されていましたが、いつからか現在の仕様になりました。このほうが便利ですね。 Automationから呼び出されるZapで ChatGPT ActionかOpenAI Actionを選択しますが、どちらを使っても結果に大きな差はないためどちらでもOKです。今回の例ではChatGPT Actionを使います。

まず要約の生成では以下のプロンプトを指定します。10文字程度と指定していますが、稀に改行が含まれてしまいJiraに設定する際にエラーになることがあるため、改行を含めないような指示も加えています。

その他のパラメタ(ModelやMemoryKeyなど)はそれぞれお好みで指定してください。 続いて説明を生成します。説明はJiraチケットの複数行フィールドのため改行は気にせずかつ文字数の制約なども指示する必要はありません。かなりシンプルな指示なためお好みでカスタマイズしてください。

タグ

続いて問い合わせ内容からタグを生成します。以下のような指示で生成しています。カンマ区切りとしているのは、後続のJiraへの反映時にそのまま投入できるからです。

なお、生成されるタグについては、文章によっては想定外のタグ(個人名やメンションなど)が含まれることもあるため、”ある程度雑に生成されたものをチームのデイリーなどで共有しながら手直しする”前提で運用しています。

それでもすべてを手動で付与していくよりははるかに効率的になったと実感しています。

余談. その他タグを使わない

LLMでタグを生成する際、分類できない場合に ”その他” を設定したくなりますが(というか最初はそうしていました)、現在はそのようなプロンプトはやめました。

理由は後続のBIツールで可視化する際に、例えば円グラフなどで件数が少ないものがまとめられるその他と、明示的に付与したその他の判別がつかなくなったからです。

分類

続いて分類を設定していきます。分類は独自に作成したカスタムフィールドであり、問い合わせの内容を文字通り分類するもので”質問”と”依頼”のいずれかから選択します。 以下のようにChat GPTの Classify Text で問い合わせ内容を質問か依頼に仕分けします。

このようなJiraで選択肢があるフィールドはこのままではZapierから投入することはできません。”質問”と”依頼”はJira上ではそれぞれ別のIDを持っており、Zapierから指定するにはこのIDを指定する必要があります。 それぞれの選択肢のIDの値はZapier上から確認できます。ZapierのJiraのアクションから対象のIssueを選択し分類を見ると以下のようになっているのでこの数値がIDとなります。

LLMで分類した値をこれらのIDに変換するためいくつか方法がありますが、今回は Utilities を使います。 Zapier UtilitiesのLookup Tableを使ってChat GPT Actionで生成した文字列をIDに変換します。

項目の追加や削除があった場合にはここもメンテナンスする必要があるため、その点はご注意ください。

これでJiraに設定するための値が出揃いました。

Jiraチケットの更新

要約、説明、タグ、分類が用意できたので、Update Issue in Jira Software Cloud のUpdate Issueを設定します。

IssueにはWebhookで受け取ったKeyを指定します。

要約・説明・タグ・分類には上記で生成した結果を設定します。

最後に 必須項目である報告者にWebhookで受け取ったreporterを設定すればOKです。

これで問い合わせ内容をもとにした自動属性付与の流れが完成です。任意の問い合わせチケットを生成して値の精度を確認しながらプロンプトを微調整してください。 なお、あくまでも生成自体は補助的なものであり、どこかで人がチェックする運用にしておくほうがより安全かつ確実です(特にタグ)。

BIツールに連携

Jira Service Managementに蓄積したデータはそのままJiraのダッシュボードで可視化することもできますが、利用できるガジェットが限られています。またJira以外のデータも含めて横断的に表現できることからLooker Studioに連携していきます。

Step1. Googleスプレッドシートに同期

Looker Studioにデータを連携するに当たってまずはGoogleスプレッドシートにデータを同期させます。方法はいくつかありますが、ノーコードでありAtlassianが公式に提供しているスプレッドシートのアドオンJira Cloud for Sheetsを使います。

JQLで必要なチケットの抽出、列の選択に加えて、定期実行なども設定できます。使い方の詳細は以下を参照ください。

support.atlassian.com

Step2. スプレッドシートをLooker Studioで可視化

スプレッドシートに蓄積したデータをLooker Studioにデータソースとして追加し、あとは任意のグラフを追加して可視化していきます。

これで常に最新のデータで可視化されたダッシュボードが完成しました。このデータを元に、振り返りでは依頼・質問それぞれの件数とタグの割合を見ながらネクストアクションを考えていきます。

例えば依頼の多いタグに関しては、依頼自体を別途フォームとして用意して効率化できないかを検討したり、質問が多いタグに関しては、ドキュメントの在り方・導線・周知方法などに課題がないかを検討していきます。

また、半期・四半期で組織変更時などは特に質問などが増えるなど組織ごとの特性が見えてくるため、それらを織り込んだ作業計画に繋げられます。

余談. 要約リンク

Jiraのダッシュボードの場合グラフをドリルダウンしてチケットの詳細を確認することができますが、Looker Studioの場合そのままでは実現できません。 そこで以下のような計算式のフィールドを用意しシンプルな表を用意すれば、任意のフィルタ条件で一覧化し、かつチケット詳細に飛ぶ流れが実現できます。

HYPERLINK(CONCAT("https://[Atlassianインスタンス名].atlassian.net/browse/",キー),CONCAT(キー," ",要約))

まとめ

ここまで、LLMを活用して問い合わせデータの蓄積を効率化し、改善サイクルを円滑に回すためのデータフローについてご紹介しました。特に重視したのは、データの蓄積と、そのデータを用いた改善プロセスです。このアプローチにより、より効果的なデータ駆動型の施策を検討することができます。

現在もなお試行錯誤を続けており、プロセス自体にはさらなる改善の余地があるものの、このブログが類似の課題に直面している他の組織や個人にとって、役立つものとなれば幸いです。

GitHub Dependabot Alertを愚直に潰し込んだ話

こんにちは、セキュリティチームでソフトウェアエンジニアをしてる@sota1235です。

明けましておめでとうございます!本年も10X Product Blogを何卒よろしくお願いします。

さて、今回はセキュリティチームで今年の6月ごろから取り組んできたGitHub Dependabot Alertの削減についてお話しします。

サマリーとしては以下です。

  • 今年の6月頃から取り組みを開始
  • 初期はセキュリティチームで毎日トリアージ、泥臭くAlertの対応を行う
  • 主要なRepositoryのAlertは一通り解消、一部は担当チームへの移譲等を行い継続的に維持できる状態へ

結果として半年間で500件弱のAlertをcloseし、残ってるAlertも対応方針が全て確定した状態になりました。

この数が多いか少ないかはソースコードの規模感にも依存するので言及しませんが、この記事では小さいリソースで取り組みを始めて、全てのAlertをハンドリングした状態に半年でたどり着いた過程について赤裸々にお話しできればと思います。

続きを読む