F@N Ad-Tech Blog

株式会社ファンコミュニケーションズ nend・nex8のエンジニア・技術ブログ

広告配信がどのように作られているのか

はじめに

はじめまして。 関西の大学院に通う博士前期課程1年の馬越です。 株式会社ファンコミュニケーションズさんにて9月2日〜9月6日の間インターンシップに参加させていただきました。 今回、私が参加させていただいたコースはScalaを利用した広告配信システムの開発でした。 それでは参加経緯、インターンシップ内容、感想、ファンコミュニケーションズさんについて書いていきたいと思います。

参加経緯

ファンコミュニケーションズさんを知ったのはサポータズさんの1on1面談イベントにて 社員さんとお話しをさせていただいたのがきっかけとなります。 そこでの会話をきっかけに、広告配信システムがどのように作られ、配信されるのか非常に気になっていました。 また、夏休み期間中に新しいことに挑戦したいと思い、何か新しい言語を学べるインターンはないかとWantedlyさんのサイト眺めていた際に ファンコミュニケーションズさんのインターンシップではScalaを利用して広告配信の裏側を知ることができると目に入り、応募いたしました。 応募からすぐに返信をいただき数日後に面談をさせていただきました。

インターンシップ内容

今回インターンシップの内容は、Scalaを利用してミニDSPを構築しようということでした。 アドテク業界は主にSSPとDSPというのに分かれております。 SSP、DSPとはなんぞや?という方は以下のサイトを参考にしてみてください。

kigyotv.jp

今回のインターンでは、メディア(アプリ等)からリクエスト(アプリIDや広告枠を売りたい最低金額)等が送られ、 その情報をもとに、広告主が買いたい金額を予測し(今回は実装していない)、最適な広告を決定し、メディアに返す処理を実装しました。

1日目

午前中は社内見学とSSP、DSPの解説がありました。 午後からはメンターに指導をいただきながら、どう開発を進めていくか話し合いました。 また、私がScalaが初心者なため、Scalaの基本的事項をおさらいしました。 その後、ミニDSPを構築するためのアーキテクチャ選定を行いました。 ここから少し技術的な内容になります。

まず、使用言語はScalaです。 Scalaはオブジェクト指向と関数型言語の両方を兼ね備えております。 (慣れまで少し時間がかかりそうだと感じました。) IDEはIntelli J Communityを利用しました。

今回の開発はDSPの仕様からサーバとデータベースが必要となります。 また、SSPからDSPへのリクエストの応答時間が100msであることが必須条件となっているので そこを考慮しメンターに相談しながらアーキテクチャを選定していきました。 サーバはWebアプリケーションフレームワークであるFinatraを利用しました。

以下のサイトを参考にしました。 qiita.com

qiita.com

FinatraでWebアプリケーションの雛形を作って1日目は終了しました。

2日目

2日目からは主にAPIの実装に入りました。 APIにリクエストがきた場合の処理を実装しました。 今回はSSPからの情報を元に、最適な広告を返す処理として、

  • データベースから広告のデータを取得
  • メディア(アプリ等)ごとに表示する広告をフィルタリング
  • 機械学習にリクエストを送信し各広告の入札金額の取得
  • メディアからの希望入札金額に下回っている広告をフィルタリング
  • 一番高い広告を決定し、SSPに送信

という流れになっております。

ここで、受け入れ条件として応答時間が100msであることが必須のため、 データベースを作る際にsqlを毎回利用していると トラフィックが増えた際に仕様を満たせないため、Redisを利用することになりました。 Redisは以下のサイトを参考にしてください。

qiita.com

今回はScalaでRedisを利用したいため、scala-redisを利用しました。

github.com

サーバとRedisを繋ぐ時は、コネクションプールを利用し接続しています。

https://wa3.i-3-i.info/word12762.html

3日目

3日目は2日目の続きです。 サーバとRedisを接続できたので、実際に広告データ(ダミー)を取得しました。 そのデータを元に、フィルター処理を実装しました。 メンターに指導をいただき、fillter関数やMap関数を利用しScalaっぽい書き方で実装できました。 if文を利用せずに関数を実装できたのがとても感動しました。 次にサーバから機械学習APIにリクエストを送信し 返ってきた値をフィルタ処理し、SSPに返信しました。 ここまでで、ミニDSPのメインの機能を完成させることができました。 実際にcurl等でAPIにリクエストを送信すると実際にデータを返すことができました。

4日目

4日目はリクエストがきた際にログ保存を行う処理を実装しました。 Scalaで何かログを保存しやすいのはないかと調べると、logstash-logback-encoder というものを発見し、こちらを利用することにしました。

labs.septeni.co.jp

一通りシステムが完成したので、実際に応答時間を調べてみました。 今回はローカル環境なのであまり意味がありませんが、形だけどのくらいか調べました。 はじめはHttpieを使用してtime curlで応答時間を調べていましたが、300ms程度で かなり遅いことに悩まされました。 原因がHttpieであることを発見し、terminal等で確認すると100ms以内で実行できました。

また、Apace Benchを利用してWebサーバの負荷テストも実施してみました。 こちらもローカル環境なのであまり意味がありませんが、以下のサイトを参考にしました。

qiita.com

最後にメンターに自分の書いたソースコードのレビューをいただき、 コードのリファクタリングを行いました。 実装するために処理を長く書いてしまい見辛いコードになっていたのを 1クラス1機能に分類し、不要なコード等を除去しました。 フィードバックがあったことにより今後どのようにコードを書いていけば良いか理解することができました。

