ChatGPTを活用したAIで商品をさがす機能実現のための工夫

こんにちは、データサイエンティストの髙橋です。業務では企画/分析/機械学習モデル作成/プロダクション向けの実装/効果検証を一貫して行っています。

この記事では 2023/11/01 に公開した AIでさがす機能の実現にあたり工夫した点について紹介します。本機能では OpenAI の Chat Completions API (Web 版の ChatGPTAPI 版のようなもの)を活用しているため、同 API 関連での工夫が中心となります。

この記事は Enigmo Advent Calendar 2023 の 9 日目の記事です。

AIでさがす機能の紹介

AIでさがす機能は BUYMA の Web サイト・アプリの検索機能の 1 つとしてボタンを追加しており、Web サイトの場合は以下のボタンを押下すると AIでさがす画面に遷移します。

ユーザーは事例から質問するか、アイテムのカテゴリを選択した上でフリーワードで質問するかのどちらかからチャットを始めることができます。事例は、アイテムのカテゴリとフリーワードの文章をあらかじめ弊社で作成したものです。
例えば、レディースアイテムカテゴリを選択した上で「30代におすすめのハイブランドレディースバッグ教えてください」と入力してメッセージを送信すると、以下のようにいくつかの商品が表示されます。

上記画面において、商品画像を押下すると該当の商品詳細画面が開き、「もっと見る」を押下すると表示されているおすすめ(シャネル チェーンバッグ など)を検索キーワードとした検索画面が開きます。

さらに、表示された商品群の末尾に以下のように「選んだ理由を聞く」ボタンが表示されており、押下すると選んだ理由が表示されます。

理由も表示できるようにすることでユーザーに納得感を得てもらったり、理由からこういう商品も良いかもと思い検索してもらったりすることを狙っています、また、弊社では FISS Project というファッションのプロが一緒に服を選んでくれるサービスも運営しており、より要望に特化した商品を選んでほしいと思われた方々の同サービスへの流入増加も狙いの1つです。そのため、以下のように理由表示後に同サービスの紹介も表示されます(カテゴリとしてメンズアイテムを選択した場合のみ表示されます)。

素早い機能公開とコスト削減の工夫にフォーカスした理由

目次を見ていただくと分かるように素早い機能公開とコスト削減に関する工夫が中心です。この2つにフォーカスした理由は以下のとおりです。

  • AIでさがす機能は他社の類似事例が少なく、どの程度の効果が見込めるか予測が難しかった
  • このような機能はどういったものであれば BUYMA の会員にとって有益であるのか予測が難しかった

そこで、可能な限り低コストで素早く公開し 分析→改善 のサイクルを回すことにより、どのようなものが有益か、どの程度効果が出そうなのかを予測しやすくしようと考えました。

結果として、本格的に開発を開始してから約6ヶ月で公開することが出来ました。なお、この期間にはソフトウェアエンジニアの方によるチャット画面周りのフロント/バッグエンド開発も含んでいます。 また、具体的な数値は出せませんがコストもかなり抑えた状態で公開できました。

素早い機能公開のため工夫

まずは素早い機能公開のための工夫を3つ紹介します。

おすすめ商品以外の質問には回答できなくする

企画の初期段階では商品のおすすめ以外の質問にもある程度対応できるようなチャットボットにすることを考えていました。例えば、BUYMA 利用時の QA でよくある「関税がかかるのか?」という質問に回答できるようにするなどです。しかし、それを実現しようとすると誤った情報を回答させないために BUYMA 公式の QA ガイドを embedding 化し、ユーザーの質問と類似した文書を抽出、その文書をプロンプトに組み込み回答させる、などが必要だろうと考えました。しかし、この作業自体に時間がかかる上に様々な質問に対して誤った情報を回答しないかを検証する時間もかかるため、思い切っておすすめの商品以外の質問には回答できないようにしました。

これを実現するために、ユーザーからのメッセージに対して Chat Completions API により回答を生成させる前に、メッセージがおすすめの商品に関するものかどうかを分類しそれ以外の質問の場合は以下のように固定したメッセージを返すようにしました。

なお、分類自体も Chat Completions API により行うこととしました。これは分類モデルを作成する手間を削減できると考え検証したところ、Chat Completions API による分類でも十分な精度が得られたためです。そのため、ユーザーのメッセージ 1 つに対して最大で 2 回 Chat Completions API を呼び出しています。

RAG は行わずシンプルに検索結果を返す仕組みとする

RAG (Retrieval-augmented Generation) とは、外部データを ChatGPT などの大規模言語モデルに与えることでそのデータに基づいた回答を生成させる手法です。

記事執筆時点(2023/12/09)で採用している方法はシンプルで、 ChatGPT におすすめ商品をいくつか生成してもらい、それぞれを検索キーワードとした検索結果内の複数個の商品 URL と検索結果の URL を表示するというものです。

企画初期段階では RAG のようなやり方(例えば商品情報を embedding 化し、回答の embedding と類似する商品を取得して画面に表示するなど)を検証していたのですが、以下の課題から RAG の方向性を突き詰めると時間がかかりそうなことを実感し、シンプルな方法を採用することとしました。embedding 化には OpenAI の text-embedding-ada-002 を利用しました。

  • 商品のメタデータ(商品名やカテゴリ、ブランド名など)を embedding 化したものと、ChatGPT の回答を embedding 化したものの類似度を取って上位の商品を見ると、回答とずれた商品がそれなりに出現する。
    • 例えば、ChatGPT の回答では「オックスフォードシャツ」と記載があるが、類似度上位にはTシャツが出現することがありました。
  • 上記のような問題があった場合に原因を特定することが難しい。
    • 商品名やカテゴリ、ブランド名などの複数の商品メタデータを embedding 化しているため、どのメタデータが原因なのか、特定のメタデータの組み合わせが原因なのかなどを特定することが難しく、また特定できたとしても今度は別のパターンで問題が発生することがありました。これを対応していると、この部分の開発のみでそれなりの時間を要してしまうと考えました。

また、仮に embedding 化がうまくいったとしても、それをシステム化することにも時間がかかるだろうと考えました。具体的には、 BUYMA には 600 万品以上の商品があり、この数の embedding と類似度を高速に計算するには Vertex Matching Engine などの利用が必要であり、弊社ではまだ利用実績もなかったため検証・構築に時間を要すると考えました。その上、コストもそれなりにかかりそうであったためシンプルな方法を採用するに至りました。

なお、記事執筆時点(2023/12/09)では RAG を利用した回答生成を高速に実現できそうな機能が OpenAI の Assistants APIGoogle Cloud の Grounding for PaLM API としてアナウンスされており、今後はユーザーの利用状況を見ながらこれらの活用も検討予定です。

API に渡す過去のメッセージの組み立てをアプリ側でやらないこととする

