indeed indeed - a presentation for indeed なう -

81
indeed Indeed 実際のとこどうなの?Indeed さん! Toru Ochiai Software Engineer @ Indeed Tokyo

Upload: toru-ochiai

Post on 15-Jul-2015

794 views

Category:

Technology


0 download

TRANSCRIPT

indeed Indeed〜 実際のとこどうなの?Indeed さん! 〜

Toru OchiaiSoftware Engineer @ Indeed Tokyo

自己紹介

自己紹介

● 東京理科大学工学部電気工学科卒○ ちゃんと 4 年

● 中堅 SIer○ 2.5 年

● 入社当時十数人だったネット系ベンチャー○ 5 年

● 独立系受託開発会社○ 3.5 年

● リクルート○ じゃらんゴルフ開発 1 年○ Indeed エンジニア 2 年

自己紹介

…は

いったん

置いておいて

自己紹介

唯一

重要な

キーワード

自己紹介

お っ ち ー

“otchy”

自己紹介

otchy

自己紹介

.netTwitter

Qiita

.com

自己紹介

全部

ぼくです

Indeedエンジニアの

一日

● 9時〜11時の間に出社する人が多い● スタンドアップミーティング

○ 昨日やったこと / 今日やること○ 作業の調整

■ 「あ、そこんとこお互い関係あるね」「この後詳しく話

そうか」○ 10 分で終了

● 早速コーディング

● フリーランチ○ いまのところ火・水・木の週3日○ 月・金はガーデンプレイス周辺を散策中

● 最近の流行りは将棋とビリヤード○ 他にも卓球、ピンボール、ぷよぷよ、マリカー、ラジコン

などなど○ 要するに好きなことしてると

● がっつりコーディング

夕方

● 引き続きコーディング● ウィークリーミーティング

○ 今週やったこと / 来週やること○ ビール○ 唯一の定例ミーティング - 1 時間 / 週

● ハッピーアワー○ 毎週金曜 17 時頃からゆるりと○ ビール

■ ビール以外のお酒、ソフトドリンクもあるよ

● 17時〜19時の間に帰る人が多い

Indeed エンジニアの一日

要するに

Indeed のエンジニアは

Indeed エンジニアの一日

コーディングと

ビールから

出来ています

Indeed エンジニアの一日

じゃあ実際

どんなコード

書いてんの?

Indeedエンジニアの

コード

Indeed エンジニアのコード

Indeed エンジニアのコード

…って

話じゃなくて

Indeed エンジニアのコード

● 超アルゴリズムなコードばかり?○ そういうのもある

○ でも Web なんでバックエンドもフロントエンドもその間あ

たりも色々ある

● AB テストめっちゃする○ 何でもデータで評価する○ CEO ですらデータ出さないと周りが納得しない

● 基礎重要○ “無駄に” 重いのはだめ○ データ構造選びはきちんとね

● 何か課題があってそれをどう解決するかの繰り返し

Indeed エンジニアのコード

具体例を紹介

…の前に

所属するチームの紹介

● カンパニーデータチームに所属● Indeed の持つたくさんの会社情報を表示する

ページ○ 概要・口コミ・写真・給与情報などなど

● それらのデータを Indeed 内の別チームに提供する API○ 検索結果に表示される口コミ評価など

所属するチームの紹介

● 会社情報ページ

所属するチームの紹介

● 会社情報 API

具体例1ABテスト

具体例1:ABテスト

課題:最近追加した給与情報ページのアクセスを増やしたい

答え:目立たせる!

本当の課題:どんなデザインが一番効果的か?

イケてるデザイナが考える??

否、AB テストが知っている!

具体例1:ABテスト

● グループ A:new! アイコン

具体例1:ABテスト

● グループ B:概要ページでチラ見せ

具体例1:ABテスト

● グループ C:サイドバーでチラ見せ

具体例1:ABテスト

● 結果 (給与情報ページの PV)何も無し(既存)

グループA

グループBグループC

具体例1:ABテスト

● 結果○ A:new! アイコン → 8.86% PV アップ○ B:概要ページチラ見せ → 4.24% PV アップ○ C:サイドバーチラ見せ → 6.97% PV アップ

● new! アイコン採用!

…?

具体例1:ABテスト

● 結果 (給与情報ページの PV)?

具体例1:ABテスト

● 結果○ new! アイコン → 8.86% PV アップ○ 概要ページチラ見せ → 4.24% PV アップ○ サイドバーチラ見せ → 6.97% PV アップ○ 全部乗せ → 97.14% PV アップ

● 当たり前の結果でもちゃんとテストする○ 仮説に確信を持つため○ 将来の決定に情報を残すため