5日目

5日目は午前中は退職手続き等を済ませ、午後から成果発表を行いました。 発表が終わり、このブログを書いて終了です。

時間が余ったのでSSPを作成して自分のDSPにリクエスト送信することになりました。

感想

今回のインターンシップで広告配信の裏側を理解することができました。 アドテク業界ではユーザ、メディア(アプリ等)、広告主の関係があり、今回はメディアと広告主を繋ぐDSPを開発しました。 その中で、実際にアドテク業界が使っている技術などをメンターに教えていただき大変勉強になりました。 また、メンターにソースコードのレビューをしていただき、どのように書いたら綺麗になるのかを教えていただきました。 インターンシップを通して様々な技術と触れることができたので大変良かったです。 今回の開発を通して、ソースコードの書き方やオブジェクト指向の概念等曖昧な部分があったので、 今後はこの経験を活かして自分なりにスキルアップを目指したいと思います。 インターンシップに受け入れていただき、そして、5日間ご指導いただき本当にありがとうございました。

ファンコミュニケーションズさんについて

最後になりますがファンコミュニケーションズさんについて少し書きたいと思います。 インターンを始める前は、どのような雰囲気で開発されているのか全く想像がつきませんでした。 いざ、インターンシップに参加してみると社内全体がほんわかしていると感じました。 自社開発のため殺伐とした環境ではないためリラックスした状態で開発ができると実感しました。

【インフラインターン2019(1)】 本番サーバを作る Redis

はじめまして

ファンコミュニケーションズさんで2週間のインターンに参加させていただきました熊田です。

今回のインターンでは、3つのメニューをこなさせていただきました。 本記事ではその1つ目である「本番サーバを作る Redis」について書かせていただきます。

続きを読む

共変量シフトへ対応したCTR予測

 インターンに参加させて頂いた濱武です.「データ分析」コースに5日間参加し,「共変量シフトへ対応したCTR予測モデルの評価」を課題として取り組みました.

共変量シフトとは

 機械学習は訓練データ,テストデータが等しい確率分布にしたがっていることを前提としています.しかしながら,実際に等しい確率分布に従っていることはほとんどありません.このように訓練データとテストデータの確率分布が異なる状況で,入出力関数は等しいという状態を「共変量シフト」と呼びます.

対策案

 共変量シフトへの対策案の1つとして,訓練データとテストデータそれぞれの確率分布の比によって定義される「重要度」という指標を利用し損失関数を重み付けする手法*1があります.簡単な直線モデルを最小二乗法によって適合させる場合は以下の数式のようになります.

{ f(x) = \theta_1 + \theta_2x}

{ \min \sum_{i=1}^{n} (f(x_i) - y_i)^{2} }

そこで,二乗誤差に対して重要度 { w(x)} を利用して重み付けした重要度重み付き最小二乗法で適合することで,テストデータに対する予測精度が向上します(より詳しい内容は脚注の論文に書かれてあります).

{ \min  \sum_{i=1}^{n} w(x_i)(f(x_i) - y_i)^{2} }

しかし,データの確率密度を求めることは困難であり,重要度をデータから推定する必要があります.この手法も様々あるのですが,今回はこちらのパッケージを利用しました.

分析の流れ

 モデルとしてロジスティック回帰を使用し,重要度を利用していないモデルと比較することで,重要度適応モデルの評価を行うという方針で進めました.分析の流れは以下のような感じです.

  1. データ取得
  2. 重要度推定
  3. One-Hotベクトル化
  4. 学習
  5. 評価

なお,重みの適応は,ロジスティック回帰のsample_weightに推定した重要度を利用しました.

結果

 インターン最終日,上述したパッケージは大規模データでの利用を想定しておらず,大量のデータを食わせるとMemoryErrorが発生することが分かりました.そのため大幅に削減したデータでの学習を余儀なくされてしまい,また,本筋とは離れた細かいトラブルへの対処に時間をかけてしまったせいで,評価をする前にタイムアップを迎えてしまう,というとても不甲斐ない結果となってしまいました.提案手法結果のカリブレーションカーブ*2(簡単な説明は他のインターンの方が書かれています)は以下のようになりましたが,散々な結果であり,テータ削減の影響や重要度の平滑度合いを調整するべきだったとか,様々に原因が考えられます.

f:id:k_hamatake:20190823182023p:plain
カリブレーションカーブ

学べたこと・反省点

 私は独学でプログラミングや機械学習,データ分析を学んでいますが,やはり実データを利用できる機会はほとんどありません.今回インターンに参加し,データベースの扱いや大規模実データのハンドリングを学ぶことができ,5日間とても貴重な経験を積まさせていただきました.

 だた反省点として,メイン手法とは別に代替妥協案みたいなものを用意して,インターン期間にきちんと課題を終了できるようなプランニングをするべきだったと感じています.重要度推定にこだわり過ぎず,例えば日付が新しいほど重みが増加するような関数を使用する方針にある段階で切り替えておけばもっと良い結果になったかなあ,と思っています.インターンで得られた知見や反省点を活かして精進していきたいです.

 

*1:杉山将 他. (2014). 非定常環境での学習:共変量シフト適応,クラスバランス変化適応,変化検知. 日本統計学会誌 第44巻 第1号 pp.113~136.

*2:https://scikit-learn.org/stable/auto_examples/calibration/plot_calibration_curve.html#sphx-glr-auto-examples-calibration-plot-calibration-curve-py