これは弊社のソフトウェアエンジニアとの連携にかかる時間を削減するための取り組みです。Chat Completions API では過去のユーザーと AI のメッセージのやり取りを API の呼び出し側で組み立てる仕様になっています。具体的には、Open AI のドキュメントに記載のように API 呼び出し時の messages パラメータに過去のユーザーと AI のやり取りを渡す必要があります。

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "system",
        "content": "You are a helpful assistant."
      },
      {
        "role": "user",
        "content": "Who won the world series in 2020?"
      },
      {
        "role": "assistant",
        "content": "The Los Angeles Dodgers won the World Series in 2020."
      },
      {
        "role": "user",
        "content": "Where was it played?"
      }
    ]
  }'

これを実現するための単純な方法は、アプリ側で画面に表示しているユーザーと AI のメッセージを取得し、 API 呼び出し時に渡すようソフトウェアエンジニアの方に依頼することです。しかし、そうすると過去のメッセージ群の一部を意図的に変更したい場合に、こちらの意図しないメッセージ群が渡されるるなどしてソフトウェアエンジニアの方との連携に時間がかかってしまうだろうと想定しました。
そこで、Chat Completions API をラップする独自 API を作成し、その API のレスポンスとして次の呼び出し時に渡すべきメッセージ群を返す仕様としました。具体的には、先程の Open AI のドキュメントの例を用いると Who won the world series in 2020? というメッセージで呼び出したときのレスポンスに、以下のように次の呼び出し時に渡すべきメッセージ群を含め、

{
    "past_messages": [
        {
            "role": "user",
            "content": "Who won the world series in 2020?"
        },
        {
            "role": "assistant",
            "content": "The Los Angeles Dodgers won the World Series in 2020."
        }
    ]
}

次の呼び出し時は以下のようにユーザーのメッセージと過去のメッセージ群をパラメータとして渡す仕様の独自 API を作成しました。

{
    "message": "Where was it played?",
    "past_messages": [
        {
            "role": "user",
            "content": "Who won the world series in 2020?"
        },
        {
            "role": "assistant",
            "content": "The Los Angeles Dodgers won the World Series in 2020."
        }
    ]
}

この独自 API を作成したことでこちらの意図しないメッセージ群が渡されてしまうことを防ぐことが出来ました。また、後述しますが過去のメッセージ群の一部を意図的に変更することを行っており、それを独自 API のレイヤーで行うことでソフトウェアエンジニアの方に意図的な変更の実装を依頼しこちらで確認するなどの連携が不要となり、開発期間の短縮に繋がりました。

コスト削減のための工夫

次にコスト削減のための工夫を 2 つ紹介します。ここで紹介するものは 1 回の Chat Completions API 呼び出し単位で見れば小さいものですが、BUYMA の会員数は 1000 万人以上であり 1 回の API 呼び出しが全体のコストに与える影響は大きいものとなります。どの程度効果が出るのか予測が難しく、また企画当初から全会員への公開を目指していたため少しのコスト削減でも検討することとしました。

一部のメッセージ群を API 呼び出し時は除外する

Chat Completions API の料金は input tokens による従量課金性であり、選んだ理由の回答が長文になりがちであるためそれに関するメッセージ群を API 呼び出し時は除外するようにしました。

例えば、ユーザーが「30代におすすめのハイブランドレディースバッグ教えてください」というメッセージを送り、「シャネル チェーンバッグ / グッチ トートバッグ / プラダ ショルダーバッグ」というメッセージが返された後に、「選んだ理由を教えて」とメッセージを送ると以下のようなメッセージが返されます。


シャネル チェーンバッグ
シャネルのチェーンバッグは、エレガントで上品なデザインが特徴です。高級感溢れる素材とクラシックなチェーンストラップが、大人の女性にふさわしい印象を与えます。また、シャネルのバッグはブランドの人気アイテムであり、長く愛用することができるため、コストパフォーマンスも高いです。

グッチ トートバッグ
グッチのトートバッグは、洗練されたデザインと高品質な素材が魅力です。ブランドのアイコンであるGG柄やロゴプリントが施されたデザインは、一目でグッチと分かる存在感を持っています。また、トートバッグは容量も大きく使い勝手が良いため、日常使いから旅行まで幅広く活躍します。

プラダ ショルダーバッグ
プラダのショルダーバッグは、モダンで洗練されたデザインが特徴です。シンプルながらも上品さを兼ね備えたデザインは、幅広いスタイルに合わせやすく、長く愛用することができます。また、プラダのバッグは高品質な素材と丁寧な作りが評価されており、耐久性も抜群です。


このメッセージの token 数は約 448 であり、以降の Chat Completions API 呼び出し毎に約 $0.00067 のコスト *1 がかかることとなります。先程述べたようにBUYMAの会員数は 1000 万人以上のため 1 呼び出しあたり約 $0.00067 のコスト増加でも大きな影響となります。そこで、過去の選んだ理由に関するメッセージ群を API 呼び出し時に除外することとしました。

具体例として、ユーザーが以下の順番でメッセージを送ったとし

  • 30代におすすめのハイブランドレディースバッグ教えてください
  • 選んだ理由を教えて
  • 小旅行で使えるおすすめレディースバッグは?

この時のメッセージ群が以下のようになったとします。

{
    "messages": [
        {
            "role": "user",
            "content": "30代におすすめのハイブランドレディースバッグ教えてください"
        },
        {
            "role": "assistant",
            "content": "シャネル チェーンバッグ / グッチ トートバッグ / プラダ ショルダーバッグ"
        },
        {
            "role": "user",
            "content": "選んだ理由を教えて"
        },
        {
            "role": "assistant",
            "content": "シャネルのチェーンバッグは、... / グッチのトートバッグは、... / プラダのショルダーバッグは、..."
        },
        {
            "role": "user",
            "content": "小旅行で使えるおすすめレディースバッグは?"
        },
        {
            "role": "assistant",
            "content": "トートバッグ / ショルダーバッグ / リュックサック"
        }
    ]
}'

この時、次の API 呼び出し時に渡す過去のメッセージ群を以下のように理由に関するやり取りを除外したものとしました。

{
    "messages": [
        {
            "role": "user",
            "content": "30代におすすめのハイブランドレディースバッグ教えてください"
        },
        {
            "role": "assistant",
            "content": "シャネル チェーンバッグ / グッチ トートバッグ / プラダ ショルダーバッグ"
        },
        {
            "role": "user",
            "content": "小旅行で使えるおすすめレディースバッグは?"
        },
        {
            "role": "assistant",
            "content": "トートバッグ / ショルダーバッグ / リュックサック"
        }
    ]
}

なお、上記の除外処理はアプリ側でも可能ですが、「API に渡す過去のメッセージの組み立てをアプリ側でやらないこととする」にも記載したようにデータサイエンティストとソフトウェアエンジニア間の連携にかかる時間を削減するために、独自 API のレイヤーで行う仕様としました。具体的には、「選んだ理由を教えて」というメッセージで独自 API を呼び出した時のレスポンスは、以下のように理由に関するメッセージ群を除外したものになる仕様としました。

{
    "past_messages": [
        {
            "role": "user",
            "content": "30代におすすめのハイブランドレディースバッグ教えてください"
        },
        {
            "role": "assistant",
            "content": "シャネル チェーンバッグ / グッチ トートバッグ / プラダ ショルダーバッグ"
        },
    ]
}