■ 他の機能の都合上どうしても給与ページの露出を減

らす場合は?■ 概要ページが一番インパクト少ない!

具体例1:ABテスト

● ちなみにこれ、実装、分析から世界中100% のユーザにリリースするまで、わずか 8 営業日の出来事○ 意志決定が早い○ リリースが早い○ AB テストフレームワークが早い○ 分析ツールが早い

具体例1:ABテスト

スピード重要

具体例1:ABテスト

何度もテストを

繰り返し

最適解に近づく

具体例2会社情報 API

具体例2:会社情報 API

● 検索ページのフロントエンド

フロントエンド

検索 API 会社情報 API認証 API などなど

フロントエンド

具体例2:会社情報 API

● 検索ページのフロントエンド○ 複数のサービス (= API) に平行してリクエストを投げる○ 全部の結果を待ってから情報をまとめて表示する

…と思うじゃないですか

具体例2:会社情報 API

(再び)スピード重要

具体例2:会社情報 API

● 検索ページのフロントエンド○ 複数のサービス (= API) に平行してリクエストを投げる○ 全部の結果を待ってから情報をまとめて表示する

○ 最低限、検索結果さえあれば他の API のレスポンスは

そんなに待たない○ 全体のスピードが全てに影響する

■ クリック率■ SEO

○ サイトが “生きてること” も超重要■ 仮に API サーバが落ちてもサイト自体は落ちない

具体例2:会社情報 API

● 通常の検索結果

関連会社情報

オートコンプリート

5つ星評価

ログインリンク

具体例2:会社情報 API

● 検索ページのフロントエンド

フロントエンド

検索 API 会社情報 API認証 API などなど

フロントエンド

タイムアウト

具体例2:会社情報 API

● 調子悪い時の検索結果

関連会社情報表示されない

オートコンプリート出来ない

5つ星評価表示されない

ログイン出来ない

具体例2:会社情報 API

課題:検索フロントエンドの要求に応じて会社の 5 つ星評価を 200msec 以内に返す

CPU 時間で見ると膨大な時間に見えるが…

1. ネットワークのレイテンシを含む2. 評価値以外のメタデータも含めて返す3. MAX 200 なので普段は 50 以下にしたい4. 5000万件の会社情報から検索する

フツーにやったら間に合わない

具体例2:会社情報 API

● 答え1:MySQL (RDB)○ フツーの Web っぽい。

○ 5000万件からの検索を数msec で返せるモンスタークラ

スタを用意する?○ オーバースペック。却下。

● 答え2:mongoDB (NoSQL/KVS)○ いまどきの Web っぽい。

○ 要するにディスク上に構築された巨大なハッシュテーブ

ルなので検索はまあまあ早い。○ ネットワークオーバーヘッドが追加になる。○ MySQL と平行してデータのメンテが必要。○ 面倒くさい。却下。

具体例2:会社情報 API

そもそも

ディスクIO(~10ms)が

遅い

具体例2:会社情報 API

メモリ(~100ns)と

105 もオーダーが違う

具体例2:会社情報 API

● 答え3:memcached (インメモリキャッシュ)○ フツーの大規模 Web っぽい。○ スピードは申し分ない。○ キャッシュが無ければ通常速度。○ 初回アクセス時は星が表示されない?○ 惜しい!イケてない。却下。

● 答え4:インメモリ DB○ 今ならありかも。

○ プロジェクト発足当時 (4 年前) に選択するにはアグレッ

シブ過ぎた。

具体例2:会社情報 API

Indeed の答え

具体例2:会社情報 API

意外なほど単純

具体例2:会社情報 API

● ソート済みの会社 ID 配列をメモリに持つ○ static int[] CMP_ID_ARR = [1, 2, 3, … 5×108];○ 実際には永続化されてるデータを読んでる

● Java の int は符号付き 32 bit 整数○ 5000万件でも高々 200MB○ 4bytes × 50M = 200MB

● 1インスタンスに 256GB メモリ積む時代にケチケチしない○ 全てのインスタンスにこの int 配列を持つ○ memcached サーバアクセスのオーバヘッドも無い

具体例2:会社情報 API

● 会社 ID 配列と同じ順で評価値配列を持つ○ static float[] CMP_RAT_ARR = [3.2, 4.3, 3.8, ...];○ 同じく全部メモリ上

● こういう関係

[ 1, 2, 3, … 1000 … ]

[3.2, 4.3, 3.8, … 3.4 … ]

か ら の

具体例2:会社情報 API

おもむろに

バイナリサーチ

具体例2:会社情報 API

● 会社 ID を見つけたら同じ index を参照

[ 1, 2, 3, … 1000 … ]

