TVer Tech Blog 2024-03-12T11:45:34+09:00 tver-techblog Hatena::Blog hatenablog://blog/26006613770846658 実務でのテーブル結合時のケア(重複排除など)について hatenablog://entry/6801883189089484798 2024-03-12T11:45:34+09:00 2024-03-12T11:45:34+09:00 こんにちは、TVerでデータ分析をしている高橋です。 弊社の分析業務の多くは BigQuery に蓄積されているログを使った分析で、大量のログを扱うため前処理から集計まで全てSQLで行っています。 本記事では、SQLを書く上で特に気を付けているテーブル結合時のケアについて紹介します。 分析業務の一例 「ホーム画面を開いてから10分以内にコンテンツを再生した割合を知りたい」という依頼が来ました1。 この集計は訪問ログと視聴ログを使い、ホーム画面に訪問したログを10分以内に再生した or 再生してないの2種類に分ければできそうです。 ここで、集計に用いるテーブルを簡単に紹介します。 訪問ログ (v… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>でデータ分析をしている高橋です。<br/> 弊社の分析業務の多くは BigQuery に蓄積されているログを使った分析で、大量のログを扱うため前処理から集計まで全て<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>で行っています。<br/> 本記事では、<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>を書く上で特に気を付けているテーブル結合時のケアについて紹介します。</p> <h1 id="分析業務の一例">分析業務の一例</h1> <p>「ホーム画面を開いてから10分以内にコンテンツを再生した割合を知りたい」という依頼が来ました<sup><a href="#1">1</a></sup>。<br/> この集計は<strong>訪問ログ</strong>と<strong>視聴ログ</strong>を使い、ホーム画面に訪問したログを<code>10分以内に再生した or 再生してない</code>の2種類に分ければできそうです。<br/> ここで、集計に用いるテーブルを簡単に紹介します。</p> <h3 id="訪問ログ-view_logs">訪問ログ (view_logs)</h3> <p>ホーム、マイページ、番組ページ、エピソードページなどに訪問したタイミングで発報されるログです。<br/> ユーザー毎に時系列順に並べることで、サービス内でのページ遷移が分かります。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synComment">-- view_logs サンプルデータ</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 19:30:00</span><span class="synSpecial">&quot;</span>) <span class="synSpecial">AS</span> viewed_at, <span class="synSpecial">&quot;</span><span class="synConstant">hoge</span><span class="synSpecial">&quot;</span> <span class="synSpecial">AS</span> user_id, <span class="synSpecial">&quot;</span><span class="synConstant">/home</span><span class="synSpecial">&quot;</span> <span class="synSpecial">AS</span> url, <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 19:32:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">hoge</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/mypage/fav</span><span class="synSpecial">&quot;</span> <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 19:35:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">hoge</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/episodes</span><span class="synSpecial">&quot;</span> <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 21:45:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">fuga</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/home</span><span class="synSpecial">&quot;</span> <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 22:25:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">piyo</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/home</span><span class="synSpecial">&quot;</span> <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 22:30:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">hogera</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/home</span><span class="synSpecial">&quot;</span> <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 22:32:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">hogera</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/search</span><span class="synSpecial">&quot;</span> <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 22:34:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">hogera</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/home</span><span class="synSpecial">&quot;</span> </pre> <table> <thead> <tr> <th> viewed_at </th> <th> user_id </th> <th> url </th> </tr> </thead> <tbody> <tr> <td> 2024-03-01 19:30:00 </td> <td> <a class="keyword" href="https://d.hatena.ne.jp/keyword/hoge">hoge</a> </td> <td> /home </td> </tr> <tr> <td> 2024-03-01 19:32:00 </td> <td> <a class="keyword" href="https://d.hatena.ne.jp/keyword/hoge">hoge</a> </td> <td> /mypage/fav </td> </tr> <tr> <td> 2024-03-01 19:35:00 </td> <td> <a class="keyword" href="https://d.hatena.ne.jp/keyword/hoge">hoge</a> </td> <td> /episodes </td> </tr> <tr> <td> 2024-03-01 21:45:00 </td> <td> fuga </td> <td> /home </td> </tr> <tr> <td> 2024-03-01 22:25:00 </td> <td> piyo </td> <td> /home </td> </tr> <tr> <td> 2024-03-01 22:30:00 </td> <td> hogera </td> <td> /home </td> </tr> <tr> <td> 2024-03-01 22:32:00 </td> <td> hogera </td> <td> /search </td> </tr> <tr> <td> 2024-03-01 22:34:00 </td> <td> hogera </td> <td> /home </td> </tr> </tbody> </table> <h3 id="視聴ログ-play_logs">視聴ログ (play_logs)</h3> <p>視聴中の行動が記録されているログです。これを見るとシークバー移動のタイミングなどが分かります。<br/> 今回は視聴開始した時刻の情報だけ使用します。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synComment">-- サンプルデータ</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 19:35:30</span><span class="synSpecial">&quot;</span>) <span class="synSpecial">AS</span> begin_at, <span class="synSpecial">&quot;</span><span class="synConstant">hoge</span><span class="synSpecial">&quot;</span> <span class="synSpecial">AS</span> user_id, <span class="synSpecial">&quot;</span><span class="synConstant">begin</span><span class="synSpecial">&quot;</span> <span class="synSpecial">AS</span> action, <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 22:26:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">piyo</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">begin</span><span class="synSpecial">&quot;</span>, <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 22:27:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">piyo</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">begin</span><span class="synSpecial">&quot;</span>, <span class="synStatement">UNION</span> <span class="synStatement">ALL</span> <span class="synStatement">SELECT</span> <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2024-03-01 22:35:00</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">hogera</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">begin</span><span class="synSpecial">&quot;</span> </pre> <table> <thead> <tr> <th> begin_at </th> <th> user_id </th> <th> action </th> </tr> </thead> <tbody> <tr> <td> 2024-03-01 19:35:30 </td> <td> <a class="keyword" href="https://d.hatena.ne.jp/keyword/hoge">hoge</a> </td> <td> begin </td> </tr> <tr> <td> 2024-03-01 22:26:00 </td> <td> piyo </td> <td> begin </td> </tr> <tr> <td> 2024-03-01 22:27:00 </td> <td> piyo </td> <td> begin </td> </tr> <tr> <td> 2024-03-01 22:35:00 </td> <td> hogera </td> <td> begin </td> </tr> </tbody> </table> <h1 id="集計用クエリを書いてみる">集計用クエリを書いてみる</h1> <p>今回の集計を行うには、どのようなクエリを書けばよいでしょうか?<br/> 素朴にやるなら、</p> <ol> <li>訪問ログからホーム画面(<code>/home</code>)のログを抽出する</li> <li>1に視聴ログを LEFT JOIN する</li> </ol> <p>でしょうか。書いてみましょう。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> view_logs.*, play_logs.begin_at, play_logs.begin_at <span class="synSpecial">IS</span> <span class="synStatement">NOT</span> <span class="synSpecial">NULL</span> <span class="synSpecial">AS</span> has_played, <span class="synSpecial">FROM</span> ( <span class="synStatement">SELECT</span> * <span class="synSpecial">FROM</span> view_logs <span class="synSpecial">WHERE</span> url = <span class="synSpecial">&quot;</span><span class="synConstant">/home</span><span class="synSpecial">&quot;</span> ) <span class="synSpecial">AS</span> view_logs <span class="synSpecial">LEFT</span> <span class="synSpecial">OUTER</span> <span class="synSpecial">JOIN</span> play_logs <span class="synSpecial">ON</span> view_logs.user_id = play_logs.user_id <span class="synComment">-- 訪問後 10 分以内に再生してるか</span> <span class="synStatement">AND</span> play_logs.begin_at <span class="synStatement">BETWEEN</span> view_logs.viewed_at <span class="synStatement">AND</span> TIMESTAMP_ADD(view_logs.viewed_at, INTERVAL <span class="synConstant">10</span> MINUTE) <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> viewed_at </pre> <table> <thead> <tr> <th> viewed_at </th> <th> user_id </th> <th> url </th> <th> begin_at </th> <th> has_played </th> </tr> </thead> <tbody> <tr> <td> 2024-03-01 19:30:00 </td> <td> <a class="keyword" href="https://d.hatena.ne.jp/keyword/hoge">hoge</a> </td> <td> /home </td> <td> 2024-03-01 19:35:30 </td> <td> true </td> </tr> <tr> <td> 2024-03-01 21:45:00 </td> <td> fuga </td> <td> /home </td> <td> </td> <td> false </td> </tr> <tr> <td> 2024-03-01 22:25:00 </td> <td> piyo </td> <td> /home </td> <td> 2024-03-01 22:26:00 </td> <td> true </td> </tr> <tr> <td> 2024-03-01 22:25:00 </td> <td> piyo </td> <td> /home </td> <td> 2024-03-01 22:27:00 </td> <td> true </td> </tr> <tr> <td> 2024-03-01 22:30:00 </td> <td> hogera </td> <td> /home </td> <td>2024-03-01 22:35:00 </td> <td> true </td> </tr> <tr> <td> 2024-03-01 22:34:00 </td> <td> hogera </td> <td> /home </td> <td> 2024-03-01 22:35:00 </td> <td> true </td> </tr> </tbody> </table> <p>一見良さそうに見えますが、以下の問題があります。</p> <ul> <li><code>user_id=piyo</code> の 1回の<code>/home</code>訪問に2回の再生が紐づいている(JOIN によってレコードが増えた、いわゆる重複) <ul> <li>分母となるホーム画面の訪問数が増えてしまう</li> </ul> </li> <li><code>user_id=hogera</code> の2回の<code>/home</code>訪問に1回の再生が紐づいている <ul> <li>時系列で考えると再生に直接寄与したのは2回目の<code>/home</code>訪問だと考えられるが、1回目の<code>/home</code>訪問も再生に寄与したと見なされてしまう</li> </ul> </li> </ul> <p>このまま集計すると間違った示唆を与えてしまうおそれがあります。<br/> 順番に解決していきましょう。</p> <h4 id="1回の訪問に2回の再生が紐づいているケース">1回の訪問に2回の再生が紐づいているケース</h4> <p>このケースは短時間で複数回再生した場合に発生します(ザッピング的な再生など)。<br/> 今回の集計で興味があるのは10分以内の再生有無だけなので、<code>/home</code>訪問後最初の視聴が紐づくログだけ残すようにしましょう。<br/> この処理は以下のような<code>QUALIFY</code>句によって実現することができます。</p> <pre class="code lang-sql" data-lang="sql" data-unlink>QUALIFY <span class="synComment">-- 最初の視聴だけ残す</span> ROW_NUMBER() OVER(PARTITION <span class="synSpecial">BY</span> user_id, viewed_at <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> begin_at <span class="synSpecial">ASC</span>) = <span class="synConstant">1</span> </pre> <p>ちなみに <code>viewed_at, user_id, url</code> をキーとして<code>GROUP BY</code>しても同様の処理が可能です。<br/> 個人的には<code>SELECT</code>文を変更する必要がない <code>QUALIFY</code>句を使用することが多いです。</p> <h4 id="2回の訪問に1回の再生が紐づいているケース">2回の訪問に1回の再生が紐づいているケース</h4> <p>短時間で回遊したのちに再生した場合などでしばしば発生します。<br/> このケースは視聴ログの突合条件に<strong>次の<code>/home</code>訪問までに再生しているか</strong>という条件を追加することで排除できそうです。<br/> はじめに、<code>view_logs</code>に次の<code>/home</code>訪問した時刻の列を追加します。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> *, <span class="synComment">-- 次の /home 訪問時刻</span> LEAD(viewed_at, <span class="synConstant">1</span>) OVER(PARTITION <span class="synSpecial">BY</span> user_id <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> viewed_at) <span class="synSpecial">AS</span> next_viewed_at, <span class="synSpecial">FROM</span> view_logs <span class="synSpecial">WHERE</span> url = <span class="synSpecial">&quot;</span><span class="synConstant">/home</span><span class="synSpecial">&quot;</span> </pre> <p>この列を使い、以下のような処理を突合部分に追加します。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synComment">-- 次の /home 訪問までに再生してるか (次の /home 訪問がなければ無視)</span> <span class="synStatement">AND</span> <span class="synSpecial">IF</span>(view_logs.next_viewed_at <span class="synSpecial">IS</span> <span class="synStatement">NOT</span> <span class="synSpecial">NULL</span>, play_logs.begin_at &lt; view_logs.next_viewed_at, <span class="synSpecial">TRUE</span>) </pre> <h1 id="改良版クエリ">改良版クエリ</h1> <p>最終的にこのようになりました。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> view_logs.* EXCEPT(next_viewed_at), play_logs.begin_at, play_logs.begin_at <span class="synSpecial">IS</span> <span class="synStatement">NOT</span> <span class="synSpecial">NULL</span> <span class="synSpecial">AS</span> has_played, <span class="synSpecial">FROM</span> ( <span class="synStatement">SELECT</span> *, <span class="synComment">-- 次の /home 訪問時刻</span> LEAD(viewed_at, <span class="synConstant">1</span>) OVER(PARTITION <span class="synSpecial">BY</span> user_id <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> viewed_at) <span class="synSpecial">AS</span> next_viewed_at, <span class="synSpecial">FROM</span> view_logs <span class="synSpecial">WHERE</span> url = <span class="synSpecial">&quot;</span><span class="synConstant">/home</span><span class="synSpecial">&quot;</span> ) <span class="synSpecial">AS</span> view_logs <span class="synSpecial">LEFT</span> <span class="synSpecial">OUTER</span> <span class="synSpecial">JOIN</span> play_logs <span class="synSpecial">ON</span> view_logs.user_id = play_logs.user_id <span class="synComment">-- 訪問後 10 分以内に再生してるか</span> <span class="synStatement">AND</span> play_logs.begin_at <span class="synStatement">BETWEEN</span> view_logs.viewed_at <span class="synStatement">AND</span> TIMESTAMP_ADD(view_logs.viewed_at, INTERVAL <span class="synConstant">10</span> MINUTE) <span class="synComment">-- 次の /home 訪問までに再生してるか (次の /home 訪問がなければ無視)</span> <span class="synStatement">AND</span> <span class="synSpecial">IF</span>(view_logs.next_viewed_at <span class="synSpecial">IS</span> <span class="synStatement">NOT</span> <span class="synSpecial">NULL</span>, play_logs.begin_at &lt; view_logs.next_viewed_at, <span class="synSpecial">TRUE</span>) <span class="synComment">-- 最初の視聴だけ残す</span> QUALIFY ROW_NUMBER() OVER(PARTITION <span class="synSpecial">BY</span> user_id, viewed_at <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> begin_at <span class="synSpecial">ASC</span>) = <span class="synConstant">1</span> <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> viewed_at </pre> <table> <thead> <tr> <th> viewed_at </th> <th> user_id </th> <th> url </th> <th> begin_at </th> <th> has_played </th> </tr> </thead> <tbody> <tr> <td> 2024-03-01 19:30:00 </td> <td> <a class="keyword" href="https://d.hatena.ne.jp/keyword/hoge">hoge</a> </td> <td> /home </td> <td> 2024-03-01 19:35:30 </td> <td> true </td> </tr> <tr> <td> 2024-03-01 21:45:00 </td> <td> fuga </td> <td> /home </td> <td> </td> <td> false </td> </tr> <tr> <td> 2024-03-01 22:25:00 </td> <td> piyo </td> <td> /home </td> <td> 2024-03-01 22:26:00 </td> <td> true </td> </tr> <tr> <td> 2024-03-01 22:30:00 </td> <td> hogera </td> <td> /home </td> <td> </td> <td> false </td> </tr> <tr> <td> 2024-03-01 22:34:00 </td> <td> hogera </td> <td> /home </td> <td> 2024-03-01 22:35:00 </td> <td> true </td> </tr> </tbody> </table> <p><code>viewed_at</code>, <code>begin_at</code> どちらも一意化することができました。<br/> このCTE を <code>GROUP BY</code>することで目的の集計をすることができます。</p> <h1 id="最後に">最後に</h1> <p>テーブル結合時のケアについて2つの事例を紹介しましたが、これらの事象の発生を集計値だけ見て気付くことは非常に難しいです。<br/> そのためレビューの際にはクエリのロジックを確認することは勿論のこと、中間テーブルの出力を確認したり個票チェックをしたりすることで集計ロジックの確<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A4%AB%A4%E9%A4%B7">からし</a>さを検証しています。<br/> 同時に「レビューしやすいクエリ」を書くために、ロジックを考えたり社内ルール整備をしたりなどを日々行っています。この取り組みは分析チームが一丸となり、相当な力を入れて取り組んでいます<sup><a href="#2">2</a></sup>。</p> <h1 id="採用のこと">採用のこと</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>では一緒に分析業務をしてくれる方を募集しています。<br/> カジュアル面談も受け付けていますので、「こういう取り組みのことをもっと知りたい」「普段どんな分析してるか知りたい」と思った方は以下よりお気軽にご連絡ください。お待ちしております!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fherp.careers%2Fv1%2Ftver%2FLiWieh7-pNVl" title="月間動画再生数3億5,000万回の「TVer」ならではの大規模データを用いて、様々な課題解決をするデータサイエンティスト(集計・分析)を募集!(ミドルクラス) - 株式会社TVer" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://herp.careers/v1/tver/LiWieh7-pNVl">herp.careers</a></cite></p> <hr /> <p><a id="1"></a>1: 一例なのでかなり大味な依頼になっており、この集計結果を受けて具体的なアクションを行うことが難しいと予想されます。実際にこのような依頼が来た場合は、ホーム画面から再生までのユーザーの振る舞いや遷移についての仮説出しをしてからクエリを作成することが望ましいです。</p> <p><a id="2"></a>2: テックブログにておいおい紹介する予定です。</p> tver-techblog AWS LambdaとSlackを連携してツールを作った話 hatenablog://entry/6801883189069608759 2023-12-25T15:25:15+09:00 2023-12-25T15:25:15+09:00 こんにちは。 アドテク領域のエンジニアをしています安部です。 こちらは TVer Advent Calendar 2023 の14日目の記事です。 13日目の記事で「ツールを作成した」という話をちらっと書きました。 今回はそのツールについて備忘として書きます。 ツールは作成時は半自動状態(起動トリガーが手動)、12月に全自動化となりました。 ツールを作ったきっかけ ツール作成時の条件 なぜAWS、Lambdaを選んだのか システム構成図 ツールの詳細 ①S3のバケットからファイルを取得 ②SQLの作成 ③RDS接続・確認 ④Slackへ結果を送信 ⑤起動トリガーの設定 全自動化 ①Slack … <p>こんにちは。<br/> アドテク領域のエンジニアをしています安部です。<br/> こちらは <a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a> の14日目の記事です。</p> <p><a href="https://techblog.tver.co.jp/entry/h-abe/2023reflection">13日目の記事</a>で「ツールを作成した」という話をちらっと書きました。<br/> 今回はそのツールについて備忘として書きます。<br/> ツールは作成時は半自動状態(起動トリガーが手動)、12月に全自動化となりました。</p> <ul class="table-of-contents"> <li><a href="#ツールを作ったきっかけ">ツールを作ったきっかけ</a></li> <li><a href="#ツール作成時の条件">ツール作成時の条件</a></li> <li><a href="#なぜAWSLambdaを選んだのか">なぜAWS、Lambdaを選んだのか</a></li> <li><a href="#システム構成図">システム構成図</a></li> <li><a href="#ツールの詳細">ツールの詳細</a><ul> <li><a href="#S3のバケットからファイルを取得">①S3のバケットからファイルを取得</a></li> <li><a href="#SQLの作成">②SQLの作成</a></li> <li><a href="#RDS接続確認">③RDS接続・確認</a></li> <li><a href="#Slackへ結果を送信">④Slackへ結果を送信</a></li> <li><a href="#起動トリガーの設定">⑤起動トリガーの設定</a></li> </ul> </li> <li><a href="#全自動化">全自動化</a><ul> <li><a href="#Slack-Appの準備">①Slack Appの準備</a></li> <li><a href="#メッセージの取得">②メッセージの取得</a></li> <li><a href="#S3へ配置">③S3へ配置</a></li> <li><a href="#Slack投稿部分のSlack-API化">④Slack投稿部分のSlack API化</a></li> <li><a href="#起動トリガーの設定-1">⑤起動トリガーの設定</a></li> </ul> </li> <li><a href="#ツール作成してどうだった">ツール作成してどうだった?</a></li> </ul> <h1 id="ツールを作ったきっかけ">ツールを作ったきっかけ</h1> <p>4月には広告入稿システムのリプレイスがありました。<br/> このシステムと対向システムでデータの同期しているのですが、データに差分が出ていないか確認する必要があります。<br/> そのため対向システムから不整合が発生している可能性のあるデータを連携していただき、確認するという定常業務がありました。<br/> 不整合の可能性があるデータは平均20件ほどあり、毎日手動で確認することは現実的ではありませんでした。<br/> どうにか自動化できないかとツールを作成することにしました。</p> <h1 id="ツール作成時の条件">ツール作成時の条件</h1> <ol> <li>連携されるデータはテキストデータとして受領する(Slackでメッセージの受信ができない)</li> <li>対向システム側に対応をお願いすることはできない(S3に直接アップロードしてください、特定の形式のファイルでくださいなど)</li> <li>項目が多すぎると全て連携されないことがある(途中で途切れたメッセージになる)</li> </ol> <p>1と2がネックとなりデータを自動でLambdaへ取り込むことができませんでした。<br/> そのため</p> <ul> <li>データを取得し.mdファイルを作成してS3に置く<br/> →手動</li> <li>ファイルを読み込み、データを突合し、その結果をSlackの特定のチャンネルに投稿<br/> →Lambdaで自動化</li> </ul> <p>という形式の半自動化ツールを作成しました。</p> <h1 id="なぜAWSLambdaを選んだのか">なぜ<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>、Lambdaを選んだのか</h1> <ul> <li>広告入稿システムが乗っている<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>と同じ場所に作ることで自分以外の人もメンテナンスできる</li> <li>RDSとの連携が容易</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>でさくっと書きたい<br/> の3点が主な理由です。</li> </ul> <h1 id="システム構成図">システム構成図</h1> <p>・半自動<br/> <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231225/20231225122834.jpg" width="1200" height="541" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>・全自動<br/> <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231225/20231225122854.jpg" width="1200" height="425" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="ツールの詳細">ツールの詳細</h1> <h2 id="S3のバケットからファイルを取得">①S3の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%B1%A5%C3%A5%C8">バケット</a>からファイルを取得</h2> <p>ライブラリ(boto3)をありがたく活用しました。</p> <pre class="code lang-python" data-lang="python" data-unlink>s3_client = boto3.client(<span class="synConstant">'s3'</span>) <span class="synComment"># ファイルを読み込み、使用できる状態にする</span> response = s3_client.get_object(Bucket=MD_BUCKET_NAME, Key=md_key_name) lines = response[<span class="synConstant">'Body'</span>].readlines() </pre> <h2 id="SQLの作成">②<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>の作成</h2> <p>ファイルを1行ずつ読み込みながらRDSへ投げる<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>を作成します。</p> <h2 id="RDS接続確認">③RDS接続・確認</h2> <p>RDSの接続情報についてはSecretsManagerに設定されているので、SecretsManagerから情報を取得しRDSへ接続します。<br/>  SecretsManagerからの取得はこんな感じ<br/>  REGION_NAMEにはリージョン名を、SECRETE_NAMEにはシークレットの名前を入れます。<br/> シークレットキー(DB_USER_NAME,DB_USER_PASSWORD)を指定することでシークレットの値を取得することができます。</p> <pre class="code lang-python" data-lang="python" data-unlink><span class="synComment"># Create a Secrets Manager client</span> session = boto3.session.Session() client = session.client( service_name=<span class="synConstant">'secretsmanager'</span>, region_name=REGION_NAME ) <span class="synStatement">try</span>: get_secret_value_response = client.get_secret_value( SecretId=SECRETE_NAME ) <span class="synStatement">except</span> ClientError <span class="synStatement">as</span> e: <span class="synStatement">raise</span> e <span class="synComment"># Decrypts secret using the associated KMS key.</span> secret_data = get_secret_value_response[<span class="synConstant">'SecretString'</span>] secret = ast.literal_eval(secret_data) <span class="synComment"># 接続情報設定</span> db_user = secret[<span class="synConstant">'DB_USER_NAME'</span>] db_pass = secret[<span class="synConstant">'DB_USER_PASSWORD'</span>] </pre> <p>この接続情報を用いてRDSへ接続します。 RDS接続の際は<a class="keyword" href="https://d.hatena.ne.jp/keyword/VPC">VPC</a>設定が必要です。<br/> <a href="https://qiita.com/kobayashim_21/items/d8bb6608d1343770b099">こちら</a>を参考に作成しました。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>の結果で不整合データの有り無しを確認します。</p> <h2 id="Slackへ結果を送信">④Slackへ結果を送信</h2> <p>Incoming Webhook URLを使用してSlackへ結果をポストします。<br/> 他の投稿と差別化したかったので引用マークが付くように設定しています。</p> <pre class="code lang-python" data-lang="python" data-unlink> <span class="synComment"># SlackのwebhookURL</span> WEB_HOOK_URL = <span class="synConstant">'WEBHOOK_URL'</span> <span class="synComment"># alert-adcas-app-error宛</span> CHANNEL_ID = <span class="synConstant">'CHANNEL_ID'</span> <span class="synComment"># Slack投稿の情報</span> send_data = { <span class="synConstant">'channel'</span>: CHANNEL_ID, <span class="synConstant">'username'</span>: <span class="synConstant">'CHECK_TOOL'</span>, <span class="synConstant">'icon_emoji'</span>: <span class="synConstant">':beer:'</span>, <span class="synConstant">'attachments'</span>:[{ <span class="synComment">#投稿の引用マーク部分の設定</span> <span class="synConstant">'color'</span>: <span class="synConstant">'#ffb6c1'</span>, <span class="synConstant">'text'</span>: <span class="synConstant">'投稿テストです。'</span>, }], } send_text = json.dumps(send_data) request = urllib.request.Request( WEB_HOOK_URL, data=send_text.encode(<span class="synConstant">'utf-8'</span>), method=<span class="synConstant">&quot;POST&quot;</span> ) <span class="synStatement">with</span> urllib.request.urlopen(request) <span class="synStatement">as</span> response: response_body = response.read().decode(<span class="synConstant">'utf-8'</span>) </pre> <p>こんな感じで投稿されます。<br/> <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231225/20231225124707.png" width="648" height="160" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h2 id="起動トリガーの設定">⑤起動トリガーの設定</h2> <p>最後に起動トリガーを設定します。<br/> S3にファイルを置いたタイミングで起動してほしいので、トリガーにS3を設定します。<br/> 関数の概要部分の「+トリガーを追加」からS3を選択し、ファイルを置く<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%B1%A5%C3%A5%C8">バケット</a>を選択します。<br/> ファイルの配置と同時になのでEvent typesはPUT(一応POSTも)、アップロードするファイルサイズが大きくなるとマルチパートになるらしいので、念のためMultipart upload completedも設定します。<br/> Suffixに「.md」が設定してあるのは、mdファイルを読み込むという条件にしているためです。<br/> <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231225/20231225125126.png" width="1200" height="700" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>これでファイルを配置と同時にツールが実行されるようになりました。</p> <p>ファイルアップロードが手動というのがもったいないですが、しばらくこれで運用していきます。</p> <h1 id="全自動化">全自動化</h1> <p>12月、ついにデータがSlackのメッセージで受信できるようになりました。<br/> これで取り込みが自動化できます。</p> <p>半自動化している部分は活用したいので、メッセージを取得しS3にファイルを配置するという関数を作成します。</p> <h2 id="Slack-Appの準備">①Slack Appの準備</h2> <p> Slack Appの作成方法は多くの方が書いていると思うのでそこに譲りまして、メッセージ取得・送信に必要なOAuthの設定だけご紹介します。<br/> 今回は<a class="keyword" href="https://d.hatena.ne.jp/keyword/Bot">Bot</a>として使用するため<a class="keyword" href="https://d.hatena.ne.jp/keyword/Bot">Bot</a> Token Scopesに必要なScopeを追加します。<br/> ※画像の黒線部分はSlack Appのアプリ名が表示されています。 <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231225/20231225132315.jpg" width="1200" height="909" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span> - groups:<a class="keyword" href="https://d.hatena.ne.jp/keyword/history">history</a><br/> 取得したいメッセージがプライベートチャンネルに投稿される場合の設定です。<br/> パブリックチャンネルの場合は「channels:<a class="keyword" href="https://d.hatena.ne.jp/keyword/history">history</a>」を追加します。 - chat:write<br/> メッセージを投稿するための設定です。<br/> - chat:write.customize<br/> メッセージ投稿をする際にユーザー名やユーザーのアイコンを自由に設定できるようにするための設定です。<br/> カスタマイズしない場合は「Basic Information」の「Display Information」で設定しているApp Nameとアイコンが表示されます。</p> <h2 id="メッセージの取得">②メッセージの取得</h2> <p>conversations.<a class="keyword" href="https://d.hatena.ne.jp/keyword/history">history</a> を使用して取得します。<br/> こんな感じ</p> <pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">def</span> <span class="synIdentifier">get_slack_message</span>(): SLACK_BOT_TOKEN = os.environ[<span class="synConstant">'SLACK_BOT_TOKEN'</span>] CHANNEL_ID = os.environ[<span class="synConstant">'CHANNEL_ID'</span>] slackGetMessageUrl = <span class="synConstant">'https://slack.com/api/conversations.history'</span> dt_today = datetime.combine(date.today(),time(<span class="synConstant">0</span>,<span class="synConstant">0</span>,<span class="synConstant">0</span>)) d_ut = datetime.timestamp(dt_today) data = { <span class="synConstant">'channel'</span>: CHANNEL_ID, <span class="synConstant">'oldest'</span>: d_ut } post_data = urllib.parse.urlencode(data) req = urllib.request.Request(slackGetMessageUrl, data=post_data.encode()) req.add_header(<span class="synConstant">'Authorization'</span>,<span class="synConstant">'Bearer '</span> + SLACK_BOT_TOKEN) <span class="synStatement">with</span> urllib.request.urlopen(req, timeout=<span class="synConstant">1</span>) <span class="synStatement">as</span> response: response_data = json.loads(response.read()) <span class="synIdentifier">print</span>(response_data) </pre> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>ンとメッセージを取得したいチャンネルのチャンネルIDはlambdaの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B4%C4%B6%AD%CA%D1%BF%F4">環境変数</a>に設定してそこから取得しています。<br/> conversations.<a class="keyword" href="https://d.hatena.ne.jp/keyword/history">history</a> には色々オプションを設定できますが、実行当日のメッセージのみ取得したいのでoldestに当日の0:00のunixtimeを設定しています。<br/> オプションについてはドキュメントに書いてあるので必要に応じて追加します。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fapi.slack.com%2Fmethods%2Fconversations.history" title="conversations.history API method" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://api.slack.com/methods/conversations.history">api.slack.com</a></cite></p> <p>確認できるようにprintでメッセージを表示するようにしています。</p> <h2 id="S3へ配置">③S3へ配置</h2> <p>取得したメッセージをこねこねして元のツールが読み取れるファイルを作成し、S3へ配置します。<br/> 実行ロールにS3のput権限をつけることをお忘れなく!<br/> (設定タブ > アクセス権限 > ロール名を押すとIAMに飛ぶので許可を追加できます)</p> <pre class="code lang-python" data-lang="python" data-unlink>expost_data = <span class="synConstant">''</span>; <span class="synStatement">for</span> line_data <span class="synStatement">in</span> <span class="synIdentifier">reversed</span>(response_data[<span class="synConstant">'messages'</span>]): <span class="synComment">#こねこねしてexport_dataに1行ずつ追加</span> expost_data += line_data[<span class="synConstant">'text'</span>]; S3_CLIENT = boto3.client(<span class="synConstant">'s3'</span>) response = S3_CLIENT.put_object( Body=expost_data, Bucket=MD_BUCKET_NAME, Key=MD_FILENAME ) </pre> <p>この1行ずつ読み取るタイミングで</p> <blockquote><p>3.項目が多すぎると全て連携されないことがある(途中で途切れたメッセージになる)</p></blockquote> <p>のチェックも行っています。 連携の最後にendの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D7%A5%EC%A5%D5%A5%A3%A5%C3%A5%AF%A5%B9">プレフィックス</a>を設定していただいているので、その<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D7%A5%EC%A5%D5%A5%A3%A5%C3%A5%AF%A5%B9">プレフィックス</a>が存在しない場合はエラー通知をSlackに送信しファイル配置と読み取りの後続処理が動かないようにしています。</p> <h2 id="Slack投稿部分のSlack-API化">④Slack投稿部分のSlack <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>化</h2> <p>最後に、Slack投稿部分をwebhookからSlack <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>に変更します。<br/> 権限は①で付与済みなのでリク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>ト送信部分をちょっと変えるだけ。</p> <pre class="code lang-python" data-lang="python" data-unlink>slackPostMessageUrl = <span class="synConstant">'https://slack.com/api/chat.postMessage'</span>; <span class="synComment"># Slack投稿の情報(ここは変わらず)</span> send_data = { <span class="synConstant">'channel'</span>: CHANNEL_ID, <span class="synConstant">'username'</span>: <span class="synConstant">'CHECK_TOOL'</span>, <span class="synConstant">'icon_emoji'</span>: <span class="synConstant">':beer:'</span>, <span class="synConstant">'attachments'</span>:[{ <span class="synComment">#投稿の引用マーク部分の設定</span> <span class="synConstant">'color'</span>: <span class="synConstant">'#ffb6c1'</span>, <span class="synConstant">'text'</span>: <span class="synConstant">'投稿テストです。'</span>, }], } send_text = json.dumps(send_data) request = urllib.request.Request( slackPostMessageUrl, data=send_text.encode(<span class="synConstant">'utf-8'</span>), method=<span class="synConstant">&quot;POST&quot;</span> ) <span class="synComment"># トークン情報だけ追加</span> req.add_header(<span class="synConstant">'Authorization'</span>,<span class="synConstant">'Bearer '</span> + SLACK_BOT_TOKEN) <span class="synStatement">with</span> urllib.request.urlopen(request) <span class="synStatement">as</span> response: response_body = response.read().decode(<span class="synConstant">'utf-8'</span>) </pre> <h2 id="起動トリガーの設定-1">⑤起動トリガーの設定</h2> <p>EventBridgeで定時起動するように設定します。<br/> Lambdaの設定タブ > トリガー > トリガーを追加 でEventBridgeを選択し、cron形式で書きました。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/UTC">UTC</a>時刻で記載することに注意です。<br/> 私は<a class="keyword" href="https://d.hatena.ne.jp/keyword/JST">JST</a>で設定し、11:30に動かしたいのに20:30に起動したことがありました。<br/> お恥ずかしい。</p> <p>これで夢の全自動化完了です。</p> <h1 id="ツール作成してどうだった">ツール作成してどうだった?</h1> <ol> <li><p>気持ちが楽になった<br/> そもそも最初は<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>手動実行だったので、手作業でミスしないかというプレッシャーがありました。<br/> ツール化することで手動でミスする不安から開放されました。 また、ファイル作って、<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>にアクセスして、S3にファイルを置いて…という時間にして3分もかからない対応ですがやるのとやらないのでは気持ちが違います。<br/> 長期休みのときもチェック漏れが起こらないので安心です。</p></li> <li><p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>好きだなぁ<br/> このツールでほぼ初めて<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>を触りましたが、個人的に書きやすくてもっと使いたいなと思いました。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>を使っているシステムはあまりないのですが、ツール職人するときは積極的に使っていこうと思います。</p></li> <li>知見が広がった<br/> 業務で使わない<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>の部分(EventBridgeなど)も触ることができて勉強になりました。<br/> もっと使いこなせるようになりたい!</li> </ol> tver-techblog GCP版Dataformで冪等性を担保する設計ポイント3つ hatenablog://entry/6801883189068639949 2023-12-24T07:00:00+09:00 2023-12-24T07:00:23+09:00 データエンジニアの遠藤です。 TVer Advent Calendar 2023の24日目の記事になります。 はじめに 本年(2023年)、Google Cloudのビッグデータ基盤として展開されるBigQueryでは、データガバナンスツールであるDataformがGA(Generally Avaialble)になりました。 cloud.google.com このDataformの登場により、BigQuery上でデータを利活用しやすいように変換する(データマートを生成する)システムの構築が容易になりました。 本記事では、Dataform上において、定常実行やリトライ実行を容易にするために、冪等… <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231222/20231222130255.png" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>データエンジニアの遠藤です。</p> <p><a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a>の24日目の記事になります。</p> <h1 id="はじめに">はじめに</h1> <p>本年(2023年)、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloudの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D3%A5%C3%A5%B0%A5%C7%A1%BC%A5%BF">ビッグデータ</a>基盤として展開されるBigQueryでは、データガバナンスツールであるDataformがGA(Generally Avaialble)になりました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcloud.google.com%2Fdataform%3Fhl%3Dja" title="Dataform | Google Cloud" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://cloud.google.com/dataform?hl=ja">cloud.google.com</a></cite></p> <p>このDataformの登場により、BigQuery上でデータを利活用しやすいように変換する(データマートを生成する)システムの構築が容易になりました。</p> <p>本記事では、Dataform上において、定常実行やリトライ実行を容易にするために、冪等性が担保される設計のテクニックを3点紹介します。(Dataformの基本的な使い方については触れませんのでご注意ください)</p> <h1 id="1-SQLX内のクエリに変数を用いる">1. SQLX内のクエリに変数を用いる</h1> <p>DataformはSQLXと呼ばれるファイルでデータ変換処理内容を管理します。 SQLXファイルにはデータ更新設定とクエリを記載しますが、クエリ中で変数を利用することができます。</p> <p>まず、 includes/dataform.<a class="keyword" href="https://d.hatena.ne.jp/keyword/json">json</a>の <code>vars</code> 内でSQLXファイル内で用いる変数を定義します。</p> <pre class="code json:dataform.json" data-lang="json:dataform.json" data-unlink>{ &#34;warehouse&#34;: &#34;bigquery&#34;, &#34;defaultDatabase&#34;: &#34;dev-project&#34;, &#34;defaultLocation&#34;: &#34;us-central1&#34;, &#34;vars&#34;: { &#34;certain_date&#34;: &#34;2023-01-01&#34; } }</pre> <p>dataform.<a class="keyword" href="https://d.hatena.ne.jp/keyword/json">json</a>で定義した変数は以下のようにSQLXのクエリ内に表記します(以下の例ではWHERE句の中でdataform.<a class="keyword" href="https://d.hatena.ne.jp/keyword/json">json</a>で定義した変数 <code>certain_date</code> を用いるように設定しています)。</p> <pre class="code sql:example.sqlx" data-lang="sql:example.sqlx" data-unlink>config { type: &#34;table&#34;, schema: &#34;result_dataset&#34;, name: &#34;result_table&#34;, } SELECT column_a, column_b, column_c, partition_column FROM ${ref(&#34;source_table&#34;)} WHERE partition_column = &#39;${ dataform.projectConfig.vars.certain_date }&#39;</pre> <p>これにより、パラメータによって可変になるクエリ表現が可能になります。</p> <h1 id="2-定期的な実行はDataform-APIから行う">2. 定期的な実行はDataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>から行う</h1> <p>一般的に、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud上のDataformは以下の方法で実行することができます。</p> <ul> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EF%A1%BC%A5%AF%A5%B9%A5%DA%A1%BC%A5%B9">ワークスペース</a>内の<a class="keyword" href="https://d.hatena.ne.jp/keyword/GUI">GUI</a>で「実行を開始」をクリックする</li> <li>リリース構成・ワークフロー構成を設定する</li> <li>Dataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>にジョブ実行リク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トを送る</li> </ul> <p>処理を冪等にするためには、SQLX内の変数のようなパラメータを毎回変えながら定期的に実行する仕組みが必要です。</p> <p>この要件を十分に満たすには、上記で3番目に挙げた実行方法「Dataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>からの実行」が最適です。</p> <p>なぜなら、「Dataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>からの実行」は、<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>でのリク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>ト情報を適切に設定することで、dataform.<a class="keyword" href="https://d.hatena.ne.jp/keyword/json">json</a>内の設定をオーバーライドして実行することが可能であるからです。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcloud.google.com%2Fdataform%2Fdocs%2Fcompilation-overrides%3Fhl%3Dja" title="Dataform API でコンパイルのオーバーライドを構成する  |  Google Cloud" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://cloud.google.com/dataform/docs/compilation-overrides?hl=ja">cloud.google.com</a></cite></p> <p>「Dataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>からの実行」は、以下の2つをDataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>で処理することで実現します。</p> <ul> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>結果の作成</li> <li>作成した<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>結果を用いてDataformジョブを実行</li> </ul> <p>まず、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>結果を作成するため、以下のDataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>「compilationResults.create」を実行します。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcloud.google.com%2Fdataform%2Freference%2Frest%2Fv1beta1%2Fprojects.locations.repositories.compilationResults%2Fcreate" title="Method: projects.locations.repositories.compilationResults.create  |  Dataform  |  Google Cloud" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://cloud.google.com/dataform/reference/rest/v1beta1/projects.locations.repositories.compilationResults/create">cloud.google.com</a></cite></p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>「compilationResults.create」は、「CodeCompilationConfig」オブジェクトに以下の情報を設定することで、「CodeCompilationConfig」内の設定情報を優先しながら<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>結果を作成します。</p> <ul> <li>出力結果格納先BigQueryプロジェクト(defaultDatabase)</li> <li>出力結果格納先デー<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BF%A5%BB%A5%C3%A5%C8">タセット</a>名の接尾辞(schemaSuffix)</li> <li>出力結果格納先テーブル名の接頭辞(tablePrefix)</li> <li>変数(vars)</li> </ul> <p>この<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>リク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トでは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>結果が正常に作成されると、<code>compilationResult</code> という<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>結果IDが返されます。</p> <p>次に、この<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>結果IDを用いて、以下のDataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>「workflowInvocations.create」を実行すると、作成した<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>結果でジョブを実行します。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcloud.google.com%2Fdataform%2Freference%2Frest%2Fv1beta1%2Fprojects.locations.repositories.workflowInvocations%2Fcreate" title="Method: projects.locations.repositories.workflowInvocations.create  |  Dataform  |  Google Cloud" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://cloud.google.com/dataform/reference/rest/v1beta1/projects.locations.repositories.workflowInvocations/create">cloud.google.com</a></cite></p> <p>このように、「Dataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>からの実行」は、パラメータ制御の自由度が高くなるため、backfill実行も容易に行うことが可能です。</p> <p>なお、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloudでは、Dataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>による一連の実行はCloud Composer・Cloud Workflowsといった他のジョブ管理ツールから行うように推奨されています。</p> <h1 id="3-クエリ結果を積み上げる場合はpre_operations処理を追加する">3. クエリ結果を積み上げる場合はpre_operations処理を追加する</h1> <p>Dataformにおける出力結果の格納方法は以下の方法が可能です(SQLXのconfigで設定します)。</p> <ul> <li>VIEW化(結果の出力はせずにVIEWで設定するのみにとどめる)</li> <li>洗い替え(格納先のテーブルにデータが存在する場合、上書きして更新する)</li> <li>積み上げ(格納先のテーブル上の既存データはそのままにしながら、クエリ結果を新たに追加する)</li> </ul> <p>結果格納の設定が「積み上げ」の場合、同じジョブが複数回実行されると、出力結果が重複して格納されてしまいます。</p> <p>そのため、ジョブを複数回実行しても出力結果が冪等になるためには、SQLX内に新規にpre_operations項目を設けてそこにDELETE文を設定することで解決します。</p> <pre class="code sql:example_incremental.sqlx" data-lang="sql:example_incremental.sqlx" data-unlink>config { type: &#34;incremental&#34;, schema: &#34;result_dataset&#34;, name: &#34;result_incremental_table&#34;, } pre_operations { DELETE FROM ${self()} WHERE partition_column = &#39;${ dataform.projectConfig.vars.certain_date }&#39; } SELECT column_a, column_b, column_c, partition_column FROM ${ref(&#34;source_table&#34;)} WHERE partition_column = &#39;${ dataform.projectConfig.vars.certain_date }&#39;</pre> <p>pre_operations内のDELETE文は、1回目の実行では何も影響がないですが、2回目以降の実行では重複を避ける処理として効果を発揮します。</p> <h1 id="おわりに">おわりに</h1> <p>本記事では、<a class="keyword" href="https://d.hatena.ne.jp/keyword/GCP">GCP</a>版Dataform上に載せるシステムにおいてジョブが冪等になるためのポイント3点を紹介させていただきました。</p> <ol> <li>SQLX内のクエリに変数を用いる</li> <li>定期的な実行はDataform <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>から行う</li> <li>クエリ結果を積み上げる場合はpre_operations処理を追加する</li> </ol> <p>以上の3点を考慮すれば、Dataform運用の効率性が高まるかと思いますので、ぜひ参考にしてみてください。</p> tver-techblog レコメンドエンジンで日本を元気に hatenablog://entry/6801883189068068233 2023-12-23T10:00:00+09:00 2023-12-23T10:00:00+09:00 こんにちは、TVer レコメンドエンジン担当の由井です。 こちらは TVer Advent Calendar 2023 の23日目の記事です。 なぜレコメンドなのか? 今年の5月からTVerにジョインして、レコメンドエンジンの開発に携わらせて頂いていますが、そもそもなぜ自分がレコメンド開発に携わることになったのかや、レコメンドエンジンにかける想いを、初心を忘れないためにも、つらつらと書かせてもらえたらと思います。 ただのポエムですのでイブ前ということで気軽に読んで頂けたらと思います。 ヨーロッパでの再発見 自分は、元々、ヨーロッパの歴史や新しい事を経験する事が好きだったため、あまり計画せずに現… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> レコメンドエンジン担当の由井です。 こちらは <a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a> の23日目の記事です。</p> <h2 id="なぜレコメンドなのか">なぜレコメンドなのか?</h2> <p>今年の5月から<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>にジョインして、レコメンドエンジンの開発に携わらせて頂いていますが、そもそもなぜ自分がレコメンド開発に携わることになったのかや、レコメンドエンジンにかける想いを、初心を忘れないためにも、つらつらと書かせてもらえたらと思います。 ただのポエムですのでイブ前ということで気軽に読んで頂けたらと思います。</p> <h2 id="ヨーロッパでの再発見">ヨーロッパでの再発見</h2> <p>自分は、元々、ヨーロッパの歴史や新しい事を経験する事が好きだったため、あまり計画せずに現地企業に転職したという過去がありまして、数年間の経験を通じて現地の文化や価値観に触れることができ、その素晴らしさを経験してきましたが、同時に日本の持つ素晴らしさも再発見することができました。例えば、日本は周りの人間と上手く協力して行動することができたり、新しい価値観を受け入れる寛容さを持ち合わせていると思います。そこから派生したアニメや漫画、その他伝統文化といった日本発祥のコンテンツは、今、世界中から高い支持を得ることができています。</p> <h2 id="TVerとの出会い"><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>との出会い</h2> <p>そんな日本に貢献したいという思いが強くなり、日本国内で大きな<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A4%A5%F3%A5%D1%A5%AF">インパク</a>トを持つ企業で働きたいと考えていた時、</p> <p>「テレビを開放して、もっとワクワクする未来を。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>と新しい世界を、一緒に」 という理念を持つ<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の素晴らしいメンバーに出会う機会がありました。</p> <h2 id="レコメンドエンジンで日本を元気に">レコメンドエンジンで日本を元気に</h2> <p>今、日本は直近30年の統計で見ると、先進諸外国と同様の成長率を維持できていない現状があります。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%E4%B8%AB">私見</a>ではありますが、日本では、かつてのような期待に胸膨らむような夢のある明るいニュースよりも暗い気持ちになってしまうニュースがどうしても増えてしまっているのではと感じています。</p> <p>日本にはアニメや漫画など、まだまだ世界に誇れる素晴らしいものが確かに存在しているにもかかわらず、必ずしも良い結果に結びついていない原因としては、</p> <p>ユーザーと情報、ユーザーとユーザー、情報と情報といった因果の無限の網の目のような複雑な関係が絡み合っていて、それら一つ一つの火花ともベクトルとも言えるような小さな方向性の単位が、大きな社会の方向性を作り出しているんだと思います。</p> <p>そしてその大きな川の流れのような社会の方向性が、日本の行く先を決定づけているのだとするならば、それらの火花の方向性を変えるためには、小さな火花の方向を少しずつ揃えていく必要があって、自分が携わるレコメンドエンジンは、個人的には、それぞれの火花であるベクトルの方向性を揃えていくことで、やがてはユーザー全体の大きな流れを良いベクトルに揃えることができる素晴らしい技術だと考えています。</p> <p>自分はレコメンドエンジン開発を通じて、小さな火花を揃えて、より大きな火花にしていき、ひいては日本のユーザー全体の火花を揃えることで、日本全体がもっとわくわくできて、もっと元気になるような日本のエンジンを作りたいです。</p> <h2 id="MLOpsへの取り組み">MLOpsへの取り組み</h2> <p>一方、話は変わって、自分がPLとして<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>上で現在取り組んでいるMLOpsは、多くのメンバーが関わる必要のある非常に大きな枠組みですので、自分ひとりでは成し遂げることができず、だからこそ、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%DA%A5%B7%A5%E3">スペシャ</a>リストであるメンバー一人一人の力が必要だと考えています。</p> <p>幸い、今、自分の周りには、リスペクトに値するようなスキルとマインドを持った本当に素晴らしい<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%DA%A5%B7%A5%E3">スペシャ</a>リストの方々がいらっしゃって、様々な想いを持って業務に従事されています。</p> <p>それらの想いは、個別の数値目標として表現されているのかもしれませんが、ここで視点を1歩引いて、その想い一つ一つを深掘りしてみると、それぞれが、「サービスを良くしてユーザーに良いものを届けたい。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>を良いサービスだと思ってもらいたい」というピュアな熱い想いを持って行動されている方たちなんだなという気づきがありました。</p> <p>チーム1人1人の想いの火花を同じ方向に揃えることができれば、1人では決して成し得ない大きな力となり、1つ1つはたしかに小さな1歩しかもしれませんが、私達のその1歩1歩が、やがてユーザーの心に響くサービスの形として繋がっていく。だからこそ、小さな火花を大事にしながら毎日の作業に励んで行きたいと思います。</p> <h2 id="カンパニーという言葉の語源について">カンパニーという言葉の語源について</h2> <p>話は変わりますが、私自身、歴オタでして、それが高じてヨーロッパに移住を決意したことがあるような無計画なタイプの人間なのですが、特に語源学(Etymology)という、それぞれの単語がどのような歴史的な経緯で生まれ、変遷していったのかを研究する学問なのですが、自分をそれを追いかけるのが週末の楽しみという珍しい趣味を持っています。</p> <p>その中で、自分が好きな言葉の一つに、カンパニー「Company」という言葉があります。日本では「会社」という意味が最も一般的に通じる意味かもしれません。 カンパニー(company)は、12世紀中頃、「共にパンを食べる仲間」という意味の後期<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%E9%A5%C6%A5%F3%B8%EC">ラテン語</a>のcompanioから派生した言葉であり、これは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%E9%A5%C6%A5%F3%B8%EC">ラテン語</a>の「共に、一緒に」を意味するcomという言葉と、「パン」を意味するpanisを組み合わせた言葉となります。</p> <p>com + panis = copanio(共にパンを食べる仲間)</p> <p>ここでの「パン」とは、教会のミサで食べるパンのことであり、companyとは、同じ教会に通い、同じ信仰を持ち、苦難を共にして助け合う人たちの集団のことを、元来指していた言葉でした。</p> <p>その後、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C2%E7%B9%D2%B3%A4%BB%FE%C2%E5">大航海時代</a>に入ると、同じ船に乗り、リスクを承知で海の向こうに出かけて貿易をする夢追い人たちが現れました。</p> <p>彼らは、未知の海に漕ぎ出すリスクもそれを乗り越えた後の莫大な利益も公平に分け合う仲間たちという意味で、自分たちのことを「カンパニー」と呼びました。 それがやがて「会社」という意味に転じていったそうです。</p> <p>つまり、「カンパニー」というのは、ただの「会社」ではなく、「リスクに対して、それぞれができることを力を合わせて乗り越え、共に利益を得ていく集団」という意味を持っているんだと思います。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の中では、</p> <p>「我々は仲間である。1人で早く。よりも、みんなで遠くへ。」</p> <p>という言葉があります。 自分が好きな言葉で、カンパニーという言葉にも通じる良い言葉だと思います。</p> <h2 id="最後にレコメンドへの抱負">最後にレコメンドへの抱負</h2> <p>時は流れ、カンパニーという言葉の定義は移り変わっていき、本来の意味でのカンパニーと呼べる気概を持った企業が、果たしてどれほど存在するのかは定かではありませんが、 だからこそ私達は、大きな変化の時代の中でも、メンバーそれぞれの火花の方向性を揃えて同じ船に乗り、共に困難を乗り越えていくことで、今後もユーザーに素晴らしい価値を提案し、社会から選ばれるカンパニーであり続けられたらと思います。</p> tver-techblog テレビとTVerと私 hatenablog://entry/6801883189064816317 2023-12-22T10:00:00+09:00 2023-12-24T13:25:03+09:00 コネクテッドTVとTVerの関わりについて <h3 id="1はじめに">1、はじめに</h3> <p>皆さん、こんにちは、3月からコネクテッドTVタスクにJoinし、ビジネス領域を担当している井出と申します。</p> <p>この記事は、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%C9%A5%D9%A5%F3%A5%C8%A5%AB%A5%EC%A5%F3%A5%C0%A1%BC">アドベントカレンダー</a>22日目の記事です。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fqiita.com%2Fadvent-calendar%2F2023%2Ftver" title="TVerのカレンダー | Advent Calendar 2023 - Qiita" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://qiita.com/advent-calendar/2023/tver">qiita.com</a></cite></p> <h3 id="2今日は何の話を">2、今日は何の話を?</h3> <p>突然ですが、皆さんはテレビという言葉からどういった言葉を連想されますでしょうか。</p> <p>いわゆる、ドラマやバラエティなどの地上波の番組を思い浮かべる方もいれば、テレビという機器を思い浮かべる方もいるのではないでしょうか。 (昨今は、テレビを持っていない方や、モニターや、プロジェクターなどで代用している方もいると思います。)</p> <p>今回は、いわゆる地上波を指すテレビではなく、 機器でいうテレビ、その中でも、 『コネクテッドTV』についてお話ししたいと思います。</p> <p>このブログに書いてあること</p> <ul> <li>コネクテッドTVの定義や、概要</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>におけるコネクテッドTVに位置付け</li> <li>私の部署の業務内容や今後の展望</li> </ul> <h3 id="3コネクテッドTVとは">3、コネクテッドTVとは</h3> <p>コネクテッドTVとは、テレビ自体がインターネットに接続されている<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A1%BC%A5%C8%A5%C6%A5%EC%A5%D3">スマートテレビ</a>はもちろん、 Fire TV、Chromecastなどのストリーミングメディアプレイヤー、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/PlayStation">PlayStation</a>や<a class="keyword" href="https://d.hatena.ne.jp/keyword/Xbox">Xbox</a>などのゲーム機、プロジェクター、セットトップボックスなどの外部機器を接続している場合のテレビも含んでいるものを指します。 (※<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>はゲーム機にはまだ対応しておりません、ごめんなさい!)</p> <p>自分の家のテレビや、モニターがインターネット接続に対応していない場合も、外部機器を接続することで、コネクテッドTVとして、動画サービスなどのエンタメを堪能することができます。</p> <h5 id="コネクテッドTVの広告について">コネクテッドTVの広告について</h5> <p>下記の記事を引用させていただくと、 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.screens-lab.jp%2Farticle%2F28172" title="コネクテッドTV、急成長中の広告市場規模とは?|Screens|映像メディアの価値を映す" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.screens-lab.jp/article/28172">www.screens-lab.jp</a></cite></p> <p>米国では、</p> <blockquote><p>先行している米国では、2020年のeMarketerの調査によると、2024年までには182.9億ドル(約2兆3800億円※)に達すると予測されています。 ちなみに2021年の米国の総広告費はおよそ2800億ドルと推計されており、コネクテッドTV広告はその4%程度を占めることになります。</p></blockquote> <p>日本では、</p> <blockquote><p>日本におけるコネクテッドTVの広告市場も順調に拡大しています。今年2022年の3月に発表されたSMN、AJA、デジタルインファクトによる調査結果によると、2021年のコネクテッドTVの広告市場規模は344億円。 米国に比べると金額的にはまだまだ小さいものですが、前年比で337%の成長をみせています。<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BF%B7%B7%BF%A5%B3%A5%ED%A5%CA%A5%A6%A5%A4%A5%EB%A5%B9">新型コロナウイルス</a>の流行で、コネクテッドTVの視聴が拡大したこの年、広告市場も大きく伸びました。 今後もさらなる成長が見込まれています。2025年には1695億円と、約5倍もの成長が予測されています。</p></blockquote> <p>と、期待されている広告出稿先であるといえそうです。</p> <h3 id="4TVerとコネクテッドTV">4、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>とコネクテッドTV</h3> <p>それでは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>におけるコネクテッドTVとの関わり方についてご紹介したいと思います。</p> <h5 id="対応状況は">対応状況は?</h5> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>がコネクテッドTVに対応したのは、2019年4月で、当初はFire <a class="keyword" href="https://d.hatena.ne.jp/keyword/TV%A5%B7%A5%EA%A1%BC%A5%BA">TVシリーズ</a>と<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BD%A5%CB%A1%BC">ソニー</a>社製の<a class="keyword" href="https://d.hatena.ne.jp/keyword/Android">Android</a> TVだけでしたが、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A1%BC%A5%C8%A5%C6%A5%EC%A5%D3">スマートテレビ</a>で9社、ストリーミングメディアプレイヤーで2社、プロジェクターで3社、セットトップボックスで3社と 大幅に増え、 現在では、リンク先の通り多くの機器に対応しています。 現在も日々対応機器を拡大すべく、取り組んでおります。 過去に遡って対応させていただくこともあるので、もしかしたら、今まで諦めていたあなたの機器も対応しているかもしれません。 ぜひチェックしてみてくださいませ! <a href="https://help.tver.jp/hc/ja/articles/222120868">https://help.tver.jp/hc/ja/articles/222120868</a></p> <p>こちらでは接続方法などもご案内しています! <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftver.jp%2F_s%2Fcampaign%2Ftvapp_promotion%2Findex.html" title="見逃し無料配信TVer(ティーバー)をテレビの大画面で見る方法" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tver.jp/_s/campaign/tvapp_promotion/index.html">tver.jp</a></cite></p> <h5 id="TVerにおけるコネクテッドTVの立ち位置"><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>におけるコネクテッドTVの立ち位置</h5> <p>今では、リリース当初1.9%ほどだったデ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9">バイス</a>別再生割合は、2023年1月には、31%達し、15倍以上に成長しました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftver.co.jp%2Fnews%2F20230221-1.html" title="[TVer] 各局ドラマが好調で 過去最高の 1 月 2,700 万 MUB 突破 国内普及率 5 割超えるコネクテッド TV TVer のデバイス別再生割合も 3 年で 15 倍以上、初の 3 割越えに | TVer INC." class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tver.co.jp/news/20230221-1.html">tver.co.jp</a></cite></p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>を使う3人に1人は、コネクテッドTVを利用して、視聴しているということになります。 現在では、 コネクテッドTV領域でのビジネスをさらに強化すべく、コネクテッドTV専門部署もできました(冒頭にも触れましたが、私もそこに所属しております)</p> <h3 id="5コネクテッドTVタスクとして">5、コネクテッドTVタスクとして</h3> <p><span style="font-size: 80%">タスクとは<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>内の用語で部署を指しています。</span></p> <p>ここまでコネクテッドTV、また、コネクテッドTVと<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>について触れてきました。 次に、コネクテッドTVタスクとして、個人として、今後どうコネクテッドTVと関わっていくかについて書いていきたいと思います。</p> <h4 id="コネクテッドTVタスクが取り組んでいること">コネクテッドTVタスクが取り組んでいること</h4> <p>コネクテッドTVタスクは、コネクテッドTVの普及率の増加も伴い、テレビ業界のビジネスをより発展させていく中で、これからは配信にも力を入れていく必要があり、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A1%BC%A5%C8%A5%D5%A5%A9%A5%F3">スマートフォン</a>・<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BF%A5%D6%A5%EC%A5%C3%A5%C8">タブレット</a>やPCとは別に、コネクテッドTVを独立した領域として切り出し、専門的に対応していこうと、チームが立ち上がりました。 一つの部署にCTVの交渉役や、ビジネスを検討するなどをするビジネス担当と、開発のディレクターによる技術担当に分かれておりまして、簡単にいうと、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%DE%A1%BC%A5%B1%A5%C6%A5%A3%A5%F3%A5%B0">マーケティング</a>と開発を1部署で行なっている小さな会社のような構成になっています。</p> <h5 id="ビジネスチーム仮が何をやっているか">ビジネスチーム(仮)が何をやっているか</h5> <p><span style="font-size: 80%">※明確なチームとして分かれているわけではなく、担当しているだけなので、(仮)と書いています。</span></p> <p>開発チームについては、ここで詳しく話しているようなので、この場では、ビジネス担当側が何をやっているかについて話しておきたいです。 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnote.com%2Ftver%2Fn%2Fn92854a1a999d" title="ユーザー拡大と事業成長に寄与する機能開発をリード!開発チームの裏側に迫る〜/コネクテッドTVタスク対談【後編】|TVer HR BLOG" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://note.com/tver/n/n92854a1a999d">note.com</a></cite></p> <p>ビジネスチームは、</p> <ul> <li>各メーカー様とアライアンスの調整</li> <li>コネクテッドTV領域の外部への<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%DE%A1%BC%A5%B1%A5%C6%A5%A3%A5%F3%A5%B0">マーケティング</a>活動全般</li> <li>社内の<a class="keyword" href="https://d.hatena.ne.jp/keyword/CRM">CRM</a>担当との調整</li> </ul> <p>などを行なっております。</p> <p>全てを説明すると多岐にわたっていきますし、一般的な<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%DE%A1%BC%A5%B1%A5%C6%A5%A3%A5%F3%A5%B0">マーケティング</a>の話と変わらない部分もあるので、 特殊性がありそうな部分だけ触れていきたいと思います。</p> <h5 id="コネクテッドTVのマーケティングについて">コネクテッドTVの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%DE%A1%BC%A5%B1%A5%C6%A5%A3%A5%F3%A5%B0">マーケティング</a>について</h5> <p>1、<a class="keyword" href="https://d.hatena.ne.jp/keyword/SNS">SNS</a>広告や、パートナー様出面での訴求について</p> <p>コネクテッドTVを擁する各メーカーさんとは、協業により<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>を使ってもらえるユーザーさんの獲得を行っています。 獲得するための枠は、多岐に渡りますが、 認知獲得を目的にする場合とユーザーさん自体の獲得を目的とするものに、大別されます。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/YouTube">YouTube</a>や、Xなどを活用して、認知を獲得することを試みたり、ユーザー獲得をすることまでは、一般的な<a class="keyword" href="https://d.hatena.ne.jp/keyword/WEB%A5%B5%A1%BC%A5%D3%A5%B9">WEBサービス</a>などの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%DE%A1%BC%A5%B1%A5%C6%A5%A3%A5%F3%A5%B0">マーケティング</a>手法と同様です。</p> <p>ただ、<a class="keyword" href="https://d.hatena.ne.jp/keyword/YouTube">YouTube</a>、Xなどは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A1%BC%A5%C8%A5%D5%A5%A9%A5%F3">スマートフォン</a>アプリや、PCサイトなどに直接遷移することで獲得までできますが、 コネクテッドTVでの利用を目的とする場合、なかなか直接遷移させることができません。 そこで、登場してくるのが、 アライアンスパートナーであるデ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9">バイス</a>メーカーさんが持っている媒体(アプリが並んでいるHOME画面など)です。</p> <p>例えば、こんな媒体があり、</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fadvertising.amazon.com%2Fja-jp%2Fresources%2Fad-specs%2Ffire-tv%2Ffeature-rotator" title="Feature Rotator" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://advertising.amazon.com/ja-jp/resources/ad-specs/fire-tv/feature-rotator">advertising.amazon.com</a></cite></p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>としては、 単一の作品を訴求したり、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>サービス自体を訴求することで、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>をお使いいただけるよう<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A5%E9%A5%A4%A5%A2%A5%F3%A5%C9%A5%A8%A5%E9%A1%BC">トライアンドエラー</a>を繰り返しています。</p> <p>もう少し、私が考えていることに触れると、 そもそも、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>をテレビで使いたいなと思っているか、 もっというと<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>をテレビで使えると知っていないと、 コネクテッドTV上の広告で、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の広告をみても、 ピンときません(TVで見られると思っていないので、起動しようという動機付けに至りません)。</p> <p>コネクテッドTVで<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>が利用できることの認知向上は、 何もせず、そのまま待っていても、 爆発的な何かが起きない限り、大きく伸ばすことはできません。 そのため、認知向上施策を日々実行、検討しております。 その件はいつかまた書き残したいと思います。</p> <p>2、各メーカー様リモコンボタンについて</p> <p>皆さんのお持ちの端末にも、動画配信アプリへダイレクトにアクセスできるボタンがついている場合もあるのではないでしょうか。 いつからそう言った取り組みが始まったのかと調べたところ、 どうやら、日本では、2015年から取り組まれているようです。 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftoyokeizai.net%2Farticles%2F-%2F428112" title="リモコン激変!「ボタン争奪戦」が熾烈極める理由" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://toyokeizai.net/articles/-/428112">toyokeizai.net</a></cite></p> <blockquote><p>テレビリモコンに専用ボタンを設置した先駆けは<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%E1%A5%EA">アメリ</a>カのネットフリックスだ。同社は2011年、北米市場で発売された<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A1%BC%A5%C8%A5%C6%A5%EC%A5%D3">スマートテレビ</a>などのリモコンに自社ボタンの設置を開始。日本市場向けにも、日本でのサービス開始前の2015年2月から、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C5%EC%BC%C7">東芝</a>が販売する一部機種が早くも「ネットフリックスボタン」に対応した。</p></blockquote> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>では、<span style="color: #ff0000"><strong>9社</strong></span>のデ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9">バイス</a>メーカーさんの端末にボタンを掲載していただいています。(2023年12月現在) <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%DE%A1%BC%A5%B1%A5%C6%A5%A3%A5%F3%A5%B0">マーケティング</a>活動として、家にいつも置いてあるリモコンに掲載されることで、テレビで利用できるという認知、気付いた時にすぐ起動できることで、TVCMや、<a class="keyword" href="https://d.hatena.ne.jp/keyword/SNS">SNS</a>広告などをみた後すぐ視聴に繋げられることがメリットです。 リテンションとして、すでに<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>を利用していただいている方には、 より、簡単に<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>を利用いただけるようになるといったメリットがあります。</p> <p>リモコンボタンへの掲載について、今後も推進していく所存でございますので、皆さんのお家にも<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のロゴがついたリモコンボタンが来る日が来るかもしれません。 ぜひその際は、たくさん<em><span style="color: #ff0000">Push</span></em>して、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>をお楽しみいただけると嬉しいです。</p> <h3 id="6おわりに">6、おわりに</h3> <p>簡単にコネクテッドTVのビジネス領域の話をしてきました。 最後に少しだけ、展望について書いてみたいと思います。</p> <p>自分自身の思いとして、 自分の仕事を通して、エンドユーザーに、 感動体験を届けることを仕事の軸にしています。 <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>でもたくさんの感動をユーザーに届けられるよう仕事に取り組んでいます。 UIUXの改善、リモコンボタンからのダイレクト起動、作品との出会い、など <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のコネクテッドTV体験を今よりもよく、 そして、テレビを解放するために、日々邁進してまいります。 ぜひ、コネクテッドTVの領域にも注目してみてください!</p> <p>ちなみに採用も頑張っています、ご興味ある方はぜひ! カジュアル面談しましょう! <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fherp.careers%2Fv1%2Ftver" title="株式会社TVer の全ての求人一覧" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://herp.careers/v1/tver">herp.careers</a></cite></p> <p>以上です。長々と稚拙な文章にお付き合いいただきありがとうございました。 また、別の話題でどこかで書いてみたいと思います。 引き続き、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>を宜しくお願いします!</p> tver-techblog URL_PARSE 再発明 hatenablog://entry/6801883189068388339 2023-12-21T12:26:28+09:00 2023-12-21T12:26:28+09:00 日々、データ分析をしている森藤です。遅くなってしまいすみません。本記事は TVer アドベントカレンダー 17日目の記事です。 (10日の記事も今度書きます) qiita.com TVer のデータを分析の中で大きな割合を占めるものにユーザジャーニーの分析や外部からの流入の分析があります。 これらはどちらも URL の解析が必要になるのですが、 URL はだいたいにおいて Google Analytics の utm パラメタや hash の値が乗っており、 Facebook などは fbclid みたいなのが乗ったりと、これらを削除する作業が必要になります。 具体的には内部の回遊としては、 … <p>日々、データ分析をしている森藤です。遅くなってしまいすみません。本記事は <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%C9%A5%D9%A5%F3%A5%C8%A5%AB%A5%EC%A5%F3%A5%C0%A1%BC">アドベントカレンダー</a> 17日目の記事です。 (10日の記事も今度書きます)</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fqiita.com%2Fadvent-calendar%2F2023%2Ftver" title="TVerのカレンダー | Advent Calendar 2023 - Qiita" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://qiita.com/advent-calendar/2023/tver">qiita.com</a></cite></p> <hr /> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> のデータを分析の中で大きな割合を占めるものにユーザジャーニーの分析や外部からの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CE%AE%C6%FE">流入</a>の分析があります。 これらはどちらも URL の解析が必要になるのですが、 URL はだいたいにおいて <a class="keyword" href="https://d.hatena.ne.jp/keyword/Google%20Analytics">Google Analytics</a> の utm パラメタや hash の値が乗っており、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/Facebook">Facebook</a> などは fbclid みたいなのが乗ったりと、これらを削除する作業が必要になります。</p> <p>具体的には内部の回遊としては、</p> <ul> <li><code>https://tver.jp/episodes/XXXXXX?utm_campaign=C1&amp;utm_medium=M2&amp;utm_source=S3#V1</code></li> </ul> <p>などのログがあったり、</p> <ul> <li><code>https://example.jp:8080/dir1/dir2/index.hml?param1=val1&amp;param2=val2#hash_value</code></li> </ul> <p>など外部からの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CE%AE%C6%FE">流入</a>があります。</p> <p>これを BigQuery でパースする際、 BigQuery にも <a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/net_functions">プリイン関数</a> があるのですが、いまいちリッチではなく、 <a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/net_functions#nethost">HOST</a> くらいしかないのです・・・</p> <p>他にもコミュニティベースの <a href="https://github.com/GoogleCloudPlatform/bigquery-utils/blob/master/udfs/community/url_parse.sqlx">URL_PARSE</a> もあるのですがこちらも、いまいち使い勝手が良くないんですよね</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> bqutil.fn.url_parse(url, <span class="synSpecial">&quot;</span><span class="synConstant">QUERY</span><span class="synSpecial">&quot;</span>) <span class="synSpecial">AS</span> query, <span class="synSpecial">FROM</span> UNNEST([ url ]) <span class="synSpecial">AS</span> url </pre> <p>僕は「クエリパラメタ」も欲しいんです! というか <a class="keyword" href="https://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a> の <code>new URL()</code> で手に入るオブジェクトくらい全部が欲しいのです!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdeveloper.mozilla.org%2Fja%2Fdocs%2FWeb%2FAPI%2FURL" title="URL - Web API | MDN" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://developer.mozilla.org/ja/docs/Web/API/URL">developer.mozilla.org</a></cite></p> <p><figure class="figure-image figure-image-fotolife" title="JS URL で手に入る結果"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231220/20231220184018.png" alt="JS URL &#x3067;&#x624B;&#x306B;&#x5165;&#x308B;&#x7D50;&#x679C;" width="1200" height="424" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>JS URL で手に入る結果</figcaption></figure></p> <h2 id="顧客が本当にほしかったもの">顧客が本当にほしかったもの</h2> <p>理想的にはこちらがほしいです</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> url, URL_PARSE(url).protocol, URL_PARSE(url).host, URL_PARSE(url).port, URL_PARSE(url).pathname, URL_PARSE(url).search, <span class="synSpecial">FROM</span> UNNEST([ url ]) <span class="synSpecial">AS</span> url </pre> <h2 id="まとめ">まとめ</h2> <p>これを使うと MDN と同じように URL の好きなところを切り出したり取り出すことができます。 searchParam もとれますので、</p> <pre class="code lang-sql" data-lang="sql" data-unlink>(SELECT param.value <span class="synSpecial">FROM</span> UNNEST(URL_PARSE(url).searchParam) <span class="synSpecial">AS</span> param <span class="synSpecial">WHERE</span> param.key = <span class="synSpecial">&quot;</span><span class="synConstant">utm_source</span><span class="synSpecial">&quot;</span>) </pre> <p>として取り出したりもできます! もちろん、コミュニティ UDF を使っても取り出せますよ! <a href="https://github.com/GoogleCloudPlatform/bigquery-utils/blob/master/udfs/community/README.md#get_valuek-string-arr-any-type">get_value</a></p> <pre class="code lang-sql" data-lang="sql" data-unlink>bqutil.fn.get_value(<span class="synSpecial">&quot;</span><span class="synConstant">utm_source</span><span class="synSpecial">&quot;</span>, URL_PARSE(url).searchParam) </pre> <p>URL の処理を楽しんでやっていきましょう!</p> <h1 id="実際のクエリ">実際のクエリ</h1> <h2 id="作成したクエリ">作成したクエリ</h2> <p>以下のようなクエリを作成しました。コミュニティに投げ込みます。 ちょっと<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C0%B5%B5%AC%C9%BD%B8%BD">正規表現</a>が鼻につく感じは自覚しているのですが、テストケースは全部通っています</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">CREATE</span> TEMP <span class="synSpecial">FUNCTION</span> url_parse(url STRING) <span class="synSpecial">AS</span> ( STRUCT( REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^([^:]+:)</span><span class="synSpecial">&quot;</span>) <span class="synSpecial">AS</span> protocol, <span class="synSpecial">IF</span>( REGEXP_CONTAINS(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://([^@/:]+):[^@/]+@</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">NULL</span> ) <span class="synSpecial">AS</span> username, <span class="synSpecial">IF</span>( REGEXP_CONTAINS(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:([^@/]+)@</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">NULL</span> ) <span class="synSpecial">AS</span> password, <span class="synIdentifier">CONCAT</span>( <span class="synSpecial">IF</span>( REGEXP_CONTAINS(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@([^:/?#]+)</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://([^:/?#]+)</span><span class="synSpecial">&quot;</span>) ), IFNULL(<span class="synSpecial">IF</span>( REGEXP_CONTAINS(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@[^/?#]+(:\d+)</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^/?#]+(:\d+)</span><span class="synSpecial">&quot;</span>) ), <span class="synSpecial">&quot;&quot;</span>) ) <span class="synSpecial">AS</span> host, <span class="synSpecial">IF</span>( REGEXP_CONTAINS(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@([^:/?#]+)</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://([^:/?#]+)</span><span class="synSpecial">&quot;</span>) ) <span class="synSpecial">AS</span> hostname, <span class="synSpecial">IF</span>( REGEXP_CONTAINS(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^@/:]+:[^@/]+@[^/?#]+:(\d+)</span><span class="synSpecial">&quot;</span>), REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^/?#]+:(\d+)</span><span class="synSpecial">&quot;</span>) ) <span class="synSpecial">AS</span> port, url <span class="synSpecial">AS</span> href, REGEXP_EXTRACT(<span class="synIdentifier">REGEXP_REPLACE</span>(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://([^@/:]+:[^@/]+@)</span><span class="synSpecial">&quot;</span>, REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://</span><span class="synSpecial">&quot;</span>)), r<span class="synSpecial">&quot;</span><span class="synConstant">^([^:]+://[^/?#]+)</span><span class="synSpecial">&quot;</span>) <span class="synSpecial">AS</span> origin, IFNULL(<span class="synIdentifier">NULLIF</span>(REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">^[^:]+://[^/]+(/[^?#]*)</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">/</span><span class="synSpecial">&quot;</span>) <span class="synSpecial">AS</span> pathname, REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">[^?#]\?([^#]+)</span><span class="synSpecial">&quot;</span>) <span class="synSpecial">AS</span> search, (<span class="synStatement">SELECT</span> ARRAY_AGG(STRUCT( SPLIT(param, <span class="synSpecial">&quot;</span><span class="synConstant">=</span><span class="synSpecial">&quot;</span>)[SAFE_OFFSET(<span class="synConstant">0</span>)] <span class="synSpecial">AS</span> key, SPLIT(param, <span class="synSpecial">&quot;</span><span class="synConstant">=</span><span class="synSpecial">&quot;</span>)[SAFE_OFFSET(<span class="synConstant">1</span>)] <span class="synSpecial">AS</span> value )) <span class="synSpecial">FROM</span> UNNEST(SPLIT(REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">[^?#]\?([^#]+)</span><span class="synSpecial">&quot;</span>), <span class="synSpecial">&quot;</span><span class="synConstant">&amp;</span><span class="synSpecial">&quot;</span>)) <span class="synSpecial">AS</span> param) <span class="synSpecial">AS</span> searchParam, REGEXP_EXTRACT(url, r<span class="synSpecial">&quot;</span><span class="synConstant">[^?#]\#(.+)</span><span class="synSpecial">&quot;</span>) <span class="synSpecial">AS</span> hashval ) ); </pre> <p>テストケースも合わせて掲載しておきます</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synSpecial">WITH</span> test_data <span class="synSpecial">AS</span> ( <span class="synStatement">SELECT</span> FORMAT(<span class="synSpecial">&quot;</span><span class="synConstant">%s//%s%s%s%s%s%s</span><span class="synSpecial">&quot;</span>, protocol, basicauth, hostname, port, pathname, search, hashval) <span class="synSpecial">AS</span> url, protocol, basicauth, hostname, port, pathname, search, hashval <span class="synSpecial">FROM</span> UNNEST([<span class="synSpecial">&quot;</span><span class="synConstant">tverapp:</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">https:</span><span class="synSpecial">&quot;</span>]) <span class="synSpecial">AS</span> protocol <span class="synSpecial">INNER</span> <span class="synSpecial">JOIN</span> UNNEST([<span class="synSpecial">&quot;&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">hoge:fuga@</span><span class="synSpecial">&quot;</span>]) <span class="synSpecial">AS</span> basicauth <span class="synSpecial">ON</span> <span class="synSpecial">TRUE</span> <span class="synSpecial">INNER</span> <span class="synSpecial">JOIN</span> UNNEST([<span class="synSpecial">&quot;</span><span class="synConstant">example.com</span><span class="synSpecial">&quot;</span>]) <span class="synSpecial">AS</span> hostname <span class="synSpecial">ON</span> <span class="synSpecial">TRUE</span> <span class="synSpecial">INNER</span> <span class="synSpecial">JOIN</span> UNNEST([<span class="synSpecial">&quot;&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">:8080</span><span class="synSpecial">&quot;</span>]) <span class="synSpecial">AS</span> port <span class="synSpecial">ON</span> <span class="synSpecial">TRUE</span> <span class="synSpecial">INNER</span> <span class="synSpecial">JOIN</span> UNNEST([<span class="synSpecial">&quot;&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/index.html</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/dir1</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/dir1/</span><span class="synSpecial">&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">/dir1/index.html</span><span class="synSpecial">&quot;</span>]) <span class="synSpecial">AS</span> pathname <span class="synSpecial">ON</span> <span class="synSpecial">TRUE</span> <span class="synSpecial">INNER</span> <span class="synSpecial">JOIN</span> UNNEST([<span class="synSpecial">&quot;&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">?param1=val1</span><span class="synSpecial">&quot;</span>]) <span class="synSpecial">AS</span> search <span class="synSpecial">ON</span> <span class="synSpecial">TRUE</span> <span class="synSpecial">INNER</span> <span class="synSpecial">JOIN</span> UNNEST([<span class="synSpecial">&quot;&quot;</span>, <span class="synSpecial">&quot;</span><span class="synConstant">#hash</span><span class="synSpecial">&quot;</span>]) <span class="synSpecial">AS</span> hashval <span class="synSpecial">ON</span> <span class="synSpecial">TRUE</span> ) </pre> tver-techblog New Relic Change Trackingを使ってアプリケーションのパフォーマンスが変化した要因を特定しやすくする hatenablog://entry/6801883189067867012 2023-12-21T10:26:59+09:00 2023-12-21T12:20:18+09:00 TVer広告事業本部の髙品です。 こちらはTVer Advent Calendar 2023の21日目の記事です。 本記事では、New RelicのChange Trackingという機能について書きたいと思います。 本記事を書く背景 Change Trackingを説明する前に、本記事を書く背景をお話させてください。 私は、2023年11月にTVer広告事業本部のエンジニアチームに参加しました。広告事業本部のエンジニアチームは、主に「TVer」で配信される広告プロダクト「TVer広告」の配信システム・広告周辺領域のシステムを開発・保守しています。TVerのエンジニア組織に関心がある方は、弊社… <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>広告事業本部の髙品です。 こちらは<a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a>の21日目の記事です。</p> <p>本記事では、New Relicの<a href="https://newrelic.com/jp/platform/change-tracking">Change Tracking</a>という機能について書きたいと思います。</p> <h2 id="本記事を書く背景">本記事を書く背景</h2> <p>Change Trackingを説明する前に、本記事を書く背景をお話させてください。</p> <p>私は、2023年11月に<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>広告事業本部のエンジニアチームに参加しました。広告事業本部のエンジニアチームは、主に「<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>」で配信される広告プロダクト「<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>広告」の配信システム・広告周辺領域のシステムを開発・保守しています。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のエンジニア組織に関心がある方は、<a href="https://recruit.tver.co.jp/developers/">弊社採用サイトのプロダクト職向けのページ</a>をご覧ください。</p> <p>さて、入社したばかりの私は現在オンボーディングの最中でして、広告の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C9%A5%E1%A5%A4%A5%F3">ドメイン</a>用語や既存システムの構成をやっと覚えたばかりなので、業務を絡めた記事を書くことができない状況です。そんな中で、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%C9%A5%D9%A5%F3%A5%C8%A5%AB%A5%EC%A5%F3%A5%C0%A1%BC">アドベントカレンダー</a>に参加するために捻り出したネタが、いまチームで導入を進めているNew RelicのChange Trackingでした。</p> <h3 id="New-Relicを使って私が目指すチームのあり方">New Relicを使って私が目指すチームのあり方</h3> <p>私はこれまでインフラエンジニア、SREとして働いてきたので、システムの運用が比較的得意です。今までの経験を活かしてチームに貢献したいと考えたときに、システムの信頼性と開発の生産性を共に最適化できるチームをつくりたい、と考えました。そのために取り組みたいことの一つに、チームがオブザーバビリティツールを使いこなせるようにする、というものがあります。</p> <p>SREやDevOpsに関心があるチームでは、何らかのオブザーバビリティツールを利用していると思いますが、私が所属するチームはNew Relicを使っています。New Relicは高機能なツールですが、所属チームではまだ一部の機能しか使えておらず、活用しているとは言えない状況です。また、普段からNew Relicを見ているメンバーは数名に限られています。</p> <p>私は、信頼性と生産性を共に最適化できるチームにおいて、システムの状態はメンバー全員の関心事であるべきだと考えているので、チームの全員にNew Relicの画面を見てほしいと思っています。そこで、チームでNew Relicの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>ボードを見て、アプリケーションの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EC%A5%A4%A5%C6%A5%F3%A5%B7%A1%BC">レイテンシー</a>や<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%EB%A1%BC%A5%D7%A5%C3%A5%C8">スループット</a>、エラー率といったパフォーマンス指標の傾向を知ることでシステムの状態を把握する定点観測の時間を作ろうとしています。いずれは、SREのサービスレベルの考え方をチームのシステム運用に導入することを見据えての活動です。</p> <p>前置きが長くなりましたが、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>ボードを見てシステムの状態を把握しようと思うときに便利な機能が、New RelicのChange Trackingです。ここからは、Change Trackingの便利な点と、この機能の導入手順を紹介します。手軽に導入できるので、New Relicのユーザーにはぜひ試してほしい機能です。</p> <h2 id="Change-Trackingの便利な点">Change Trackingの便利な点</h2> <p>まず、Change Trackingの便利な点を一言で述べると、アプリケーションの変更(アプリケーションのデプロイイベント)をグラフ上に表示することで、変更によるパフォーマンスへの影響があったかどうか分かりやすくなる、というものです。</p> <p>あとで導入手順を紹介する際にキャプチャを貼りますが、<a href="https://newrelic.com/jp/blog/nerdlog/change-tracking#toc--">New Relicのブログ</a>の説明を読んでいただくと、この機能について理解し易いと思います。リンク先の画像を見るとResponse time(ms)とThroughputのグラフの上に縦方向の点線が入っていますが、この時点でシステムに変更が加えられたことを意味しています。もし、ある点線を境にグラフに変化が生じた場合、その点線が指している変更と関連性があることがすぐに分かります。</p> <p>とてもシンプルな機能ですが、これだけでグラフから読み取れる情報量が増えます。グラフを集めた<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>ボードを眺めていると、パフォーマンスは安定していることもあれば、悪くなったり良くなったりすることもあるでしょう。特に悪化した場合は原因を調査する必要がありますが、単にグラフがそこにあるだけでは、ある時点から悪くなった、ということしか読み取れません。そこから先は、アプリケーションの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BD%A1%BC%A5%B9%A5%B3%A1%BC%A5%C9">ソースコード</a>が置かれた<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>や、ログ・メトリクスなどが保存された場所などを見て回って、パフォーマンス悪化要因となるイベントがないか探すことになります。ところが、グラフ上にアプリケーションの変更も一緒に記録されていると、New Relicの画面からすぐに関連のあるイベントを特定することができます。</p> <p>New Relicにアプリケーションの変更を記録するときはアプリケーションのバージョンの情報を送る必要があります。一般的にはコミットハッシュやタグがバージョン情報として使用されます。<a href="https://docs.newrelic.com/jp/docs/change-tracking/change-tracking-view-analyze/">こちらのNew Relicのドキュメントに載っている1つ目のキャプチャ</a>のように、点線にマウスオーバーするとアプリケーションのバージョンが表示されるため、パフォーマンスを変化させた可能性がある変更がすぐに分かります。Change Trackingを使用することで、パフォーマンス悪化の要因を特定して修復するまでにかかる時間(<a class="keyword" href="https://d.hatena.ne.jp/keyword/MTTR">MTTR</a>)を短縮できる可能性があります。</p> <h2 id="Change-Trackingの導入手順">Change Trackingの導入手順</h2> <p>基本的には<a href="https://docs.newrelic.com/jp/docs/change-tracking/change-tracking-introduction/#start-tracking">こちらのNew Relicのドキュメントに記載の手順</a>に従えば、難なく導入できると思います。特にJenkinsもしくは<a class="keyword" href="https://d.hatena.ne.jp/keyword/GitHub">GitHub</a> Actionsを使用している場合は、New Relic社が提供しているpluginやactionを追加してパラメータを渡すだけで使うことができます。</p> <p>本記事では、NerdGraph(GraphQL)<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>を使用するユーザーに参考になる手順として、Bitbucket pipelinesからChange Trackingを使う方法を紹介したいと思います。紹介する手順は、いくつかの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B4%C4%B6%AD%CA%D1%BF%F4">環境変数</a>を除けばCIツールに依存しない方法です。</p> <p>さて、NerdGraph <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>にデータを送信するためにHTTPクライアントを準備する必要がありますが、多くの環境で追加インストールが不要であると思われる<a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>コマンドを使います。New Relicの<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>エンドポイントに<a class="keyword" href="https://d.hatena.ne.jp/keyword/JSON">JSON</a>をPOSTする必要があるので、まずは<a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>コマンドを組み立てていきます。</p> <p>ここからは<a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>コマンドを組み立てる手順です。まず、New Relicにログインして、画面左のアイコン群から虫眼鏡を選んで、検索窓に「Apps」と入力して選択してください。Your appsと表示されているアプリの中に「NerdGraph <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Explorer">Explorer</a>」があるので、選択して開いてください。私はこのアプリにスターをつけているので、Favorite appsに移動しています。 <figure class="figure-image figure-image-fotolife" title="NerdGraph API Explorerを探す"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231218/20231218161924.png" width="1200" height="460" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>NerdGraph <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Explorer">Explorer</a>を探す</figcaption></figure></p> <p>するとGraphQLのクエリを組み立てる画面が開くので、mutationの一覧から「changeTracking」を探して「changeTrackingCreateDeployment」にチェックを入れてください。 <figure class="figure-image figure-image-fotolife" title="changeTrackingCreateDeploymentにチェックを入れる"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231218/20231218162111.png" width="1200" height="536" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>changeTrackingCreateDeploymentにチェックを入れる</figcaption></figure></p> <p>続いて、以下のキャプチャと同じようにチェックを入れてください。オプション属性ですが、本記事では<code>deepLink</code>にもチェックを入れています。必須属性は<code>entityGuid</code>と<code>version</code>です。指定可能な属性については<a href="https://docs.newrelic.com/jp/docs/change-tracking/change-tracking-graphql/">こちらのNew Relicのドキュメント</a>を参照してください。キャプチャではtestと入力していますが、実際の<code>entityGuid</code>はNew Relicにおいてアプリケーションを特定するために振られた一意のID,<code>version</code>はコミットハッシュ、タグ等が入ります。 <figure class="figure-image figure-image-fotolife" title="mutationに属性を追加する"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231218/20231218162238.png" width="1200" height="533" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>mutationに属性を追加する</figcaption></figure></p> <p>画面左上の「tools」を押して、「Copy as <a class="keyword" href="https://d.hatena.ne.jp/keyword/CURL">CURL</a>」を押すと<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A5%C3%A5%D7%A5%DC%A1%BC%A5%C9">クリップボード</a>に以下のようなコマンドがコピーされます。 <figure class="figure-image figure-image-fotolife" title="curlコマンドを生成する"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231218/20231218162434.png" width="1200" height="538" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>コマンドを生成する</figcaption></figure></p> <pre class="code lang-sh" data-lang="sh" data-unlink>curl https://api.newrelic.com/graphql <span class="synStatement">\</span> <span class="synSpecial">-H</span> <span class="synStatement">'</span><span class="synConstant">Content-Type: application/json</span><span class="synStatement">'</span> <span class="synStatement">\</span> <span class="synSpecial">-H</span> <span class="synStatement">'</span><span class="synConstant">API-Key: your USER key</span><span class="synStatement">'</span> <span class="synStatement">\</span> <span class="synSpecial">--data-binary</span> <span class="synStatement">'</span><span class="synConstant">{&quot;query&quot;:&quot;mutation {\n changeTrackingCreateDeployment(\n deployment: {entityGuid: \&quot;test\&quot;, version: \&quot;test\&quot;, deepLink: \&quot;test\&quot;}\n ) {\n entityGuid\n version\n deepLink\n }\n}&quot;, &quot;variables&quot;:&quot;&quot;}</span><span class="synStatement">'</span> </pre> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>-Keyヘッダーの値、<code>entityGuid</code>と<code>version</code>に適切な値が入力された状態でコマンドを実行すると、<code>entityGuid</code>に対応するNew Relic <a class="keyword" href="https://d.hatena.ne.jp/keyword/APM">APM</a>, Browserのアプリケーションのグラフ上に点線が引かれたはずです。このようにNerdGraph <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Explorer">Explorer</a>で<a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>コマンドを生成すると楽ですから、使ってみてください。</p> <p>ところで、Bitbucket pipelinesのようなCIツールでこの<a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>コマンドを実行するときは、各属性値はパラメータにしておかないと使い物になりません。Bitbucket pipelinesで使いやすいようにコマンドを以下のように修正します。(ついでに<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B7%A5%A7%A5%EB%A5%B9%A5%AF%A5%EA%A5%D7%A5%C8">シェルスクリプト</a>ファイルにします)</p> <pre class="code lang-sh" data-lang="sh" data-unlink><span class="synComment">#!/usr/bin/env bash</span> <span class="synStatement">set</span><span class="synIdentifier"> </span><span class="synSpecial">-euo</span><span class="synIdentifier"> pipefail</span> curl <span class="synSpecial">-X</span> POST https://api.newrelic.com/graphql <span class="synStatement">\</span> <span class="synSpecial">-H</span> <span class="synStatement">&quot;</span><span class="synConstant">Content-Type: application/json</span><span class="synStatement">&quot;</span> <span class="synStatement">\</span> <span class="synSpecial">-H</span> <span class="synStatement">&quot;</span><span class="synConstant">API-Key: </span><span class="synPreProc">$NEW_RELIC_USER_KEY</span><span class="synStatement">&quot;</span> <span class="synStatement">\</span> <span class="synSpecial">--data-binary</span> <span class="synStatement">'</span><span class="synConstant">{&quot;query&quot;:&quot;mutation {\n changeTrackingCreateDeployment(deployment: {version: \&quot;</span><span class="synStatement">'&quot;</span><span class="synPreProc">$BITBUCKET_COMMIT</span><span class="synStatement">&quot;'</span><span class="synConstant">\&quot;, entityGuid: \&quot;</span><span class="synStatement">'&quot;</span><span class="synPreProc">$NEW_RELIC_ENTITY_GUID</span><span class="synStatement">&quot;'</span><span class="synConstant">\&quot;, deepLink: \&quot;</span><span class="synStatement">'&quot;</span><span class="synPreProc">$BITBUCKET_GIT_HTTP_ORIGIN</span><span class="synStatement">&quot;</span>/commits/<span class="synStatement">&quot;</span><span class="synPreProc">$BITBUCKET_COMMIT</span><span class="synStatement">&quot;'</span><span class="synConstant">\&quot;}) {\n deploymentId\n entityGuid\n deepLink\n }\n}&quot;}</span><span class="synStatement">'</span> </pre> <p><code>BITBUCKET_</code>のprefixを持つ変数は、Bitbucket pipelines固有の変数です。使用可能な変数は<a href="https://support.atlassian.com/ja/bitbucket-cloud/docs/variables-and-secrets/">Bitbucketのこちらのドキュメント</a>を参照してください。他のツール使う場合は、適当に書き替えてください。</p> <p><code>$NEW_RELIC_USER_KEY</code>はBitbucket pipelinesの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>変数やデプロイ変数に、保護された変数としてセットしておきます。機密情報なので扱いに注意してください。</p> <p><code>$BITBUCKET_COMMIT</code>はCI(パイプライン)を起動したブランチのコミットハッシュが入ります。</p> <p><code>$NEW_RELIC_ENTITY_GUID</code>も、<code>$NEW_RELIC_USER_KEY</code>と同様にします。</p> <p><code>$BITBUCKET_GIT_HTTP_ORIGIN</code>には、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>のURLが入ります。 <code>$BITBUCKET_GIT_HTTP_ORIGIN</code>+commits+<code>$BITBUCKET_COMMIT</code>を連結することで、コミットに含まれる内容が記されたURLを作成することができます。URLを動的に生成して<code>deepLink</code>の値に格納することで、New Relicの画面から<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>に移動しやすくします。</p> <p>変数展開についても補足しておきます。シングルクォート内ではすべての文字が特別な意味を持たなくなるため、<code>"$BITBUCKET_COMMIT"</code>と書くと変数展開が行われません。そのため、本記事では<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B4%C4%B6%AD%CA%D1%BF%F4">環境変数</a>をシングルクォートで囲うことで変数展開されるようにしています。上記の<a class="keyword" href="https://d.hatena.ne.jp/keyword/JSON">JSON</a>程度の長さであれば、個人的にはこの方法で構わないと感じますが、より複雑な構造の<a class="keyword" href="https://d.hatena.ne.jp/keyword/JSON">JSON</a>をPOSTするときは他の書き方にしないと、可読性が悪くなると思います<a href="#f-5332a074" id="fn-5332a074" name="fn-5332a074" title="複雑な長いJSONをcurlコマンドでPOSTするときはヒアドキュメントを使うと便利です。 [https://qiita.com/nekoyamada/items/8154f1c369f99e3213b6:title] ">*1</a>。</p> <p>もう一つ、tipsを書いておきます。<a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>コマンドを、CIの定義ファイル内の別々の箇所に繰り返し書くのは筋が悪いです。コマンドを修正するときに、修正漏れしてしまう懸念があります。本記事では、処理を共<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C4%CC%B2%BD">通化</a>するために<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B7%A5%A7%A5%EB%A5%B9%A5%AF%A5%EA%A5%D7%A5%C8">シェルスクリプト</a>ファイルに書いておき、各環境のCIを実行するときにsourceコマンドで呼び出すようにします。例えばBitbucket pipelinesでは以下のように記述できます。</p> <pre class="code lang-yaml" data-lang="yaml" data-unlink><span class="synStatement">- </span><span class="synIdentifier">step</span><span class="synSpecial">:</span> <span class="synIdentifier">name</span><span class="synSpecial">:</span> Send deployment event to NewRelic ChangeTracking <span class="synIdentifier">deployment</span><span class="synSpecial">:</span> develop <span class="synIdentifier">script</span><span class="synSpecial">:</span> <span class="synStatement">- </span>source ./scripts/newrelic_change_tracking.sh <span class="synStatement">- </span><span class="synIdentifier">step</span><span class="synSpecial">:</span> <span class="synIdentifier">name</span><span class="synSpecial">:</span> Send deployment event to NewRelic ChangeTracking <span class="synIdentifier">deployment</span><span class="synSpecial">:</span> production <span class="synIdentifier">script</span><span class="synSpecial">:</span> <span class="synStatement">- </span>source ./scripts/newrelic_change_tracking.sh </pre> <p><code>deployment: env</code>の記述により、事前定義されたデプロイ変数が読み込まれます。デプロイ変数は、CIを実行するときに環境固有のパラメータを参照したいケース等で便利です<a href="#f-5e66f3cc" id="fn-5e66f3cc" name="fn-5e66f3cc" title="https://support.atlassian.com/ja/bitbucket-cloud/docs/set-up-and-monitor-deployments/">*2</a>。本記事の文脈では、<code>$NEW_RELIC_USER_KEY</code>と<code>$NEW_RELIC_ENTITY_GUID</code>は環境固有の値なので、これらをデプロイ変数としてセットしておくと、処理そのものは<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B7%A5%A7%A5%EB%A5%B9%A5%AF%A5%EA%A5%D7%A5%C8">シェルスクリプト</a>ファイルに書いて共<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C4%CC%B2%BD">通化</a>しながら、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EA%A5%D7%A5%C8">スクリプト</a>の実行時に環境固有の値を参照することができます。</p> <p>以上を設定してBitbucket pipelinesでCIを実行すると、以下のようにNew Relicに変更が記録されます。 <figure class="figure-image figure-image-fotolife" title="NewRelic APMの画面"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231218/20231218162515.png" width="1200" height="676" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>NewRelic <a class="keyword" href="https://d.hatena.ne.jp/keyword/APM">APM</a>の画面</figcaption></figure></p> <h2 id="おわりに">おわりに</h2> <p>いかがでしょうか。Change Trackingが便利であることを伝えきるには情報が不足しているかもしれませんが、簡単に導入できることは伝わったと思いますので、試していただけたら幸いです。</p> <p>最後に、個人的な決意表明ですが、所属チームにSREやDevOpsの文化・考え方を浸透させるために、New Relicを活用してきたいと思います。</p> <div class="footnote"> <p class="footnote"><a href="#fn-5332a074" id="f-5332a074" name="f-5332a074" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">複雑な長い<a class="keyword" href="https://d.hatena.ne.jp/keyword/JSON">JSON</a>を<a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>コマンドでPOSTするときはヒアドキュメントを使うと便利です。 <a href="https://qiita.com/nekoyamada/items/8154f1c369f99e3213b6">bash&#x30B9;&#x30AF;&#x30EA;&#x30D7;&#x30C8;&#x3067;JSON&#x3092;&#x7D44;&#x307F;&#x7ACB;&#x3066;&#x3066;curl&#x3067;POST&#x3059;&#x308B; #Bash - Qiita</a> </span></p> <p class="footnote"><a href="#fn-5e66f3cc" id="f-5e66f3cc" name="f-5e66f3cc" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://support.atlassian.com/ja/bitbucket-cloud/docs/set-up-and-monitor-deployments/">https://support.atlassian.com/ja/bitbucket-cloud/docs/set-up-and-monitor-deployments/</a></span></p> </div> tver-techblog Xcode Cloud 触ってみた hatenablog://entry/6801883189067971242 2023-12-20T15:24:19+09:00 2023-12-20T15:24:19+09:00 本記事はTVer Advent Calendar 2023の19日目の記事です。 はじめに こんにちは、TVerでiOSアプリ開発を担当しています小森です。 Xcode Cloudの発表からしばらく経ちましたが、 CI/CDサービスを検討するに当たってXcode Cloudを初めて触ってみましたので、 本記事でXcode Cloudについてのセットアップ方法と、触ってみた感想をまとめたいと思います。 Xcode Cloudを検討されている方の参考になれば幸いです。 Xcode Cloudとは Xcode CloueはAppleが提供するAppleプラットフォームのためのCI/CDサービスです。… <p>本記事は<a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a>の19日目の記事です。</p> <h1 id="はじめに">はじめに</h1> <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>で<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%D7%A5%EA%B3%AB%C8%AF">アプリ開発</a>を担当しています小森です。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloudの発表<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A4%AB%A4%E9%A4%B7">からし</a>ばらく経ちましたが、 CI/CDサービスを検討するに当たって<a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloudを初めて触ってみましたので、<br/> 本記事で<a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloudについてのセットアップ方法と、触ってみた感想をまとめたいと思います。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloudを検討されている方の参考になれば幸いです。</p> <h1 id="Xcode-Cloudとは"><a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloudとは</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloueは<a class="keyword" href="https://d.hatena.ne.jp/keyword/Apple">Apple</a>が提供する<a class="keyword" href="https://d.hatena.ne.jp/keyword/Apple">Apple</a>プラットフォームのためのCI/CDサービスです。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdeveloper.apple.com%2Fjp%2Fxcode-cloud%2F" title="Xcode Cloud - Apple Developer" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://developer.apple.com/jp/xcode-cloud/">developer.apple.com</a></cite></p> <h2 id="利用手順について">利用手順について</h2> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a>のReport NavigatorのCloudタブからWorkflowの作成をして実行します。</p> <h3 id="Workflowについて">Workflowについて</h3> <p>下記に簡易的なWorkflowの設定についてまとめます。 詳細情報は公式ドキュメントを参照してください。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdeveloper.apple.com%2Fdocumentation%2Fxcode%2Fconfiguring-your-first-xcode-cloud-workflow" title="Configuring your first Xcode Cloud workflow | Apple Developer Documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://developer.apple.com/documentation/xcode/configuring-your-first-xcode-cloud-workflow">developer.apple.com</a></cite></p> <p><figure class="figure-image figure-image-fotolife" title="Workflow 編集画面"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231219/20231219225202.jpg" width="1200" height="791" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Workflow 編集画面</figcaption></figure></p> <h3 id="General">General</h3> <p>ここではWorkflow名、ワークフロー説明文、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>、対象のProject or Workspaceの設定を行います。</p> <h3 id="Environment">Environment</h3> <p>ここでは実行する<a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Versionと<a class="keyword" href="https://d.hatena.ne.jp/keyword/macOS">macOS</a> Versionの選択と<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B4%C4%B6%AD%CA%D1%BF%F4">環境変数</a>の設定を行います。 事前定義されている<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B4%C4%B6%AD%CA%D1%BF%F4">環境変数</a>はこちらを参照してください。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdeveloper.apple.com%2Fdocumentation%2Fxcode%2Fenvironment-variable-reference" title="Environment variable reference | Apple Developer Documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://developer.apple.com/documentation/xcode/environment-variable-reference">developer.apple.com</a></cite></p> <h3 id="Start-Conditions">Start Conditions</h3> <p>Workflowの起動トリガーの設定を行います。 他のCI/CDサービスと同じようにブランチの変更、プルリク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トの変更、タグの変更、スケジュール実行などに対応しています。</p> <h3 id="Actions">Actions</h3> <p>ActionはBuild, Test, Analyze, Archiveの4つから追加できます。 各Actionは並列実行することが可能です。</p> <h3 id="Post-Actions">Post-Actions</h3> <p>Post-ActionsはTestFlight External Testing, TestFlight Internal Testing, Notarize, Notifyの4つから追加できます。 NotifyはSlackとEmailに対応しています。</p> <h1 id="触ったみた個人的感想">触ったみた個人的感想</h1> <ul> <li>とにかくシンプルで楽</li> </ul> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a>に組み込まれている機能ということもあり、セットアップはとても楽で簡単でした。<br/> また、証明書やProvisioningProfileなどの管理が自動で対応されるのでfastlane matchを導入してごにょごにょなどする必要がありません。<br/> そして、Test FlightやAppStoreConnectの連携も簡単にできます。<br/> AppStoreConnectからWorkflowの実行も可能なので開発者以外も容易にWorkflow実行が可能なのは魅力的です。<br/></p> <ul> <li>メンテナンスしにくいかも</li> </ul> <p>ほかのCI/CDサービスだとWorkflowの設定を<a class="keyword" href="https://d.hatena.ne.jp/keyword/yaml">yaml</a>ファイルなどで記述し管理することができますが、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloudの場合は、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a>もしくはAppStoreConnectからの<a class="keyword" href="https://d.hatena.ne.jp/keyword/GUI">GUI</a>での編集か<a class="keyword" href="https://d.hatena.ne.jp/keyword/App%20Store">App Store</a> Connect <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>経由での編集のみになります。<br/> チームでメンテナンスしていくために<a class="keyword" href="https://d.hatena.ne.jp/keyword/App%20Store">App Store</a> Connect <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>も用意していると公式ドキュメントには記載されていますが <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BD%A1%BC%A5%B9%A5%B3%A1%BC%A5%C9">ソースコード</a>でWorkflowの設定を管理することが可能な他のCI/CDサービスと比較するとちょっとメンテナンスしにくそうだなという印象を持ちました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdeveloper.apple.com%2Fdocumentation%2Fappstoreconnectapi%2Fxcode_cloud_workflows_and_builds" title="Xcode Cloud Workflows and Builds | Apple Developer Documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://developer.apple.com/documentation/appstoreconnectapi/xcode_cloud_workflows_and_builds">developer.apple.com</a></cite></p> <ul> <li>キャッシュ機能がイマイチ</li> </ul> <p>Deriverd Data配下のみがキャッシュ対象でSwift Package Managerを使用してインストールしたライブラリのみキャッシュされるみたいです。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%C9%A5%D1%A1%BC%A5%C6%A5%A3">サードパーティ</a>製のツールやライブラリを導入する場合は、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloudが提供しているHomebrewを使用し、 任意のタイミングで実行されるcustom build scriptsを使用してインストールする必要があります。<br/> そのインストールしたツールやライブラリをキャッシュすることはできないので毎回インストールしなければならずイマイチだなという印象を持ちました。<br/> ただ、Git <a class="keyword" href="https://d.hatena.ne.jp/keyword/LFS">LFS</a>をサポートしてるので、CocoaPodsなどに関しては<a class="keyword" href="https://d.hatena.ne.jp/keyword/Pods">Pods</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リをGit管理下に置くアプローチを採用していればキャッシュ意識する必要がないので問題なく運用可能だと思います。</p> <h1 id="まとめ">まとめ</h1> <p>今回は<a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloudの簡易的なセットアップ方法と触ってみた個人的感想を述べた記事でした。 個人開発をする上では<a class="keyword" href="https://d.hatena.ne.jp/keyword/Xcode">Xcode</a> Cloud一択で十分ではないかと思いますが、他のCI/CDサービスと比較するとメンテナンス性やキャッシュ機能などが少しネックかなと考えております。<br /> ただ、料金に関しては比較的安く機能に関してもシンプルで使いやすい印象を受けたのでデメリットを補う案を模索しながら引き続き採用検討を進めたいと思いました。</p> tver-techblog SnapHelperがどうやってSnappingを実現しているのか hatenablog://entry/6801883189068044174 2023-12-20T10:07:57+09:00 2023-12-20T10:07:57+09:00 本記事は TVer Advent Calendar 2023 の20日目の記事です。 はじめに こんにちは、TVerでAndroidアプリ開発をしています石井です。 AndroidViewでコンテンツの一覧などを表示する際にRecyclerViewがよく使われると思いますが、カルーセルのようなUIにするためにはどうすれば良いでしょうか。 一般的にはRecyclerViewにLinearSnapHelperをアタッチすることで、カルーセルのようにコンテンツを中央寄せさせるUIを作ることが可能です。 ただし、LinearSnapHelperはあくまでも中央へのSnappingしか提供していないため… <p>本記事は <a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a> の<a class="keyword" href="https://d.hatena.ne.jp/keyword/20%C6%FC">20日</a>目の記事です。</p> <h2 id="はじめに">はじめに</h2> <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>で<a class="keyword" href="https://d.hatena.ne.jp/keyword/Android">Android</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%D7%A5%EA%B3%AB%C8%AF">アプリ開発</a>をしています石井です。</p> <p>AndroidViewでコンテンツの一覧などを表示する際にRecyclerViewがよく使われると思いますが、カ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EB%A1%BC%A5%BB%A5%EB">ルーセル</a>のようなUIにするためにはどうすれば良いでしょうか。</p> <p>一般的にはRecyclerViewにLinearSnapHelperをアタッチすることで、カ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EB%A1%BC%A5%BB%A5%EB">ルーセル</a>のようにコンテンツを中央寄せさせるUIを作ることが可能です。<br/> ただし、LinearSnapHelperはあくまでも中央へのSnappingしか提供していないため、左寄せや右寄せなど中央以外にしたい場合は独自にSnapHelperを継承した実装をしなければなりません。独自に実装するとして、各関数がSnappingに対してどのような役割を担っているか理解が必要です。</p> <p>では、どのようにしてこのSnappingは実現しているのでしょうか。</p> <p>今回はLinearSnapHelperを例にしつつ、SnapHelperがどのようにしてSnappingを実現しているのかを深ぼっていこうと思います。</p> <h3 id="LinearSnapHelperを用いた中央寄せ">LinearSnapHelperを用いた中央寄せ</h3> <p>前提にはなりますが、そもそもSnappingがどういった挙動なのか、どう実装すればSnappingができるのかを簡単に見てみましょう。</p> <p>今回はよくある横スクロールで挙動を確認していきたいので、横スクロールのRecyclerViewを作成します。</p> <pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synType">val</span> layoutManager = LinearLayoutManager( requireContext(), LinearLayoutManager.HORIZONTAL, <span class="synConstant">false</span>, ) recyclerView.layoutManager = layoutManager </pre> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231219/20231219110842.png" width="584" height="1200" loading="lazy" title="" class="hatena-fotolife" style="width:200px" itemprop="image"></span></p> <p>それではLinearSnapHelperでSnappingを実装していきます。</p> <pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synType">val</span> snapHelper = LinearSnapHelper() snapHelper.attatchToRecyclerView(recyclerView) </pre> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231219/20231219110934.gif" width="584" height="1200" loading="lazy" title="" class="hatena-fotolife" style="width:200px" itemprop="image"></span></p> <p>これで簡単に中央にSnappingするRecyclerViewが完成しました。</p> <h2 id="Snappingの仕組み">Snappingの仕組み</h2> <p>では、どのようにSnappingを実現しているのでしょうか。</p> <p>SnapHelperには3つの抽象関数があります。</p> <ul> <li>calculateDistanceToFinalSnap</li> <li>findSnapView</li> <li>findTargetSnapPosition</li> </ul> <p>特に関連しそうな <code>calculateDistanceToFinalSnap</code> と <code>findTargetSnapPosition</code> にフォーカスして、まずは<a href="https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/SnapHelper.java">SnapHelper</a>の実装を見ていきます。</p> <p>SnapHelper側ではFlingが実行されると <code>snapFromFling</code> が実行されます。</p> <pre class="code lang-java" data-lang="java" data-unlink><span class="synType">private</span> <span class="synType">boolean</span> snapFromFling( <span class="synPreProc">@NonNull</span> RecyclerView.LayoutManager layoutManager, <span class="synType">int</span> velocityX, <span class="synType">int</span> velocityY ) { <span class="synComment">// 省略</span> <span class="synType">int</span> targetPosition = findTargetSnapPosition( layoutManager, velocityX, velocityY ); <span class="synStatement">if</span> (targetPosition == RecyclerView.NO_POSITION) { <span class="synStatement">return</span> <span class="synConstant">false</span>; } smoothScroller.setTargetPosition(targetPosition); layoutManager.startSmoothScroll(smoothScroller); <span class="synStatement">return</span> <span class="synConstant">true</span>; } </pre> <p><code>findTargetSnapPosition</code> で計算されたpositionの位置まで <code>startSmoothScroll</code> でスクロールが実行されていくのが分かります。また <code>smoothScroller</code> に対象の位置をsetしているのもわかります。</p> <p>次に <code>calculateDistanceToFinalSnap</code> の方を見ていきましょう。</p> <pre class="code lang-java" data-lang="java" data-unlink><span class="synPreProc">@Nullable</span> <span class="synPreProc">@Deprecated</span> <span class="synType">protected</span> LinearSmoothScroller createSnapScroller( <span class="synPreProc">@NonNull</span> RecyclerView.LayoutManager layoutManager ) { <span class="synStatement">if</span> (!(layoutManager <span class="synStatement">instanceof</span> RecyclerView.SmoothScroller.ScrollVectorProvider)) { <span class="synStatement">return</span> <span class="synConstant">null</span>; } <span class="synStatement">return</span> <span class="synStatement">new</span> LinearSmoothScroller(mRecyclerView.getContext()) { <span class="synPreProc">@Override</span> <span class="synType">protected</span> <span class="synType">void</span> onTargetFound( View targetView, RecyclerView.State state, Action action ) { <span class="synStatement">if</span> (mRecyclerView == <span class="synConstant">null</span>) { <span class="synComment">// The associated RecyclerView has been removed so there is no action to take.</span> <span class="synStatement">return</span>; } <span class="synType">int</span>[] snapDistances = calculateDistanceToFinalSnap( mRecyclerView.getLayoutManager(), targetView ); <span class="synType">final</span> <span class="synType">int</span> dx = snapDistances[<span class="synConstant">0</span>]; <span class="synType">final</span> <span class="synType">int</span> dy = snapDistances[<span class="synConstant">1</span>]; <span class="synType">final</span> <span class="synType">int</span> time = calculateTimeForDeceleration( Math.max(Math.abs(dx), Math.abs(dy)) ); <span class="synStatement">if</span> (time &gt; <span class="synConstant">0</span>) { action.update(dx, dy, time, mDecelerateInterpolator); } } <span class="synPreProc">@Override</span> <span class="synType">protected</span> <span class="synType">float</span> calculateSpeedPerPixel(DisplayMetrics displayMetrics) { <span class="synStatement">return</span> MILLISECONDS_PER_INCH / displayMetrics.densityDpi; } }; } </pre> <p>先ほどsetした対象の位置に対して <code>onTargetFound</code> が実行され、 <code>calculateDistanceToFinalSnap</code> で計算された距離分だけ動いていくことがわかります。</p> <p>まとめると以下のことがわかります。</p> <ul> <li><code>findTargetSnapPosition</code> で対象となるViewの位置を計算</li> <li>計算した位置までスクロール</li> <li>対象となるViewが画面上に出てきたら <code>onTargetFound</code> が実行される</li> <li>微調整を行なってSnappingを実現させる</li> </ul> <h3 id="LinearSnapHelperの中央寄せ">LinearSnapHelperの中央寄せ</h3> <p>では最後に<a href="https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/LinearSnapHelper.java">LinearSnapHelper</a>の実装を見て、どのように中央へSnappingをしているかを見てみます。</p> <pre class="code lang-java" data-lang="java" data-unlink><span class="synPreProc">@Override</span> <span class="synType">public</span> <span class="synType">int</span>[] calculateDistanceToFinalSnap( <span class="synPreProc">@NonNull</span> RecyclerView.LayoutManager layoutManager, <span class="synPreProc">@NonNull</span> View targetView ) { <span class="synType">int</span>[] out = <span class="synStatement">new</span> <span class="synType">int</span>[<span class="synConstant">2</span>]; <span class="synStatement">if</span> (layoutManager.canScrollHorizontally()) { out[<span class="synConstant">0</span>] = distanceToCenter( targetView, getHorizontalHelper(layoutManager) ); } <span class="synStatement">else</span> { out[<span class="synConstant">0</span>] = <span class="synConstant">0</span>; } <span class="synStatement">if</span> (layoutManager.canScrollVertically()) { out[<span class="synConstant">1</span>] = distanceToCenter( targetView, getVerticalHelper(layoutManager) ); } <span class="synStatement">else</span> { out[<span class="synConstant">1</span>] = <span class="synConstant">0</span>; } <span class="synStatement">return</span> out; } <span class="synType">private</span> <span class="synType">int</span> distanceToCenter(<span class="synPreProc">@NonNull</span> View targetView, OrientationHelper helper) { <span class="synType">final</span> <span class="synType">int</span> childCenter = helper.getDecoratedStart(targetView) + (helper.getDecoratedMeasurement(targetView) / <span class="synConstant">2</span>); <span class="synType">final</span> <span class="synType">int</span> containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / <span class="synConstant">2</span>; <span class="synStatement">return</span> childCenter - containerCenter; } </pre> <p><code>distanceToCenter</code> で対象となるViewの中央とコンテナの中央間の距離が計算されます。</p> <p><code>findTargetSnapPosition</code> の方はコード量が多いので割愛しますが、スクロールした時のスクロール量とViewの大きさをもとに最も中心に表示できるViewの位置を返すロジックになっていました。</p> <p>改めてSnapHelper含め、LinearSnapHelperを振り返ると以下のようになります。</p> <ul> <li><code>findTargetSnapPosition</code> でスクロール量から対象となるViewを事前計算</li> <li>対象のViewまで <code>startSmoothScroll</code> を使ってスクロール</li> <li>対象となるViewが画面上に出てきたら <code>onTargetFound</code> が実行される</li> <li><code>calculateDistanceToFinalSnap</code> で対象のViewの中心とコンテナの中心間の距離を計算</li> <li>その分移動させることで、Viewの中心とコンテナの中心が重なり中央へのSnappingが実現できる</li> </ul> <h2 id="まとめ">まとめ</h2> <p>今回はSnappingの挙動からSnapHelperのSnappingに関わる部分を掻い摘んでざっくりと解説させていただきました。Snapping自体は珍しい挙動ではなく様々なサービスで利用されています。 SnapHelperの挙動について理解を深めておくことで多様なSnappingの実装が簡単にできるようになりますし、SnapHelperに依存せず同様な処理を実装できるのではないかと思います。</p> tver-techblog ISUCON初挑戦記 hatenablog://entry/6801883189066669279 2023-12-19T10:47:11+09:00 2023-12-19T10:47:11+09:00 こんにちは、TVerでバックエンドエンジニアをやっている水野です。 こちらは TVer Advent Calendar 2023 の18日目の記事です。 初めてISUCONに挑戦しました。結果は最終スコア0で、悔いが残りますが、次回ISUCON14(開催未定)に向けての備忘録として振り返ります。 参加までの流れ 当日やったこと 会社からのサポート 来年への抱負 参加までの流れ 私がISUCON13に参加したきっかけは、ISUCON夏祭りへの参加でした。 techblog.tver.co.jp ISUCON夏祭りのハンズオンでprivate-isuを解いたり、トークセッションで先人たちの戦略を聞… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>でバックエンドエンジニアをやっている水野です。</p> <p>こちらは <a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a> の18日目の記事です。</p> <p>初めてISUCONに挑戦しました。結果は最終スコア0で、悔いが残りますが、次回ISUCON14(開催未定)に向けての備忘録として振り返ります。</p> <ul class="table-of-contents"> <li><a href="#参加までの流れ">参加までの流れ</a></li> <li><a href="#当日やったこと">当日やったこと</a></li> <li><a href="#会社からのサポート">会社からのサポート</a></li> <li><a href="#来年への抱負">来年への抱負</a></li> </ul> <h2 id="参加までの流れ">参加までの流れ</h2> <p>私がISUCON13に参加したきっかけは、ISUCON夏祭りへの参加でした。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fmizuno%2Fisucon-summer-fes" title="ISUCON 夏祭り 2023 参加レポート - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/mizuno/isucon-summer-fes">techblog.tver.co.jp</a></cite></p> <p>ISUCON夏祭りのハンズオンで<a href="https://github.com/catatsuy/private-isu">private-isu</a>を解いたり、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>セッションで先人たちの戦略を聞いたりしているうちに、自分も参加者としてスキルを試してみたいという強い思いが芽生えました。</p> <p>チームメンバーは社内で募ったSREエンジニア(tomoner_94444)、データチームエンジニア(sy6124)、そして私の3人で構成されました。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231215/20231215104348.png" width="1200" height="676" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><a href="https://youtu.be/YJ1_JnuZp0U?t=8935">ISUCON13 &#x30AA;&#x30F3;&#x30E9;&#x30A4;&#x30F3;&#x30E9;&#x30A4;&#x30D6;&#x4E2D;&#x7D99; - YouTube</a></p> <h2 id="当日やったこと">当日やったこと</h2> <p>各自が当日に行った作業は以下の通りです。詳細は割愛し、サマリのみを記載します。</p> <p><strong>私</strong></p> <ul> <li>スロークエリ、N+1調査</li> <li>Index貼る</li> <li>tagsテーブルのオンメモリキャッシュ化</li> </ul> <p><strong>tomoner_94444</strong></p> <ul> <li>DB分割(アプリ側、<a class="keyword" href="https://d.hatena.ne.jp/keyword/DNS">DNS</a>)</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a> replication構成</li> <li>HA proxy導入クエリ分散</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AB%A1%BC%A5%CD%A5%EB">カーネル</a>設定変更 <a class="keyword" href="https://d.hatena.ne.jp/keyword/TCP">TCP</a> 周り</li> <li>Nginx cache周りの設定追加</li> </ul> <p><strong>sy6124</strong></p> <ul> <li>pprofを入れようとして失敗</li> <li>アプリの改善(forでクエリを投げまくっているところのforをなくす</li> </ul> <h2 id="会社からのサポート">会社からのサポート</h2> <p>株式会社<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>は、ISUCONへの挑戦を後押しする文化があり、以下のサポートを提供していただきました。</p> <p>また、ISUCON13の企業スポンサーとして、大会への直接的なサポートも行っています。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Futsumi%2Fisucon13-sponsor" title="今年もTVer はISUCON13に協賛します #isucon #tver - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/utsumi/isucon13-sponsor">techblog.tver.co.jp</a></cite></p> <ol> <li>ISUCON素振り、ISUCON当日を勤務扱い</li> <li>ISUCON企業スポンサー枠として参加</li> <li>ISUCON素振り時、会社の<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> SandBox環境を提供</li> <li>ISUCON当日に、昼食とコーヒーの差し入れ</li> </ol> <blockquote><p>ISUCON素振り、ISUCON当日を勤務扱い</p></blockquote> <p>休日に行ったISUCON素振りとISUCON当日を勤務扱いとして認めて頂きました。勤務扱いにより、土日をフルに使った素振りを行うことができました。ISUCONと通常業務を両立させやすい環境で助かりました。</p> <blockquote><p>ISUCON企業スポンサー枠として参加</p></blockquote> <p>ISUCON企業スポンサー枠を得て、ISUCON13への参加が可能となりました。これにより、激しいISUCONエントリーの競争をスポンサー枠で回避し、無事に参加できました。</p> <blockquote><p>ISUCON素振り時、会社の<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> SandBox環境を提供</p></blockquote> <p>ISUCON素振り時、会社の<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> SandBox環境を利用させて頂きました。<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>のコストを気にすることなく、本番同様の素振りができるのは非常にありがたかったです。</p> <blockquote><p> ISUCON当日に、昼食とコーヒーの差し入れ</p></blockquote> <p>ISUCON当日に、CTOから<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AB%A5%C4%A5%B5%A5%F3%A5%C9">カツサンド</a>、マネージャー陣からコーヒーとスイーツを差し入れして頂きました。人情厚い差し入れに感謝です!</p> <h2 id="来年への抱負">来年への抱負</h2> <p>今年のISUCONは最終スコア0で終わり、悔しさが残ります。来年が開催されるならば、再び参加し、納得のいくスコアを収めたいと考えています。</p> <p>最終スコアが0になった原因は恥ずかしいので触れませんが、十分な素振りの時間を確保していれば防げたでしょう。。。来年はさらに準備をして臨みます。</p> <p>「百聞は一見に如かず」のように、100回のISUCON素振りをしても一回のISUCON本戦参加によって得られる課題と楽しさがあると思います。今回それを知ることができ、ISUCON迷い中の方にはぜひとも参加をおすすめします。</p> <p>今年のISUCON参加を通じて、自身のバックエンドエンジニアとしての通用する技術や不足している技術を明確にできました。これを日々の業務や自己研鑽に生かしていきます!</p> tver-techblog Media-JAWS にて登壇しました #jawsug #mediajaws hatenablog://entry/6801883189066456699 2023-12-15T12:18:46+09:00 2023-12-15T12:18:46+09:00 本記事はTVer Advent Calendar 2023の15日目の記事です。 はじめに こんにちは。去年も15日目の記事を書いていたバックエンドエンジニアの伊藤です。 11/15にInterBEEに合わせて海浜幕張で開催されたMedia-JAWSにて初の登壇をしてきました。 ということで今年は登壇ブログを書いていきたいと思います。 media-jaws.doorkeeper.jp Media-JAWSとは 以下、公式サイトからの引用です。 Media-JAWSは、例えば急激なトラフィック処理や映像や画像のワークロード処理、セキュリティ対策など、放送・ラジオ・新聞・雑誌・Web・SNSなどの… <p>本記事は<a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a>の15日目の記事です。</p> <h1 id="はじめに">はじめに</h1> <p>こんにちは。去年も15日目の記事を書いていたバックエンドエンジニアの伊藤です。</p> <p>11/15にInterBEEに合わせて<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%A4%C9%CD%CB%EB%C4%A5">海浜幕張</a>で開催されたMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>にて初の登壇をしてきました。</p> <p>ということで今年は登壇ブログを書いていきたいと思います。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fmedia-jaws.doorkeeper.jp%2Fevents%2F164378" title="Media-JAWS【第14回】InterBEEに合わせて幕張開催!#jawsug #mediajaws" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://media-jaws.doorkeeper.jp/events/164378">media-jaws.doorkeeper.jp</a></cite></p> <h1 id="Media-JAWSとは">Media-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>とは</h1> <p>以下、公式サイトからの引用です。</p> <blockquote><p>Media-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>は、例えば急激な<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A5%E9%A5%D5%A5%A3%A5%C3%A5%AF">トラフィック</a>処理や映像や画像のワークロード処理、セキュリティ対策など、放送・ラジオ・新聞・雑誌・Web・<a class="keyword" href="https://d.hatena.ne.jp/keyword/SNS">SNS</a>などのメディア特有の性質が求められるサービスを、<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>を活用してどのように構築・運用しているか、といった情報交換や、交流の場として活用される勉強会です。</p> <p>開催頻度は、3ヶ月に一度を目標にしています。 関東以外の方のために、基本的に<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%E9%A5%A4%A5%D6%C7%DB%BF%AE">ライブ配信</a>を実施します。 いずれは関東以外での開催や、関東以外の方によるリモートでの登壇なども行いたいと考えています。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%CF%A5%C3%A5%B7%A5%E5%A5%BF%A5%B0">ハッシュタグ</a>は #mediajaws</p></blockquote> <h1 id="登壇の経緯">登壇の経緯</h1> <p>SREチームの加我さんから登壇しない?とお話があり、やりますということで登壇させていただきました。</p> <p>やりますと言って締切が決まれば大体なんとかなるの精神です。</p> <p>元々登壇はいつかしたいと思っていたのですが、今年の4月に行われた<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Summit Tokyo 2023で色々な方々と交流する機会がありそこでモチベーションを得たことも大きなきっかけの一つです。とても良い体験でした。</p> <h1 id="登壇内容について">登壇内容について</h1> <p>資料はこちらです。 <iframe id="talk_frame_1108462" class="speakerdeck-iframe" src="//speakerdeck.com/player/442852c111de439aaf6339ce0bc7098b" width="710" height="399" style="aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/techtver/20231115-media-jaws-seo-ogp">speakerdeck.com</a></cite> 発表内容についてですが、2022/4のリニューアルを機に大幅に下がってしまった<a class="keyword" href="https://d.hatena.ne.jp/keyword/SEO">SEO</a>のスコアを取り戻すためにバックエンドエンジニアがやったこととその延長線上で行ったOGP対応についてのお話ししました。</p> <p>4行にまとめれば、以下のようなことが書いてあります。</p> <ul> <li>2022/04にリニューアルしたけど<a class="keyword" href="https://d.hatena.ne.jp/keyword/SEO">SEO</a>のスコア下がっちゃった</li> <li>検索結果に<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>出てこないからバックエンドで対策して欲しい</li> <li>頑張って対策したらリニューアル前より良くなったよ</li> <li>ついでにOGP対応もやったよ</li> </ul> <p>大枠の実装は今も変わらず<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>で使われているものです。ただ実はまだ何個か対応しなければいけないこともあり現在も改修は続けられています。</p> <p>特に<a class="keyword" href="https://d.hatena.ne.jp/keyword/SEO">SEO</a>対策に使っている簡易<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%ED%A1%BC%A5%E9%A1%BC">クローラー</a>はECSタスクで定期的に実行しているのですが、chromedpがハングしてタスクが終わらないという事象<a href="#f-d50bdf99" id="fn-d50bdf99" name="fn-d50bdf99" title="無限にアラート飛んできてとてもつらい">*1</a>に立ち向かっていたり、OGP対応ではLPから切り替えきれていないページの切り替えを引き続き対応しています。アラートに一区切りつけて無事落ち着いて年を越せると良いなと思っております。</p> <p>余談ですが、<a href="https://techblog.tver.co.jp/entry/s-ito/intro-go-html-parser-package">去年のアドベントカレンダー</a> で寄稿したHTMLの編集の話はこの<a class="keyword" href="https://d.hatena.ne.jp/keyword/SEO">SEO</a>対策のためにやっていたことだったので、ちょうど一年越しに取り組みについて深掘りする形の資料を書くことになりました。</p> <p>また上の資料にある<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>についての情報は以下の資料の引用になります。 <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>について全ての資料を確認したい場合は是非こちらをご覧ください。</p> <p><iframe id="talk_frame_920082" class="speakerdeck-iframe" src="//speakerdeck.com/player/49965b8557e748cea81c6d26e19317c2" width="710" height="399" style="aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/techtver/we-are-hiring">speakerdeck.com</a></cite></p> <h1 id="おわりに">おわりに</h1> <p>初めての登壇ということで緊張しましたが、なんとか無事終えることができました。資料作成や人前で話すこと自体卒研ぶりで、ほぼ未知の世界でしたが良い経験でした。 今年できたら良いなーくらいのゆるい目標でしたが、年内に登壇することができ満足しています。</p> <p>資料のレビューをしてくれた社内の方々や、当日サポートしてくれたスタッフの方々ありがとうございました。 また機会があればどこかで登壇したいなと思いました。</p> <p>SREチームの加我さん <a href="#f-e30a39e8" id="fn-e30a39e8" name="fn-e30a39e8" title="最初から最後までとてもお世話になった">*2</a> によるInterBEEやMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>の参加レポートもありますので是非。 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fkaga%2Finter-bee-2023-mediajaws" title="Inter BEE 2023 参加レポート &amp; Media-JAWSを開催しました #interbee #mediajaws - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/kaga/inter-bee-2023-mediajaws">techblog.tver.co.jp</a></cite></p> <div class="footnote"> <p class="footnote"><a href="#fn-d50bdf99" id="f-d50bdf99" name="f-d50bdf99" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">無限にアラート飛んできてとてもつらい</span></p> <p class="footnote"><a href="#fn-e30a39e8" id="f-e30a39e8" name="f-e30a39e8" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">最初から最後までとてもお世話になった</span></p> </div> tver-techblog 私とAWSと2023年 hatenablog://entry/6801883189066157701 2023-12-13T12:01:09+09:00 2023-12-13T12:01:09+09:00 こんにちは。アドテク領域のエンジニアをしています安部です。こちらは TVer Advent Calendar 2023 の13日目の記事です。 個人的に今年はAWSに縁があった年でしたのでAWSにからめて1年を振り返ります。 1月〜3月 フロントエンド開発をがんばっていました。(いきなりAWSじゃない!)OCJP Silver取ったりしてました。(バックエンド!)開発業務専門でAWSをどう使っているか、どうデプロイされているのかはあまり気にしていませんでした。転機になったのは3月にログのアラートをslackに連携したいという話が出てきて、CloudWatch LogsとLambdaを使用してs… <p>こんにちは。<br />アドテク領域のエンジニアをしています安部です。<br />こちらは <a href="https://qiita.com/advent-calendar/2023/tver" target="_blank">TVer Advent Calendar 2023 </a>の13日目の記事です。</p> <p>個人的に今年は<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>に縁があった年でしたので<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>にからめて1年を振り返ります。</p> <h3 id="1月3月">1月〜3月</h3> <p>フロントエンド開発をがんばっていました。(いきなり<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>じゃない!)<br />OCJP Silver取ったりしてました。(バックエンド!)<br />開発業務専門で<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>をどう使っているか、どうデプロイされているのかはあまり気にしていませんでした。<br />転機になったのは3月にログのアラートをslackに連携したいという話が出てきて、CloudWatch LogsとLambdaを使用してslack通知をするツールを作成したことでした。<br /><a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>のサービス駆使して色々できそう!これはサービス知っておいたほうが得だな!と思い始めた時期です。</p> <h3 id="4月6月">4月〜6月</h3> <h4 id="AWS-Summit-Tokyo参加"><a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Summit Tokyo参加</h4> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Summit Tokyoに行きました。</p> <p>個人的テーマは「<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>を知ること」でした。<br />その時の記事はこちら</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fh-abe%2Faws-summit-tokyo-2023" title="AWS Summit Tokyo に参加しました(AWS初心者編) - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/h-abe/aws-summit-tokyo-2023">techblog.tver.co.jp</a></cite></p> <p>ここで<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>のサービスを色々知りました。<br />認定資格を取ってみようかなとも考え始めた時期です。<br />余談ですが、このときにもらったクッションは今でも使ってます。</p> <h4 id="ツール作成">ツール作成</h4> <p>4月には広告入稿システムのリプレイスがありました。<br />このシステムと対向システムでデータの同期しているのですが、データに差分が出ていないか確認する必要があります。<br />そのため対向システムから不整合が発生している可能性のあるデータを連携していただき、確認するという定常業務がありました。<br />元々の確認方法は連携データを1データずつ<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>を実行して確認する方式だったのですが、Lambdaを使い自動化しました。<br />ツールについては詳しい内容を別ブログにしたいなと思っています。</p> <h3 id="7月12月">7月〜12月</h3> <h4 id="資格取得">資格取得</h4> <p>7月に<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Certified Cloud Practitioner を取得しました。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="なんとか合格"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212200109.jpg" width="1015" height="571" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">なんとか合格</figcaption> </figure> <p> </p> <p>2週間Udemyの問題集をひたすら解いて挑みました。<br />次はASSOCIATE資格を狙っています。</p> <h4 id="CICD構築">CI/CD構築</h4> <p>Bitbucket Pipelinesを使用したCI/CD構築を担当しました。<br />そこで<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>のどのサービスをどのように使っているのか、どのような設定をすればいいのかがちょっとわかりました。<br />CLF資格取得と被っている時期にやっていたので「ここ見たぞ!」「これかやったわ!」と心のなかで呟きながら作業したり資格勉強したりしていました。<br />資格のための勉強が業務に繋がったので資格を取ったかいがありました。</p> <p> </p> <h4 id="JAWS-Festa-参加"><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 参加</h4> <p>10月は福岡で行われた<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaに参加しました。</p> <p>その時のブログはこちら</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fh-abe%2F2023-jawsfesta-ambassador-repo" title="JAWS Festa 2023 に参加しました! - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/h-abe/2023-jawsfesta-ambassador-repo">techblog.tver.co.jp</a></cite>福岡ならではの事例を聞くことができたり、懇親会で多くの参加者の方とお話できたりして楽しかったです。<br />個人的目標の「地元福岡であるテック系イベントに参加する」が達成できて嬉しくもありました。</p> <p>天神のエンジニアカフェ、年末に行ってみたいなと思っています。</p> <p> </p> <h3 id="2023年まとめ">2023年まとめ</h3> <p>・<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>に興味を持って、学び、業務に反映できた</p> <p> <a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>を知ると面白そうだぞと興味を持ち、イベントに行ったり資格の取得を通して知見を広め、それを業務に還元することができました。</p> <p> おそらく年初に興味を持って学んでいなかったらツールを開発しようとも思わなかったし、CI/CDの構築も時間がかかったのではないかと思います。</p> <p> 興味と業務をリンクさせることができたのは収穫でした。</p> <p>・テックブログの執筆は難しい</p> <p> 前職も含めイベントには何度か参加しましたが、フィードバックは社内クローズのちょっとした報告書を作成する程度でした。</p> <p> テックブログでイベントのレポートを書くということは新鮮で、どう書けばちゃんと伝わるか、何を学んだか理解してもらえるかを考え書くことに苦労しました。</p> <p> もっと文章力を上げたいと思う1年でした。</p> <p>・イベント参加はおもしろい+難しい</p> <p> イベントで事例を聞くこと、ハンズオン<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BB%A5%DF">セミ</a>ナーを受講して実際に体験すること、どのように業務に活かすかを考えることはとても面白いことだと感じています。</p> <p> その一方、イベント参加者とたくさんお話したいと思いつつも「何を喋ろう…」や「今話しかけていいタイミングなのかしら…」と若干の人見知りを発動してなかなか交流を図ることができないことがありました。</p> <p> コミュニケーションの取り方難しいと改めて実感する1年でした。</p> <h3 id="来年の抱負">来年の抱負</h3> <p>せっかくなので来年の抱負も書きます。<br />・テックブログ書く<br /> 私が書いているブログ、今のところイベントに参加しました!系ブログしかありません。<br /> 来年は「こんなことやったよ!」というブログも書きたいと思います。<br />・Lambdaともっと仲良くなる<br /> ツールを作ることがきっかけで使うようになったLambdaですが、まだLambdaのことを半分も活用できていない気がしています。<br /> もっとLamdbaを知って業務に取り入れていければと思っています。</p> <p>・資格取得</p> <p> ASSOCIATE資格のどれか1つは取りたいです。</p> <p> 弊社では資格取得支援制度があり、事前に申請し合格した場合は受験料の補助があります。</p> <p> すでにSAAの事前申請はしているので来年の早い時期に取得できるように勉強しています!<br />・イベント参加<br /> 来年はもっといろんなイベントに行きたいと思います。<br /> 東京・福岡はもちろん、日本全国イベント巡り(<span style="text-decoration: line-through;">と温泉行って観光</span>)したい!<br /> </p> tver-techblog New Relicをフルに活用するためにデータ量とコストに気を配る hatenablog://entry/6801883189065075106 2023-12-13T11:56:32+09:00 2023-12-13T11:57:31+09:00 こんにちは、TVerの加我です。 こちらは TVer Advent Calendar 2023 と New Relic 使ってみた情報をシェアしよう! by New Relic Advent Calendar 2023 の8日目の記事です。 みなさまNew Relicを活用していますか?サービスの信頼性を担保していますか?オブザーバビリティの導入・実現に向けてNew Relicを使い倒していますか? New Relicは非常に高機能なオブザーバビリティプラットフォームです。TVerではフロントエンドからバックエンドまでNew Relicを活用した横断的な観測を行っています。しかしNew Rel… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の加我です。<br/> こちらは <a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a> と <a href="https://qiita.com/advent-calendar/2023/newrelic">New Relic 使ってみた情報をシェアしよう! by New Relic Advent Calendar 2023</a> の8日目の記事です。</p> <p>みなさまNew Relicを活用していますか?サービスの信頼性を担保していますか?オブザーバビリティの導入・実現に向けてNew Relicを使い倒していますか?</p> <p>New Relicは非常に高機能なオブザーバビリティプラットフォームです。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>ではフロントエンドからバックエンドまでNew Relicを活用した横断的な観測を行っています。しかしNew Relicを導入し活用していくにつれて気になってくるのがコストです。</p> <p>ということで、New Relicを活用しつつコストを最適化するためのポイントについて考えていきます。</p> <h1 id="New-Relicのコスト計算についておさらい">New Relicのコスト計算についておさらい</h1> <p>まずはNew Relicの価格設定について理解していきましょう。<br/> New Relicでは「有償のユーザー数」と「取り込むデータ量」の2点が請求対象となります。</p> <p>ユーザー数による請求については後述する有償のユーザー追加がなければ変動がない部分なのでほぼ固定費、取り込むデータ量についてはアクセス数やイベント数により大きく変動することがあるため<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CA%D1%C6%B0%C8%F1">変動費</a>と考えることができます。つまり取り込むデータ量を最適化することが重要です。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdocs.newrelic.com%2Fjp%2Fdocs%2Faccounts%2Faccounts-billing%2Fnew-relic-one-pricing-billing%2Fnew-relic-one-pricing-billing%2F" title="New Relicの価格設定の仕組み | New Relic Documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://docs.newrelic.com/jp/docs/accounts/accounts-billing/new-relic-one-pricing-billing/new-relic-one-pricing-billing/">docs.newrelic.com</a></cite></p> <p>こちらについてはAdministrationのPlan &amp; usageにて利用状況を確認することができます。</p> <p><figure class="figure-image figure-image-fotolife" title="Plan &amp; usage"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212132033.png" width="1200" height="890" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Plan &amp; usage</figcaption></figure></p> <p>Plan &amp; usageのUsage breakdownからView detailsを選択することでデータソース毎の取り込むデータ量を確認することができます。</p> <p><figure class="figure-image figure-image-fotolife" title="Data ingested (GB) per day by data source "><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212132800.png" width="1200" height="710" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Data ingested (GB) per day by data source </figcaption></figure></p> <h3 id="1-有償のユーザー数">1. 有償のユーザー数</h3> <p>New Relicには「Full Platform User」「Core User」「Basic User」という3つのユーザー種別があります。このうち有償のユーザーとして請求対象になるのは「Full Platform User」と「Core User」です。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>ではFull Platform UserとBasic Userを利用した権限管理を行っています。Core Userは<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>がマッチしなかったので利用していません。</p> <table> <thead> <tr> <th>ユーザー区分</th> <th>利用者</th> <th>利用目的</th> </tr> </thead> <tbody> <tr> <td>Full Platform User</td> <td>エンジニア<br>カスタマーサポート</td> <td>バックエンド<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>のTransaction調査<br>モバイルアプリのクラッシュ調査<br><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>インフラのリソース調査</td> </tr> <tr> <td>Core User</td> <td>-</td> <td>-</td> </tr> <tr> <td>Basic User</td> <td>ディレクター<br>エンジニア</td> <td><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>ボードを通じたデータ確認</td> </tr> </tbody> </table> <p>ユーザー毎の権限については下記ドキュメントを参照ください。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdocs.newrelic.com%2Fjp%2Fdocs%2Faccounts%2Faccounts-billing%2Fnew-relic-one-user-management%2Fuser-type%2F" title="ユーザータイプ:ベーシックユーザー、コアユーザー、フルプラットフォーム ユーザー | New Relic Documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://docs.newrelic.com/jp/docs/accounts/accounts-billing/new-relic-one-user-management/user-type/">docs.newrelic.com</a></cite></p> <h3 id="2-取り込むデータ量">2. 取り込むデータ量</h3> <p>イベントやメトリクスやログといった<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C6%A5%EC%A5%E1%A5%C8%A5%EA%A1%BC">テレメトリー</a>データをNew Relic (NRDB) に取り込む際に請求対象となります。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>ではフロントエンドからバックエンドまでNew Relicを利用しているため、各所で発生した<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C6%A5%EC%A5%E1%A5%C8%A5%EA%A1%BC">テレメトリー</a>データがNew Relic (NRDB) に取り込まれ請求対象となります。</p> <table> <thead> <tr> <th>主なデータの発生元</th> <th>New Relicへの取り込み方法</th> <th>主なデータソース (NRDB)</th> </tr> </thead> <tbody> <tr> <td><a class="keyword" href="https://d.hatena.ne.jp/keyword/Web%A5%D6%A5%E9%A5%A6%A5%B6">Webブラウザ</a>ー</td> <td>New Relic Browser</td> <td>Browser events</td> </tr> <tr> <td>Mobileアプリ</td> <td>New Relic Mobile</td> <td>Mobile events</td> </tr> <tr> <td>バックエンド<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a></td> <td>New Relic <a class="keyword" href="https://d.hatena.ne.jp/keyword/APM">APM</a></td> <td><a class="keyword" href="https://d.hatena.ne.jp/keyword/APM">APM</a> events</td> </tr> <tr> <td><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>インフラ<br>(<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>や<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud)</td> <td>New Relic Infrastructure</td> <td>Metrics<br>Infrastructure integrations</td> </tr> <tr> <td>各種ログ</td> <td>New Relic Logs</td> <td>Logging</td> </tr> </tbody> </table> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdocs.newrelic.com%2Fjp%2Fdocs%2Fdata-apis%2Fmanage-data%2Fmanage-data-coming-new-relic%2F" title="データの取り込みを理解して管理する | New Relic Documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://docs.newrelic.com/jp/docs/data-apis/manage-data/manage-data-coming-new-relic/">docs.newrelic.com</a></cite></p> <p>今回はこちらの「取り込むデータ量」についてのお話です。</p> <h1 id="何が起こったのか">何が起こったのか</h1> <p>2022年4月のサービスリニューアル以降、定期的なNew Relic Agentのアップデートを行えていませんでした。New Relic Agentには定期的な<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%B0%A5%D5%A5%A3%A5%C3%A5%AF%A5%B9">バグフィックス</a>やセキュリティアップデートや機能追加が行われているため、2023年3月12日頃に諸々のAgentのアップデートを行いました。しかしアップデートを実施した結果、New Relic Browser Agent (Web) の更新によりBrowser eventsで取り込むデータ量が10倍程度に膨れ上がってしまいました。</p> <p><figure class="figure-image figure-image-fotolife" title="Browser eventsのデータ量が急増"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212182844.png" width="1200" height="345" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Browser eventsのデータ量が急増</figcaption></figure></p> <p>New Relicのサポートにもアップデート内容の確認や原因の調査についてご相談したのですが、残念ながらこれという決定的な証拠を見つけることができませんでした。可能性としては「当初の設定の不備により必要なデータを取得できていなかった」もしくは「分散トレーシング周りのアップデートがあり取得できるイベントが増えた」かと考えています。</p> <p><figure class="figure-image figure-image-fotolife" title="フロントエンド系のデータを扱うNew Relicアカウントで急激なデータ増加"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212162246.png" width="1200" height="674" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>フロントエンド系のデータを扱うNew Relicアカウントで急激なデータ増加</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="BrowserEventsBytesで急激なデータ増加"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212162243.png" width="1200" height="669" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>BrowserEventsBytesで急激なデータ増加</figcaption></figure></p> <p>当時はNew Relicを駆使してサービスの信頼性を可視化・担保するというミッションを推進していたため「今はどんどん可視化を進めていきたい」「何はともあれオブザーバビリティ」といった流れで進めていった結果、データ量やコストの意識が二の次になってしまいました。New Relicにかかるコストのオブザーバビリティは後回しになってしまい恥ずかしい限りです。</p> <p>特定のURLが高頻度で閲覧されていたり<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EC%A5%A4%A5%D4%A5%F3%A5%B0">スクレイピング</a>されている可能性も疑いましたが、全体的なイベント数が増加していることを確認して改善案を考えました。</p> <h1 id="改善">改善</h1> <p>取り込むデータ量の可視化と通知、そしてデータ量の削減という二軸で対応しました。</p> <h3 id="1-取り込むデータ量の可視化--定期的な通知">1. 取り込むデータ量の可視化 &amp; 定期的な通知</h3> <p>まずは「現状どのような取り込みデータ量になっているのか」「いつからデータ量が増加したのか」「どのデータソースで増加があったのか」を判断できるようなデータおよび<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>ボードを整備しました。そのためにNew Relicアカウント別のグラフとデータソース別のグラフを用意しました。</p> <p>NRQLだとこんな感じです。24時間のグラフだと増減がわかりにくかったので3日間のデータを毎日見るようにしています。</p> <pre class="code" data-lang="" data-unlink># [前日比] アカウント別のデータ量 SELECT rate(sum(GigabytesIngested), 1 day) AS avgGbIngestTimeseriesByAccount FROM NrConsumption WHERE productLine = &#39;DataPlatform&#39; FACET consumingAccountName TIMESERIES AUTO SINCE 3 days AGO COMPARE WITH 1 day ago</pre> <pre class="code" data-lang="" data-unlink># [前日比] データソース別のデータ量 SELECT rate(sum(GigabytesIngested), 1 day) AS avgGbIngestTimeseries FROM NrConsumption WHERE productLine = &#39;DataPlatform&#39; FACET usageMetric LIMIT MAX TIMESERIES AUTO SINCE 3 days AGO COMPARE WITH 1 day ago</pre> <p>上記のNRQLをグラフにしたのが下記の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EA%A1%BC%A5%F3%A5%B7%A5%E7%A5%C3%A5%C8">スクリーンショット</a>です。</p> <p><figure class="figure-image figure-image-fotolife" title="New Relic全体のデータ量推移 (アカウント別とデータソース別)"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212184139.png" width="1200" height="495" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>New Relic全体のデータ量推移 (アカウント別とデータソース別)</figcaption></figure></p> <p>また、バックエンド (New Relic <a class="keyword" href="https://d.hatena.ne.jp/keyword/APM">APM</a>, New Relic Infrastructure) に比べるとフロントエンド (New Relic Browser, New Relic Mobile) の方がデータ量にばらつきが大きいことがわかっているため、主要なイベント数の推移を把握できるグラフを用意しました。こちらも24時間のグラフだと増減がわかりにくかったので3日間のデータを毎日見るようにしています。</p> <pre class="code" data-lang="" data-unlink># とあるBrowserアプリケーションのグラフをイベントごとに作成 SELECT count(*) FROM AjaxRequest WHERE appName = &#39;&lt;ブラウザアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM BrowserInteraction WHERE appName = &#39;&lt;ブラウザアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM JavaScriptError WHERE appName = &#39;&lt;ブラウザアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM PageView WHERE appName = &#39;&lt;ブラウザアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM PageViewTiming WHERE appName = &#39;&lt;ブラウザアプリ&gt;&#39; TIMESERIES SINCE 3 days ago</pre> <pre class="code" data-lang="" data-unlink># とあるMobileアプリケーションのグラフをイベントごとに作成 SELECT count(*) FROM Mobile WHERE appName = &#39;&lt;モバイルアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM MobileCrash WHERE appName = &#39;&lt;モバイルアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM MobileRequest WHERE appName = &#39;&lt;モバイルアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM MobileRequestError WHERE appName = &#39;&lt;モバイルアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM MobileSession WHERE appName = &#39;&lt;モバイルアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM MobileVideo WHERE appName = &#39;&lt;モバイルアプリ&gt;&#39; TIMESERIES SINCE 3 days ago SELECT count(*) FROM Span WHERE appName = &#39;&lt;モバイルアプリ&gt;&#39; TIMESERIES</pre> <p>上記のNRQLをグラフにしたのが下記の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EA%A1%BC%A5%F3%A5%B7%A5%E7%A5%C3%A5%C8">スクリーンショット</a>です。各グラフをStacked Bar形式にして積み上げて確認しています。</p> <p><figure class="figure-image figure-image-fotolife" title="Browser系のイベント数推移"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212184443.png" width="1200" height="418" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Browser系のイベント数推移</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="Mobile系のイベント数推移"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212184705.png" width="1200" height="421" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Mobile系のイベント数推移</figcaption></figure></p> <p>推移を見るグラフが整備できたのであればあとは通知です。クラスメソッド株式会社の新井成一さんがNew Relicの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>ボードをSlackへ定期的に投稿するためのツールを公開してくれていたため、こちらを利用させていただきました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fseiichi1101%2Fnewrelic-dashboard-slack-exporter" title="GitHub - seiichi1101/newrelic-dashboard-slack-exporter: This generate aws resources that notify newrelic dashboard snapshot to slack." class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/seiichi1101/newrelic-dashboard-slack-exporter">github.com</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdev.classmethod.jp%2Farticles%2Fnewrelic-dashboard-slack-exporter%2F" title="NewRelicのダッシュボードのスナップショットを定期的にSlackへ送信する仕組みをAWSで作ってみた | DevelopersIO" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://dev.classmethod.jp/articles/newrelic-dashboard-slack-exporter/">dev.classmethod.jp</a></cite></p> <p>実際にSlackに送られるとこのような感じになります。</p> <p><figure class="figure-image figure-image-fotolife" title="Slack通知"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212191240.png" width="1200" height="848" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Slack通知</figcaption></figure></p> <p>これにより、データ量の推移と異常を見逃すことがなくなりました。Anomalyでデータ容量に対してアラートを設定するのもアリかもしれません。</p> <h3 id="2-取り込みデータ量の削減">2. 取り込みデータ量の削減</h3> <p>New Relicで取り込みデータ量を削減するには「取り込みデータのサンプリングを実施する」か「Data <a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleを設定してデータの除外設定をする」という2つの方法があります。当時はデータのサンプリングについての検証が行えていなかったため、素直にData <a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleを設定して不要なデータを除外する方向で対応しました。</p> <p>Data <a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> RuleについてはNerdGraphというGraphQLの<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>を利用してデータを除外するためのルールを作成・削除することが可能です。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdocs.newrelic.com%2Fjp%2Fdocs%2Fdata-apis%2Fmanage-data%2Fdrop-data-using-nerdgraph%2F" title="NerdGraphでデータを落とす | New Relic Documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://docs.newrelic.com/jp/docs/data-apis/manage-data/drop-data-using-nerdgraph/">docs.newrelic.com</a></cite></p> <p><a href="https://one.newrelic.com/nerdgraph-graphiql">NerdGraph API Explorer</a> にアクセスすると下記のような画面が表示されます。</p> <p><figure class="figure-image figure-image-fotolife" title="NerdGraph API Explorer"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212225852.png" width="1200" height="754" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>NerdGraph <a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Explorer">Explorer</a></figcaption></figure></p> <p>例えば<a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleの一覧を取得したい場合には下記のようなクエリを入力して実行することで<a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleの一覧を取得することが可能です。</p> <pre class="code" data-lang="" data-unlink>{ actor { account(id: &lt;対象となるNew RelicのアカウントID&gt;) { nrqlDropRules { list { rules { id nrql accountId action createdBy createdAt description } error { reason description } } } } } } </pre> <p>また、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleを追加したい場合には下記のようなクエリを入力して実行することで<a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleを追加することが可能です。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/DROP">DROP</a>_DATAは指定したNRQLに該当するデータを除外するもの、<a class="keyword" href="https://d.hatena.ne.jp/keyword/DROP">DROP</a>_ATTRIBUTESはNRQLに該当する属性・カラムのデータのみを除外することが可能です。</p> <pre class="code" data-lang="" data-unlink>mutation { nrqlDropRulesCreate( accountId: &lt;対象となるNew RelicのアカウントID&gt; rules: {action: &lt;DROP_DATA|DROP_ATTRIBUTES&gt;, description: &#34;&lt;Dropルールの説明&gt;&#34;, nrql: &#34;&lt;Dropしたいデータを抽出するためのNRQL&gt;&#34;} ) { failures { error { description reason } } successes { account { id name } accountId action createdAt createdBy description creator { id name } id source nrql } } }</pre> <p>しかしNerdGraphはあまり利便性が高いとは言えないため、ここに関してはTerraformで管理することをおすすめします。</p> <pre class="code" data-lang="" data-unlink># drop_dataの例 resource &#34;newrelic_nrql_drop_rule&#34; &#34;foo&#34; { account_id = 12345 description = &#34;Drops all data for MyCustomEvent that comes from the LoadGeneratingApp in the dev environment, because there is too much and we don’t look at it.&#34; action = &#34;drop_data&#34; nrql = &#34;SELECT * FROM MyCustomEvent WHERE appName=&#39;LoadGeneratingApp&#39; AND environment=&#39;development&#39;&#34; } # drop_attributeの例 resource &#34;newrelic_nrql_drop_rule&#34; &#34;bar&#34; { account_id = 12345 description = &#34;Removes the user name and email fields from MyCustomEvent&#34; action = &#34;drop_attributes&#34; nrql = &#34;SELECT userEmail, userName FROM MyCustomEvent&#34; }</pre> <p><strong>Resource: newrelic_nrql_<a class="keyword" href="https://d.hatena.ne.jp/keyword/drop">drop</a>_rule</strong> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fregistry.terraform.io%2Fproviders%2Fnewrelic%2Fnewrelic%2Flatest%2Fdocs%2Fresources%2Fnrql_drop_rule" title="Terraform Registry" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://registry.terraform.io/providers/newrelic/newrelic/latest/docs/resources/nrql_drop_rule">registry.terraform.io</a></cite></p> <p>Data <a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleの整備により不要なデータを除外することに成功しました。オレンジ色のBrowser eventsの領域が小さくなっていることがわかります。この後に青のMobile eventsを最適化するために<a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleの調整を行っています。</p> <p><figure class="figure-image figure-image-fotolife" title="Plan &amp; usageにてBrowser eventsの減少を確認"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212232902.png" width="1200" height="310" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Plan &amp; usageにてBrowser eventsの減少を確認</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="フロントエンド系のデータを扱うNew Relicアカウントでデータの減少を確認"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212232938.png" width="1200" height="669" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>フロントエンド系のデータを扱うNew Relicアカウントでデータの減少を確認</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="BrowserEventsBytesのデータ減少を確認"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212233055.png" width="1200" height="678" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>BrowserEventsBytesのデータ減少を確認</figcaption></figure></p> <h1 id="今後の展望">今後の展望</h1> <p>現在モバイル<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%D7%A5%EA%B3%AB%C8%AF">アプリ開発</a>にて取り込みデータのサンプリングの検証を進めており、Data <a class="keyword" href="https://d.hatena.ne.jp/keyword/Drop">Drop</a> Ruleとサンプリングの併用でデータ量の最適化を行う予定です。</p> <p>私達が不要と考えて除外している特定のデータが実はユーザーの体験に関わる問題に関連しており、それを見逃してしまうという可能性を回避したいというのが背景です。本来であれば全てのデータを取得したうえで一律に削減したほうが良いと考えていますが、まだまだ検証中の段階でありリリースは2024年前半の見込みです。</p> <h1 id="まとめ">まとめ</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>におけるオブザーバビリティの導入・推進の裏側で発生していたデータ量とコストの問題にフォーカスした記事でした。<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D1%A5%D6%A5%EA%A5%C3%A5%AF%A5%AF%A5%E9%A5%A6%A5%C9">パブリッククラウド</a>も<a class="keyword" href="https://d.hatena.ne.jp/keyword/SaaS">SaaS</a>も便利ですが請求に影響するデータのチェックを怠ってはいけません。1つの設定変更で大きな請求が発生してしまう可能性があります。まずはしっかりと状況を可視化したうえで対処していきましょう。</p> <p>余談ですが、株式会社ヘンリー様のエンジニアブログにある「オブザーバビリティにはお金がかかる」という記事を拝見しまして「私も会社にはNew Relicとオブザーバビリティの重要さについて説明してきたし理解して貰ってると思うけど、とはいえ安くはないし悩ましいよなぁ・・・」という思いから今回の記事の執筆のモチベーションとさせていただきました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdev.henry.jp%2Fentry%2Fobservability-and-cost" title="オブザーバビリティにはお金がかかる - 株式会社ヘンリー エンジニアブログ" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://dev.henry.jp/entry/observability-and-cost">dev.henry.jp</a></cite></p> tver-techblog BigQueryのNULLの扱いまとめ hatenablog://entry/6801883189064693184 2023-12-12T12:17:24+09:00 2023-12-12T12:17:24+09:00 こんにちは、TVerでデータ分析をしている高橋です。 こちらは TVer Advent Calendar 2023 の12日目の記事です。 弊社の分析業務は、主にBigQueryに蓄積されたデータを対象としています。データ処理の効率を向上させるため、データの前処理から集計までを一貫してSQLクエリで実施しています。この過程でNULL値の取り扱いは避けて通れない重要なテーマとなっています。 この記事では、(直近タスクでNULL含む処理の検証に多くの時間を溶かした筆者が)弊社で頻繁に使用されるSQLクエリの処理においてNULLがどのように扱われるかをまとめたのでご紹介します。 チートシート 今回調… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>でデータ分析をしている高橋です。<br/> こちらは <a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023 の12日目の記事です</a>。<br/> 弊社の分析業務は、主にBigQueryに蓄積されたデータを対象としています。データ処理の効率を向上させるため、データの前処理から集計までを一貫して<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>クエリで実施しています。この過程で<code>NULL</code>値の取り扱いは避けて通れない重要なテーマとなっています。<br/> この記事では、(直近タスクで<code>NULL</code>含む処理の検証に多くの時間を溶かした筆者が)弊社で頻繁に使用される<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>クエリの処理においてNULLがどのように扱われるかをまとめたのでご紹介します。</p> <h1 id="チートシート"><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C1%A1%BC%A5%C8%A5%B7%A1%BC%A5%C8">チートシート</a></h1> <p>今回調べた内容を整理すると以下の3パターンになりました。</p> <table> <thead> <tr> <th>種類</th> <th><a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a>、構文、関数など</th> </tr> </thead> <tbody> <tr> <td><code>NULL</code>として扱われる</td> <td>四則<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a>, ビット<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a>, 比較<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a>, 論理<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a>, <br>ARRAY_AGG, FIRST_<a class="keyword" href="https://d.hatena.ne.jp/keyword/VALUE">VALUE</a>, LAST_<a class="keyword" href="https://d.hatena.ne.jp/keyword/VALUE">VALUE</a>, ORDER BY</td> </tr> <tr> <td>無視される</td> <td><a class="keyword" href="https://d.hatena.ne.jp/keyword/AVG">AVG</a>, MAX, MIN, SUM, STRING_AGG, LOGICAL_AND, LOGICAL_OR, COUNT</td> </tr> <tr> <td><code>FALSE</code> として扱われる</td> <td>CASE, IF</td> </tr> </tbody> </table> <p>以下、サンプルクエリとともに個別に見ていきます。</p> <h1 id="演算子"><a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a></h1> <p><a href="%E2%80%8Bhatena:http-notation:1d2b8798249a2e5f2ba15df40bba41aa4eae05d5%E2%80%8B">公式ドキュメント</a>には、特に指定がない場合、すべての<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a>において被<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a>のいずれかが <code>NULL</code> の場合は<code>NULL</code> を返す、と記載されています。</p> <p>例えば以下のクエリは全て<code>NULL</code> を返します。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> <span class="synComment">-- NULL = 1 &lt;-- これはエラーが発生する</span> <span class="synIdentifier">CAST</span>(<span class="synSpecial">NULL</span> <span class="synSpecial">AS</span> INT64) = <span class="synConstant">1</span>, <span class="synComment">--&gt; NULL</span> <span class="synIdentifier">CAST</span>(<span class="synSpecial">NULL</span> <span class="synSpecial">AS</span> INT64) + <span class="synConstant">1</span>, <span class="synComment">--&gt; NULL</span> <span class="synIdentifier">CAST</span>(<span class="synSpecial">NULL</span> <span class="synSpecial">AS</span> INT64) &lt; <span class="synConstant">1</span> , <span class="synComment">--&gt; NULL</span> </pre> <p><a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/operators#logical_operators">論理演算子</a>の場合は3値論理に基づいて判定が行われます。<br/> 被<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B1%E9%BB%BB%BB%D2">演算子</a>に<code>NULL</code>を含んでいながら<code>NULL</code>ではない値が返ってくるケースがあるようです。</p> <p><figure class="figure-image figure-image-fotolife" title="公式ドキュメントより"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231207/20231207092144.png" width="566" height="557" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>公式ドキュメントから引用</figcaption></figure></p> <h1 id="条件式">条件式</h1> <p><a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/conditional_expressions#case_expr">CASE文</a>で<code>FALSE</code>と<code>NULL</code>は区別されないようです。<br/> 以下のクエリを実行すると、すべてのWHEN句で<code>NULL</code>となるので<code>unknown</code>が返ってきます。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> <span class="synSpecial">CASE</span> <span class="synSpecial">WHEN</span> <span class="synSpecial">NULL</span> <span class="synStatement">AND</span> <span class="synSpecial">TRUE</span> <span class="synSpecial">THEN</span> <span class="synSpecial">&quot;</span><span class="synConstant">a</span><span class="synSpecial">&quot;</span> <span class="synSpecial">WHEN</span> <span class="synIdentifier">CAST</span>(<span class="synSpecial">NULL</span> <span class="synSpecial">AS</span> INT64) = <span class="synConstant">1</span> <span class="synSpecial">THEN</span> <span class="synSpecial">&quot;</span><span class="synConstant">b</span><span class="synSpecial">&quot;</span> <span class="synSpecial">ELSE</span> <span class="synSpecial">&quot;</span><span class="synConstant">unknown</span><span class="synSpecial">&quot;</span> <span class="synSpecial">END</span> <span class="synComment">--&gt; &quot;unknown&quot;</span> </pre> <p><a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/conditional_expressions#if">IF文</a>も同様です。以下クエリを実行すると2が返ってきます。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> <span class="synSpecial">IF</span>(<span class="synSpecial">NULL</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>) <span class="synSpecial">AS</span> col1 <span class="synComment">--&gt; 2</span> </pre> <h1 id="集計関数">集計関数</h1> <p><a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/aggregate_functions#function_list">集計関数</a>のうち、<code>AVG, MAX, MIN, SUM, STRING_AGG</code>は<code>non-NULL</code>値を対象として処理が行われるようです。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> <span class="synIdentifier">AVG</span>(val) <span class="synSpecial">AS</span> avg_val, <span class="synComment">--&gt; 3.0</span> <span class="synIdentifier">MAX</span>(val) <span class="synSpecial">AS</span> max_val, <span class="synComment">--&gt; 4</span> <span class="synIdentifier">MIN</span>(val) <span class="synSpecial">AS</span> min_val, <span class="synComment">--&gt; 2</span> <span class="synIdentifier">SUM</span>(val) <span class="synSpecial">AS</span> sum_val, <span class="synComment">--&gt; 6</span> STRING_AGG(<span class="synIdentifier">CAST</span>(val <span class="synSpecial">AS</span> STRING)) <span class="synSpecial">AS</span> str_vals <span class="synComment">--&gt; &quot;2,4&quot;</span> <span class="synSpecial">FROM</span> ( <span class="synStatement">SELECT</span> val <span class="synSpecial">FROM</span> UNNEST(ARRAY[<span class="synConstant">2</span>, <span class="synConstant">4</span>, <span class="synSpecial">NULL</span>]) <span class="synSpecial">AS</span> val ) </pre> <p><code>LOGICAL_AND, LOGICAL_OR</code> も同様に<code>non-NULL</code>値を対象として処理が行われます。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> LOGICAL_AND(flag), <span class="synComment">--&gt; [TRUE, FALSE] の AND なので FALSE</span> LOGICAL_OR(flag) <span class="synComment">--&gt; [TRUE, FALSE] の OR なので TRUE</span> <span class="synSpecial">FROM</span> UNNEST(ARRAY[<span class="synSpecial">TRUE</span>, <span class="synSpecial">FALSE</span>, <span class="synSpecial">NULL</span>]) <span class="synSpecial">AS</span> flag </pre> <p><code>COUNT</code> は入力の行数または式が<code>NULL</code>以外の値に評価された行数を取得します。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> <span class="synIdentifier">COUNT</span>(<span class="synConstant">1</span>), <span class="synComment">--&gt; 3</span> <span class="synIdentifier">COUNT</span>(flag), <span class="synComment">--&gt; 2</span> <span class="synIdentifier">COUNT</span>(<span class="synSpecial">NULL</span>) <span class="synComment">--&gt; 0</span> <span class="synSpecial">FROM</span> UNNEST(ARRAY[<span class="synSpecial">TRUE</span>, <span class="synSpecial">FALSE</span>, <span class="synSpecial">NULL</span>]) <span class="synSpecial">AS</span> flag </pre> <p><code>ARRAY_AGG</code> は配列に<code>NULL</code>要素が含まれているとエラーが発生します。<br/> <code>IGNORE NULLS</code>で除外してあげましょう。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> <span class="synComment">-- ARRAY_AGG(val) AS arr --&gt; Error</span> ARRAY_AGG(val IGNORE NULLS) <span class="synSpecial">AS</span> arr <span class="synComment">--&gt; [2,4]</span> <span class="synSpecial">FROM</span> ( <span class="synStatement">SELECT</span> val <span class="synSpecial">FROM</span> UNNEST(ARRAY[<span class="synConstant">2</span>, <span class="synConstant">4</span>, <span class="synSpecial">NULL</span>]) <span class="synSpecial">AS</span> val ) </pre> <h1 id="ナビゲーション関数">ナビゲーション関数</h1> <p><code>FIRST_VALUE, LAST_VALUE</code>は<code>NULL</code>値を含んで計算されます。<br/> 例えば、ユーザーが最後に視聴した日付を日次で取得する処理を考えます。<br/> この場合<code>IGNORE NULLS</code>オプションで<code>NULL</code>を無視することで所望の結果を得ることができます。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synSpecial">WITH</span> play_logs <span class="synSpecial">AS</span> ( <span class="synStatement">SELECT</span> <span class="synSpecial">&quot;</span><span class="synConstant">xxx</span><span class="synSpecial">&quot;</span> <span class="synSpecial">AS</span> user_id, day, logs.begin_d <span class="synSpecial">IS</span> <span class="synStatement">NOT</span> <span class="synSpecial">NULL</span> <span class="synSpecial">AS</span> has_played, <span class="synSpecial">FROM</span> UNNEST(GENERATE_TIMESTAMP_ARRAY( <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2023-12-01 00:00:00</span><span class="synSpecial">&quot;</span>), <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2023-12-05 00:00:00</span><span class="synSpecial">&quot;</span>), INTERVAL <span class="synConstant">1</span> DAY )) <span class="synSpecial">AS</span> day <span class="synSpecial">LEFT</span> <span class="synSpecial">OUTER</span> <span class="synSpecial">JOIN</span> ( <span class="synStatement">SELECT</span> begin_d <span class="synSpecial">FROM</span> UNNEST(ARRAY[ <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2023-12-01 00:00:00</span><span class="synSpecial">&quot;</span>), <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2023-12-02 00:00:00</span><span class="synSpecial">&quot;</span>), <span class="synType">TIMESTAMP</span>(<span class="synSpecial">&quot;</span><span class="synConstant">2023-12-05 00:00:00</span><span class="synSpecial">&quot;</span>) ]) <span class="synSpecial">AS</span> begin_d ) <span class="synSpecial">AS</span> logs <span class="synSpecial">ON</span> day = logs.begin_d ) <span class="synStatement">SELECT</span> *, LAST_VALUE(<span class="synSpecial">IF</span>(has_played, day, <span class="synSpecial">NULL</span>)) OVER(PARTITION <span class="synSpecial">BY</span> user_id <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> day <span class="synSpecial">ASC</span> <span class="synSpecial">ROWS</span> <span class="synStatement">BETWEEN</span> UNBOUNDED PRECEDING <span class="synStatement">AND</span> <span class="synSpecial">CURRENT</span> <span class="synSpecial">ROW</span>) <span class="synSpecial">AS</span> day_last_played, LAST_VALUE(<span class="synSpecial">IF</span>(has_played, day, <span class="synSpecial">NULL</span>) IGNORE NULLS) OVER(PARTITION <span class="synSpecial">BY</span> user_id <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> day <span class="synSpecial">ASC</span> <span class="synSpecial">ROWS</span> <span class="synStatement">BETWEEN</span> UNBOUNDED PRECEDING <span class="synStatement">AND</span> <span class="synSpecial">CURRENT</span> <span class="synSpecial">ROW</span>) <span class="synSpecial">AS</span> day_last_played_ignore_nulls <span class="synSpecial">FROM</span> play_logs </pre> <p><figure class="figure-image figure-image-fotolife" title="実行結果"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231208/20231208101416.png" width="860" height="246" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>実行結果</figcaption></figure></p> <h1 id="ORDER-BY句">ORDER BY句</h1> <p>昇順に並べると<code>NULL</code>は一番先頭に来るようです。<br/> 順序は以下の通り(<a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#orderable_floating_points">公式doc</a>)。</p> <p><figure class="figure-image figure-image-fotolife" title="はいはいなるほどNULLが最初で...NaN?"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231208/20231208092836.png" width="528" height="334" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>はいはいなるほどNULLが最初で...NaN?</figcaption></figure></p> <p><code>NaN (Not a Number)</code>は不正な演算を行った場合に返ってくる値のようです(<code>SELECT IEEE_DIVIDE(0, 0)</code>は<code>NaN</code>を返す)。<br/> <code>NULLS LAST</code>オプションで<code>NULL</code>を末尾に追いやることが可能です。</p> <pre class="code lang-sql" data-lang="sql" data-unlink><span class="synStatement">SELECT</span> val <span class="synSpecial">FROM</span> UNNEST(ARRAY[<span class="synConstant">1</span>, <span class="synConstant">3</span>, <span class="synConstant">2</span>, <span class="synSpecial">NULL</span>]) <span class="synSpecial">AS</span> val <span class="synSpecial">ORDER</span> <span class="synSpecial">BY</span> val NULLS <span class="synIdentifier">LAST</span> </pre> <p><figure class="figure-image figure-image-fotolife" title="1が先頭になりました"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231212/20231212094058.png" width="442" height="481" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>1が先頭になりました</figcaption></figure></p> <h1 id="まとめ">まとめ</h1> <ul> <li><code>NULL</code>含む論理演算と条件式は難しいので<code>NULL</code>埋めしてあげたい</li> <li>ORDER BY句の<code>NULLS LAST</code>は便利そう</li> </ul> <h1 id="最後に">最後に</h1> <p>ニッチ感の否めない記事となりましたが、このように<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>ではデータ分析を通じてより確<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A4%AB%A4%E9%A4%B7">からし</a>い示唆を得ようと日々精進を重ねています。<br/> もしご興味があれば以下よりご連絡ください。お待ちしております!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Frecruit.tver.co.jp%2F" title="株式会社TVer 採用サイト" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://recruit.tver.co.jp/">recruit.tver.co.jp</a></cite></p> tver-techblog Inter BEE 2023 参加レポート & Media-JAWSを開催しました #interbee #mediajaws hatenablog://entry/6801883189062005521 2023-12-04T11:59:59+09:00 2023-12-04T12:28:20+09:00 こんにちは、TVerの加我です。 こちらは TVer Advent Calendar 2023 の4日目の記事です。 先日Inter BEE 2023に併せてMedia-JAWSを開催しましたのでそちらのレポートになります。 昨年のレポートはこちら。 techblog.tver.co.jp Inter BEE 2023 今年は11/15 - 11/17にかけて幕張メッセで開催されました。Inter BEE自体の説明については昨年のレポートをご覧ください。 会場 昨年は予備知識というか業界知識がゼロの状態で参加したので展示を見ても何が何やらという状態でしたが、今年は多少なりとも知識があったので展… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の加我です。<br/> こちらは <a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a> の4日目の記事です。</p> <p>先日<a class="keyword" href="https://d.hatena.ne.jp/keyword/Inter%20BEE">Inter BEE</a> 2023に併せてMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>を開催しましたのでそちらのレポートになります。</p> <p>昨年のレポートはこちら。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Finter-bee-2022-and-media-jaws" title="Inter BEE 2022 参加レポート &amp; Media-JAWSで登壇してきました #interbee2022 #mediajaws - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/inter-bee-2022-and-media-jaws">techblog.tver.co.jp</a></cite></p> <h1 id="Inter-BEE-2023"><a class="keyword" href="https://d.hatena.ne.jp/keyword/Inter%20BEE">Inter BEE</a> 2023</h1> <p>今年は11/15 - 11/17にかけて<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CB%EB%C4%A5%A5%E1%A5%C3%A5%BB">幕張メッセ</a>で開催されました。<a class="keyword" href="https://d.hatena.ne.jp/keyword/Inter%20BEE">Inter BEE</a>自体の説明については昨年のレポートをご覧ください。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130234452.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h2 id="会場">会場</h2> <p>昨年は予備知識というか業界知識がゼロの状態で参加したので展示を見ても何が何やらという状態でしたが、今年は多少なりとも知識があったので展示機材を見て「それが何であるか」程度は理解できました。とはいえ、放送に関する技術要素を体系的に学んだわけではないので「名前だけは聞いたことがある」程度のレベルのままですが・・・。</p> <p><figure class="figure-image figure-image-fotolife" title="実際に納品されたというサブ (デジタルミキシングコンソール)"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130234610.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>実際に納品されたというサブ (デジタルミキシングコンソール)</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="いつもお世話になっているNew Relic様のブース"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130234828.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>いつもお世話になっているNew Relic様のブース</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="ちょっと気になった在京放送局システム会社アライアンス"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231201/20231201001256.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>ちょっと気になった在京放送局システム会社アライアンス</figcaption></figure></p> <p>在京放送局システム会社アライアンスについて補足しておきますと、放送関連のシステムなどで各局が協力できる領域についてはみんなで協力してDX推進を行い、そのうえでコンテンツで勝負しようというのがコンセプトの団体とのことです。</p> <blockquote><p>現在の放送局システム会社にはいくつかの共通して抱えている課題があります。人的リソースからITインフラに至るまで、広範囲の課題をスピード感を持って解決するには限界があります。この背景から、各社との協調領域を定義し、協力体制を構築する試みを開始しました。その第一歩として『在京放送局システム会社アライアンス』をスタートし、新機軸と最適化軸の両輪で放送業界のDX推進を目指します。</p></blockquote> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnewscast.jp%2Fnews%2F5866318" title="2023年国際放送機器展(Inter BEE 2023) 在京放送局システム会社アライアンス共同出展に関して" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://newscast.jp/news/5866318">newscast.jp</a></cite></p> <h2 id="セッション-1">セッション (1)</h2> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>様のブースにてブライトコーブ様との対談形式のセッションがあり、弊社から2名が登壇いたしました。</p> <p><figure class="figure-image figure-image-fotolife" title="対談セッション"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130234907.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>対談セッション</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="ブライトコーブ様との対談形式セッション"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130215634.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>ブライトコーブ様との対談形式セッション</figcaption></figure></p> <p>11/15と11/17はモバイルアプリとWebアプリケーションのディレクターを務める岡田 銀平が担当し、11/16はAndroidTV・FireTVといったコネクテッドTV (CTV) のディレクターを務める若林 紘大が担当しました。</p> <p><figure class="figure-image figure-image-fotolife" title="ディレクターの岡田 銀平"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130221828.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>ディレクターの岡田 銀平</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="ディレクターの若林 紘大"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130222052.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>ディレクターの若林 紘大</figcaption></figure></p> <p>セッションでは「導入前の課題とブライトコーブを選んだ理由」「ブライトコーブ導入後の放送局との連携に関する変化」などについて対談が行われました。お二人ともお疲れ様でした!</p> <h2 id="セッション-2">セッション (2)</h2> <p>11/15に民放技術報告会 企画セッションにて「CTV上の諸技術に関する研究と考察」というセッションを聴講しました。</p> <p>技術的な側面からコネクテッドTVを分析し、ユーザー体験など将来的にどうあるべきなのかといった話が勉強になりました。セッションでは米国FASTや、英国Freeviewなどを参考にさせて頂いたとのことです。<br/> 残念ながらこちらのセッションについては<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A1%BC%A5%AB%A5%A4%A5%D6">アーカイブ</a>配信は行われていませんが、主な内容は「放送技術誌 (兼六館出版) 11月号」にまとめられています。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.inter-bee.com%2Fja%2Fforvisitors%2Fconference%2Fsession%2F%3Fconference_id%3D2423" title="コンファレンス詳細 - JBA-152 (アーカイブ中) | 映像・音響、放送・通信業界の情報発信サイト INTER BEE 2023" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.inter-bee.com/ja/forvisitors/conference/session/?conference_id=2423">www.inter-bee.com</a></cite></p> <p><figure class="figure-image figure-image-fotolife" title="まいとうさんによるCTVの技術に関する研究と考察"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231201/20231201005535.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>まいとうさんによるCTVの技術に関する研究と考察</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="CTVデバイスの視聴時間割合は増えているとの調査結果"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231201/20231201011025.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>CTVデ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9">バイス</a>の視聴時間割合は増えているとの調査結果</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="放送についてはARIB等の標準規格があるが、CTVのアプリの機能については各ベンダーの仕様に基づくサービスが展開されている"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231201/20231201010727.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>放送については<a class="keyword" href="https://d.hatena.ne.jp/keyword/ARIB">ARIB</a>等の標準規格があるが、CTVのアプリの機能については各ベンダーの仕様に基づくサービスが展開されている</figcaption></figure></p> <h2 id="セッション-3">セッション (3)</h2> <p>11/17にNew Relic様の出展者<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BB%A5%DF">セミ</a>ナー 企画セッションにて「TBS IDの構築によるサービス統合とグループ全体の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B7%A5%CA%A5%B8%A1%BC">シナジー</a>: VISION2030に向けた内製化への挑戦」というセッションを聴講しました。</p> <p>TBS様がTBS IDを開発・運用するにあたってNew Relicをどのように導入したのか、オブザーバビリティがどのように内製化に寄与したのかをお話頂きました。最後にQ&amp;Aにて質問させていただいたのですが、丁寧に回答いただきありがとうございました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.inter-bee.com%2Fja%2Fforvisitors%2Fconference%2Fsession%2F%3Fconference_id%3D2417" title="コンファレンス詳細 - ES1-171 (アーカイブ中) | 映像・音響、放送・通信業界の情報発信サイト INTER BEE 2023" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.inter-bee.com/ja/forvisitors/conference/session/?conference_id=2417">www.inter-bee.com</a></cite></p> <h1 id="Media-JAWS-14">Media-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> #14</h1> <p>昨年に引き続き今年も<a class="keyword" href="https://d.hatena.ne.jp/keyword/Inter%20BEE">Inter BEE</a> 2023に併せてMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>を開催しました。思えば昨年11月に開催されたMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>から運営に携わることになりあっという間の1年でした。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fmedia-jaws.doorkeeper.jp%2Fevents%2F164378" title="Media-JAWS【第14回】InterBEEに合わせて幕張開催!#jawsug #mediajaws" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://media-jaws.doorkeeper.jp/events/164378">media-jaws.doorkeeper.jp</a></cite></p> <p>昨年は<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>様のプライベート<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BB%A5%DF">セミ</a>ナーとして会議室を使わせていただいたのですが、今年は自分たちで会場を探すことになり<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%A4%C9%CD%CB%EB%C4%A5">海浜幕張</a>付近の貸し会議室を検討することになりました。いくつか候補を挙げた中から「キャパシティと予算感が適当で、かつ会場と同じビルの居酒屋で懇親会ができる」という理由でイオンコンパス幕張会議室を利用させていただきました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=http%3A%2F%2Fwww.aeoncompass-kaigishitsu.com%2Fmakuhari%2F" title="海浜幕張駅南口徒歩1分!イオンコンパス幕張会議室" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="http://www.aeoncompass-kaigishitsu.com/makuhari/">www.aeoncompass-kaigishitsu.com</a></cite></p> <p>今回の開催では<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>で会場スポンサーをさせていただいたのと、バックエンドエンジニアの伊藤が<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGでの初登壇を成し遂げました。登壇の詳細については後日こちらのブログにて共有して貰える予定です。</p> <p>伊藤については4月の<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Summit Tokyo 2023に参加したときに<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG周りの人と話して良い刺激を受けたようで、今回の登壇について相談した際に快く引き受けてくれました。非常に嬉しく思います。</p> <p><figure class="figure-image figure-image-fotolife" title="会場スポンサーをさせていただきました"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130205742.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>会場スポンサーをさせていただきました</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="TVerバックエンドエンジニアの伊藤"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130224808.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>バックエンドエンジニアの伊藤</figcaption></figure></p> <p>そして、今回の<a class="keyword" href="https://d.hatena.ne.jp/keyword/Inter%20BEE">Inter BEE</a> + Media-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>に併せて<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>のIVS (<a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon">Amazon</a> Interactive Video Service) のチームが来日し登壇していただけることになりました。運営メンバーの1人としてこの場を借りてお礼申し上げます。</p> <p>過去にオンラインで開催された<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGのイベントにて<a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon">Amazon</a> IVSを利用していること、<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGの中でもメディア系企業の登壇が多いMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>と<a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon">Amazon</a> IVSとの親和性が高いとの理由からコラボレーションに至りました。ステッカーやTシャツ、靴下など大量の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%CE%A5%D9%A5%EB%A5%C6%A5%A3">ノベルティ</a>を持参していただきイベントを盛り上げてくれました。改めてありがとうございました!</p> <p><figure class="figure-image figure-image-fotolife" title="IVSステッカー"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130164319.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>IVSステッカー</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="IVS Tシャツ"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130164345.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>IVS Tシャツ</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="IVSチーム"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130205624.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>IVSチーム</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="IVチームのHaoさんとToddさん"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130213425.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>IVチームのHaoさんとToddさん</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="Amazon IVSリアルタイムストリーミングのデモ"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130213726.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon">Amazon</a> IVSリアルタイムストリーミングのデモ</figcaption></figure></p> <p>今回のMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>では<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CB%CC%B3%A4%C6%BB%CA%B8%B2%BD%CA%FC%C1%F7">北海道文化放送</a>様と<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C0%C5%B2%AC%CA%FC%C1%F7">静岡放送</a>様に初登壇していただけました。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%CB%CC%B3%A4%C6%BB%CA%B8%B2%BD%CA%FC%C1%F7">北海道文化放送</a>の杉本さんとは今年の夏季休暇で札幌に帰省したときに知り合ったのですが、先日11月4日に札幌で開催された <a href="https://connpass.com/event/295336/">AWSカーニバル</a> でお会いした際に「<a class="keyword" href="https://d.hatena.ne.jp/keyword/Inter%20BEE">Inter BEE</a>参加されますか?Media-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>興味ありませんか?もしよければ登壇いかがですか?」といった若干強引な流れでお誘いしまして登壇していただけました。</p> <p><figure class="figure-image figure-image-fotolife" title="北海道文化放送の杉本さん"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130210522.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/%CB%CC%B3%A4%C6%BB%CA%B8%B2%BD%CA%FC%C1%F7">北海道文化放送</a>の杉本さん</figcaption></figure></p> <p>杉本さんの登壇内容は個人的にとても魅力的だと感じていまして「弊社ではまだFAXを使っています」からの「FAXで送られてきた原稿をFAXを<a class="keyword" href="https://d.hatena.ne.jp/keyword/OCR">OCR</a>で文字起こしして<a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon">Amazon</a> Bedrockで原稿を作成し、手直ししたものをPollyで音声化して<a class="keyword" href="https://d.hatena.ne.jp/keyword/YouTube">YouTube</a>でAI自動音声ニュースとして配信してます」というレガシーとモダンの温度差にやられそうになりました。杉本さんは純粋なエンジニアではなく、しかも<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>歴は2年とのことで強い衝撃を受けました。</p> <p><iframe id="talk_frame_1107436" class="speakerdeck-iframe" src="//speakerdeck.com/player/6cbdf5dbd2ad4ea8a1d52b54c8a9659b" width="710" height="399" style="aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/ayuki_sugimoto/15-media-jaws-ee2d2bad-7d88-4177-a95e-d8cc75aca027">speakerdeck.com</a></cite></p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%C0%C5%B2%AC%CA%FC%C1%F7">静岡放送</a>様ではコミュニケーション改善のためのサービス開発をされている話や、放送局と<a class="keyword" href="https://d.hatena.ne.jp/keyword/VTuber">VTuber</a>がコラボして地元の盛り上げに貢献していたりテレビ局のオープニング映像にも起用しているという面白い話がありました。後者は直接的な技術的の話ではありませんが、放送局が手掛けるビジネスの一環ということで興味深く聞かせていただきました。</p> <p><figure class="figure-image figure-image-fotolife" title="静岡放送 高橋さん"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130212530.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/%C0%C5%B2%AC%CA%FC%C1%F7">静岡放送</a> 高橋さん</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="静岡放送 牧野さん"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130213250.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/%C0%C5%B2%AC%CA%FC%C1%F7">静岡放送</a> 牧野さん</figcaption></figure></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.screens-lab.jp%2Farticle%2F26768" title="日本初!新聞・テレビ・ラジオ公認のVTuber「木乃華サクヤ」が静岡新聞社・静岡放送からデビュー|Screens|映像メディアの価値を映す" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.screens-lab.jp/article/26768">www.screens-lab.jp</a></cite></p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/PkkNx0e0B5o?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="SBSテレビ【静岡放送JOVR-DTV】オープニング「VTuber 木乃華サクヤとともに目覚め」2023年6月1日〜"></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=PkkNx0e0B5o">www.youtube.com</a></cite></p> <p>ちなみに<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C0%C5%B2%AC%CA%FC%C1%F7">静岡放送</a>様は<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A1%BC%A5%EB%A5%B5%A5%A4%A5%F3">コールサイン</a> (テレビ) が <code>JOVR-DTV</code> ということもあって<a class="keyword" href="https://d.hatena.ne.jp/keyword/VTuber">VTuber</a>っぽい響きであることに局所的な盛り上がりがありました。放送業界2年目の私はすぐに反応できずまだまだ未熟であることを実感しました。</p> <p>懇親会にはなんと40名前後の方が参加してくれまして、登壇内容についての話やら次回のMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>開催地の話などで盛り上がりました。来年の開催については既にいくつか候補がありまして、今年に引き続き来年も精力的に活動していく予定ですのでご期待ください。</p> <h1 id="まとめ">まとめ</h1> <p>今年も<a class="keyword" href="https://d.hatena.ne.jp/keyword/Inter%20BEE">Inter BEE</a>は大盛況で、そこに併せて開催したMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>も多くの方に参加していただけました。</p> <p>昨年は業界に知り合いがおらず肩身の狭さと若干の居心地の悪さを感じたものですが、Media-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>を通じて放送業界の方々と知り合えたおかげで今年の<a class="keyword" href="https://d.hatena.ne.jp/keyword/Inter%20BEE">Inter BEE</a>では多くの人と交流することができました。引き続きメディア業界の盛り上げと技術発信に貢献するため頑張っていく所存です。</p> tver-techblog #ISUCON13 に パカパカアルパカとして参加して22位でフィニッシュでした!(86,322点) hatenablog://entry/6801883189062871471 2023-12-02T00:00:00+09:00 2023-12-02T00:00:03+09:00 こんにちは! こちらは TVer Advent Calendar 2023 の2日目の記事です。 TVerのサービスバックエンドのリードエンジニアをやっております内海です🐶! 今年も昨年同様、チーム:パカパカアルパカとして出場してきました。 isucon.net 22位 86,322 パカパカアルパカ いえーい🎉 やったこと 担当範囲 基本、私はいつもアプリケーションレイヤーばかりみています。 toritori0318氏がインフラをメインに担当。 teraken氏がツール周りと遊撃担当。 開始直後 AWS上のリソース構築 レギュレーション、マニュアルの読み合わせ リソース構築完了後 初回ベンチ… <p>こんにちは!</p> <p>こちらは <a href="https://qiita.com/advent-calendar/2023/tver">TVer Advent Calendar 2023</a> の2日目の記事です。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のサービスバックエンドのリードエンジニアをやっております内海です🐶!</p> <p>今年も昨年同様、チーム:パカパカアルパカとして出場してきました。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130141258.png" width="1200" height="672" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fisucon.net%2Farchives%2F57993937.html" title="ISUCON13 受賞チームおよび全チームスコア : ISUCON公式Blog" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://isucon.net/archives/57993937.html">isucon.net</a></cite></p> <p><code>22位 86,322 パカパカアルパカ</code></p> <p>いえーい🎉</p> <h2 id="やったこと">やったこと</h2> <h3 id="担当範囲">担当範囲</h3> <p>基本、私はいつもアプリケーションレイヤーばかりみています。</p> <p>toritori0318氏がインフラをメインに担当。 teraken氏がツール周りと遊撃担当。</p> <h4 id="開始直後">開始直後</h4> <ul> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>上のリソース構築</li> <li>レギュレーション、マニュアルの読み合わせ</li> </ul> <h4 id="リソース構築完了後">リソース構築完了後</h4> <ul> <li>初回ベンチ実行</li> <li>各リソースの負荷状況確認</li> <li>マニュアルからトピックの抜き出し</li> </ul> <p>このタイミングではまだやれることが少ないポジションなので、マニュアルから課題になりそうなトピックを抜き出してまとめていました。</p> <p>また負荷状況はどうみても<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>が<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%DC%A5%C8%A5%EB%A5%CD%A5%C3%A5%AF">ボトルネック</a>になっていることを確認。</p> <p>どうせ分散していかなきゃいけないことは明白だったため、一旦1台でいけるところまでチューニングをしてから負荷状況に合わせてサーバーを割り当てる作戦でいくことにしました。</p> <h4 id="icon対応">icon対応</h4> <p>マニュアルと読んでいると <code>If-None-Match</code> ヘッダーに対しての記載が丁寧だったので、まず深追いせずに</p> <ul> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>にデータ保持をしているiconを静的ファイル化</li> <li>hash値をredisで保持</li> <li><code>If-None-Match</code> ヘッダーがある場合304を返すように変更</li> </ul> <p>スコア下がる 🤔</p> <h4 id="PowerDNS">PowerDNS</h4> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/DNS">DNS</a>周りの運用は経験がなかったので、問題をみた瞬間にすっぱり切り捨てていた課題だったのですが<a class="keyword" href="https://d.hatena.ne.jp/keyword/TTL">TTL</a>が0になっていることに気づいて対応をいれました</p> <p>ここでお昼前5,000弱</p> <h4 id="モデレートAPIのN1解消">モデレート<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>のN+1解消</h4> <p>これでもかってくらいN+1だらけだったので、どこから手をつけるか悩んでましたが</p> <p>配信品質が上がると視聴者数があがるというマニュアル記載があったため、ブロッカーになりそうなモデレート<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>から着手しました</p> <h4 id="themeの廃止">themeの廃止</h4> <p>ユーザーのダークモード設定が別テーブルで毎回呼ばれていたためusersテーブルに移行し、UserModelで保持できるようにしました</p> <p>ここでやっと6,801。どのメンバーの対応も微増ではありつつも、着実にスコアは伸びていきました。</p> <h4 id="作戦会議">作戦会議</h4> <p>そろそろいろんな箇所の課題が見えてきたので一旦ホワイトボードに現在の構成などを書きながら、それぞれの気づきと方向性の共有を行いました</p> <p>一旦昼過ぎのこのタイミングでは</p> <ul> <li>Nginxでiconをちゃんと返すようにする</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/DNS">DNS</a>サーバーとAppサーバーはわけたい</li> </ul> <p>という方針になりました</p> <h4 id="iconをNginxでキャッシュするように変更">iconをNginxでキャッシュするように変更</h4> <p>toritori0818氏がNginxでキャッシュできるように対応してくれて 8,796 点</p> <p>まだここでも1サーバーしか使ってない状況です。</p> <p>そろそろ分散して課題の深掘りにフェーズ移行していこうと言う話になりました。</p> <h3 id="MySQLサーバー"><a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>サーバー</h3> <p>2台目のサーバーを<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>専用サーバーに変更しました</p> <p>このときは</p> <pre class="code" data-lang="" data-unlink>BenchTarget: Server1 Server1: PowerDNS / App(Go) / redis / Nginx Server2: MySQL Server3: </pre> <p>という状況になりました。</p> <p>ここでスコアが伸びて 18,181 🎉</p> <p>ここからはN+1を潰しつつ、それぞれの負荷状況を見て、分散構成を考えていました。</p> <p>結果的に</p> <pre class="code" data-lang="" data-unlink>サーバー BenchTarget: Server1 Server1: PowerDNS / App1(Go) / Nginx Server2: MySQL Server3: App2(Go) アプリケーション App1: icon / dns系APIのみ App2: その他</pre> <p>という構成でわけました。</p> <p>Server1にPowerDNSが居たので、できるだけ触らなくていいようユーザー登録<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>をServer1:App1で受け付けることにしましたw</p> <p>また、それだけだと少しApp1が余るので、比較的CPU負荷の少ないiconAPIもApp1に同居させました。</p> <p>構成を変えてスコアは 27,702 🎉</p> <h4 id="最後の追い込み">最後の追い込み</h4> <ul> <li>出来うるN+1を解消していく</li> <li>iconのBinaryをそのまま<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>に書き込んでいたのをやめる</li> <li>iconAPIでApp(Go)までたどり着いた場合、原則的にicon未設定者と断定してfallbackImageを即レスするように</li> </ul> <p>などなどやっていると、めきめきとスコアがあがっていきました💪</p> <p>午前中にやっていた細々したものが開花してきた感があって、アドレナリンでちゃう感じでした!</p> <h2 id="感想">感想</h2> <p>ISUCONに出場すると毎年思うのですが、</p> <ul> <li>瞬間的な取捨選択の嗅覚</li> <li>わからない状況でも前にコケる練習</li> <li>Webエンジニアとして足りていない部分の再確認</li> </ul> <p>というなかなか普段の業務では獲得し辛いスキルが磨かれるなぁ。と感じています。</p> <p>日々の業務でもきっと活きてくるスキルだと思いますので、是非ISUCONに参加してみてはいかがでしょう。</p> <p>来年(まだあるかわからないですが)、対戦出来ること楽しみにしております 😘</p> <p>運営のみなさん、参加者のみなさん本当にありがとうございました。今年も最高でした!!!!</p> <p>ISUCON13の問題や、ベンチマーカーの実装は</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fisucon%2Fisucon13" title="GitHub - isucon/isucon13" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/isucon/isucon13">github.com</a></cite></p> <p>こちらで公開してくださっています</p> <h2 id="後日談">後日談</h2> <p>再起動テスト終わって、提出スコア出すためのベンチしてたんですが…</p> <p>なぁんかベストスコアでないんだよなぁ。と思ってました。</p> <p>終わってから<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>みてみると、マージされてないPullRequestが残ってました😇(ログの出力消したりするくらいのやつ</p> <p>みなさんも、ちゃんとPRがMergeされてるかは確認しましょう😇</p> tver-techblog 「TVer Advent Calendar 2023」開催のお知らせ hatenablog://entry/6801883189062900042 2023-12-01T11:48:30+09:00 2023-12-01T11:48:30+09:00 こんにちは、TVerの加我です。 昨年に引き続き今年もTVer Advent Calendarを開催します! こちらはTVer Advent Calendar 2023 の1日目の記事となります。 qiita.com 昨年のはこちら。 qiita.com 今年のアドベントカレンダーに向けて 現在のTVerは下記のような組織体制となっております。 全体の組織図 speakerdeck.com その中でサービスの開発に携わっている部門 ≒ 開発組織は主に下記が挙げられます。 TVerの開発・運用を担っているサービスプロダクト本部 TVer広告プラットフォームの開発・運用を担っている広告事業本部 昨… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の加我です。</p> <p>昨年に引き続き今年も<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> Advent Calendarを開催します!<br/> こちらは<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> Advent Calendar 2023 の1日目の記事となります。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fqiita.com%2Fadvent-calendar%2F2023%2Ftver" title="TVerのカレンダー | Advent Calendar 2023 - Qiita" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://qiita.com/advent-calendar/2023/tver">qiita.com</a></cite></p> <p>昨年のはこちら。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fqiita.com%2Fadvent-calendar%2F2022%2Ftver" title="TVerのカレンダー | Advent Calendar 2022 - Qiita" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://qiita.com/advent-calendar/2022/tver">qiita.com</a></cite></p> <h2 id="今年のアドベントカレンダーに向けて">今年の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%C9%A5%D9%A5%F3%A5%C8%A5%AB%A5%EC%A5%F3%A5%C0%A1%BC">アドベントカレンダー</a>に向けて</h2> <p>現在の<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>は下記のような組織体制となっております。</p> <p><figure class="figure-image figure-image-fotolife" title="全体の組織図"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231130/20231130153654.png" width="1200" height="667" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>全体の組織図</figcaption></figure></p> <p><iframe id="talk_frame_920082" class="speakerdeck-iframe" src="//speakerdeck.com/player/49965b8557e748cea81c6d26e19317c2" width="710" height="399" style="aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/techtver/we-are-hiring?slide=13">speakerdeck.com</a></cite></p> <p>その中でサービスの開発に携わっている部門 ≒ 開発組織は主に下記が挙げられます。</p> <ul> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の開発・運用を担っているサービスプロダクト本部</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>広告プラットフォームの開発・運用を担っている広告事業本部</li> </ul> <p>昨年は現サービスプロダクト本部のエンジニアがメインで<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%C9%A5%D9%A5%F3%A5%C8%A5%AB%A5%EC%A5%F3%A5%C0%A1%BC">アドベントカレンダー</a>の執筆に取り組んでいたのですが、なにしろ<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の開発組織が発足し動き出した年だったので執筆者が少なく、どのような記事を出そうかみんなで頭をひねったりもしました。</p> <p>しかし今年の開発組織は昨年に比べて約2倍の人数になり、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>広告プラットフォームの開発・運用に関わる広告事業本部にもエンジニアが増えてきているのでバラエティ豊かな記事が出てきそうな気配があります。</p> <h2 id="ということで">ということで</h2> <p>初日は私が<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%C9%A5%D9%A5%F3%A5%C8%A5%AB%A5%EC%A5%F3%A5%C0%A1%BC">アドベントカレンダー</a>開会の儀を執り行わせていただきました。</p> <p>明日はバックエンドエンジニアである内海が先日開催されたISUCON13について話してくれますのでお楽しみに!</p> tver-techblog JAWS Festa 2023参加レポート #jawsug #jawsfesta #jawsfesta2023 hatenablog://entry/6801883189051882808 2023-11-02T12:01:12+09:00 2023-11-02T12:01:12+09:00 こんにちは、TVerの加我です。 先日10/7に福岡で開催されたJAWS Festa 2023 in Kyushuに企業サポーター兼当日スタッフとして参加してきました。コミュニティというキーワードに着目しつつ写真多めでレポートしていきます。 アンバサダーである広告事業本部の安部がJAWS Festa 2023の応援ブログと現地参加レポートを投稿してくれていますので先にご紹介します。 techblog.tver.co.jp techblog.tver.co.jp JAWS Festaについて JAWS-UGには大きな年次イベントが2つありまして、それがJAWS DAYSとJAWS Festaです… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の加我です。<br/> 先日10/7に福岡で開催された<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023 in Kyushuに企業サポーター兼当日スタッフとして参加してきました。コミュニティというキーワードに着目しつつ写真多めでレポートしていきます。</p> <p>アンバサダーである広告事業本部の安部が<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023の応援ブログと現地参加レポートを投稿してくれていますので先にご紹介します。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fh-abe%2F2023-jawsfesta-ambassador" title="TVerは JAWS Festa 2023 を応援しています! - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/h-abe/2023-jawsfesta-ambassador">techblog.tver.co.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fh-abe%2F2023-jawsfesta-ambassador-repo" title="JAWS Festa 2023 に参加しました! - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/h-abe/2023-jawsfesta-ambassador-repo">techblog.tver.co.jp</a></cite></p> <h1 id="JAWS-Festaについて"><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaについて</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGには大きな年次イベントが2つありまして、それが<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> DAYSと<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaです。<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> DAYSは都内近郊で行われるイベントに対して<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaは地方開催かつ毎年別の都市で開催されるという特徴があります。</p> <p>今年の<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaは4月の<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Summit Tokyoの時点で九州での開催が決まり、具体的には福岡にある<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CA%A1%B2%AC%B9%A9%B6%C8%C2%E7%B3%D8">福岡工業大学</a>での開催となりました。会場は非常に綺麗で学食も利用することができ、学生気分を少し取り戻しつつ気持ちよくイベントに参加することが出来ました。改めて会場を提供して頂いた<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CA%A1%B2%AC%B9%A9%B6%C8%C2%E7%B3%D8">福岡工業大学</a>の皆さま、そしてイベントを成功に導いた運営スタッフの皆さまお疲れ様でした。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjft2023.jaws-ug.jp%2F" title="JAWS FESTA 2023 KYUSHU" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://jft2023.jaws-ug.jp/">jft2023.jaws-ug.jp</a></cite></p> <h1 id="前夜祭">前夜祭</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaは前日から始まっていると言っても過言ではありません。<br/> いつもお世話になっているNew Relic様や、<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGの知人と一緒にコミュニティについて話しつつ福岡名物の料理で前夜祭を楽しみました。炊き餃子も<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B8%C6%BB%D2">呼子</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A4%A5%AB">イカ</a>の姿造りも美味しかったです。</p> <p><figure class="figure-image figure-image-fotolife" title="福岡は新鮮なイカが美味しいんですよね"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231019/20231019222647.jpg" width="1200" height="676" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>福岡は新鮮な<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A4%A5%AB">イカ</a>が美味しいんですよね</figcaption></figure></p> <h1 id="当日">当日</h1> <p>会場の受付にて企業サポーターと個人サポーターの受付をしてイベントがスタートです。今回久しぶりに会う方も多くおり「いよいよ<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023が始まるぞ!」という気持ちの高まりを感じました。当日は撮影スタッフをするかとても迷ったのですが、せっかくの地方開催のイベントなのでイベントを楽しみたいと考え、一般参加かつ野良カメラマンとして参加させていただきました。</p> <p><figure class="figure-image figure-image-fotolife" title="サポーターブース付近でのスタッフ打ち合わせの様子"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231019/20231019224217.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>サポーターブース付近でのスタッフ打ち合わせの様子</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="サポーターブースでは新しいTVerのラバーコースターを配布しました"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231019/20231019225149.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>サポーターブースでは新しい<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のラバーコースターを配布しました</figcaption></figure></p> <h3 id="オープニング">オープニング</h3> <p>オープニングはC棟地下ホールで開催されたのですが、どこに座っても前が見やすい階段教室形式でした。どうやら2018年にリニューアルされたようです。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.kotobuki-seating.co.jp%2Fprojects%2Flist%2Fdetail.html%3Fpdid1%3D00907" title="福岡工業大学 C棟 階段教室(地下ホール)(リニューアル)|コトブキシーティング株式会社" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.kotobuki-seating.co.jp/projects/list/detail.html?pdid1=00907">www.kotobuki-seating.co.jp</a></cite></p> <p><figure class="figure-image figure-image-fotolife" title="C棟地下ホール"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231019/20231019230627.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>C棟地下ホール</figcaption></figure></p> <p>私はフロアの中段ど真ん中に位置取りつつオープニングを待機している一方、ステージでは運営スタッフである清家さんと北川さんが会場の諸注意をしつつ笑いを交えて会場を温めてくれていました。</p> <p><figure class="figure-image figure-image-fotolife" title="オープニングアクトで会場を温めてくれるお二人"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231019/20231019231311.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AA%A1%BC%A5%D7%A5%CB%A5%F3%A5%B0%A5%A2%A5%AF%A5%C8">オープニングアクト</a>で会場を温めてくれるお二人</figcaption></figure></p> <p>会場でのアンケートによると<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGや<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaへの参加が初めてという方が多かったため、そういう人たちがイベントに参加しやすいように会場を温めるといった細かな気配り・気遣いを感じられました。ホスピタリティですね。特に初めて参加する人にとっては「<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG / <a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaってどんな雰囲気なんだろう。学会や<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BB%A5%DF">セミ</a>ナーみたいなお硬い感じなのかな?」と思う人は多少なりともいるはずです。それに対して「<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaは硬い雰囲気じゃなくてみんなで盛り上げていく・盛り上がっていくイベントだから楽しんでいってね!」という運営からのメッセージがあると参加者がリラックスできるので良いですね。</p> <p>ということでオープニングでは実行委員長の阿部さんの挨拶から始まります。<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023にかける思いや今回の協賛(企業サポーター、個人サポーター、アプリケーション提供、会場提供)の紹介がありました。<br/> <figure class="figure-image figure-image-fotolife" title="実行委員長の阿部さん"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231019/20231019233204.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>実行委員長の阿部さん</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="JAWS Festa 2023には多くの企業が協賛しています"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231019/20231019233741.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023には多くの企業が協賛しています</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="JAWS Festa 2023には多くの個人サポーターも協賛しています"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231019/20231019233911.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023には多くの個人サポーターも協賛しています</figcaption></figure></p> <p>ここから私が参加した一部のセッションの振り返りをしていきます。</p> <h3 id="地方コミュニティの存在意義とは"><a href="https://jft2023.jaws-ug.jp/session/panel_discussion/">地方コミュニティの存在意義とは?</a></h3> <p>オープニングが終わり、同じ会場ですぐにパネルディスカッションが始まります。パネルディスカッションは大体イベントの最後に配置されることが経験上多かったため、パネルディスカッションから始まるイベントはなかなか斬新です。</p> <p>「地方コミュニティの存在意義とは?」をテーマとして、<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Users Group – Japan (<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG) の立花さん、Japan Azure User Group (JAZUG) の松村さん、Japan <a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud User Group for Enterprise (Jagu'e'r) の家壽田さんがそれぞれのコミュニティのあり方や地方でコミュニティをやる意味などについてディスカッションしていました。モデレーターは<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Community Builderの鈴木さんが担当していました。</p> <p><figure class="figure-image figure-image-fotolife" title="異なるコミュニティに所属する3名によるパネルディスカッション"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231020/20231020012754.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>異なるコミュニティに所属する3名によるパネルディスカッション</figcaption></figure></p> <p>私としては<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGのコミュニティイベントの最初のセッションで競合関係ともいえるJAZUGやJagu'e'rの方とパネルディスカッションを行うというのに驚きました。てっきり<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGに参加している地元の著名なエンジニアの方が基調講演を担当するものだと思っていたのですが、別のセッションでは<a class="keyword" href="https://d.hatena.ne.jp/keyword/PHP">PHP</a>コミュニティ・<a class="keyword" href="https://d.hatena.ne.jp/keyword/Java">Java</a>コミュニティ・Swiftコミュニティなどの方も登壇しており「今年の<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaは<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGだけじゃない、九州全体のコミュニティを巻き込んで盛り上げていく」という強い意志と熱量を感じました。</p> <h3 id="JAWS-FESTA版グループ対抗-AWS-ウルトラクイズ"><a href="https://jft2023.jaws-ug.jp/session/festa_03/">JAWS FESTA版!グループ対抗 AWS ウルトラクイズ</a></h3> <p>今回の個人的目玉セッションである<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%EB%A5%C8%A5%E9%A5%AF%A5%A4%A5%BA">ウルトラクイズ</a>です。私は回答者ではなく賑やかし(一般参加者)として参加しました。</p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">お祭りトラック<br><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> FESTA版!グループ対抗 <a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%EB%A5%C8%A5%E9%A5%AF%A5%A4%A5%BA">ウルトラクイズ</a><br><br>めちゃめちゃ盛り上がってます!!<br>優勝するのは、どのチームだ!!!<a href="https://twitter.com/hashtag/jawsfesta2023_E?src=hash&amp;ref_src=twsrc%5Etfw">#jawsfesta2023_E</a><a href="https://twitter.com/hashtag/jawsfesta2023?src=hash&amp;ref_src=twsrc%5Etfw">#jawsfesta2023</a> <a href="https://twitter.com/hashtag/jawsfesta?src=hash&amp;ref_src=twsrc%5Etfw">#jawsfesta</a> <a href="https://twitter.com/hashtag/jawsug?src=hash&amp;ref_src=twsrc%5Etfw">#jawsug</a> <a href="https://t.co/ND6cbe1k69">pic.twitter.com/ND6cbe1k69</a></p>&mdash; <a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG (@jawsdays) <a href="https://twitter.com/jawsdays/status/1710526417052811768?ref_src=twsrc%5Etfw">2023年10月7日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p>過去に開催された<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Summit Tokyoではメインセッション終了後に<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGのイベントが開催されていました。そのイベント内で行われていた<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>に関するクイズ大会が<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%EB%A5%C8%A5%E9%A5%AF%A5%A4%A5%BA">ウルトラクイズ</a>です。出題者は<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>に関する<strong>ディープな問題</strong>を出題し、正解者だけが残り、最終的に勝ち残った人が豪華景品 (re:Inventのカンファレンスパスなど) をゲットできるというアツいイベントとなっております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdev.classmethod.jp%2Farticles%2Faws-summit-tokyo-2019-ultra-quiz%2F" title="AWS ウルトラクイズで優勝してきた (AWS Summit 2019 re:Mix) #AWSSummit | DevelopersIO" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://dev.classmethod.jp/articles/aws-summit-tokyo-2019-ultra-quiz/">dev.classmethod.jp</a></cite></p> <p>今回は<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B8%C4%BF%CD%C0%EF">個人戦</a>ではなく、4組に分けられたチームがメンバーをローテしつつクイズに回答するという<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C3%C4%C2%CE%C0%EF">団体戦</a>です。メンバーによってはフロントエンドが得意・バックエンドが得意・ネットワークレイヤーが得意など個人差があるため、結果が読めないところも盛り上がりポイントです。</p> <p><figure class="figure-image figure-image-fotolife" title="ルール説明"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231031/20231031172207.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>ルール説明</figcaption></figure></p> <p>印象に残った問題がこちらです。</p> <pre class="code" data-lang="" data-unlink>2014年に発表されたAWSのサービスは下記のどれか 1. AWS Lambda 2. Amazon Aurora 3. AWS Config 4. 上記全て</pre> <p>私としては<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Lambdaと<a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon%20Aurora">Amazon Aurora</a>は同じ時期、<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Configはもう少し後だった印象があったのですが、正解は「4. 上記全て」でした。無念。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.publickey1.jp%2Fblog%2F14%2Faws_lambdaaws_reinvent_2014.html" title="[速報]まるでクラウドで走るマクロ言語「AWS Lambda」発表。AWS re:Invent 2014" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.publickey1.jp/blog/14/aws_lambdaaws_reinvent_2014.html">www.publickey1.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.publickey1.jp%2Fblog%2F14%2Famazon_auroramysql5aws_reinvent_2014.html" title="[速報]Amazon Aurora発表。MySQL互換で性能5倍、商用リレーショナルデータベースと同等の機能を提供するマネージドなデータベースサービス。AWS re:Invent 2014" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.publickey1.jp/blog/14/amazon_auroramysql5aws_reinvent_2014.html">www.publickey1.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Faws.amazon.com%2Fjp%2Fabout-aws%2Fwhats-new%2F2014%2F11%2F12%2Fintroducing-aws-config%2F" title="Introducing AWS Config" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://aws.amazon.com/jp/about-aws/whats-new/2014/11/12/introducing-aws-config/">aws.amazon.com</a></cite></p> <p>また、利用者が多いと思われる「ELB」の正式名称についてのクイズがありましたが、なんと公式ドキュメントも混乱しているという話があり、後日正式名称で修正・更新されていました。<br/> <figure class="figure-image figure-image-fotolife" title="みなさまおわかりでしょうか"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231031/20231031174238.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>みなさまおわかりでしょうか</figcaption></figure></p> <h3 id="福岡のコミュニティから世界への挑戦までの軌跡-ある学生だったエンジニアの話"><a href="https://jft2023.jaws-ug.jp/session/community_08/">福岡のコミュニティから世界への挑戦までの軌跡 〜ある学生だったエンジニアの話〜</a></h3> <p>HAKATA.swiftという<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a>関連のコミュニティに所属している秋 勇紀さんによるセッションです。福岡のコミュニティに所属している秋さんがコミュニティを通じたつながりや経験、学びを活かしてどのようにしてグローバルな登壇や技術書の執筆に至ったのかを話してくれました。</p> <p>秋さんは「コミュニティに参加して人とのつながりができたおかげで色々な挑戦を行うことができた」と話しており、自分も<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGというコミュニティのおかげで人生が変わったうちの一人なので、コミュニティの価値にまだ気づけていない人たちに気づきを与えてあげられるよう精力的に活動していきたいと決意を新たにすることができました。</p> <p><figure class="figure-image figure-image-fotolife" title="コミュニティによるつながり"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231031/20231031180403.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>コミュニティによるつながり</figcaption></figure></p> <h3 id="クロージング">クロージング</h3> <p>すべてのセッションが終わり、オープニングが行われたC棟地下ホールに戻りクロージングと集合写真の撮影が行われました。</p> <p><figure class="figure-image figure-image-fotolife" title="コールアンドレスポンスを行う実行委員長"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231102/20231102010900.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>コール<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%F3%A5%C9%A5%EC">アンドレ</a>スポンスを行う実行委員長</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="撮影スタッフのみなさま。お疲れ様です。"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231102/20231102003814.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>撮影スタッフのみなさま。お疲れ様です。</figcaption></figure></p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> FESTA 2023に参加されたみなさま、ありがとうございました!!<br><br>4年ぶりの完全オフラインイベント。福岡の地で、コミュニティへの想いをそれぞれ深めた1日になったのではないでしょうか✨<br><br>最後の記念撮影をお届けします🦈<br>皆さん素敵な笑顔です!!☺️<a href="https://twitter.com/hashtag/jawsfesta?src=hash&amp;ref_src=twsrc%5Etfw">#jawsfesta</a> <a href="https://twitter.com/hashtag/jawsfesta2023?src=hash&amp;ref_src=twsrc%5Etfw">#jawsfesta2023</a> <a href="https://twitter.com/hashtag/jawsug?src=hash&amp;ref_src=twsrc%5Etfw">#jawsug</a> <a href="https://twitter.com/hashtag/AWS?src=hash&amp;ref_src=twsrc%5Etfw">#AWS</a> <a href="https://t.co/MNKWh5qIZd">pic.twitter.com/MNKWh5qIZd</a></p>&mdash; <a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>公式☁️アマゾン ウェブ サービス ジャパン/<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>サービス (@awscloud_jp) <a href="https://twitter.com/awscloud_jp/status/1710583684565455090?ref_src=twsrc%5Etfw">2023年10月7日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p>そして来年2024年の3月2日(土)に<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> DAYS 2024がオフライン会場にて開催されることを実行委員長である早川さんのビデオレターにて発表されました!<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>もスポンサーや登壇などでイベントの盛り上げを手伝いたいと思っており情報のアップデートを楽しみにしております。</p> <p><figure class="figure-image figure-image-fotolife" title="実行委員長によるJAWS DAYS 2024開催のお知らせ"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231102/20231102013107.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>実行委員長による<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> DAYS 2024開催のお知らせ</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="代理としてSecurity-JAWS運営の吉江さんから説明がありました"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231102/20231102013157.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>代理としてSecurity-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>運営の吉江さんから説明がありました</figcaption></figure></p> <h1 id="まとめ">まとめ</h1> <p>今年の<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festaは<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGだけではなく複数のコミュニティを集めたイベントとなり、まさにFestaの名前に相応しい盛り上がりでした。コミュニティ同士のディスカッションがあったり、コミュニティの歴史を振り返ってみたり、地方におけるコミュニティの存在意義やあり方を考えたりと、コミュニティ運営に携わる者の1人として多くの学びを得ることができました。</p> <p>私はMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>の運営に携わっており、イベントの開催や登壇のために色々な地域に行くことが増えました。その地域でイベントを開催するためにはどういった登壇者を集めたらよいのか、継続して開催するにはどうしたらよいのか、コミュニティを支援するにはどういう仕組みが必要なのかといった悩みがあったのですが、コミュニティの活動が活発な福岡に着目することで多くの気づきを得ることができました。</p> <p>改めて実行委員長の阿部さん、運営スタッフのみなさま、サポーターのみなさま、参加者のみなさま、本当にお疲れ様でした。企業サポーターとして支援できたことを嬉しく思います。</p> tver-techblog JAWS Festa 2023 に参加しました! hatenablog://entry/6801883189050952436 2023-10-17T15:45:05+09:00 2023-10-17T15:45:05+09:00 こんにちは。アドテク領域のエンジニアをしています安部です。 10月7日に開催されたJAWS Festa 2023に参加してきました。 jft2023.jaws-ug.jp JAWS Festa 2023には企業サポーターとして参加しました。 参加の意気込みについてはこちらを御覧ください。 techblog.tver.co.jp 当日の会場の様子 会場の福岡工業大学。駅直結でアクセスがとてもよかったです。 企業サポーターブースではラバーコースターを置いていました。 他の企業のアンバサダーさんたちとたくさんお話できて楽しかったです! ノベルティも個性があって見ているだけでも楽しかったです。 オープ… <p>こんにちは。<br />アドテク領域のエンジニアをしています安部です。</p> <p>10月7日に開催された<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023に参加してきました。</p> <p> </p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjft2023.jaws-ug.jp%2F" title="JAWS FESTA 2023 KYUSHU" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://jft2023.jaws-ug.jp/">jft2023.jaws-ug.jp</a></cite></p> <p> </p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023には企業サポーターとして参加しました。</p> <p>参加の意気込みについてはこちらを御覧ください。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fh-abe%2F2023-jawsfesta-ambassador" title="TVerは JAWS Festa 2023 を応援しています! - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/h-abe/2023-jawsfesta-ambassador">techblog.tver.co.jp</a></cite></p> <p> </p> <h3 id="当日の会場の様子">当日の会場の様子</h3> <figure class="figure-image figure-image-fotolife mceNonEditable" title="会場の福岡工業大学。駅直結でアクセスがとてもよかったです。"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231016/20231016162325.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">会場の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CA%A1%B2%AC%B9%A9%B6%C8%C2%E7%B3%D8">福岡工業大学</a>。駅直結でアクセスがとてもよかったです。</figcaption> </figure> <p>企業サポーターブースではラバーコースターを置いていました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231016/20231016163702.jpg" width="799" height="533" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>他の企業のアンバサダーさんたちとたくさんお話できて楽しかったです!</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%CE%A5%D9%A5%EB%A5%C6%A5%A3">ノベルティ</a>も個性があって見ているだけでも楽しかったです。</p> <p> </p> <p>オープニングでは実行委員長の熱い開会宣言がありました。</p> <p>その後に続いたディスカッション<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>でも地方のコミュニティのあり方、コミュニティへのかかわり方について熱いディスカッションが行われていました。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="スタートの時の大喝采でホールが揺れました。"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231016/20231016165102.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">スタートの時の大<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%E5%BA%D3">喝采</a>でホールが揺れました。</figcaption> </figure> <h3 id="参加したセッション">参加したセッション</h3> <h4 id="福岡市のスタートアップ支援について">福岡市のスタートアップ支援について</h4> <p>福岡市の成長戦略、DXの推進、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C0%AF%CE%E1">政令</a>市の強みを生かしたスタートアップ支援についてのお話でした。<br />fgn.(Fukuoka <a class="keyword" href="https://d.hatena.ne.jp/keyword/growth">growth</a> Next)という創業前→成長期→事業拡大期を<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B0%EC%B5%A4%C4%CC%B4%D3">一気通貫</a>でサポートする仕組みとEngineer Cafeの紹介がありました。<br />Engineer Cafeには<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%EF%A1%BC%A5%AD%A5%F3%A5%B0%A5%B9%A5%DA%A1%BC%A5%B9">コワーキングスペース</a>もあるようなので、今度行ってみようと思います。</p> <h4 id="ECSの-CICD改善と標準化の取り組み">ECSの CI/CD改善と標準化の取り組み</h4> <p><iframe id="talk_frame_1087036" class="speakerdeck-iframe" src="//speakerdeck.com/player/80033d7f2c484c009f5a0e03e444b8d5" width="710" height="399" style="aspect-ratio: 710/399; border: 0; padding: 0; margin: 0; background: transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/cohalz/jaws-festa-2023-in-kyushu">speakerdeck.com</a></cite></p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%ED%A5%B0">はてなブログ</a>のEC2からECSの移行時に発覚したCI/CDの問題を改善、社内で標準化するプロセスについてのお話でした。<br />最近よくCI/CDを触っているのでとても勉強になり、業務に反映できそうなお話でした。</p> <p> </p> <h3 id="クロージング">クロージング</h3> <p>2024/3/2 に池袋<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B5%A5%F3%A5%B7%A5%E3%A5%A4%A5%F3%A5%B7%A5%C6%A5%A3">サンシャインシティ</a>にて<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> DAYS 2024が行われることが発表されました!</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231016/20231016165551.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h3 id="さいごに">さいごに</h3> <p>たくさんの方と交流できてとても楽しかったです。</p> <p>行きの電車で隣に座っていた方が実は企業サポーターの方だったり、地元企業の方と福岡<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>できたり、懇親会でエンジニアカフェについて色々聞けたり、とても充実した1日を過ごすことができました。</p> <p>お話した方によく聞かれたことが「広告事業本部ってどんなことしているのですか?」ということでした。</p> <p>これからもっと広告事業本部についても広めていくことが大事だなと改めて思いました。</p> <p>アドテク領域についてはこちらでお話しているので、ぜひ見てください!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnote.com%2Ftver%2Fn%2Fn47835bc5f83a" title="事業成長も技術者としての成長も実感!アドテクエンジニアの業務とやりがいとは?〜/広告ソリューションタスク 鶴貝・安部 インタビュー|TVer HR BLOG" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://note.com/tver/n/n47835bc5f83a">note.com</a></cite></p> <h3 id="おまけ">おまけ</h3> <p>昼食に学食を利用させていただきました。</p> <p>がっつり系でとても美味しくて安くてこれを毎日食べられる学生さんは羨ましいです。</p> <p>学生に戻った気分を味わえました。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="おすすめのチキン南蛮ライス"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231016/20231016170743.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">おすすめのチキン南蛮ライス。最高でした!</figcaption> </figure> <p> </p> tver-techblog TVerはJAWS Festa 2023に企業サポーターとして協賛します! #jawsfesta #jawsfesta2023 #jawsug hatenablog://entry/820878482973008670 2023-10-04T19:04:18+09:00 2023-10-04T19:04:18+09:00 こんにちは、TVerの加我です。 遂にJAWS Festa 2023が今週末の10/7(土)に開催となります👏 TVerでは企業サポーターとして協賛しておりまして、自社のノベルティを持参・配布する予定です。ぜひお手にとっていただけると私たちが喜びます。前回作成したものから微妙にリファインしておりますので、お気づきの方はこっそり教えてください。 企業サポーターの一覧ページはこちら。 jft2023.jaws-ug.jp 現地には広告事業本部でアドテク周りの開発を行っているアンバサダーの安部と、サービスプロダクト本部でSREとしてTVerを幅広く見ている私の2名が参加予定ですので、気軽にお声がけく… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の加我です。</p> <p>遂に<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023が今週末の10/7(土)に開催となります👏<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>では企業サポーターとして協賛しておりまして、自社の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%CE%A5%D9%A5%EB%A5%C6%A5%A3">ノベルティ</a>を持参・配布する予定です。ぜひお手にとっていただけると私たちが喜びます。前回作成したものから微妙にリファインしておりますので、お気づきの方はこっそり教えてください。</p> <p>企業サポーターの一覧ページはこちら。 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjft2023.jaws-ug.jp%2Fsupporters%2Fcorporate%2F" title="JAWS FESTA 2023 KYUSHU" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://jft2023.jaws-ug.jp/supporters/corporate/">jft2023.jaws-ug.jp</a></cite></p> <p>現地には広告事業本部でアドテク周りの開発を行っているアンバサダーの安部と、サービスプロダクト本部でSREとして<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>を幅広く見ている私の2名が参加予定ですので、気軽にお声がけください。ぜひ<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>や<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>の話題で盛り上がりましょう!</p> <p><figure class="figure-image figure-image-fotolife" title="広告事業本部 安部"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231004/20231004182315.png" width="512" height="512" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>広告事業本部 安部</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="サービスプロダクト本部 加我"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231004/20231004182721.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>サービスプロダクト本部 加我</figcaption></figure></p> <p>また、アンバサダーである安部が先日投稿した<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023への応援ブログも併せてご覧ください。 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fh-abe%2F2023-jawsfesta-ambassador" title="TVerは JAWS Festa 2023 を応援しています! - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/h-abe/2023-jawsfesta-ambassador">techblog.tver.co.jp</a></cite></p> <p>それでは当日現地でお会いできることを楽しみにしております!</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20231004/20231004184445.png" width="1200" height="676" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> tver-techblog DatastreamによるTVer ID会員情報の分析環境改善 hatenablog://entry/820878482968902404 2023-09-28T10:57:08+09:00 2023-09-28T10:57:08+09:00 TVerでデータシステムなど担当しております黒瀬です。 この記事では、弊社のサービスとして運用しているTVer ID の会員情報を保持するDB(以下、会員DB)のデータの集計にかかる時間を短縮した施策についてご紹介します。 サマリ DatastreamとPolicy Tagを利用することで、プライバシー保護を考慮しつつBigQueryで会員DBを高速で集計できるようにしました。 背景 TVerでは、GKEでセルフホストしているRedashを利用してデータ集計や分析を行っています。 また、弊社では分析用のデータはBigQueryに集約する方針のため、基本的にはRedashでの集計はBigQuer… <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>でデータシステムなど担当しております黒瀬です。</p> <p>この記事では、弊社のサービスとして運用している<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> ID の会員情報を保持するDB(以下、会員DB)のデータの集計にかかる時間を短縮した施策についてご紹介します。</p> <h1 id="サマリ">サマリ</h1> <p>DatastreamとPolicy Tagを利用することで、プライバシー保護を考慮しつつBigQueryで会員DBを高速で集計できるようにしました。</p> <h1 id="背景">背景</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>では、GKEでセルフホストしているRedashを利用してデータ集計や分析を行っています。</p> <p>また、弊社では分析用のデータはBigQueryに集約する方針のため、基本的にはRedashでの集計はBigQueryの<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>構文でクエリを作成しています。</p> <p>このRedashでクエリを実行するタスクの一つとして、弊社が提供している<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> IDの会員の動向を集計・分析するというものがあります。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> IDの会員DBは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon">Amazon</a> RDSで構築した<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>でホストしており、RedashからはEC2で作成した踏み台経由でアクセスしていました。</p> <p>また、Redashからは個人情報を含むフィールドをマスクするためのviewにクエリを実行することで、プライバシーも考慮した仕組みとしていました。</p> <p><figure class="figure-image figure-image-fotolife" title="従来の構成図"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230927/20230927184259.png" width="763" height="511" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>従来の構成</figcaption></figure></p> <h1 id="課題">課題</h1> <p>この従来の構成では下記の課題がありました。</p> <ul> <li>Redashで作成するクエリは大部分がBigQueryの<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>であるにも関わらず、会員DBは<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>の<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>構文でクエリを作成する必要があり、仕様の差異に留意する必要があったり突合しにくいといったことから、運用がしにくい問題がありました。</li> <li>これは会員DBのスペック上の制約でもありますが、従来の構成では会員DBに対して実行したクエリのレスポンスに数時間かかっていました。結果、集計担当者がRedashで実行したクエリの様子を見に行く必要があったりRedashのワーカーを長時間占有するなど、分析が滞る原因となっていました。</li> <li>稀に調査などでフィールドをマスクしていないデータを見る必要がある際は、Redash経由ではなく踏み台などから直接クエリを実行しなければなりませんでした。</li> </ul> <p>そこで、これまで利用していたRedashの上で、高速かつセキュアにデータを集計するための仕組みについて検討しました。</p> <h1 id="方針">方針</h1> <p>上記の課題を解決するため、次のような方針で進めることにしました。</p> <ul> <li>BigQueryにデータを同期することで、<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>でクエリを書かなくていいようにしつつ、サーバレスのクエリ実行環境であるBigQueryによるレスポンス改善を目指しました。</li> <li>フィールドをBigQuery側で隠蔽することで、分析の要件に合わせてフィールドへのアクセス権やマスキングをBigQueryで制御できることを目指しました。</li> </ul> <p>ここからは、これらを実現するための詳細についてご紹介いたします。</p> <h1 id="アプローチと効果">アプローチと効果</h1> <h2 id="DatastreamでMySQLからBigQueryにデータを同期する">Datastreamで<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>からBigQueryにデータを同期する</h2> <p>Datastreamは<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloudで手軽にデータ変更キャプチャ(CDC; Change Data Capture)によるデータ同期ができるサービスです。今回はこのサービスを利用して<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>のデータを都度BigQueryに同期することで、BigQueryで会員DBのデータを分析できるようにしました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcloud.google.com%2Fdatastream%2Fdocs%2Foverview" title="Overview of Datastream  |  Google Cloud" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://cloud.google.com/datastream/docs/overview">cloud.google.com</a></cite></p> <p>導入も非常に簡単で、今回は<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>でbinlogを設定し、踏み台の認証情報をDatastreamで指定するだけでBigQueryにデータを同期できるようになりました。</p> <p>この施策により、BigQueryの<a class="keyword" href="https://d.hatena.ne.jp/keyword/SQL">SQL</a>で会員DBのデータを分析できるようになり、またこれまで数時間かかっていたクエリも、<a class="keyword" href="https://d.hatena.ne.jp/keyword/MySQL">MySQL</a>の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%B9%A5%BF">クラスタ</a>のスペックによらず、十数秒で結果が返ってくるようになりました。</p> <p><figure class="figure-image figure-image-fotolife" title="新しい構成"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230927/20230927184338.png" width="1112" height="513" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>新しい構成</figcaption></figure></p> <h2 id="BigQueryに同期したテーブルのフィールドにPolicy-Tagを付与する">BigQueryに同期したテーブルのフィールドにPolicy Tagを付与する</h2> <p>Policy TagはBigQueryのフィールド単位で権限やマスキング方法の制御ができる機能です。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcloud.google.com%2Fbigquery%2Fdocs%2Fcolumn-level-security-intro" title="Introduction to column-level access control  |  BigQuery  |  Google Cloud" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://cloud.google.com/bigquery/docs/column-level-security-intro">cloud.google.com</a></cite></p> <p>このPolicy Tagが関係するロールとしてはMasked ReaderとFine-Grained Readerの2つがあります。Policy Tagが付与されているフィールドを含むテーブルへのクエリは、クエリを実行したアカウントがどのロールが付与されているかによって次のように結果が変わります。</p> <ul> <li>Masked Readerが付与されているアカウントが実行した場合: Policy Tagが付与されているフィールドがマスキングされて結果が返ってくる</li> <li>Fine-Grained Readerが付与されているアカウントが実行した場合: Policy Tagが付与されているフィールドがマスキングされずに結果が返ってくる</li> <li>いずれのロールも付与されていないアカウントが実行した場合: クエリは権限エラーになる</li> </ul> <p>今回は、氏名やメールアドレスといった会員DBに記録されている個人情報ごとに、マスク方法を適切に設定したPolicy Tagを作成し、該当するフィールドへ付与しました。</p> <p>そして、Redashでクエリを実行するためのサービスアカウントとしては想定する用途によって2つを用意しました。</p> <ul> <li>通常の分析ではマスキングされたデータを利用するため、Masked Readerが付与されているアカウントを利用</li> <li>調査などでマスキングされていないデータを利用する場合は、Fine-Grained Readerが付与されているアカウントを利用</li> </ul> <p>この施策により、BigQueryに閉じた設定でプライバシーを考慮したアクセス権限の制御ができるようになりました。</p> <h1 id="まとめ">まとめ</h1> <p>今回、Datastreamの導入によって会員DBのデータの分析にかかる時間を効率化することができました。また、Policy Tagによってプライバシー保護もロールによる制御へ簡潔化することができました。</p> <p>一方で、Datastreamによるデータ同期ではコストも相応にかかってくるため、今後はこのコストを抑える施策について検討していきたいと思います。</p> <h1 id="TVerではエンジニアを募集しています"><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>ではエンジニアを募集しています</h1> <p>今回ご紹介したデータシステム以外にもバックエンドやフロントエンドなど多彩なフィールドでエンジニアを募集しています!ご興味ある方はぜひ以下の採用サイトからご連絡ください!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Frecruit.tver.co.jp%2F" title="株式会社TVer 採用サイト" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://recruit.tver.co.jp/">recruit.tver.co.jp</a></cite></p> tver-techblog iOSDC Japan 2023にてTVerのモバイルアプリの品質改善をテーマに登壇してきました #iosdc hatenablog://entry/820878482969123507 2023-09-22T17:30:43+09:00 2023-09-22T17:31:54+09:00 こんにちは、TVerの加我です。最近ではフロントエンド周りのモニタリング強化やオブザーバビリティを推進しております。 先日の9/1 - 9/3に開催されましたiOSDC Japan 2023にて登壇してまいりました。 fortee.jp ちなみにTVerはシルバースポンサーとして協賛いたしました。 techblog.tver.co.jp © 2023 iOSDC Japan 2023 実行委員会 iOSDC Japanとは 以下、公式サイトからの引用です。 iOSDC Japan 2023はiOS関連技術をコアのテーマとしたソフトウェア技術者のためのカンファレンスです。今年もリアル会場とオンラ… <p>こんにちは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の加我です。最近ではフロントエンド周りのモニタリング強化やオブザーバビリティを推進しております。</p> <p>先日の9/1 - 9/3に開催されましたiOSDC Japan 2023にて登壇してまいりました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ffortee.jp%2Fiosdc-japan-2023%2Fproposal%2Fdd08cde4-d391-4538-800b-27bdf975f983" title="iOSエンジニアがいなくても泣かない!配信サービスのiOSアプリにおけるオブザーバビリティの実装と改善" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://fortee.jp/iosdc-japan-2023/proposal/dd08cde4-d391-4538-800b-27bdf975f983">fortee.jp</a></cite></p> <p>ちなみに<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>はシルバースポンサーとして協賛いたしました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fyoshida%2F20230901-iosdc2023" title="TVerはiOSDC Japan 2023に協賛をいたします! - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/yoshida/20230901-iosdc2023">techblog.tver.co.jp</a></cite></p> <p><figure class="figure-image figure-image-fotolife" title="© 2023 iOSDC Japan 2023 実行委員会"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230921/20230921170854.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>© 2023 iOSDC Japan 2023 実行委員会</figcaption></figure></p> <h1 id="iOSDC-Japanとは">iOSDC Japanとは</h1> <p>以下、公式サイトからの引用です。</p> <blockquote><p>iOSDC Japan 2023は<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a>関連技術をコアのテーマとしたソフトウェア技術者のためのカンファレンスです。今年もリアル会場とオンライン配信のハイブリッド開催です。<br/> 日本中、世界中から公募した知的好奇心を刺激する<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>の他にも、パンフレットに掲載された技術記事、参加者であれば誰でも作れる即興の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>・アンカンファレンスなど、初心者から上級者まで楽しめるコンテンツがみなさんを待っています。 9月1日(金) 〜 9月3日(日)はお祭りです!お楽しみに!!<br/> 開催に関連するニュースは公式<a class="keyword" href="https://d.hatena.ne.jp/keyword/Twitter">Twitter</a>アカウントからお知らせします。 是非フォローしておいてください。</p></blockquote> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fiosdc.jp%2F2023%2F" title="iOSDC Japan 2023" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://iosdc.jp/2023/">iosdc.jp</a></cite></p> <p><figure class="figure-image figure-image-fotolife" title="© 2023 iOSDC Japan 2023 実行委員会"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230922/20230922114519.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>© 2023 iOSDC Japan 2023 実行委員会</figcaption></figure></p> <h1 id="iOSDC-Japanと私">iOSDC Japanと私</h1> <p>初回のiOSDC Japanは2016年に練馬のココネリホールにて開催されました。私は<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a>エンジニアではないのですが、主催者と知り合いであり、かつカメラを持っているという理由から撮影スタッフとしてお誘いいただきました。それから毎年撮影スタッフを担当しております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fiosdc.jp%2F2016%2F" title="iOS Developers Conference Japan 2016" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://iosdc.jp/2016/">iosdc.jp</a></cite></p> <p>普段は撮影スタッフをしている私もいつかはiOSDC Japanで登壇したいという思いが少しずつ大きくなり、今年はフロントエンド・モバイルアプリの改善に携わっていたのでチャンスだと思いまして、プロポーザルを提出してみたところ登壇に至りました。</p> <h3 id="撮影スタッフとしての私">撮影スタッフとしての私</h3> <p>朝はスタッフ集合写真の撮影から始まり、スピーカーやスポンサー、参加者の写真などを撮ってます。 <figure class="figure-image figure-image-fotolife" title="© 2023 iOSDC Japan 2023 実行委員会"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230921/20230921154309.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>© 2023 iOSDC Japan 2023 実行委員会</figcaption></figure></p> <h3 id="スピーカーとしての私">スピーカーとしての私</h3> <p>念願のiOSDC Japanでの登壇ということもあり若干緊張しました。<br/> <figure class="figure-image figure-image-fotolife" title="© 2023 iOSDC Japan 2023 実行委員会"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230921/20230921154515.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>© 2023 iOSDC Japan 2023 実行委員会</figcaption></figure></p> <h1 id="トークのテーマ"><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>のテーマ</h1> <p>「<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a>の内製エンジニア不在という状況でどのようにしてアプリの品質を可視化し改善しているのか」という話をしてまいりました。</p> <p>昨年4月に<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>はサービスのリニューアルを行い、機能の追加と同時にバックエンド (サーバーサイド, インフラ) の内製化を行いました。しかし、フロントエンド (Web, モバイル, テレビアプリ) に関しては引き続き協力会社との共同開発であるため、アプリの品質の計測・可視化については事業者である私たちが責任を持ってやる必要があり、New Relic Mobileを活用してどのようにモバイルアプリの品質を改善しているかという取り組みについてお話してきました。</p> <h1 id="トークへのフィードバック"><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>へのフィードバック</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%D7%A5%EA%B3%AB%C8%AF">アプリ開発</a>における設計や新機能の具体的な活用といった<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>ではなく、どちらかというと組織的な取り組みといった側面が強かったため、iOSDC Japanに来場される参加者の需要があるのか正直心配でした。来場者0人の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>会場で喋る悪夢を何度か見ましたが、当日は多くの方に足を運んでいただき、ありがたいことに温かいフィードバックを沢山頂戴しました。当日は別のセッションを見ていたが動画で私の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>を見てフィードバックしてくれたという方もいまして、本当に感謝しております。</p> <p>現地の<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a>エンジニアの方々と話してみたところ、モバイル<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%D7%A5%EA%B3%AB%C8%AF">アプリ開発</a>だとやはりFirebaseを利用しているケースが多く、Firebase CrashlyticsやPerformance Monitoringは使ったことがあるけどNew Relic Mobileは使ったことがないという意見が多かったです。New Relic Mobileの採用については「小規模な技術組織である私達がツールのサイロ化を避けつつフロントエンドからバックエンドまで横断的にサービスの可視化をする」という弊社の事情に理解を示してくれる方もいました。</p> <p>将来的に<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のモバイルチームが発足するのであれば、ツールのサイロ化を恐れずにFirebaseとNew Relic Mobileを使い分けるという可能性もあるかと思います。こちらについては今後進展がありましたら何かしらの場にて発表したいと思います。</p> <h1 id="まとめ">まとめ</h1> <p>iOSDC Japan 2023で<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のモバイルアプリの品質計測と改善について登壇してまいりました。直近ではさらに踏み込んだ視聴体験の可視化・改善を少しずつ進めています。</p> <p>私の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>を聞いてくれた方、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>後のask the speakerに来てくれた方、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>へのフィードバックをくれた方、<a class="keyword" href="https://d.hatena.ne.jp/keyword/SNS">SNS</a>にて言及してくれた方、ありがとうございました!!</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>の最後の方でもお話しましたが、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>では<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a>アプリの品質の可視化と改善を一緒に進めてくれるエンジニアを募集しています。もし<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の技術組織について興味を持った方がいましたら弊社の採用サイトにぜひアクセスしてみてください。一緒に視聴体験の可視化と改善をやっていきましょう!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Frecruit.tver.co.jp%2F" title="株式会社TVer 採用サイト" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://recruit.tver.co.jp/">recruit.tver.co.jp</a></cite></p> <p>ということで、iOSDC Japanの次回の開催も楽しみにしております!それではまた来年お会いしましょう! <figure class="figure-image figure-image-fotolife" title="© 2023 iOSDC Japan 2023 実行委員会"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230921/20230921152625.jpg" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>© 2023 iOSDC Japan 2023 実行委員会</figcaption></figure></p> tver-techblog 現地参加してきたGoogle Cloud Next '23で発表されたBigQuery data clean roomsを紹介します! hatenablog://entry/820878482960381897 2023-09-07T11:00:00+09:00 2023-09-07T15:01:38+09:00 こんにちは。データエンジニア 遠藤(TVerにJOINしてまだ3ヶ月)とアドテクエンジニア 鶴貝です。 2023年8月29日~31日にGoogle Cloudの技術カンファレンスGoogle Cloud Next '23がサンフランシスコで開催されました。(4年ぶりのオフライン開催) 弊社では、民放公式テレビ配信サービスTVer・TVer広告のデータ分析で用いるビッグデータ基盤にGCPを採用しています。そこで、先述したエンジニア2名がGoogle Cloud Next '23に現地参加させて頂きました。 Next '23ではGCPの新機能リリースや世界中での活用事例が多く紹介されました。本記事… <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230904/20230904054824.png" width="1200" height="800" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>こんにちは。データエンジニア 遠藤(<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>にJOINしてまだ3ヶ月)とアドテクエンジニア 鶴貝です。</p> <p>2023年8月29日~31日に<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloudの技術カンファレンス<a href="https://cloud.withgoogle.com/next">Google Cloud Next '23</a>がサンフランシスコで開催されました。(4年ぶりのオフライン開催)</p> <p>弊社では、民放公式テレビ配信サービス<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>・<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>広告のデータ分析で用いる<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D3%A5%C3%A5%B0%A5%C7%A1%BC%A5%BF">ビッグデータ</a>基盤に<a class="keyword" href="https://d.hatena.ne.jp/keyword/GCP">GCP</a>を採用しています。そこで、先述したエンジニア2名が<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Next '23に現地参加させて頂きました。</p> <p>Next '23では<a class="keyword" href="https://d.hatena.ne.jp/keyword/GCP">GCP</a>の新機能リリースや世界中での活用事例が多く紹介されました。本記事では、Next '23で発表された話題のうち、BigQuery data clean roomsを重点的に報告します。</p> <p>さらに、サンフランシスコまではるばる出向きましたので、撮って出し写真と共に<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Next '23の様子をレポートします!</p> <ul class="table-of-contents"> <li><a href="#BigQuery-data-clean-rooms">BigQuery data clean rooms</a><ul> <li><a href="#データクリーンルームとは">データクリーンルームとは</a></li> <li><a href="#Ads-Data-HubAnalytics-Hubを経てのリリース">Ads Data Hub・Analytics Hubを経てのリリース</a></li> <li><a href="#BigQuery-data-clean-roomsを実際に使ってみる">BigQuery data clean roomsを実際に使ってみる</a><ul> <li><a href="#1-BigQueryでデータクリーンルームを使用できる状態にする">1. BigQueryでデータクリーンルームを使用できる状態にする</a></li> <li><a href="#2-プロバイダ側でデータクリーンルームを新規作成">2. プロバイダ側でデータクリーンルームを新規作成</a></li> <li><a href="#3-コンシューマ側でデータクリーンルーム参照を設定">3. コンシューマ側でデータクリーンルーム参照を設定</a></li> <li><a href="#4-コンシューマ側がデータクリーンルームからデータを抽出する">4. コンシューマ側がデータクリーンルームからデータを抽出する</a></li> </ul> </li> </ul> </li> <li><a href="#おまけGoogle-Cloud-Next-23-現地参加レポート">おまけ:Google Cloud Next '23 現地参加レポート!</a></li> <li><a href="#おわりに">おわりに</a></li> <li><a href="#We-are-hiring">We are hiring</a></li> </ul> <h1 id="BigQuery-data-clean-rooms">BigQuery data clean rooms</h1> <p><a href="https://cloud.withgoogle.com/next?session=ANA100">「What's new with BigQuery」</a>・<a href="https://cloud.withgoogle.com/next?session=ANA200">「Share securely with data clean rooms」</a>の各セッションにおいてBigQuery data clean roomsの<a class="keyword" href="https://d.hatena.ne.jp/keyword/Preview">Preview</a>リリースが発表されました。データ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>は他<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>では既にリリースされていますが、ついに<a class="keyword" href="https://d.hatena.ne.jp/keyword/GCP">GCP</a>にも本格的に登場します。</p> <h2 id="データクリーンルームとは">データ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>とは</h2> <p>データ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>とは個人を特定することなくプライバシーを保護しながらデータの分析・利活用ができる<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>環境のことです。</p> <p>社外へのデータ共有は、集計結果のメール送付や共有サーバへのアップロード・社内ネットワークへのアクセス権限を関係者に付与…といった方法が一般的でした。しかし、従来の共有方法では運用を一歩間違えれば意図しない第<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%B0%BC%D4">三者</a>へのデータ漏洩・<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C9%D4%C0%B5%A5%A2%A5%AF%A5%BB%A5%B9">不正アクセス</a>の発生といったリスクがあります。</p> <p>さらに近年では、法規制・ベンダーのト<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%E9%A5%C3%A5%AD%A5%F3%A5%B0">ラッキング</a>規制に伴うデータ利用の厳格化、個人情報取扱いに違反すると社会問題にまで発展…といった新たな問題も勃発しています。</p> <p>そのため、リスクを最小限に抑えた効率的なデータ共有の必要性がますます叫ばれています。そこで、データの提供側と利用側それぞれの不利な点を解消しながらデータ共有する技術がデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>です。</p> <h2 id="Ads-Data-HubAnalytics-Hubを経てのリリース">Ads Data Hub・Analytics Hubを経てのリリース</h2> <p>BigQueryは、IAMユーザに適切な権限を付与すれば、BigQueryデータの他Projectからのアクセスは基本的に可能です。しかし、この運用では以下の問題があります。</p> <ul> <li>他Projectにあるテーブル参照はBigQuery WebUI的に不便(例:アクセスできる他ProjectのテーブルはBigQuery WebUIのサイドバー「<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%AF%A5%B9%A5%D7%A5%ED%A1%BC%A5%E9">エクスプローラ</a>」には載らない)</li> <li>組織外に公開したBigQueryテーブルに対する組織外アカウントの使用状況がテーブルを所有するProjectから把握できない</li> <li>他組織に対してデータ取得に関する細かな制御条件が設定できない</li> </ul> <p>一方、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a>ではAds Data HubとAnalytics Hubという機能が既に提供されています。</p> <p><a href="https://developers.google.com/ads-data-hub">Ads Data Hub</a>は、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a>の広告プロダクトのデータとクライアントが<a class="keyword" href="https://d.hatena.ne.jp/keyword/%CA%DD%CD%AD">保有</a>するデータを突合する機能です。</p> <p>また、Ads Data Hubは以下の特徴があり、プライバシーを考慮したユーザレベルでの広告分析を可能にしています。</p> <ul> <li>ユーザIDのような個人レベルの情報は一切出力されない</li> <li>集計結果が一定の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%EF%E7%C3%CD">閾値</a>未満の場合は集計結果の数値自体出力されない</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/Google%20Ads">Google Ads</a>・Display &amp; Video 360のデータと広告主データ間の共有のみに限られる(=用途が<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a>広告の分析のみに限定される)</li> </ul> <p>昨年BigQuery上でGenerally Available(GA)になった<a href="https://cloud.google.com/analytics-hub">Analytics Hub</a>は、BigQueryオブジェクト(テーブル、ビュー、MLモデル)を組織間で共有できる機能です。</p> <p>共有する側(プロバイダ)が公開したいDatasetをExchange/Listingとして登録してShared Datasetに追加します。一方、共有される側(コンシューマ)はListing検索して、プロバイダのShared DatasetをLinked Datasetとして自分のProjectに登録します。これにより、Project間のDataset共有が容易に実現できます。</p> <p>つまり、Ads Data Hubのプライバシー保護に特化した特徴をAnalytics Hubに適用した機能が<a href="https://cloud.google.com/bigquery/docs/data-clean-rooms">BigQuery data clean rooms</a>です。(そのためBigQuery data clean roomsはAnalytics Hub上の機能としてリリースされます)</p> <h2 id="BigQuery-data-clean-roomsを実際に使ってみる">BigQuery data clean roomsを実際に使ってみる</h2> <p>BigQuery data clean roomsでは以下の手順でデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>を作成・運用します。</p> <ol> <li>BigQueryでデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>を使用できる状態にする</li> <li>プロバイダ側でデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>を新規作成</li> <li>コンシューマ側でデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>参照を設定</li> <li>コンシューマ側がデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>からデータを抽出する</li> </ol> <h3 id="1-BigQueryでデータクリーンルームを使用できる状態にする">1. BigQueryでデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>を使用できる状態にする</h3> <p>まず、BigQueryでデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>機能を使用するには、プロバイダ・コンシューマの各Projectで以下の前処理が必要です。</p> <ul> <li><a href="https://console.cloud.google.com/apis/library/analyticshub.googleapis.com">Analytics Hub API</a>を有効化</li> <li>データ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>作成・参照設定を行うそれぞれのIAMユーザに対して適切なAnalytics Hubロールを付与</li> </ul> <p>次に、プロバイダProjectにおいてコンシューマへシェアするDatasetとそのDataset上に存在するViewをあらかじめ新規に作成します。なぜなら、データ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>は、Analytics HubのExchangeとは違い、Viewのみ共有されるからです。(テーブルは共有されません)</p> <p>そのため、データ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>では以下の<a class="keyword" href="https://d.hatena.ne.jp/keyword/DDL">DDL</a>文のような<a href="https://cloud.google.com/bigquery/docs/privacy-policies">「Privacy Policyを設定した承認付きView」</a>の作成を推奨しています。</p> <pre class="code SQL" data-lang="SQL" data-unlink>CREATE OR REPLACE VIEW `provider_project.cleanroom_share.dcr_provide_data_view` OPTIONS ( privacy_policy=TO_JSON_STRING( STRUCT( STRUCT( &#34;column_a&#34; AS privacy_unit_columns, 2 AS threshold ) AS aggregation_threshold_policy ) ) ) AS ( SELECT * FROM `provider_project.cleanroom_data.dcr_provide_data_table` )</pre> <h3 id="2-プロバイダ側でデータクリーンルームを新規作成">2. プロバイダ側でデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>を新規作成</h3> <p>プロバイダProjectのAnalytics Hub WebUI上で新規にデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>を作成します。</p> <p>2-1. BigQueryメニューから『Analytics Hub』を選択 → 『CREATE CLEAN ROOM』をクリック(下図参照)</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230905/20230905190038.png" width="750" height="249" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>2-2. 表示名などの情報を入力してデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>を作成</p> <p>2-3. 2-2.で作成したデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>の表示名をクリック → 『データを追加』をクリック</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230904/20230904050351.png" width="1065" height="362" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>2-4. 共有するDatasetを設定(Datasetを設定すると、共有される予定のDataset内にあるViewがprivacy policy情報とともに確認できます)</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230904/20230904050313.png" width="848" height="685" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h3 id="3-コンシューマ側でデータクリーンルーム参照を設定">3. コンシューマ側でデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>参照を設定</h3> <p>次はコンシューマProjectの設定です。</p> <p>3-1. BigQueryメニューから『Analytics Hub』を選択 → 『リスティングを検索』をクリック(下図参照)</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230905/20230905190038.png" width="750" height="249" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>そうすると、以下の図のように2.で設定されたDatasetがListing検索できる画面が表れます。ここから参照するDatasetを検索します。</p> <p>3-2. Listing検索からプロバイダ側のDatasetをさがし、選択して、登録</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230904/20230904065132.png" width="1172" height="283" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>最終的に、コンシューマProjectのBigQuery WebUI中の「<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%AF%A5%B9%A5%D7%A5%ED%A1%BC%A5%E9">エクスプローラ</a>」に表示されるテーブル一覧中に <code>【Analytics Hub 表示名】_【データ表示名】</code> という名のDatasetが作成されます。(下図参照)</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230904/20230904055705.png" width="455" height="449" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h3 id="4-コンシューマ側がデータクリーンルームからデータを抽出する">4. コンシューマ側がデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>からデータを抽出する</h3> <p>コンシューマProjectにおいてデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>内のデータを抽出するクエリは以下になります。</p> <pre class="code SQL" data-lang="SQL" data-unlink>SELECT WITH AGGREGATION_THRESHOLD column_b,COUNT(1) FROM `consumer_project.test_cleanroom_dcr_share.dcr_provide_data_view` GROUP BY 1</pre> <p>クエリ内で参照したテーブルのDatasetは3.で参照設定したDatasetであり、まるで自ProjectのDatasetのように扱うことができます。</p> <p>「SELECT WITH AGGREGATION_THRESHOLD」はPrivacy Policyを設定したViewに対するSELECT句であり、以下の特徴があります。</p> <ul> <li><a href="https://cloud.google.com/bigquery/docs/privacy-policies#agg_threshold_policy_functions">特定の集計関数</a>・GROUP BYをクエリに含めることが最低条件(そのためレコード抽出はできない)</li> <li>Privacy Policyのprivacy_unit_columnsで指定したカラムをGROUP BYに含めることはできない(privacy_unit_columnsは個人を特定するカラムを表す)</li> <li>Privacy PolicyのTHRESHOLDで設定した数値以上の集計値のレコードのみを集計結果に返す</li> </ul> <p>データ抽出の制約は、現在のPublic <a class="keyword" href="https://d.hatena.ne.jp/keyword/Preview">Preview</a>時点では『SELECT WITH AGGREGATION_THRESHOLD』句に関連した設定しかできないようですが、Generally Available(GA)時に以下の設定ができるように対応する見込みであると「Share securely with data clean rooms」セッション内で発表されました。(このときにAnalytics HubのExchangeと明確な機能差別化を図ると思われます)</p> <ul> <li>オーバーラップ分析</li> <li>差分プライバシー</li> <li>joinの制限</li> </ul> <p>さらに、データ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>Datasetを参照したクエリをモニタリングする機能が実装されており、プロバイダ側でデータ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%EA%A1%BC%A5%F3%A5%EB%A1%BC%A5%E0">クリーンルーム</a>の利用状況の把握が可能です。</p> <h1 id="おまけGoogle-Cloud-Next-23-現地参加レポート">おまけ:<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Next '23 現地参加レポート!</h1> <p>さて、ここからは<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Next '23の模様をレポートします!</p> <p>サンフランシスコの夏は乾季のため、Next '23期間中はずっと快晴&気温は常に30℃を超えないので、とても過ごしやすい気候でした。</p> <p>会場は「Moscone Center」というサンフランシスコで有名なコンベンション施設でした。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230905/20230905200113.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230905/20230905195623.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>お昼どきには会場近くの庭でランチが無料で提供されました。(毎日違うメニュー & <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B0%A5%EB%A5%C6%A5%F3">グルテン</a>フリー・<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D9%A5%B8%A5%BF%A5%EA%A5%A2%A5%F3">ベジタリアン</a>にも対応していました)</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230905/20230905195829.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230905/20230905195832.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>上記の写真は3日目ランチのメニュー表です。</p> <p>この写真を早朝に撮っていたら準備中の設営スタッフから笑われてしまったので、</p> <p>「I'm expecting today's lunch time!!」</p> <p>と伝えました。</p> <p>スポンサーブースはとにかく規模が大きく、周りがいがありました。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230905/20230905195619.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>サンフランシスコといえばゴールデンゲートブリッジ。<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B5%A5%DE%A1%BC%A5%BF%A5%A4%A5%E0">サマータイム</a>の影響でこの写真を撮ったのは19時過ぎでしたが、まだ太陽が出ています。素晴らしい光景でした。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230905/20230905195841.jpg" width="1200" height="904" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>Next '23期間中、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Japan Teamの皆様が独自に以下のイベントを現地で開催してくださり、それぞれ参加させて頂きました。</p> <ul> <li>Japan Welcome Lounge(Next '23開催前日に催された日本からの参加者のウェルカムアワー)</li> <li>カジュアルディナー @ NEXT(日本から参加した同じ業界の皆様との懇親会)</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud 個別ミーティング(現地<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud TeamのProduct Managerとのミーティング)</li> <li>Japan Session &amp; Reception(Next '23のハイライトを日本語で伝えるRecap的イベント&<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a>グッズが当たるクイズ大会もあった懇親会)</li> </ul> <p>これらのイベントにより、今回の発表内容の理解がさらに深められ、日本から参加した他社の皆様と交流できました。(<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Japan Teamの皆様にはこの場をお借りして改めて御礼申し上げます)</p> <h1 id="おわりに">おわりに</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Next '23で紹介されたトピックのうち、BigQuery data clean roomsをいち早く紹介させていただきました。(BigQuery関連はこの他にBigQuery Studio、Duet AI in BigQuery…といったリリースが多数発表されましたが、なくなく割愛します…)</p> <p>弊社では社外にデータ共有する要件の案件が多くあるため、今回の機能を用いたシステムの導入を検討する予定です。</p> <p>さらに、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Next '23に現地参加したので写真と共にレポートさせていただきました。</p> <p>今回の現地参加は、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a>のホームである<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%E1%A5%EA">アメリ</a>カで日進月歩的に進化する<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>技術の最先端にいち早く触れられたので、エンジニアにおいてとても貴重な機会でした。</p> <p>ちなみに、今回の現地参加に関わる<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C5%CF%B9%D2">渡航</a>費・宿泊費などは全て会社に負担していただきました。(貴重な機会をいただけて本当に感謝です)</p> <hr /> <h1 id="We-are-hiring">We are hiring</h1> <p>このように<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>では、テックカンファレンスへの参加などを通して最新技術のキャッチアップやエンジニアの成長に積極的に投資しています。引き続き、エンジニアリングで<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の未来を一緒に作っていく仲間も募集していますので、ご興味のある方は以下のリンクからぜひご応募ください!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftver.co.jp%2Frecruit%2Findex.html" title="株式会社TVer の全ての求人一覧" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tver.co.jp/recruit/index.html">tver.co.jp</a></cite></p> tver-techblog TVerは JAWS Festa 2023 を応援しています! hatenablog://entry/820878482963308831 2023-08-31T16:52:55+09:00 2023-08-31T16:52:55+09:00 こんにちは。アドテク領域のエンジニアをしています安部です。 10月7日に開催される JAWS Festa 2023 に企業ロゴサポーターとして協賛します。福岡出身の私としては4年ぶりのリアル全国イベントが地元なのがとても嬉しいです! jft2023.jaws-ug.jp JAWS Festa とは HPより引用します。AWSユーザーのエキスパートたち、九州各県やスタートアップの事例などいまの九州だからこそやっていきたい、そんなコンテンツ/セッションと盛りだくさんのコミュニティイベントです。 jft2023.jaws-ug.jp 弊社とJAWS-UGの関わり 昨年のJAWS DAYS 2022 … <p>こんにちは。<br />アドテク領域のエンジニアをしています安部です。</p> <p>10月7日に開催される <a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023 に企業ロゴサポーターとして協賛します。<br />福岡出身の私としては4年ぶりのリアル全国イベントが地元なのがとても嬉しいです!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjft2023.jaws-ug.jp%2F" title="JAWS FESTA 2023 KYUSHU" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://jft2023.jaws-ug.jp/">jft2023.jaws-ug.jp</a></cite></p> <p> </p> <h3 id="JAWS-Festa-とは"><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa とは</h3> <p>HPより引用します。<br /><a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>ユーザーのエキスパートたち、九州各県やスタートアップの事例などいまの九州だからこそやっていきたい、そんなコンテンツ/セッションと盛りだくさんのコミュニティイベントです。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjft2023.jaws-ug.jp%2F" title="JAWS FESTA 2023 KYUSHU" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://jft2023.jaws-ug.jp/">jft2023.jaws-ug.jp</a></cite></p> <p> </p> <h3 id="弊社とJAWS-UGの関わり">弊社と<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGの関わり</h3> <p>昨年の<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> DAYS 2022 にセッションサポーターとして参加&弊社エンジニアが登壇しました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2F2022%2F10%2F11%2F161049" title="JAWS DAYS 2022にセッションサポーターとして協賛しました&登壇しました #jawsug #jawsdays2022 #TVer - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/2022/10/11/161049">techblog.tver.co.jp</a></cite></p> <p> </p> <p>また、Media-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>や<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG東北で弊社エンジニアが登壇しております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fkaga%2F202302-media-jaws-in-osaka" title="Media-JAWS #11 in 大阪 参加レポート #jawsug #mediajaws - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/kaga/202302-media-jaws-in-osaka">techblog.tver.co.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fkaga%2F20230729-jawsug-tohoku" title="JAWS-UG 東北(秋田)で登壇してきました #jawsug #jawsugtohoku #jawsugakita - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/kaga/20230729-jawsug-tohoku">techblog.tver.co.jp</a></cite></p> <p> </p> <h3 id="コミュニティ">コミュニティ</h3> <p>iOSDC Japan 2023や ISUCONへの協賛、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Daysでの登壇など積極的に技術情報のキャッチアップや発信をしております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fyoshida%2F20230901-iosdc2023" title="TVerはiOSDC Japan 2023に協賛をいたします! - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/yoshida/20230901-iosdc2023">techblog.tver.co.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Futsumi%2Fisucon13-sponsor" title="今年もTVer はISUCON13に協賛します #isucon #tver - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/utsumi/isucon13-sponsor">techblog.tver.co.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fkurose%2Fgcd23-wrap-up" title="Google Cloud Day '23 Tourで登壇しました #GoogleCloudDay - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/kurose/gcd23-wrap-up">techblog.tver.co.jp</a></cite></p> <p> </p> <h3 id="さいごに">さいごに</h3> <p>今年の<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Summitに参加して<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>面白そうだなと感じました。<br />その後業務でも<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>を触る機会が増え、7月に<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> CLFを取得しました。<br />次はコミュニティにも参加してみたいと思っていたところで<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a> Festa 2023が開催されるとのこと。<br />しかも開催場所が地元福岡なので何か貢献できれば!と思い参加を決めました。<br />当日はアンバサダーとして会場に居ます。多分会場中をうろうろしています。<br />皆様とコミュニケーションが取れることを楽しみにしています。<br />ぜひ<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>、エンジニア<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>、福岡<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>などしましょう!</p> <p> </p> <h3 id="We-are-hiring">We are hiring!</h3> <p>様々なポジションで採用中です。<br />「やりたい!」と言えばチャレンジさせてくれる環境です。<br /><a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a>でやってみたいことがあるという思いがある方、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>をよりよくしたいと思う方、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のミッション「テレビを開放して、もっとワクワクする未来を」に共感いただける方、ご応募お待ちしております!</p> <p> </p> <p>アドテク領域の業務についてお話させていただいた内容はこちら</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnote.com%2Ftver%2Fn%2Fn47835bc5f83a" title="事業成長も技術者としての成長も実感!アドテクエンジニアの業務とやりがいとは?〜/広告ソリューションタスク 鶴貝・安部 インタビュー|TVer HR BLOG" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://note.com/tver/n/n47835bc5f83a">note.com</a></cite></p> <p> </p> <p>募集職種はこちら</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fherp.careers%2Fv1%2Ftver" title="株式会社TVer の全ての求人一覧" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://herp.careers/v1/tver">herp.careers</a></cite></p> tver-techblog TVerはiOSDC Japan 2023に協賛をいたします! hatenablog://entry/820878482960352691 2023-08-30T15:30:00+09:00 2023-08-30T18:09:46+09:00 こんにちは! TVerでフロントエンド開発チーム(iOS, Android, Web)のマネジメントをしている吉田と申します。 私は2023年4月よりTVerにジョインしまして、過去20年程度IT業界で開発からマネジメントまで携わって参りました。 今後もTVerのブログ記事など執筆することもあるかと思いますが、何卒よろしくお願いいたします! TVerサービスと開発チーム TVerのサービスは、2023年5月には月間再生回数も3.5億回を超え、月間ユニークブラウザ数も2,800万を超えるサービスへと成長をしているものの[1]、まだまだ開発スピードの向上(=ビジネスの成長速度)を高めていける余地が… <p>こんにちは! <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>でフロントエンド開発チーム(<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a>, <a class="keyword" href="https://d.hatena.ne.jp/keyword/Android">Android</a>, Web)のマネジメントをしている吉田と申します。</p> <p>私は2023年4月より<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>にジョインしまして、過去20年程度IT業界で開発からマネジメントまで携わって参りました。 今後も<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のブログ記事など執筆することもあるかと思いますが、何卒よろしくお願いいたします!</p> <h3 id="TVerサービスと開発チーム"><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>サービスと開発チーム</h3> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のサービスは、2023年5月には月間再生回数も3.5億回を超え、月間ユニークブラウザ数も2,800万を超えるサービスへと成長をしているものの[1]、まだまだ開発スピードの向上(=ビジネスの成長速度)を高めていける余地があり、より迅速にユーザーの方々にお楽しみいただける体験を提供し続けて参りたいと考えております。</p> <p>[1] <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fprtimes.jp%2Fmain%2Fhtml%2Frd%2Fp%2F000000241.000002492.html" title="【TVer】2023年5月の動画再生数が前年比1.8倍の3.5億回を達成!月間ユーザー数も過去最高記録を更新" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://prtimes.jp/main/html/rd/p/000000241.000002492.html">prtimes.jp</a></cite></p> <p>2023年現在、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のサービス提供チャネルとしては、<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a>, <a class="keyword" href="https://d.hatena.ne.jp/keyword/Android">Android</a>, Web, コネクテッドTV(<a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon">Amazon</a> FireTVやAndroidTVなど)といったプラットフォームで展開をしておりますが、現在の開発体制としては、社内の開発チームと開発パートナーさんとが混在しているチームで構成されサービスのグロースを継続しております。</p> <p>このような状況の中、よりビジネスの成長サイクルを向上させるべく、開発チームの強化を組織的課題として捉え、今年度より<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>内製の開発チームの発足を開始いたしました。2023年4月からは<a class="keyword" href="https://d.hatena.ne.jp/keyword/Android">Android</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%D7%A5%EA%B3%AB%C8%AF">アプリ開発</a>の内製チームが立ち上がり、同年8月からは品質管理の内製チームが立ち上がり、また、2023年10月からは<a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%D7%A5%EA%B3%AB%C8%AF">アプリ開発</a>の内製チームが立ち上がる予定です。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/iOS">iOS</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%D7%A5%EA%B3%AB%C8%AF">アプリ開発</a>チームの発足に伴い、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>として技術コミュニティにも何かしらの形で貢献をしていきたいよね、という話があがりまして、今回の「iOSDC Japan 2023」に些細ながらも協賛をさせていただく運びとなりました。</p> <p>また、弊社の加我が9月2日11時からのセッションで登壇をいたしますので、ご興味ございましたら是非ご覧くださいませ。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ffortee.jp%2Fiosdc-japan-2023%2Fproposal%2Fdd08cde4-d391-4538-800b-27bdf975f983" title="iOSエンジニアがいなくても泣かない!配信サービスのiOSアプリにおけるオブザーバビリティの実装と改善" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://fortee.jp/iosdc-japan-2023/proposal/dd08cde4-d391-4538-800b-27bdf975f983">fortee.jp</a></cite></p> <h3 id="We-are-hiring">We are hiring!</h3> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>ではフロントエンドだけではなく、バックエンド開発、データサイエンス、SREといったエンジニアも在籍しており、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Daysでの登壇[2]や<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> Summit Tokyoへの参加[3]、ISUCONへの協賛[4]など、積極的に技術情報のキャッチアップや発信をしております。</p> <p>[2] <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fkurose%2Fgcd23-wrap-up" title="Google Cloud Day &#39;23 Tourで登壇しました #GoogleCloudDay - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/kurose/gcd23-wrap-up">techblog.tver.co.jp</a></cite></p> <p>[3] <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2F2023%2F04%2F12%2F110006" title="AWS Summit Tokyo 2023にTVerのエンジニアが5名参加します #jawsug #awssummittokyo - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/2023/04/12/110006">techblog.tver.co.jp</a></cite></p> <p>[4] <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Futsumi%2Fisucon13-sponsor" title="今年もTVer はISUCON13に協賛します #isucon #tver - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/utsumi/isucon13-sponsor">techblog.tver.co.jp</a></cite></p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のミッション「#テレビを開放して、もっとワクワクする未来を」に共感いただけるテレビの未来を支えるエンジニアの方をお待ちしております!(iOSDCの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>ンは<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のミッションです)</p> <p>募集職種はこちらをご参照くださいませ!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftver.co.jp%2Frecruit" title="株式会社TVer の全ての求人一覧" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tver.co.jp/recruit">tver.co.jp</a></cite></p> tver-techblog ISUCON 夏祭り 2023 参加レポート hatenablog://entry/820878482962424618 2023-08-29T15:11:13+09:00 2023-08-29T15:14:07+09:00 こんにちは。TVerの水野です。 2023年8月26日(土)、ヤフー株式会社 17F LODGE & セミナールームで開催された、ISUCON 夏祭り 2023に参加してきました。 isucon.connpass.com ISUCONとは ISUCON夏祭りとは 会場 ISUCON個人スポンサー ノベルティ ハンズオン トークセッション 登壇動画 登壇資料 Fireside Chat 交流会 感想 最後に ISUCONとは ISUCONについては、下記のインタビュー記事より引用させて頂きます。 『ISUCON(イスコン)』とは『Iikanjini Speed Up Contest(いい感じに … <p>こんにちは。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の水野です。</p> <p>2023年8月26日(土)、ヤフー株式会社 17F LODGE &amp; <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BB%A5%DF">セミ</a>ナールームで開催された、ISUCON 夏祭り 2023に参加してきました。 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fisucon.connpass.com%2Fevent%2F288820%2F" title="ISUCON 夏祭り 2023 (2023/08/26 09:30〜)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://isucon.connpass.com/event/288820/">isucon.connpass.com</a></cite></p> <ul class="table-of-contents"> <li><a href="#ISUCONとは">ISUCONとは</a><ul> <li><a href="#ISUCON夏祭りとは">ISUCON夏祭りとは</a><ul> <li><a href="#会場">会場</a></li> <li><a href="#ISUCON個人スポンサー">ISUCON個人スポンサー</a></li> <li><a href="#ノベルティ">ノベルティ</a></li> </ul> </li> </ul> </li> <li><a href="#ハンズオン">ハンズオン</a></li> <li><a href="#トークセッション">トークセッション</a><ul> <li><a href="#登壇動画">登壇動画</a></li> <li><a href="#登壇資料">登壇資料</a></li> </ul> </li> <li><a href="#Fireside-Chat">Fireside Chat</a></li> <li><a href="#交流会">交流会</a></li> <li><a href="#感想">感想</a></li> <li><a href="#最後に">最後に</a></li> </ul> <h1 id="ISUCONとは">ISUCONとは</h1> <p>ISUCONについては、下記のインタビュー記事より引用させて頂きます。</p> <blockquote><p>『ISUCON(イスコン)』とは『Iikanjini Speed Up Contest(いい感じに スピードアップ コンテスト)』を略したイベント名。ISUCONでは「お題となる<a class="keyword" href="https://d.hatena.ne.jp/keyword/Web%A5%B5%A1%BC%A5%D3%A5%B9">Webサービス</a>を決められたレギュレーションの中で限界まで高速化を図るチューニングバトル」が繰り広げられます。優勝賞金はなんと100万円。</p></blockquote> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fzine.qiita.com%2Finterview%2F202209-isucon12%2F%23%3A~%3Atext%3D%25E3%2580%258EISUCON%25EF%25BC%2588%25E3%2582%25A4%25E3%2582%25B9%25E3%2582%25B3%25E3%2583%25B3%25EF%25BC%2589%25E3%2580%258F%25E3%2581%25A8%2C%25E3%2581%25AF%25E3%2581%25AA%25E3%2582%2593%25E3%2581%25A8100%25E4%25B8%2587%25E5%2586%2586%25E3%2580%2582" title="「なんでもあり」なWebアプリのチューニングバトル『ISUCON』はエンジニアの輪が広がる文化祭? ISUCON12出題者に大人気の秘密を聞いた - Qiita Zine" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://zine.qiita.com/interview/202209-isucon12/#:~:text=%E3%80%8EISUCON%EF%BC%88%E3%82%A4%E3%82%B9%E3%82%B3%E3%83%B3%EF%BC%89%E3%80%8F%E3%81%A8,%E3%81%AF%E3%81%AA%E3%82%93%E3%81%A8100%E4%B8%87%E5%86%86%E3%80%82">zine.qiita.com</a></cite></p> <h2 id="ISUCON夏祭りとは">ISUCON夏祭りとは</h2> <p>ISUCON夏祭りは、ISUCON好きな人たちが集まり、ハンズオン、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>セッション、交流会などを楽しむお祭りです。</p> <p><a href="https://isucon.connpass.com/event/288820/">イベントサイトより引用</a></p> <blockquote><p>ISUCON 夏祭り 2023はISUCONが好きな人であれば誰でも参加できるISUCONのお祭りです。</p> <p>・ISUCON何もわからないけどチャレンジしてみたい</p> <p>・ISUCONのことが好きすぎるので、同じような人とISUCONについて語りたい</p> <p>・ISUCONについて語っている人を間近で見たい</p> <p>といった方に特にオススメです。</p></blockquote> <h3 id="会場">会場</h3> <p>会場は<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>セッションや夏祭りブース(スポンサーブース、射的など)があり、これらをワンフロアで実施されていましたので、エリアによる熱量の差なく、常に盛り上がっている雰囲気でした。</p> <p>9:30-19:00のイベントでしたが、こうした夏祭りブースのおかげで気分転換を挟みながら1日を過ごせました。</p> <table> <thead> <tr> <th> </th> <th> </th> <th> </th> </tr> </thead> <tbody> <tr> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828155943.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828160037.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828160108.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> </tr> </tbody> </table> <table> <thead> <tr> <th> </th> <th> </th> <th> </th> </tr> </thead> <tbody> <tr> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828161019.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828161038.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828161102.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> </tr> </tbody> </table> <table> <thead> <tr> <th> </th> <th> </th> </tr> </thead> <tbody> <tr> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828161220.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828161241.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> </tr> </tbody> </table> <table> <thead> <tr> <th> </th> <th> </th> <th> </th> <th> </th> </tr> </thead> <tbody> <tr> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828164118.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828164136.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828164202.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828164220.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> </tr> </tbody> </table> <table> <thead> <tr> <th> </th> <th> </th> <th> </th> <th> </th> </tr> </thead> <tbody> <tr> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828164253.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828164358.jpg" width="1200" height="900" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828164423.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828164453.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> </tr> </tbody> </table> <p>Splunk Services Japan<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B9%E7%C6%B1%B2%F1%BC%D2">合同会社</a>様のお写真を撮り損ねてしまいましたので、ISUCON公式 Xをご確認ください... <blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">🎆 ISUCON 夏祭り 2023 🎆<br>協賛頂いた企業様の出展ブース紹介👏<br><br>Splunk Services Japan<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B9%E7%C6%B1%B2%F1%BC%D2">合同会社</a>様<br>アンケート企画 &amp; F1<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BF%A5%A4%A5%E0%A5%A2%A5%BF%A5%C3%A5%AF">タイムアタック</a>を実施されています🚗 1位の人には豪華景品が?!楽しみです。 <a href="https://twitter.com/hashtag/isucon?src=hash&amp;ref_src=twsrc%5Etfw">#isucon</a> <a href="https://twitter.com/hashtag/isucon_summer_fes?src=hash&amp;ref_src=twsrc%5Etfw">#isucon_summer_fes</a> <a href="https://t.co/b9W2HYlPQP">pic.twitter.com/b9W2HYlPQP</a></p>&mdash; ISUCON公式 (@isucon_<a class="keyword" href="https://d.hatena.ne.jp/keyword/official">official</a>) <a href="https://twitter.com/isucon_official/status/1695262222061338739?ref_src=twsrc%5Etfw">2023年8月26日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <h3 id="ISUCON個人スポンサー">ISUCON個人スポンサー</h3> <p>ISUCON個人スポンサーの特典グッズが紹介されており、実用的なアイテムが多く用意されていました。</p> <p>いつかISUCONの特典グッズだけでキャンプにいけそうなバリエーション...</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fisucon.net%2Farchives%2F57790473.html" title="ISUCON13 個人スポンサーの募集について : ISUCON公式Blog" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://isucon.net/archives/57790473.html">isucon.net</a></cite></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828152143.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <table> <thead> <tr> <th>ISUCON12</th> <th>ISUCON12</th> <th>ISUCON11</th> <th>ISUCON10</th> </tr> </thead> <tbody> <tr> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828152059.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828152033.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828152011.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828151905.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> </tr> </tbody> </table> <h3 id="ノベルティ"><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%CE%A5%D9%A5%EB%A5%C6%A5%A3">ノベルティ</a></h3> <p>こちらがISUCON 夏祭りの参加者<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%CE%A5%D9%A5%EB%A5%C6%A5%A3">ノベルティ</a>です。 <figure class="figure-image figure-image-fotolife" title="ノベルティ一覧"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828144834.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%CE%A5%D9%A5%EB%A5%C6%A5%A3">ノベルティ</a>一覧</figcaption></figure></p> <p>さくらの<a class="keyword" href="https://d.hatena.ne.jp/keyword/VPS">VPS</a> 2Gクーポンが入ってました。これでしっかり素振りできます。 <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828172731.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="ハンズオン">ハンズオン</h1> <p>ハンズオンは、座学 + ライブコーディング形式で行われました。</p> <p><iframe id="talk_frame_1068229" class="speakerdeck-iframe" src="//speakerdeck.com/player/fd6e01c1053841aaaa213fd195abefc3" width="710" height="532" style="aspect-ratio:710/532; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/rosylilly/isucon-xia-ji-ri-2023-hanzuonzi-liao">speakerdeck.com</a></cite></p> <p>座学の初めに、約100人の参加者を対象にアンケートが行われ、ISUCONに何の言語で参加する予定かを挙手する時間がありました。その結果、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Ruby">Ruby</a>と<a class="keyword" href="https://d.hatena.ne.jp/keyword/PHP">PHP</a>が約4人ずつで、残りのほとんどがGoを選んでました。今年もGoの人気が高いことが感じられました。</p> <p>座学では、</p> <ul> <li>問題の出題傾向として、なんとなく流行っている技術が使われがち</li> <li>8時間コーディングをし続けるのではなく、ベンチを回し続ける大会</li> <li>8時間で800回デプロイする競技。1時間で10回。だからワークフローを高速に構築することが大事</li> </ul> <p>など、ISUCON参加者に向けた多くのポイントを解説して頂きました。</p> <p>ライブコーディングでは、private-isuという<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>を使用しました。この<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>は私自身も知っていたものの、実際に触る機会がなかったため、今回のハンズオンでその内容に触れることができて良かったです。興味を持った方は、この<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>をクローンして<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D9%A5%F3%A5%C1%A5%DE%A1%BC%A5%AF">ベンチマーク</a>を試してみることで、ISUCONに対するイメージが湧いてくると思います。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fcatatsuy%2Fprivate-isu" title="GitHub - catatsuy/private-isu: 社内ISUCON" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/catatsuy/private-isu">github.com</a></cite></p> <h1 id="トークセッション"><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>セッション</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>セッションについては、登壇動画と登壇資料がアップロードされており、詳細はそちらでご確認いただけます。</p> <p>全てのセッションが非常に有益な内容でしたが、特に「NaruseJunの戦略とコミュニケーション / とーふとふさん」というセッションでは、昨年の優勝チームであるNaruseJunの方が、自身のチームの戦略やコミュニケーションについて話していました。また、ISUCONの参加中の様子を動画として残していたようで、登壇中にその動画を視聴することができました。</p> <p>優勝の瞬間は、まるで本番同様に会場が盛り上がってました。</p> <h3 id="登壇動画">登壇動画</h3> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/rjp1WouNMzM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="ISUCON 夏祭り 2023"></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=rjp1WouNMzM">www.youtube.com</a></cite></p> <h3 id="登壇資料">登壇資料</h3> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fisucon.connpass.com%2Fevent%2F288820%2Fpresentation%2F" title="ISUCON 夏祭り 2023 - 資料一覧 - connpass" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://isucon.connpass.com/event/288820/presentation/">isucon.connpass.com</a></cite></p> <h2 id="Fireside-Chat">Fireside Chat</h2> <p>Fireside Chatとは暖炉を囲み、カジュアルに会話をする座談会のようなことを指します。参加者の質問に、登壇者の方が答えて頂きました。</p> <p>各質問の回答については、<a class="keyword" href="https://d.hatena.ne.jp/keyword/YouTube">YouTube</a>の動画をご覧いただくのが良いですが、個人的に気になった下記を以下に抜粋します。</p> <blockquote><p>ChatGPT、Copilotどう使う?</p></blockquote> <p>まず、前提としてChatGPT、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Github">Github</a> Copilotは、レギュレーション未定とのことでした。後日発表されるとのことです。</p> <p>もし、レギュレーションが許可される場合、</p> <ul> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/Github">Github</a> Copilotは普段も使っており、賢いから使う。</li> <li>ChatGPTは任せて外した時に困る。</li> <li>ChatGPTはハマった時に使ってみる。</li> </ul> <p>などの意見が上がってました。</p> <p><figure class="figure-image figure-image-fotolife" title="質問一覧"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828145542.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>質問一覧</figcaption></figure></p> <h1 id="交流会">交流会</h1> <p>イベントの最後に行われた交流会では、軽食とドリンクが提供され、参加者同士の交流が深まる場となりました。</p> <p>参加者たちはISUCONに関する失敗談や<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B7%D0%B8%B3%C3%CC">経験談</a>、また自身の意気込みなどについて初対面のエンジニア間で話すことができました。</p> <p>また、交流会の中で、抽選会まで用意して頂き、HHKBキーボード、ヘッドホン、マウス、サイン入り<a href="https://gihyo.jp/book/2022/978-4-297-12846-3">達人が教えるWebパフォーマンスチューニング</a>といった豪華な賞品が用意されました。</p> <table> <thead> <tr> <th>乾杯</th> <th>抽選会</th> </tr> </thead> <tbody> <tr> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828145206.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> <td><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230828/20230828145228.jpg" width="900" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></td> </tr> </tbody> </table> <h1 id="感想">感想</h1> <p>ISUCON 夏祭りに参加することを決めたきっかけは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の先輩エンジニアからのサブリミナルメッセージでした。「ISUCONはいいぞ!」という言葉が私の中で引っかかり、実際に参加してみることになりました。結果的に、その選択は正解で、素晴らしいイベント体験になりました。</p> <p>当初はISUCON14からの参加を考えていましたが、ISUCON夏祭りのハンズオンや<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>セッションを経て、今年のISUCON13に挑戦することを決意しました。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のバックエンドチームとして、以下の点でISUCON参加を支援する文化、強みもありますので、得た知識や経験を<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のプロダクト開発に還元していく意向です。</p> <ul> <li>業務時間をISUCONの素振りなどに割り当てることも可能</li> <li>ISUCONの素振りのインフラコストは会社負担</li> <li>ISUCON参加の当日、業務扱い可能</li> <li><a href="https://www.screens-lab.jp/article/29125">2830万MUB</a>の高負荷な<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>プロダクト開発で得た設計、実装の知見を活かせる</li> </ul> <h1 id="最後に">最後に</h1> <p>2023年11月25日に開催されるISUCON13に、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>は協賛させて頂きます!</p> <p>詳細は、先日アップされたこちらの記事に!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Futsumi%2Fisucon13-sponsor" title="今年もTVer はISUCON13に協賛します #isucon #tver - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/utsumi/isucon13-sponsor">techblog.tver.co.jp</a></cite></p> <p>今年のISUCONも熱いイベントとなることを願っています!参加される方、お互い頑張りましょう!</p> tver-techblog 今年もTVer はISUCON13に協賛します #isucon #tver hatenablog://entry/820878482959714452 2023-08-22T11:53:55+09:00 2023-08-22T11:53:55+09:00 こんにちは!!!! バックエンドエンジニアの内海です。 タイトルの通りなのですが、2023/11/25に開催されるISUCON13に協賛させていただくことになりました🎉 昨年のISUCON12も協賛させていただいております。 ISUCONとは?や、協賛への思いはこちらに書いておりますので、お時間のあるときにお読みいただければ幸いです。 techblog.tver.co.jp ISUCON13 今年のISUCONは今までの予選→本選の形式から、大きく変更があり本選のみとなりました。 isucon.net 昨年までとは違い、いきなり本選なのでわくわくしちゃいますね! TVer と ISUCON 昨… <p>こんにちは!!!!</p> <p>バックエンドエンジニアの内海です。</p> <p>タイトルの通りなのですが、2023/11/25に開催されるISUCON13に協賛させていただくことになりました🎉</p> <p>昨年のISUCON12も協賛させていただいております。</p> <p>ISUCONとは?や、協賛への思いはこちらに書いておりますので、お時間のあるときにお読みいただければ幸いです。 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fisucon12-sponsor" title="TVerはISUCON12に協賛します #isucon - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/isucon12-sponsor">techblog.tver.co.jp</a></cite></p> <h2 id="ISUCON13">ISUCON13</h2> <p>今年のISUCONは今までの予選→本選の形式から、大きく変更があり本選のみとなりました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fisucon.net%2Farchives%2F57566481.html" title="ISUCON13開催決定!今年は本選のみ開催! #isucon : ISUCON公式Blog" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://isucon.net/archives/57566481.html">isucon.net</a></cite></p> <p>昨年までとは違い、いきなり本選なのでわくわくしちゃいますね!</p> <h2 id="TVer-と-ISUCON"><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> と ISUCON</h2> <p>昨年から協賛させていただいていることはもちろん、我々<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>のバックエンドチームはISUCONのような高負荷な<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A5%E9%A5%D5%A5%A3%A5%C3%A5%AF">トラフィック</a>をテーマにした課題と日常的に向き合っています。</p> <p>おかげ様でたくさんのユーザーさんに使っていただけていることや、2022/04のリニューアルより本格的に開始した地上波のリアルタイム配信などでは配信時刻が決まってるためどうしてもユーザーアクションによる<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A5%E9%A5%D5%A5%A3%A5%C3%A5%AF">トラフィック</a>スパイクが日常的に発生します。</p> <p>そのため我々バックエンドチームはISUCON好きが自然と集まっている環境ですw</p> <p>如何に効率的にかつ、アクセス特性を考慮した実装をするかが肝になっており、ISUCONとテーマが非常に近いです。 そんな中、高負荷でも安定してユーザーさんにコンテンツを届けるのが<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>バックエンドの楽しみの一つだと思っています。</p> <h2 id="最後に">最後に</h2> <p>ISUCONに出場される皆様、運営企画をされている皆様を少しでも応援したいという気持ちで協賛させていただいております。</p> <p>まだ内容は内緒ですが、今年も<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>賞ありますので是非狙ってみてください!</p> <p>スポンサーとして、参加者として両方で最大限ISUCONを楽しんでいきたいと思いますので皆様も楽しんでいただけますと幸いです。</p> <hr /> <h2 id="We-are-hiring">We are hiring</h2> <p>ISUCONを楽しめる方なら<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>バックエンドはとても楽しい刺激的な環境です。 様々なポジションで絶賛採用中ですので、ご興味あればカジュアルなお話からエントリーまでいつでもお待ちしております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=http%3A%2F%2Ftver.co.jp%2Frecruit%2F" title="株式会社TVer の全ての求人一覧" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="http://tver.co.jp/recruit/">tver.co.jp</a></cite></p> tver-techblog JAWS-UG 東北(秋田)で登壇してきました #jawsug #jawsugtohoku #jawsugakita hatenablog://entry/820878482956852118 2023-08-10T12:25:15+09:00 2023-08-10T12:25:15+09:00 こんにちは。TVerの加我です。 人生初の3ヶ月連続登壇という予定を組んでしまいまして、7/29にその第一弾となるJAWS-UG 東北(秋田)にて登壇してまいりました。 jaws-tohoku.doorkeeper.jp JAWS-UGとは 公式サイトより引用させて貰いました。 JAWS-UGとは、AWS (Amazon Web Services) が提供するクラウドコンピューティングを利用する人々の集まり(コミュニティ)です。 一人ではできない学びや交流を目的としてボランティアによる勉強会の開催や交流イベントなどを行なっています。 私たちは日本全国に「支部」の形でグループを持ち、それぞれのテ… <p>こんにちは。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の加我です。<br/> 人生初の3ヶ月連続登壇という予定を組んでしまいまして、7/29にその第一弾となる<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG 東北(秋田)にて登壇してまいりました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjaws-tohoku.doorkeeper.jp%2Fevents%2F156109" title="[秋田][オフライン開催] JAWS-UG 東北 〜東北エンジニアの祭典〜 [初心者大歓迎]" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://jaws-tohoku.doorkeeper.jp/events/156109">jaws-tohoku.doorkeeper.jp</a></cite></p> <h1 id="JAWS-UGとは"><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGとは</h1> <p>公式サイトより引用させて貰いました。</p> <blockquote><p><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGとは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/AWS">AWS</a> (<a class="keyword" href="https://d.hatena.ne.jp/keyword/Amazon%20Web%20Services">Amazon Web Services</a>) が提供する<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9%A5%B3%A5%F3%A5%D4%A5%E5%A1%BC%A5%C6%A5%A3%A5%F3%A5%B0">クラウドコンピューティング</a>を利用する人々の集まり(コミュニティ)です。 一人ではできない学びや交流を目的としてボランティアによる勉強会の開催や交流イベントなどを行なっています。 私たちは日本全国に「<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%D9%C9%F4">支部</a>」の形でグループを持ち、それぞれのテーマに基づいて活動を行なっています。 このコミュニ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C6%A5%A3%A1%BC">ティー</a>は、非営利目的で活動しています。</p></blockquote> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjaws-ug.jp%2Fabout-us%2F" title="JAWS-UGとは" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://jaws-ug.jp/about-us/">jaws-ug.jp</a></cite></p> <h3 id="JAWS-UG東北秋田とは"><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG東北(秋田)とは</h3> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UGには専門<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%D9%C9%F4">支部</a>と地域<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%D9%C9%F4">支部</a>という考え方があり、<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG東北(秋田)は地域<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%D9%C9%F4">支部</a>にあたります。ちなみに私が運営に携わっているMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>は専門<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%D9%C9%F4">支部</a>にあたります。</p> <p><figure class="figure-image figure-image-fotolife" title="専門支部と地域支部"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230809/20230809155827.png" width="1200" height="666" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>専門<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%D9%C9%F4">支部</a>と地域<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BB%D9%C9%F4">支部</a></figcaption></figure></p> <p><iframe id="talk_frame_1057407" class="speakerdeck-iframe" src="//speakerdeck.com/player/9b4bad483d0946c5808409efd241ab49" width="710" height="399" style="aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/awsjcpm/jaws-ugdong-bei-qiu-tian-dong-bei-enzinianoji-dian-awstojaws-ug">speakerdeck.com</a></cite></p> <h1 id="登壇の経緯">登壇の経緯</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG東北(秋田)の主催を務めている知人からイベント参加へのお誘いを頂きまして、当初は有給休暇を利用した一般参加者として参加する予定でした。しかし、LT枠が1つ空いているので登壇しませんか?とのお誘いも頂きまして、急遽資料を作り上げて登壇させて頂きました。ただ、今回のテーマが <code>東北にゆかりのある企業、エンジニアの皆様にAWSを使った事例や業務についてLTをしていただきます</code> だったので正直ちょっとマッチしないかなーと悩んだのですが、私自身大学の4年間を仙台で過ごしていたのでヨシとして頂きました。</p> <h1 id="登壇内容について">登壇内容について</h1> <p>スライドは公開済みです。<br/> <iframe id="talk_frame_1057389" class="speakerdeck-iframe" src="//speakerdeck.com/player/86121199dee94941a166e0aca2926c54" width="710" height="399" style="aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/techtver/20230729-jawsug-tohoku-tver-frontend-monitoring">speakerdeck.com</a></cite></p> <p>内容としては「ユーザー体験はサービス全体で作り上げるもの。ユーザー目線であるフロントエンドのモニタリングも大事だよね」というお話をしてきました。今回はServerlessのLTが3つもあり、地方こそスケーラブルなインフラ・サービスをどんどん活用していこう!という話で盛り上がっていたので、ユーザー目線のモニタリングも忘れずにね!という私のLTが意味を成せたかなぁと思っております。</p> <p>ちなみに今回の登壇ネタですが、昨年の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%C9%A5%D9%A5%F3%A5%C8%A5%AB%A5%EC%A5%F3%A5%C0%A1%BC">アドベントカレンダー</a>で「動画の視聴体験を可視化したい(けどまだできていない)」というブログを書いた事へのアンサーになります。バックエンドやインフラのモニタリングに加えてフロントエンド(Web・モバイルアプリケーション)のモニタリングを行っているが、究極的にはユーザーが番組を快適に視聴できるのかどうかを動画プレイヤーを通じて観測する必要があり、道具(New Relic Video Agent)はあるけど使いこなせていないというのが当時のお話でした。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.tver.co.jp%2Fentry%2Fkaga%2Fnewrelic-video-agent-tsukaitai" title="動画の視聴体験を可視化したいんだ #NewRelic #NRUG - TVer Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://techblog.tver.co.jp/entry/kaga/newrelic-video-agent-tsukaitai">techblog.tver.co.jp</a></cite></p> <p>New Relic様のご協力により他社様との<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B0%D5%B8%AB%B8%F2%B4%B9%B2%F1">意見交換会</a>を開催して頂いたり、他社の事例紹介の記事を漁ったりしつつ、これまで取得してきたNew Relic Video Agentの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C6%A5%EC%A5%E1%A5%C8%A5%EA%A1%BC">テレメトリー</a>データを活用するためのノウハウを少しずつ溜めることができました。動画プレイヤーのモニタリングは発生するイベント数とデータ量が多いため、コスト的な部分も含めて本格的な分析にはまだ至っておりませんが、今回活用の一端をお見せすることができました。</p> <p><figure class="figure-image figure-image-fotolife" title="デバイスと視聴エラーの話"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230809/20230809173814.png" width="1200" height="671" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>デ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9">バイス</a>と視聴エラーの話</figcaption></figure></p> <p>ちなみに今回の登壇資料では最新の会社紹介資料のスライドを拝借しております。<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>を知る上でとてもわかりやすい資料となっておりますのでぜひご覧下さい。</p> <p><iframe id="talk_frame_920082" class="speakerdeck-iframe" src="//speakerdeck.com/player/49965b8557e748cea81c6d26e19317c2" width="710" height="399" style="aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/techtver/we-are-hiring">speakerdeck.com</a></cite></p> <h1 id="宣伝">宣伝</h1> <p>8/18 (金) に<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B4%E4%BC%EA%B8%A9">岩手県</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%C0%B9%B2%AC%BB%D4">盛岡市</a>にて<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>-UG東北(いわて)とMedia-<a class="keyword" href="https://d.hatena.ne.jp/keyword/JAWS">JAWS</a>のコラボイベントを開催します!!!<br/> 会場はマリオス 盛岡地域交流センターで、<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>が会場スポンサーとして協賛させて頂いておりますので、みなさまの参加をお待ちしております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjaws-tohoku.doorkeeper.jp%2Fevents%2F157194" title="[東北][岩手][オフライン開催]JAWS-UGいわて 特別編 Media-JAWSコラボ LT会 #jawsug #mediajaws #jawsugtohoku #jawsugiwate " class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://jaws-tohoku.doorkeeper.jp/events/157194">jaws-tohoku.doorkeeper.jp</a></cite></p> <p>実は今回の秋田での登壇は岩手でのイベントで話す内容を先取りという形でお話させて頂いたのでした。<br/> ということでみなさま、次は岩手でお会いしましょう!!</p> tver-techblog 行動経済学に基づく効果的なプロモーション手法の共同研究を実施しました hatenablog://entry/820878482950594455 2023-07-20T12:11:55+09:00 2023-07-24T13:24:19+09:00 こんにちは、主としてデータにまつわる四方山を相手にしている森藤です。 昨年の2022年6月から取り組んでいた、慶應義塾大学 星野ゼミ様との共同研究「行動経済学に基づく効果的なプロモーション手法」が一旦、完了しましたので、本技術ブログでも公開いたします。 tver.co.jp hoshinoseminar.com 課題 TVer は「見逃し配信サービス」であるにも関わらず、それすらも「見逃してしまう」ユーザに対して、どのように「見逃さないでいてもらうか」が大きな課題となっていました。 バラエティであれば、連続する回で無い限りは、次のエピソードから視聴していただくことも可能ですが、ドラマやアニメの… <p>こんにちは、主としてデータにまつわる四方山を相手にしている森藤です。</p> <p>昨年の2022年6月から取り組んでいた、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B7%C4%D8%E6%B5%C1%BD%CE%C2%E7%B3%D8">慶應義塾大学</a> 星野ゼミ様との共同研究「<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B9%D4%C6%B0%B7%D0%BA%D1%B3%D8">行動経済学</a>に基づく効果的なプロモーション手法」が一旦、完了しましたので、本技術ブログでも公開いたします。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftver.co.jp%2Fnews%2F20220616-1.html" title="[TVer] 行動経済学に基づく効果的なプロモーション手法に関する 共同研究を慶應義塾大学と開始 | TVer INC." class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tver.co.jp/news/20220616-1.html">tver.co.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fhoshinoseminar.com%2F" title="慶應義塾大学経済学部 星野崇宏研究会" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://hoshinoseminar.com/">hoshinoseminar.com</a></cite></p> <h2 id="課題">課題</h2> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> は「見逃し配信サービス」であるにも関わらず、それすらも「見逃してしまう」ユーザに対して、どのように「見逃さないでいてもらうか」が大きな課題となっていました。 バラエティであれば、連続する回で無い限りは、次のエピソードから視聴していただくことも可能ですが、ドラマやアニメのような連続する番組の場合は、一話の見逃しがそれ以降全ての見逃し = 離脱につながってしまい、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> のビジネスモデルである <a class="keyword" href="https://d.hatena.ne.jp/keyword/AVOD">AVOD</a> (広告型動画配信) の広告在庫の源泉である再生機会を逸してしまうことになってしまいます。</p> <p>この「見逃し配信を見逃してしまう」ことを抑止するために、放送局でも強く訴求している<a href="https://help.tver.jp/hc/ja/articles/5111238325913-%E3%81%8A%E6%B0%97%E3%81%AB%E5%85%A5%E3%82%8A%E3%81%AE%E7%99%BB%E9%8C%B2%E6%96%B9%E6%B3%95%E3%82%92%E6%95%99%E3%81%88%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84-">お気に入り</a>に登録いただいたり、<a href="https://tver.jp/newer">新着</a> などを表示したりしています。 これに加えて、 新しいエピソードが再生可能になったり、次の回が始まるため再生期間が終了してしまうエピソードがある場合には Push 通知を送るようにしています。</p> <p>ただ、この Push 通知ですが、下記のような課題があります。</p> <ol> <li>そもそも Push 通知はノイズ (=有用ではない) だと考えられている</li> <li>Push 通知を送ったとしても他アプリの通知もあり混ざってしまい、なかなか<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>されない</li> </ol> <p>特に1は重要な課題であり、一旦、煩わしいと思われ Push 通知の受信拒否をされるとその後、改めて受信許可をしていただくタイミングが殆どありません。 とはいえ、せっかく再生意向があったにも関わらず、期間内に見逃してしまったがために、離脱してしまうのは、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> のビジネスはもとより、ユーザにとっても良いことではありません。</p> <p>どのようにして、ユーザに取って Push 通知を価値ある情報として感じていただくか、 Push 通知を<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>して有用なものであることを理解していただくか、は重要な課題でした。 ユーザ心理を推測しながら、少なくともデメリット(ノイズ)として思われない、できればメリットとして感じていただくための Push 通知の内容・文言・頻度・タイミングなどを模索していました。</p> <p>このようなユーザである人間心理を社会の構成要素として捉え、経済学のモデル理論に当てはめ、解釈・理解していこうとする学問に<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B9%D4%C6%B0%B7%D0%BA%D1%B3%D8">行動経済学</a>があります。 縁あって、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B9%D4%C6%B0%B7%D0%BA%D1%B3%D8">行動経済学</a>を専門の一つとしている<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B7%C4%D8%E6%B5%C1%BD%CE%C2%E7%B3%D8">慶應義塾大学</a> 星野ゼミ 星野教授とつながりを持てたので共同研究を行うことができました。</p> <h2 id="研究内容">研究内容</h2> <p>今回の共同研究では、まずは取っ掛かりとして内容ではなく、文言・頻度・ジャンルにおける Push 通知の効果の有無や、その効果の持続性などを<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C4%EA%CE%CC">定量</a>的に明らかにするところまでを行いました。 具体的には、ドラマ・バラエティからサンプル番組を選び、ターゲットユーザ群に対して、以下のような文言の表現・頻度を変えてその<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>率・(みなしを含む)再生率を計測しました。</p> <ol> <li>通知の文言が通知の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>や再生に影響を与えるか</li> <li>短期間に同じ内容の通知を送った際に<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>や再生への効果に変化が見られるか</li> </ol> <h3 id="表現">表現</h3> <ul> <li>タイムプレッシャー: 「あとX日」のように期限が明示されることで「見なければという圧力」が生じる</li> <li>損失回避: 利益よりも損失を回避する方を選ぶ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BF%B4%CD%FD%C5%AA">心理的</a>作用を活かし「得られたはずの利益が得られなくなる」ように、「まもなく無料配信終了」といった表現</li> <li>ベースライン: 上記とは異なる「『番組名』配信中✨」という表現</li> </ul> <h3 id="頻度-ドラマのみ">頻度 (ドラマのみ)</h3> <p>下記のように頻度を変えて2群に通知を行いました - 週に1度: 配信終了の1日前 - 週に2度: 配信終了の1日前と2日前</p> <h3 id="回数">回数</h3> <p>同一の番組の異なるエピソードに対して 4 週間 Push 通知を送信し、経過における効果を計測 なお、表現の送信パターンを変えた実験群に対して送信しました。 また、第4週はデータの期間の都合で分析結果からは除外しました。</p> <table> <thead> <tr> <th> </th> <th>1週目</th> <th>2週目</th> <th>3週目</th> <th>4週目</th> </tr> </thead> <tbody> <tr> <td>Group.1</td> <td>BL</td> <td>BL</td> <td>BL</td> <td>BL</td> </tr> <tr> <td>Group.2</td> <td>BL</td> <td>BL</td> <td>TP</td> <td>TP</td> </tr> <tr> <td>Group.3</td> <td>BL</td> <td>BL</td> <td>LA</td> <td>LA</td> </tr> <tr> <td>Group.4</td> <td>TP</td> <td>TP</td> <td>BL</td> <td>BL</td> </tr> <tr> <td>Group.5</td> <td>TP</td> <td>TP</td> <td>TP</td> <td>TP</td> </tr> <tr> <td>Group.6</td> <td>TP</td> <td>TP</td> <td>LA</td> <td>LA</td> </tr> <tr> <td>Group.8</td> <td>LA</td> <td>LA</td> <td>BL</td> <td>BL</td> </tr> <tr> <td>Group.7</td> <td>LA</td> <td>LA</td> <td>TP</td> <td>TP</td> </tr> <tr> <td>Group.9</td> <td>LA</td> <td>LA</td> <td>LA</td> <td>LA</td> </tr> </tbody> </table> <p>※ BL: Baseline, TP: タイムプレッシャー, LA: 損失回避</p> <p>まとめると以下のようなパターンになります</p> <p>2ジャンルx2頻度x9群(8実験群+1対照群)x3週間(最終週は期間が短いため除外)</p> <h2 id="実験結果">実験結果</h2> <p>結果の詳細は割愛しますが、各ジャンルにおける表現ごとの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>率・再生率を図1、図2に示します。 この結果を評価するために母比率の検定を行った結果、下記の条件で有意であることが示されました。</p> <ul> <li>ドラマにおける1週目のタイムプレッシャーとベースラインの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>率 (両側5%)</li> <li>バラエティにおける3週目の損失回避とベースラインの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>率 (両側5%)</li> <li>ドラマ・バラエティにおける1週目のタイムプレッシャーとベースラインの再生率 (両側1%)</li> </ul> <p><figure class="figure-image figure-image-fotolife" title="ドラマにおける表現ごとの開封率・再生率"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230717/20230717182737.png" alt="&#x30C9;&#x30E9;&#x30DE;&#x306B;&#x304A;&#x3051;&#x308B;&#x8868;&#x73FE;&#x3054;&#x3068;&#x306E;&#x958B;&#x5C01;&#x7387;&#x30FB;&#x518D;&#x751F;&#x7387;" width="1046" height="796" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>図1 ドラマにおける表現ごとの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>率・再生率</figcaption></figure></p> <p><figure class="figure-image figure-image-fotolife" title="図2 バラエティにおける表現ごとの開封率・再生率"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230717/20230717182856.png" alt="&#x30D0;&#x30E9;&#x30A8;&#x30C6;&#x30A3;&#x306B;&#x304A;&#x3051;&#x308B;&#x8868;&#x73FE;&#x3054;&#x3068;&#x306E;&#x958B;&#x5C01;&#x7387;&#x30FB;&#x518D;&#x751F;&#x7387;" width="1052" height="804" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>図2 バラエティにおける表現ごとの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>率・再生率</figcaption></figure></p> <h2 id="まとめ">まとめ</h2> <p>結果から、今回選んだドラマとバラエティの番組において特にタイムプレッシャーと損失回避が<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B3%AB%C9%F5">開封</a>率に与える影響に違いがあり、ドラマにおいては初週のタイムプレッシャーの効果があり毎週送ると効果が減衰すること、逆にバラエティにおいては慣れてきた頃に損失回避の効果があることが示されました。 また再生率においてはいずれのジャンルにおいてもタイムプレッシャーの効果があることが示されました。</p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> では、これまで重要な課題として位置づけておりながらもリソースの都合や運用上の課題で<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C4%EA%CE%CC">定量</a>的な評価ができていませんでした。 そのため、運用者の勘と経験によって文言や頻度、時間帯などを決めていました。</p> <p>今回の星野ゼミとの共同研究により一部ではありますが<a class="keyword" href="https://d.hatena.ne.jp/keyword/%C4%EA%CE%CC">定量</a>的に評価ができ、勘と経験に裏付けが得られた点、効果が減衰する・効果が見られてくるパターンがある発見などは、大きな前進でした。</p> <p>今回の研究では、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> 社の運用上の課題から、他のジャンルを評価することや同一ジャンルで多くの番組を対象とする事ができませんでした。 また、諸般の事情で細かく取り切れなかったデータがあるため、星野ゼミの方々にご迷惑もおかけしました。 今後はこれらの課題を解消していくと同時に、星野ゼミの皆様からも継続的な共同研究の申し出も頂いており、 <a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> としてもより効果的な、ユーザにとってノイズではなく価値ある情報として Push 通知を受け入れていただき、「見逃し配信を見逃さない」でいただけるように努力していければと思っております。</p> <h2 id="最後に">最後に</h2> <p>今回の取組は Screens でも星野ゼミの皆様とのインタビューが行われましたのでそちらも興味ありましたら御覧ください。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.screens-lab.jp%2Farticle%2F29054%3Futm_campaign%3Dtver_tech_blog_2307%26utm_medium%3Dreferral%26utm_source%3Dtvertechblog" title="ユーザーを動かすプッシュ通知の“最適解”は? TVer ✕ 慶應大共同研究インタビュー|Screens|映像メディアの価値を映す" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.screens-lab.jp/article/29054?utm_campaign=tver_tech_blog_2307&utm_medium=referral&utm_source=tvertechblog">www.screens-lab.jp</a></cite></p> <h2 id="そして">そして</h2> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a> ではデータを分析し、ユーザにとってよりよい放送・配信の視聴体験をサポートしたり、広告やそれ以外の事業にコミットするために活用したりしたいデータエンジニア・データサイエンティストを募集しています。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftver.co.jp%2Frecruit%2Findex.html" title="株式会社TVer の全ての求人一覧" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tver.co.jp/recruit/index.html">tver.co.jp</a></cite></p> tver-techblog Google Cloud Day '23 Tourで登壇しました #GoogleCloudDay hatenablog://entry/820878482937929169 2023-06-02T15:44:36+09:00 2023-06-06T16:27:13+09:00 TVerの黒瀬です。 先日開催されましたGoogle Cloud Day '23 Tourの東京会場にて、Breakout Session枠で登壇しました。 この記事では、その発表内容について概要を簡単にご紹介いたします。 なお、本発表の細かい内容については下記ページからオンデマンド配信でご覧になれます。 cloudonair.withgoogle.com speakerdeck.com 背景 TVerは今後のサービス改善のために、提供中の機能などの利用状況をBigQueryで集計・分析するための環境を持っていました。 そこでは、収集したいログごとに異なるサービス・プロダクトを契約し、それらを… <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>の黒瀬です。</p> <p>先日開催されました<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloud Day '23 Tourの東京会場にて、Breakout Session枠で登壇しました。</p> <p>この記事では、その発表内容について概要を簡単にご紹介いたします。</p> <p>なお、本発表の細かい内容については下記ページからオンデマンド配信でご覧になれます。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcloudonair.withgoogle.com%2Fevents%2Fgoogle-cloud-day-23%3Ftalk%3Dtok-d1-da01" title="Google Cloud Day ’23 Tour" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://cloudonair.withgoogle.com/events/google-cloud-day-23?talk=tok-d1-da01">cloudonair.withgoogle.com</a></cite></p> <p><iframe id="talk_frame_1034768" class="speakerdeck-iframe" src="//speakerdeck.com/player/d9c293fee7d44e32aaffc68e12f21592" width="710" height="399" style="aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe> <cite class="hatena-citation"><a href="https://speakerdeck.com/techtver/20230523-google-cloud-day-23-tour-tvertag">speakerdeck.com</a></cite></p> <h1 id="背景">背景</h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>は今後のサービス改善のために、提供中の機能などの利用状況をBigQueryで集計・分析するための環境を持っていました。</p> <p>そこでは、収集したいログごとに異なるサービス・プロダクトを契約し、それらを突合するなどして集計・分析していました。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602112320.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="課題">課題</h1> <p>この従来の分析環境は次の3つの課題がありました。</p> <ol> <li>異なるログ同士の突合に手間がかかる点</li> <li>従来収集していなかったログを後から追加できるかどうかがログ収集サービス・プロダクト依存になっており、拡張性が限られる点</li> <li>ログ収集サービス・プロダクトごとに費用がかかるため、分析環境の維持費が高くなる点</li> </ol> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602112733.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602112754.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602112809.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="方針">方針</h1> <p>そこで、上記の課題を解決することを目的として、弊社での分析に必要なログを統合的に収集・集約するためのログ基盤であるTVerTagを開発することにしました。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602123856.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="アプローチ">アプローチ</h1> <p>収集部分・集約部分それぞれを次の方法で実装することにしました。</p> <ul> <li><p>収集部分: Cloud <a class="keyword" href="https://d.hatena.ne.jp/keyword/CDN">CDN</a>とLoad Balancerで構成したEndpointに対するtracking用pixel dataをHTTP GETする<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%AF%A5%BB%A5%B9%A5%ED%A5%B0">アクセスログ</a>をCloud Loggingで収集します。</p></li> <li><p>集約部分: <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%AF%A5%BB%A5%B9%A5%ED%A5%B0">アクセスログ</a>をCloud Pub/Subへ転送し、それをCloud RunでPullして加工し、Cloud Storageに格納します。集計・分析時はそのCloud StorageをBigQueryのExternal Table経由で参照するようにします。</p></li> </ul> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602132757.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>当初この構成で運用していたのですが、問題が出てきたため、それぞれ次のように解決しました。</p> <ul> <li><p>External Tableへクエリを実行するためにはExternal TableだけでなくCloud Storageの読み取り権限も必要となり、権限を2重管理する手間が発生しました。そこで当時GAになったBigLakeを利用することで、Cloud Storageへの読み取り権限をBigQueryに移譲させ、結果External Tableへの読み取り権限のみケアすればよくなりました。</p></li> <li><p>Cloud Storageに格納されているオブジェクトの数が増えてくるとExternal Tableへのクエリのレスポンスが悪化しました。そこで、定期的にNative Tableへ取り込むバッチを後段に追加し、集計・分析時はそのNative Tableを参照することで、データ量に対してクエリのレスポンスがスケールするようにしました。</p></li> </ul> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602134140.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602134153.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602134414.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="運用実績">運用実績</h1> <p>ここまでの構成で現在まで運用しており、1日あたりの11億レコード・920GiBのログを処理しており、ピークの時間帯においては秒間で21000アクセスを処理しています。また、ログ欠損によりログを集約できなかった期間は1度も発生せずに運用できています。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602141003.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="リアーキテクチャ">リ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A1%BC%A5%AD%A5%C6%A5%AF%A5%C1%A5%E3">アーキテクチャ</a></h1> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a> Cloudで日々リリースされる新しい機能を利用した構成改善を検討しており、開発中のものですがその一部をご紹介します。</p> <p>Cloud Loggingでログを収集してからBigQueryのNative Tableへ集約するまでのパスをできるだけ簡素にする方法を検討し、その中でもCloud LoggingのLog Analyticsを利用する方針で進めています。</p> <p>また、速報版と確定版を使い分ける構成としてLambda Architectureを採用する予定です。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602141543.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602141456.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="結論">結論</h1> <p>TVerTagによって<a class="keyword" href="https://d.hatena.ne.jp/keyword/TVer">TVer</a>における集計・分析に必要なログを統合的に収集・集約することができるようになりました。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tver-techblog/20230602/20230602141715.png" width="1200" height="675" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h1 id="おわりに">おわりに</h1> <p>今回登壇にあたっては<a class="keyword" href="https://d.hatena.ne.jp/keyword/Google">Google</a>様のご担当の皆様に多方面でサポートいただきました。</p> <p>スムーズに準備および登壇に臨むことができました。この場をお借りして御礼申し上げます。</p> tver-techblog