そして、次に「小旅行で使えるおすすめレディースバッグは?」というメッセージで独自 API を呼び出す時は、上記の理由に関するメッセージ群が除外された過去のメッセージ群をそのまま渡す仕様としました。

{
    "message": "小旅行で使えるおすすめレディースバッグは?",
    "past_messages": [
        {
            "role": "user",
            "content": "30代におすすめのハイブランドレディースバッグ教えてください"
        },
        {
            "role": "assistant",
            "content": "シャネル チェーンバッグ / グッチ トートバッグ / プラダ ショルダーバッグ"
        },
    ]
}

プロンプトに質問と回答の例を含めないこととする

この機能ではユーザーからのメッセージに対して弊社システム側でプロンプトを追加し、Chat Completions API にリクエストを送信しています。そのプロンプトについて、開発初期は以下のようにユーザからのメッセージと AI からのメッセージの例をいくつか含めることでこちらの意図したフォーマットで回答を生成させ、複数のおすすめを分割していました(以下のプロンプトは実際に利用しているものとは異なります)。

「おすすめ1 / おすすめ2 / おすすめ3」というフォーマットで回答してください。
以下が質問と回答の例です。
質問:30代におすすめのハイブランドレディースバッグ教えてください
回答:シャネル チェーンバッグ / グッチ トートバッグ / プラダ ショルダーバッグ

質問:小旅行で使えるおすすめレディースバッグは?
回答:トートバッグ / ショルダーバッグ / リュックサック

しかし、ある程度開発が進んだ時点でコストを見積もったところ、予想以上にコストがかかる結果となりました。そこで、上記のプロンプトの 以下が質問と回答の例です。 以降を除外することを検討しました。

以下が質問と回答の例です。 以降の token 数は約 140 であり、 Chat Completions API 呼び出し毎に約 $0.00021 のコストがかかることとなります。先程述べた通り BUYMA の会員数は 1000 万人以上のため 1 呼び出しあたり約 $0.00021 のコスト削減でも見積もり上のコスト削減は大きなものでした。

一方で、実際に上記のプロンプトの 以下が質問と回答の例です。 以降を除外し、様々なユーザーのメッセージパターンで検証してみたところ、おすすめされるものにはほとんど変化がないもののフォーマットにブレが生じ、おすすめがうまく分割出来ないことがありました(半角の / が全角の になるなど)。 そこで、うまく抽出できなかったパターンに対し正規表現などの後処理を利用して対応しました。

結果として、公開から1ヶ月程度が経過した時点でフォーマットのブレによりおすすめが抽出出来ない問題は1件も発生しておらず、コストを削減しつつ安定して回答を生成することが出来ています。

まとめ

先日公開した AIでさがす機能実現のための工夫を紹介しました。特に素早い機能公開とコスト削減にフォーカスすることで安価に早く公開することが出来ました。今後は、利用状況を分析し RAG などにより BUYMA データとの連携を強化したり、Fine-tuning などによりさらにユーザーにとって有益な回答を生成させたりなどを検討予定です。


株式会社エニグモ すべての求人一覧

hrmos.co

*1:当機能の作成期間(2023/05 ~ 2023/11)では gpt-3.5-turbo の 1K tokens あたりの料金は $0.0015 であったためその数値を用いて計算しました。

ChatGPT✖︎GASを駆使した効率的データ収集方法

こんにちは、エンジニアの川本です。
主にBUYMAの決済・配送を担当しているチームでバックエンドの開発をしています。

この記事は Enigmo Advent Calendar 2023 の 6 日目の記事です。

昨今の生成AIブームでChatGPTが注目を集めておりますが、私もChatGPTを積極的に業務に活用しています。毎日ChatGPTに質問することが当たり前になりつつあります。

今回は、実際の業務でChatGPTとGoogle Apps Script(GAS)を組み合わせてデータ収集を効率化できた事例を紹介します。

背景

弊社では各バッチ処理の実行時間が規定の時間よりも長い場合にGmailでアラートメールを送信するシステムが稼働しているのですが、ある案件で過去数ヶ月のアラートデータを参照する必要が生じました。

しかし、アラートデータはDBに保存されておらず、Gmailに直接送信されているため、SQLで直接データを参照することが難しい状況でした。

DBに新しいテーブルを作成してアラートデータを保存する案も検討しましたが、データが十分に蓄積されるまでには半年近く時間がかかりそうでした。

長期的な解決策としては有用かもしれませんが、今回は案件の都合で即座にデータが必要でした。そこで、Gmailに送信されたアラートメールからGASを利用してデータを抽出し、スプレッドシートにまとめる方法を考えることにしました。

とはいえGASは未経験だったので1から調べながら実装するのは手間だなと感じ、物は試しにChatGPTに実装させてみました!

ChatGPT✖︎GASの活用

実際にChatGPTに入力したプロンプトと、ChatGPTが出力したGASについて紹介します。

ChatGPTに入力したプロンプト

あなたのGmailのメールボックスには以下のフォーマットのメールが届いています。
2023年1月1日から2023年3月30日までに届いた下記メールからバッチ名(batch_id)、実行状態(run_status)のデータを抽出し、
スプレッドシートにまとめるためのGoogle Apps Scriptを作成してください。

# メールのフォーマット

## メールタイトル

`[CRITICAL]過去1時間止まっているバッチを検出`

## メール本文

過去1時間エラーで停止しているか、実行し続けているバッチを検出しました。
状態を確認してください。

| batch_id | start_date | run_status |
| Batch1 | Aug 17 2023 04:51PM | ERROR |
| Batch2 | Aug 17 2023 10:01AM | RUNNING |
| Batch3 | Aug 17 2023 01:04AM | RUNNING |
| Batch4 | Aug 17 2023 15:04AM | ERROR |

ChatGPTが作成したGAS

function extractStopBatchIdStatusPair() {
  // メールタイトル
  var subjectQuery = "[CRITICAL]過去1時間止まっているバッチを検出";
  
  // 対象期間
  var startDate = "2023/01/01";
  var endDate = "2023/03/30";

  // 対象期間のアラートメールを取得するクエリ
  var query = "subject:" + subjectQuery + " after:" + startDate + " before:" + endDate;

  // メールスレッドを取得
  var threads = GmailApp.search(query);

  // スプレッドシートを指定
  var spreadsheet = SpreadsheetApp.openById("スプレッドシートID");
  var sheet = spreadsheet.getSheetByName("シート名");
  sheet.clearContents();
  
  // 抽出したアラートデータ
  var values = [];

  // メールスレッドごとに処理
  for (var i = 0; i < threads.length; i++) {
    var thread = threads[i];
    var messages = thread.getMessages();

    // メッセージごとに処理
    for (var j = 0; j < messages.length; j++) {
      var message = messages[j];
      var body = message.getPlainBody();
      var subject = message.getSubject();

      // メール本文から正規表現で対象データ抽出
      var tableMatches = body.match(/\| ([^\|]+) \| ([^\|]+) \| ([^\|]+) \|/g);

      if (tableMatches) {
        for (var k = 0; k < tableMatches.length; k++) {
          var tableRow = tableMatches[k].split("|").map(item => item.trim());
          // batch_id
          var batchId = tableRow[1];
          // run_status
          var runStatus = tableRow[3];

          values.push([batchId, runStatus]);
        }
      }
    }
  }

  // データをスプレッドシートに一括で書き込む
  if (values.length > 0) {
    sheet.getRange(2, 1, values.length, 2).setValues(values);
  }
}