[3.2, 4.3, 3.8, … 3.4 … ]● いくつかの主要メタデータは全部こう

[ 1, 2, 3, … 1000 … ]

[ a, b, c, … x … ]

具体例2:会社情報 API

難しい問題を

シンプルに解く

具体例2:会社情報 API

常にシンプルな

方法を考える

具体例3ABテスト

フレームワーク

具体例3:AB テストフレームワーク

課題:アクセスしてくるユーザを複数のテストグループにランダムに振り分ける

● 同じユーザはずっと同じグループ● 数学的に (ある程度) 正しくランダム● 違う種類のテストにおいて相関はなし

具体例3:AB テストフレームワーク

3つの要求を

満たす実装を

考えてみる

具体例3:AB テストフレームワーク

● 同じユーザはずっと同じグループ○ 少なくとも各ユーザを識別するユニークキーが必要

● ログイン中のユーザ○ ユーザ ID (=メールアドレス)

● 非ログイン中のユーザ○ Indeed 全体で共有しているトラッキングクッキーの値

同じユーザの識別については問題なし

具体例3:AB テストフレームワーク

● 同じユーザはずっと同じグループ○ ユニークキーごとにどのグループに所属しているか覚え

ておく必要がある

○ テストをリセットする時には過去のグループを削除して振

り分け直す

● しかし常時 100 以上のテストを実施○ 1ユーザあたり 100 レコード保持?○ 1億5000万ユーザ / 月いるのに?

具体例3:AB テストフレームワーク

● 数学的に (ある程度) 正しくランダム○ 正しいシードを使って乱数を発生させる○ 例えば、現在時刻 XOR hash(ユニークキー) とか

● 違う種類のテストにおいて相関なし○ 乱数の使いまわしはせず、グループ振り分けを行う度に

異なる乱数を発生させる

○ 疑似乱数発生器が十分確からしくランダムなら、シード

の再設定までは要らない (はず)● しかし常時 100 以上のテストを実施

○ 毎回 100 回以上も乱数発生させるの?○ 1億5000万ユーザ / 月いるのに?

具体例3:AB テストフレームワーク

つまり

難しいのは

ここ

具体例3:AB テストフレームワーク

100テスト

1億5000万ユーザ

具体例3:AB テストフレームワーク

ここで再び

シンプルな方法を

考える

具体例3:AB テストフレームワーク

Indeed の答え

具体例3:AB テストフレームワーク

● 同じユーザはずっと同じグループ○ ユニークキーごとにどのグループに所属しているか覚え

ておく必要がある○ 100×1億5000万も覚えておかない

● 数学的に (ある程度) 正しくランダム● 違う種類のテストにおいて相関なし

○ 正しいシードを使って乱数を発生させる

○ 乱数の使いまわしはせず、グループ振り分けを行う度に

異なる乱数を発生させる○ そもそも乱数使わない

具体例3:AB テストフレームワーク

それで実現可能?

具体例3:AB テストフレームワーク

できます!

具体例3:AB テストフレームワーク

● 各テストごとにユニークな Salt を持つ● ユーザのユニークキー×Salt のハッシュを計算

する● ハッシュ値を 100 で割ったあまりをとる● 0~49 → グループA、50~99 → グループB

hash(unique_key XOR test_salt) % 100

※だいたいの概念。本当はもうちっと複雑。

具体例3:AB テストフレームワーク

● 十分に “良い” ハッシュ関数があれば○ ユーザのユニークキーが決定した瞬間に、ユーザのグ

ループは潜在的に決定済み○ グループの振り分けは十分にランダム○ 振り分けの計算は常に O(1)○ Salt が変わればグループ分けに相関なし

○ あえて Salt を同じにすることで、異なるテストのグルー

プ分けをあえて同じにすることもできる

○ グループ分けの割合を変更した場合も、なんら再計算の

必要が無い

いいことづくめ!

具体例3:AB テストフレームワーク

難しい問題を

シンプルに解く

具体例3:AB テストフレームワーク

ちなみに

具体例3:AB テストフレームワーク

● このフレームワーク● Proctor という名前でオープンソース化済み

http://indeedeng.github.io/proctor/

● AB テスト結果の分析に適したツールも● Imhotep という名前で同じくオープンソース化済

http://indeedeng.github.io/imhotep/

結 論

エンジニアにとっての Indeed

取り組むべき

課題が

いっぱい

エンジニアにとっての Indeed

コードで解決

エンジニアにとっての Indeed

データで証明

エンジニアにとっての Indeed

めっちゃ

楽しい

Q & A※ #askindeed で Twitter 検索すると質疑応答のおおよそが見れます