ChatGPTが作成したGASの実行結果

以下のように期待通りにスプレッドシートにデータが出力されました!

まとめ

ChatGPTが生成するGASの精度は期待以上であり、ゼロからGASを調査・実装する手間を考えると、非常に時間を節約でき、効率的であると感じました。

また、高い精度の出力を得るためには、入力するプロンプトの内容が重要であることがわかりました。詳細に要件を整理し、適切なプロンプトを作成することで、ChatGPTによる出力もより精度が向上します。

初めての試行で高い精度を達成できなかったとしても、修正やリファクタリングの要望を的確に伝えることで、最終的には期待通りの結果を得ることができます。

今後は、プロンプトの適切な書き方を学びつつ、より高い精度の出力を得る方法を探求していきたいと考えています。

明日の記事はT&Sチームの杉山さんが担当しますので、お楽しみに!


株式会社エニグモ すべての求人一覧

hrmos.co

不正対策の機械学習導入までに検証したこと

こんにちは、データアナリストの井原です。

この記事は Enigmo Advent Calendar 2023 の 5日目の記事です。
この記事では、不正対策のデータ分析から機械学習モデルの導入を決定した経緯についてご紹介します。

私は普段、データアナリストとしてBUYMAの様々な業務にデータ分析担当としてかかわっています。
分析内容は施策の効果検証、ユーザーの行動分析、売れ筋商品の分析などマーケティング的な要素が多く、ビジネス判断の正確性を上げることを目的とした業務が多いです。

機械学習については、ある程度の知識と経験もありますが、本職のデータサイエンティストが社内にいることもあり、どちらかといえば、統計検定や因果推論などの手法を使用することが多いです。

ただ、今回は、不正対策をしているチームからの不正検知の精度を上げたいという相談があり、検証の結果として機械学習モデルを導入しようという結論になりました。
本記事では、その経緯について詳しくお伝えしたいと思います。

なお、この記事では、立ち上がり~検証内容の決定~検証実行と、検証を進めていったプロセスにフォーカスして記載します。
分析内容の詳細(プログラム、アルゴリズムの説明など)は記載しませんので、ご了承ください。

依頼の経緯

近年、多くのECサイトで決済の不正利用の被害が増えています。
決済の不正利用とは、フィッシングなどの悪質な手段によって他者のクレジットカード情報やサービスのログイン情報を不正に取得し、それを利用して換金性の高い商品を購入しようとする犯罪行為です。

BUYMAでは、高額なブランド品が新品で購入できるということもあり、一定量、こういった不正利用による被害が発生してしまう状況にあります。
対策として、不正利用を防止するためのチームが社内に存在しており、日々対応を行なっています。

今回、そのチームから以下の依頼をデータ活用推進室にいただきました。

  • これまで、チームの知見を元に、不正疑いのある取引を検知する条件をルールベースで設定し、条件に該当した取引を一時的に止めて確認する(以下、買付保留*1)という対応を行っていた。
  • 近年、不正利用のパターンが多様化してきており、不正の事前検知の難易度が上がってきている。
  • 蓄積したナレッジとデータを活用し、データから不正な取引を止めることが出来ないか?

ということで、こちらの依頼に自分がアサインされ、データから不正検知を行うことが出来るか?を検証してみることになりました。

分析の進め方の策定

最初に実施したこととしては、検証内容を整理することです。
データ分析に関わっている方は想像つくと思いますが、分析のステップの中でおそらく一番重要なステップになります。

ここで、何を知りたいのか?それを知るための適切な方法は何なのか?を徹底的に考え、ビジネス側(今回は不正対策のチーム)と合意する必要があります。

目的は不正の早期検知ができることと明確でしたので、ここでは、検証方法について以下の3点を整理し、ビジネス側に提示しました。

  1. 精度の測り方
  2. 分析手法
  3. 検証に使用するデータ

ひとつづつ、見ていきます。

1.精度の測り方

今回の案件では、精度をどのように定義するのか?が要所の一つでもありました。
単純に考えると、不正な取引を何件検知できたか?が指標になるように思われます。

この考え方であれば解決は簡単です。全ての取引を買付保留にしてしまえばよいのです。
全ての取引を買付保留にして、全て不正かどうかをチェックすれば、理論上、不正はすべて止められます。

しかし、当然ながらこの方法は取れません。
全ての取引を不正疑いとしてチェックすることはコスト的に現実的ではないですし、ユーザーからしても取引完了までの時間が長くなるため、ユーザビリティーが下がってしまいます。

今回のような検証内容の場合、見るべき指標は二つあります。

  • 不正と予測した取引が実際に不正である確率(以下、買付保留的中率)
  • 不正である取引を不正と検知できる確率(以下、検知成功率)

ちなみに、機械学習の二値分類タスクでこの指標はよく出てきます。
(それぞれの指標は機械学習の言葉では適合率、再現率と言います。詳細は書きませんが二値分類の指標は他にも色々あったりしますので、知っておくだけでも便利です。)
図にしてみると以下のようになります。

買付的中率と検知成功率

基本的に、この指標は片側を改善すると片側が悪化する傾向があります。
例えば、検知成功率を上げるためには、買付保留の数を増やす必要がありますが、(きれいに不正だけを検知することは基本ないので)母数が増えて買付保留的中率は下がります。

検知成功率をあげようとしたときのイメージ

逆も同様で買付保留的中率は、基本的に母数を減らすことになるので検知成功率が下がります。

買付保留的中率をあげようとしたときのイメージ

このあたりをどのラインで許容できるかは、ケースバイケースになります。
本ケースでも、二つの指標を総合的に見ながら、ビジネス側と方針を詰めていくこととしました。

2.分析手法

指標を決めましたので、どのように精度を改善していくか?という手法の選択に移ります。
選択肢としては、以下の二つの手法を考えました。

  • 決定木分析で重要な要素を抽出し、ルールベース案を検討する。
  • LightGBMで機械学習モデルを構築し、不正予測スコアから推定する。

検証内容的に機械学習モデルを使った方が、精度は改善するだろうという感覚がこの時点でありました。
しかし、それでもルールベース案の検討を入れたのは、コスト的な観点からです。

経緯にも記載した通り、これまでも不正対策のチームではルールベースで買付保留を行うという運用を行ってきていました。

つまり、ルールベースであれば、すでにあるその運用に乗せることができ、開発などのコストも少なく短い期間での対応が可能でした。

一方の機械学習は全社での活用歴はいくつもあるものの、不正対策への適用は初めてでしたので、検証はともかく実行環境の構築にはコストも時間もかかります。

そのため、ルールベースでそれなりの精度改善が見込めるのであれば、わざわざ機械学習環境を構築する必要がなくなるというコスト的メリットがあるのです。

3.検証に使用するデータ

最後に検証に使用するデータの決定です。
幸いなことに、これまでの不正対策の取り組みのおかげでログは蓄積されていましたので、どの取引が不正だったのかという実データを使うことが出来ました。

過去ログは「学習用データ」と「検証用データ」に分割しました。
これは、学習させたデータでそのまま精度を検証すると精度が過剰に高く出て検証にならないので、学習させていないデータで検証を行う必要があるためです。

また、最新の1ヶ月のデータは、完全に学習用データから除外しました。
不正というのは一人の不正者が不正を一つだけ行うというものではないため、過去のデータ同士だとランダムに分割しても類似パターンを学習してしまう可能性があります。
そのため、未知のデータに対応しても精度がよいか検証する必要があり、最新1ヶ月分はそれ用の検証用データとしました。

まとめると以下のようなイメージになります。

データの用意

分析の実行

検証方法をビジネス側と合意しましたので、ここからは分析を実行していきます。
前項で書いた通り、「決定木分析からルールベース案の検討」と「LightGBMを使った機械学習モデルの構築」を行っていきます。

1.決定木分析からルールベース案の検討

途中の作業は省略しますが、決定木分析を行うと以下のようなアウトプットが出てきて、どのような変数・閾値で分割すると、不正とそうではない取引をうまく見分けることが出来るかを可視化してくれます。
※変数名や結果はダミーです。

決定木分析のイメージ

決定木の結果をそのまま使ったわけではないですが、重要そうな要素と閾値を見ながらルールベース案を4つほど作成しました。
また、決定木自体も予測を行うことが出来ますので、決定木によるモデル推定というパターンも用意しました。

これら5つのパターンと既存のパターン、合計6パターンについて、全組み合わせ(63パターン)での予測結果と精度を算出しました。

具体的な数字は出せませんが、この時点でモデル推定の精度が突出していました。
単純なモデル推定と既存パターンの比較では、買付保留的中率が数倍レベルで大きく改善し、検知成功率もかなり改善していました。
つまり、より少ない買付保留の数で多くの不正を検知することが、(シミュレーション上ですが)可能になったということになります。
また、モデル推定に既存ルールベースを組み合わせると、買付保留的中率は多少下がりますが検知成功率が大きく改善しました。
上記3つだけのイメージ図を書くと以下のようになります。

モデル推定と既存パターンの比較イメージ

この結果からは、機械学習モデルの導入に対する期待値が高まりました。
決定木分析は精度があまり高くないと言われている手法ですので、この後実施するLightGBMならより改善するのでは?とも思えました。

また、指標を事前にすり合わせていたことで、この時点で数字を使った会話ができるようになりました。
数字は仮のものですが、例えば、以下のように整理ができます。

  • 既存パターンでは1,000件買付保留を行い100件の不正検知が出来ている。
  • モデル推定+既存パターン+新ルール案すべてでは、5,000件買付保留を行い、200件の不正検知が出来る。
  • モデル推定+既存パターン+新ルールA案のみでは、2,000件買付保留を行い、195件の不正検知が出来る

数字でイメージがつくので、例えば、買付保留が5倍になっても不正検知を最大化するのか?多少の不正検知数が減っても、買付保留は2倍までに抑えたいか?などの議論を行うことができました。

2.LightGBMを使った機械学習モデルの構築

続いて、LightGBMを使って、機械学習モデルを構築しました。
※LightGBMとはなんぞや?という説明は省略します。非常にメジャーな機械学習モデルですので、興味ある方は調べてみてください。

こちらは、シンプルに(LightGBMによる)モデル推定、既存パターンのみ、モデル推定+既存パターンで精度を比較しました。なお、決定木と比較するとやはりLightGBMのモデル推定の方が精度は高くなっていました。
※予測スコアの閾値の検証なども行っていますが、これも省略しています。

最終的な結果だけ記載しますが、モデル推定+既存パターンでは既存パターンと比較して不正検知率が大幅に改善し、買付保留的中率もそれなりに改善することが確認できました。
買付保留件数も増加していたのですが、ビジネス側で許容範囲と確認いただきました。
コスト面を考えても大きな改善が見込めると検証できたので、機械学習モデルの導入に向けてプロジェクトが動くことになりました。

まとめ

本ケースで行った検証の大まかな流れは以上になります。
機械学習モデルを実際に導入するには時間がかかるため、検証したルールベースの中で精度のよいものをまず導入し、機械学習モデルの導入は順次進めている状況になります。

今回は、明白な結果の差が出たため、導入の判断をすぐに行うことが出来ました。
機械学習の精度がすごいというのはありますが、それとあわせてログとナレッジが大量に溜まっていたことが成功要因でした。

「Garbage in, garbage out」という言葉があります。
精度の高いアルゴリズムでも、ゴミデータを入れればゴミデータしか出てこないという意味ですが、今回は良質なデータのおかげで良質な結果がアウトプットされたと思います。

過去の取り組みまではデータアナリストはなかなか介入できません。
データアナリストとしては、これまでのビジネス側の蓄積された過去のナレッジをうまくヒアリングして、データに変換していくスキルが重要かと思いますが、それらがうまくマッチした事例になれたのではないかと思いました。

本日の記事は以上になります。最後まで読んでいただきありがとうございました。
明日の記事の担当はエンジニアの川本さんです。お楽しみに。


株式会社エニグモ すべての求人一覧

hrmos.co

*1:BUYMAはCtoCの買付代行サイトのため、多くの場合、注文が入ったあとに出品者が商品を買い付けています。万が一、不正利用だった場合、商品買い付け後にキャンセルになると余分な在庫が発生してしまうため、取引のチェックを行うまで、出品者の方に一時的に買い付けを待ってもらう対応が「買付保留」という仕組みです。買付保留となる取引は確定した不正とは別物です。買付保留は不正疑いというニュアンスで読み進めていただくと分かりやすいと思います。

振り返り、得意ですか?

こんにちは、SE本部の hashino です。 現在、2年目の新卒入社のエンジニアです。BUY Domainに所属しており、BUYMAの購入者向け機能を開発しています。

この記事は Enigmo Advent Calendar 2023 の 4 日目の記事です。

みなさんは振り返りをしていますか?
週ごとや月ごと、年単位......振り返りの頻度や粒度は人によってさまざまだと思います。
仕事の進捗や自己成長を確認し、改善点を見つけるためには振り返りは不可欠です。

エニグモの開発部門の新卒やジュニアは、YWT方式で毎週振り返りをおこなっています。
詳しくは以下の記事をご覧ください。 tech.enigmo.co.jp

この記事では、振り返りが苦手で週の振り返り記事の作成にとても時間がかかっていた私が実践した振り返りの手法とその結果とともに紹介していきます。
前提として、できるだけ技術的なこと以外にも仕事のやり方などを振り返ることが推奨されています。
例えばわかったことにRubyにこのような仕様があることを知った。だけ書いてしまうのは次のアクションにつながりにくく非推奨です。

振り返りの作成をその都度していく。

振り返り記事を週末に一気に書くのではなく、日々気づいたことをその都度まとめておくことで、時間の節約になります。

私の結果: 最初は順調でしたが、徐々に習慣が薄れ、日報との二重作業に疲れてしまいました。 私には微妙でした。

三者目線になる。

自分ごととして捉えると何に気付けたのか、何が悪かったのかがわからなくなりませんか? 自分の仕事を客観的に見ることができるようになるために、第三者目線で振り返ります。 同じ悩みをもった後輩に今週の仕事をより良くするためのアドバイスを自分だったらどう声を掛けるかなどと考えるといいかもしれません。

私の結果: 成功や良い点を記述することが難しく感じましたが、失敗に焦点を当てると自分に合っているやり方でした。

振り返りの目的を忘れない

何か書かなければいけない〜!と焦ってしまい、余計になにも書けないことはありませんか? 振り返りは書くことが目的ではなく、自己成長や仕事の進捗を把握する手段です。

私の結果: 焦らず、冷静に振り返りの目的を忘れないように心がけました。 何を伝えたいかを明確にし、それに基づいて振り返りを進めることで、メンターとの振り返りでは有益な情報を得られるようになりました。

たくさん書いてフィードバックをもらう

振り返りの内容を先輩やチームの人と共有し、フィードバックを得ることが重要です。 新たな気づきや改善点が見つかります。 よかったことも悪かったこともどんなことでも書いてみましょう!

私の結果: もう少し書いてほしい!と言われても、最初は何を書けばよいのか戸惑いました。
しかし、小さな工夫や日々の取り組みを積極的に記述するようになりました。
私がどういう取り組みをして結果がどうであったかという記録が残っていくので、自分の傾向がわかるようになりました。

少しずつ振り返りが早くなり、自分の仕事の仕方の傾向を理解できるようになりました。
振り返りははじめこそ手間がかかるかもしれませんが、継続することで大きな成果を生むことができます。
同じような悩みを抱える方には、この経験が少しでも参考になれば幸いです。仕事の振り返りは、自分の成長を促進するための重要なステップであることを肝に銘じています。


株式会社エニグモ すべての求人一覧

hrmos.co

頑張りすぎないソフトウェア見積り

こんにちは、エンジニアの岡本です。 主にBUYMAの出品者向け機能のサーバーサイドの開発を行っています。

この記事は Enigmo Advent Calendar 2023の1日目の記事です。

今年のアドベントカレンダーは生成AIの話題が各所でたくさん提供されると思いますが、私はソフトウェア開発における見積り、そして私がプロジェクトの計画を立てる上で実践していることについてご紹介しようと思います。

プロジェクト当初になんとなく立てた見積りが甘くて、リリース予定日が近づいているのに差し込みタスクが発生したり不備が発覚したりで、当初のスケジュールから遅れを出し、精神的に苦しい思いをしてしまうという経験が私にはあります。

見積りと計画立てに科学的なアプローチを取り入れたいという思いから、まず先人の知恵を求めました。

見積りを科学的に解説する本を探していたときに「ソフトウェア見積り 人月の暗黙知を解き明かす」という名著と出会いました。

通読した時点で、自身の経験と照らし合わせた上で以下の感想を持ちました。

  • 100%正確な見積もりは不可能

  • 3点見積りなどはちゃんとやろうとするのは難易度が高そう…

  • なんでも良いので、各タスクの規模感をカウントできるようにすると良いらしい

以下では、実際に取り組んでいることを紹介します。

作業スケジュールを立てる上での工夫

タスクを切ってコードを書くだけではないので、以下の工程もスケジュールに組み入れるようにしています。

  • プロジェクト開始時点で「QA」「QA過程で判明した不具合修正」「リリース作業」もサイズを見積もっておく

  • 遅れることはあっても、早まることは基本的にないということで1~2週間程度作業バッファを初めから入れておく

見積もりに慣れていなかった頃、この二つをやっていなかったために失敗したことがありましたが、これらを意識するようになってからは大幅にスケジュールがずれることは無くなった感覚があります。

ストーリーポイント

人月などを試したことがありますがいい感触でなかったので、ストーリーポイントを使ってみることにしました。

プロジェクト管理方法はJiraで行っています。Jiraは見積もりという観点においては「ストーリーポイントが定義できる」という点が良いと思っています。

基準となるタスクを決めて、それを2ポイントと定義しています。フィボナッチ数に基づいて、振り返りミーティングにてスプリント計画を行うときに各タスクにポイントを割り振っています。基準タスクよりもすぐ完了できそうなら1ポイント、それよりも1日くらいプラス必要なら3ポイント、1スプリント(今のチームでは1週間)内で完結できるなら5ポイントという感じです。

1個のタスクに当てられるポイントの最大値は13と決めているのですが、大体のタスクは2~5ポイントくらいになるように分割されています。

私がいるチーム(squad)ではおよそ1年以上試行錯誤をしながらこのような方針でスケジュールを管理するようになっています。もしかしたら他にもいい方法があるかもしれないですが、その場合は適切にアップデートしていきたいと思っています。

現時点での結論

100%正確な見積りは不可能であると割り切った上で、各タスクの規模を数えられる形で単位化するという考えのもと、スプリントを計画・実行しています。

見積りの重要性を理解しつつも、実装の正確性やスピードの向上に焦点を当てることがソフトウェアエンジニアにとって重要な課題であると考えています。

私からは以上です。お読みいただきありがとうございました。

明日の記事は採用チームの廣島さんが登場します。


株式会社エニグモ すべての求人一覧

hrmos.co

エンジニア組織マネジメントのさらなる進化へ

~「Committee・新開発体制」導入後の成果と魅力~

目次

エニグモのエンジニア組織の新しいマネジメント体制と、新開発体制についてCOOの安藤、エンジニアリングマネージャー(EM)の木村・山本にインタビューした記事の続編です。

前編は、Committee体制(エンジニア組織をCTOや部長を頂点とするワントップ型ではなく、EM陣で構成する「Committee」という合議体を意思決定のトップ機関)ができた経緯や、どのような体制でエンジニア組織を運営しているかを中心にお話ししました。
後編は、エンジニア組織全体がどのような体制になり、エニグモのプロダクトを開発しているのか、実際に新しい体制になりどのような効果があったのか、当社エンジニア組織の魅力やキャリアなどについてお話しします。

前回の記事はこちらです。
tech.enigmo.co.jp

新開発体制について

大谷:
Committee体制の取り組みの第一弾として、エンジニア組織・開発体制をDomain、Squad、Chapter体制(以下、新開発体制)に移行したかと思います。後編ではまずは、新開発体制の概要についてお聞きできればと思います。

木村:
エンジニアの新開発体制は、実態としてはチームトポロジーの概念( Spotifyモデル)を参考に組織設計しました。

プロダクトの開発を担う機能別のDomain(ドメイン)と呼ばれるチームがあり、それをさらに細分化・構造化する形で、縦割りチームのSquad(スクワッド)や、横串チームのChapter(チャプター)があります。

Squadは事業的なミッションが与えられ、そのミッション達成に向けたシステムについてオーナーシップを持ちます。システムの全開発ライフサイクル(設計、開発、テスト、本番化、運用、不具合対応など)を担当します。

Chapterは、Squadの中でも特定の専門分野を担当するメンバーを横串に束ねた組織です。Squadに所属しながらSquad外でも、テクニカルな改善・基盤整備を独自に実施します。

※新開発体制の詳細は下記記事でまとめていますのでご覧いただければと思います。
tech.enigmo.co.jp

新開発体制導入の背景/なぜこのような体制にしたのか

大谷:
Committee体制の中で、なぜこのような新体制を構想したのかについて背景をお聞かせください。

木村:
トップの役割をCommittee体制に引き継ぐ際に、開発組織はトップに依存せず、各チームに裁量を持たせ、自律的に成長・進化し続けることで、ビジネス課題を迅速に解決できる組織としたいという考えがありました。
各組織・チームに裁量を持たせるためには、各組織・チームが担うべきロール(役割)を改めて明確に定義し直す必要があると考えました。 その中で最適な組織の形は何かを考えた結果、この新開発体制が上手くフィットしました。

安藤:
以前からエニグモでは、ビジネスメンバー、ディレクター、エンジニアが、Oneチームで同じ事業課題解決に向かってプロダクト開発する「ユニット」体制がありました。昔からどういった体制がベストであるかを模索していた中で、この1、2年でDomainやSquadとして再定義し、メンバーをアサインして、継続的にプロダクトを磨いていこうという体制になったと記憶しています。

山本:
そうですね。SquadはもともとSpotifyのSquadモデルを参考にしたり、「ユニット」の考え方を応用して、一部のチームでは導入していました。Squadの領域を定義し、リーダーを決め、縦に割って効率化しつつもSquad間でも横で連携して取り組もうという体制がありました。
また、ミッションが類似・関連しているSquadを束ねたDomainという考え方も以前からありました。

Committee体制を導入するタイミングで、木村さんがトップの役割を棚卸した際に、以前からあったDomainやSquadをより言語化・明確化することで、上手くかみ合ったのかなと思います。
もともとはChapterの概念は省いていましたが、専門のロールをChapterとして整備し取り入れました。

安藤:
Committee体制で進めることで、組織的にどのような体制で進めるのが自然であるかを改めて考える良い機会となりました。
トップの仕事は属人的であるということに気づき、トップが変わったとしても、組織を存続させるためには、こういうCommittee体制というハコ(仕組み)でやるのが自然だよねとなり、新開発体制へと昇華されました。

新体制導入後に感じている進化や手ごたえ

大谷:
Committee体制、新開発体制の導入後に感じる手ごたえはどうでしょうか?

木村:
手ごたえとしては、各メンバーが裁量を持ち、且つ負担がかかりすぎない良い体制で、元々のコンセプト通りに運営できているように感じます。

私はCommittee Headですが、HeadというのはあくまでCommitteeの中の役割で私がタッチしていない部分も多いです。そんな中でも、トップ(Head)に依存しすぎず、各メンバーが決めた持ち場でしっかり役割を担っていただいていると感じます。

山本:
マネージャーやSquadリーダー同士での話し合う機会が増えてました。
例えば「開発で、今こういうことをやっていて、ちょっと相談したいんですけど」みたいな話は、Squad Weekly(Squadのリーダー以上が参加するミーティング)でしており、他のチームリーダーにも意見や相談ができます。
開発に関わること以外でも、「採用はどうしましょうか?」「組織をもっとこうしたい」「チームのマネジメントについて相談したい」といった話題はCommittee体制になりより話すようになりました。

大谷:
経営側からみて、安藤さんが感じる「ここらへんが変わり始めたな」というところはありますでしょうか。

安藤:
すでに明確に変わっていると感じるところはあり、今まで言語化されていなかった組織やチームの役割やミッションが「こういうチームを目指していきたい」としっかりと言語化され、クリアになりました。そのことで、経営やビジネス的な視点で意思決定する際も説得力が持てるようになりました。

例えば、本来は優秀なメンバーは機能開発にアサインしたいところです。直近立ち上がった(技術的な課題を解決する)チームも「Squadメンバーの生産性を最大化させるためにあるチーム」と定義することで、これからのエンジニア組織やサービス成長において重要な役割であることが明確になり、メンバーのアサインにおいて納得感あるコンセンサスになりました。
採用に関しても、新しい体制下でのスピーディーでチームが一体となった採用活動ができるようになったことも、大きな進化だと感じています。 大谷:
新開発体制に移行したことによる、プロジェクトの進め方やメンバー間コミュニケーションの変化について、さらに詳しくお聞きしたいです。

木村:
以前は、プロジェクトが始まるタイミングで手が空いているメンバーを優先的にアサインしていました。新開発体制のSquadではエンジニアとして担当する機能が固定化され、システムについてのオーナーシップを持つことができるようになりました。この変化により、技術領域とドメイン領域の両方に精通することができ、非常に効果的であると感じています。

以前は、「今日からあなたは、この機能を開発してください」となったときに、都度キャッチアップしながら探り探り進めることが多くありました。その結果、コードを壊してしまったり、元々の設計志向を理解せずに違う方向に修正してしまうことがありました。しかしこのような事態は新開発体制の導入によって解消されました。

山本:
Squadは毎回新しいメンバーと組むわけでなく、2〜3名の小さいチームで同じメンバーで開発・振り返りを行うことができるため、チームごとにノウハウが蓄積し、息の合った開発・プロジェクト進行が可能となります。さらに、蓄積されたノウハウは他のチームにも共有され、良いアイデアが取り入れられる好循環が生まれています。

安藤:
新開発体制となり、エンジニアと企画•ビジネスメンバーが同じOKRをディスカッションして決めて、良い形で一体となってプロダクト・サービスを作っているように感じます。これは2人にとってはどう映っていますか?

木村:
エニグモの企画・ビジネスメンバーはエンジニアへの理解が強く、理解しよう・寄り添おうとしてくれるメンバーが多いように感じます。 エンジニアが強すぎるというわけでも、ビジネス側が強すぎるわけでもなく、言われた物を言われたままに作るというわけでもなく、バランスのとれた形で開発が進められていると思います。
エンジニアも、長く働くメンバーが多いのは(10年以上在籍するメンバーもいる)のは、そういう環境にやりがいや面白みを感じているからかもしれません。

山本:
もともとはビジネス側から、こういう企画がやりたいという話があり、さらに間にディレクターが入り要件定義し、エンジニアに下りて来るという形で、比較的受託開発のような開発の流れがあり、ビジネス側との距離感が少し遠いと以前は感じていました。

新開発体制になった後は、ビジネス側のメンバーが同じチームに所属することで、エンジニアが直接コミュニケーションを取れるようになりました。 エンジニアも参加するMonthly定例で、ビジネス側で持っている課題感や数値の進捗共有があり、「こういう数値を見てたんだ」といった新しい発見もあります。ビジネス側との距離がより近くなったと感じます。

さらに、SquadでOKRを決めて開発を進めるため、ビジネス的な目標についてもエンジニアとしてコミットし、プロダクトへの意識が変わってきています。 OKRを設定するためにはエンジニアも含めて多くのディスカッションが必要なため、ビジネス側の視点を持って開発をしたい方にとっては面白い環境であると思います。

当社エンジニア組織の魅力・キャリア

大谷:
エニグモではエンジニアとして、どのような経験やスキルを身につけたり、キャリアを積むことができますか?

木村:
エンジニアは事業志向と技術志向の方がいると思っています。
事業志向の方は事業のミッションと向き合えるようなポジションに配置されるため、プロダクトの成長にどう貢献するかを考える機会があり、そういった方向でスキルを伸ばし、キャリアが積めると思います。

技術志向の方は、Squadで開発の一連のサイクルを経験できますし、またChapterやその他専門チームに所属することで、専門的なスキル・技術を深めることができます。 また、マネジメントを志向する方にも、DomainやChapterごとにマネージャーが配置されているため、そういったマネジメントのポジションを目指すこともできます。

山本:
実際のユーザーとの距離が近く、フィードバックをダイレクトに受け取ることができます。ユーザーのフィードバックを受けながらビジネス側のチームと協力して、エンジニアの視点でサービスやプロダクトに関する課題解決に取り組むことができます。

技術的な面では、大量のトラフィックを想定した開発など、大規模なアプリケーションの開発についての一通りの経験が得られるのが魅力です。
また、BUYMAはユーザーも機能もすごく多く、機能も複雑に絡み合っているため、コードの一部を変更すると他の機能に影響が及ぶ可能性があります。そのため、自然と質の高い開発をする意識が養われます。

安藤:
確かに、プロダクト志向やビジネスに興味がある人も、技術的に突き詰めたい人にも、マネジメント志向の人にも様々なキャリアの可能性がありますね。

まとめ

エニグモにマッチするエンジニアとは?

大谷:
最後に、さらなる組織進化にむけて今後どのような人材に加わっていただきたいか、こういう方はエニグモで活躍できる(マッチする)などお話ください。

山本:
事業や、組織的、システム的なところなど課題をどんどん見つけて、もっとこういう風にした方が良いという思い(改善思考)を持ち、周囲を巻き込んで行動し、挑戦できる人が一番かと思います。

木村:
どういう方が楽しめるのかなと考えると、世の中一般的にこうあるべきみたいなのがあって、そこに向かって今のその会社の形を無理やり変えていくみたいな人というよりは、会社それぞれで最適な形というのは当然あるため、会社や事業、組織、人のリアルな課題に向き合い最適解を探せる方ではないでしょうか。

安藤:
エニグモが求めている人物像は、基本的にはエニグモのバリューに沿った方が良いと思っています。
※バリューについての詳細はこちら
チームワークで解決できる人、物事をよりよく・より深く考えることのできる人。現状に満足せずに変えることができる人ですね。

変革の過程でギスギスすることやハードなこともあるため、そういった場面でも楽しみながら業務に取り組み、最終的には「夕日を見て肩を組めるような人、いろいろあったけど一緒にやれて良かった」と感じられる人が良いと思います。そんなに熱くなくてもいいですけどね笑。

大谷:
夕日を見て肩を組む、、、いいフレーズですね(笑)エニグモが求める人物は「変革期で逆境やカオスな状況を乗り越えた先に、夕日を見て肩を組める人」ということで今回のインタビューは締めといたします。ありがとうございました。

NodeGroup単位でのメトリクス収集

こんにちは。
インフラグループKubernetesチームの福田です。
先日、こちらでPrometheus Stackを使った監視構成の概要を紹介させていただきました。
本記事はそれに関連して、NodeGroup単位でのメトリクスの取得に関してハマりポイントがあったので、それを紹介できればと思います。

NodeGroupとは

EKSにはNodeGroupという機能があります。
これは名前の通り、Nodeをグループとしてまとめる機能で、NodeGroup単位でマシンスペックを指定したりすることが可能です。
NodeGroupの詳細はこちらの記事が特に参考になります。
また、NodeGroupの名前等の情報は各nodeにラベルとして付与することが可能です。

やりたいこと

我々の場合、EKS上に複数のプロジェクトをホスティングしており、これらのプロジェクトに1:1でNodeGroupが存在しています。
そして、プロジェクト単位(NodeGroup単位)でnodeに関するメトリクスを収集したい要件があります。
例えば、あるプロジェクトのnodeの負荷を収集して、そのプロジェクトが設定しているEC2(Kubernetes node)マシンスペックが適切かどうか判断したい場合です。
言い換えると、あるnodeに関するメトリクスがどのNodeGroupに属するものか知りたいのです。

問題点

Prometheus metricsにはラベルが付いていて、このラベルを使ってメトリクスをフィルタしたり、グルーピングしたりできます。
我々の監視構成ではnodeのメトリクスはNode Exporter経由で収集していますが、Node Exporterが提供するメトリクスにNodeGroupラベルは付与されていません。
また、relabel_configs等のPrometheusが提供するラベル付与機能では決まった文字列のラベルを付与することはできても、「メトリクスの送信元ラベルからNodeGroupラベルをマッピングして付与する」といった動的なラベル付与はできません。

解決策

nodeにラベル(メトリクスのラベルではなく、Kubernetes nodeに付与されているラベル)として付与されているNodeGroupの名前をKubernetes API経由で取得し、メトリクスにNodeGroupラベルを付与するプロキシ(Proxy Container)をNode Exporter Podにアダプタとして追加しました。

Proxy ContainerはGoで実装していて、以下のように動作します。

NodeGroupラベルの取得の挙動

  1. 自分自身がデプロイされているkubernetes nodeのhostnameを取得。
  2. 前のステップで取得したhostnameに対応するnodeのラベル一覧をKubernetes API経由で取得。
    • 取得したnodeのラベル一覧にNodeGroupラベルが含まれる。

Proxyとしての挙動

  1. Prometheusからリクエストを受信する。
  2. Node Exporterコンテナにメトリクスのリクエストをする。
  3. Node Exporterコンテナからレスポンスとしてメトリクス情報を受信する。
  4. 取得したメトリクス情報にテキスト処理を行い、メトリクスにNodeGroupラベル付与する。
  5. Prometheusにレスポンスを返す。

まとめ

NodeGroup単位でメトリクスを収集する方法について紹介させていただきました。
本記事で紹介したProxy ContainerはPrometheus形式のメトリクスに対して、任意のラベルを挿入できるように実装しています。
動的にメトリクスのラベルを弄りたくなる状況が同じようにあれば、これを再利用していきたいと思います。

エニグモではエンジニアを含む各種ポジションで求人を募集しております。

株式会社エニグモ すべての求人一覧

hrmos.co