万人以上のユーザーに出会いの機会を提供するマッチングアプリです。有意義な関係をもたらす、楽しく安全で質の高い出会いの経験をもたらすことに焦点を当てているため、当社のモットーは「量よりも質」です。した約束を果たすために、私たちが提供するすべてのマッチングは、ユーザーが求める厳格な基準を満たす必要があります。ところが、現在のトラフィックでは、高品質のマッチングを作成することは困難な問題となっています。人のエンジニアしかいません)。これは、すべてのエンジニアが当社の製品に大きな影響を与えることを意味します。当社のアプリは、それぞれの現地時間の正午にプッシュ通知によって、アプリにログインするようユーザーに促します。この機能は日々のエンゲージメントを促進するには最適ですが、予想されるように、この時間帯のトラフィックは急増します。サービスやモバイルクライアントのレイテンシーをできるだけ短くしながら、高品質のマッチングを作成するにはどうすればよいか。つの解決策は、ユーザーがアプリにログインする前にランク付けされた推奨されるマッチングを作成することです。億件のマッチングを保存する必要があります。この数は、新しいユーザーを獲得するにつれて二次的に増加します。つの解決策は、要求に応じてマッチングを作成することです。検索データベースに潜在的なマッチングを保存することで、指定された基準に基づいてマッチングのセットを取得し、関連性で並べ替えることができます。実際に、私たちはこのメカニズムを通してマッチングの一部を取得しています。残念なことに、インデックス付きの基準だけで検索すると、ある種の機械学習モデルを利用することができなくなります。インデックスの保守の負担が増大します。結局、両方のアプローチの組み合わせを選ぶことにしました。ゼロデイモデルとして使用しますが、オフラインプロセスを使用してすべてのユーザーに対してさまざまな機械学習によるリコメンデーションを事前に計算し、それらをオフラインキューに保存します。選択した理由について説明します。エンジニアリングチームの管理およびインフラストラクチャメンテナンスの作業が、どのように簡略化されたかについても説明します。本当に気に入っている理由はたくさんありますが、ここではこの特定のユースケースに関連するいくつかの理由を概説します。読み取りは、全体的なレイテンシーへの影響が非常に少ないです。アクセスパターンはセミランダムになります。この状況から、ディスクから読み取る必要があるデータベースで処理するとかなりのオーバーヘッドが発生する可能性があります。日の中で最も忙しい時間帯には、数分で何十万ものマッチングが行われるため、読み取りが低レイテンシーであることが基本です。ユーザーが選択した基準に合う高品質のマッチングを提供することに誇りを持っています。(明らかにCMBを通じて結婚したため)、あるいはプロフィールの一部を変更することを決定した場合、すべてのリコメンデーションをできるだけ早く更新することが重要です。したシナリオの実行を非常に簡単にする整合性を保証します。これは、リスト内の項目を自動的にデキューおよびエンキューする組み込みコマンドを提供します。これらのリストとソート済みセットを使って、リコメンデーションに役立てます。良いところは、やり取りするのが非常に簡単であることです。世界でも有数の優れた企業が使っているのです。データ構造、ドキュメンテーション、各操作の複雑さはとてもよく定義されています。私たちは皆、単純であることで、コードの複雑さやバグが増える可能性が少ないことを知っています。これは、読み取りである程度の低レイテンシーを保証しながら、高スループットの書き込みを約束したためです。変更することを決定したことですぐに解消した、いくつかの問題点がありました。結果整合性を約束しています。当初、私たちのユースケースはこの問題の影響を大きく受けないと考えていましたが、それは間違っていました。読み書きの整合性を高めようともしましたが、残念ながら、レイテンシーが急増してアプリの信頼性が低下しました。抱えていた主な問題はメンテナンスに関連していました。停止のために常にページングされていました。悪いことに、ノードのクラッシュが大量のヒープダンプを生成し、それがディスクを一杯にしました。クラスターの最適なチューニングを学ぶことはできたかもしれませんが、すでにクラスターのメンテナンスに膨大な時間を費やしていました。移行することを決定した時に、これらの問題はすべて解消し、私たちの小さなチームは、気難しいクラスターを管理するよりもっと重要な問題に集中することができるようになりました。選択することは、当社のエンジニアリングチームにとって大きな動きでした。スタートアップ企業にとって、時間は本当に重要です。管理作業の実行、ハードウェアのプロビジョニング、ソフトウェアのパッチのチェック、インフラストラクチャの保守を行う必要がないので、アイデアやアルゴリズムに取り組む時間が大幅に増えます。最新の安定バージョンに非常に早く対応できることです。容易にスケールアウトできるようになりますが、物事がうまくいかない場合に備えてまだ冗長という魔法の層があります。使うことは特に有益であると思います。インメモリデータストアであるからであり、メモリ管理、フラグメンテーション、バックアップには細心の注意を払う必要があるためです。すべてを行ってくれます。つの主要コンポーネントで構成されています。時に実行される一連のスケジュールされたタスクです。人のユーザーの親和性を効果的に定量化し、マッチングの可能性を「スコア」にすることを可能にします。あり、これを使用することで、ユーザーに対して高品質のマッチングを作成できます。主要なデータストアとやり取りします。このアプリのバッチコンポーネントがリコメンデーションモデルをトレーニングして特徴を抽出するのに対し、オンラインコンポーネントは適格なユーザーのペアのマッチングをスコア化する仕事をします。このコンポーネントは、ユーザーごとに複数のリコメンデーションのキューを作成/維持する役割を果たします。「リコメンデーション」データストアには、これらのキューがソート済みセットの形式で含まれています。当社のウェブアプリは、リコメンデーションをこのデータストアから読み取り、リアルタイムで顧客に提供します。特徴を利用して、ユーザー間の類似性を計算しています。大半の人は機械学習における「特徴」の概念に精通しています。そこでいう特徴とは、人間である私たちがユーザーに帰属させるメタデータです。(私たちの文脈では、アルゴリズムがより高品質のマッチングを予測する方法を学ぶと想定しています)。文脈では、以下のような特徴の例があります。場所ほとんどの場合、人間として私たちが選択する特徴は、直接観測可能であるため、高品質のマッチングを予測するための最も強力なインジケータ―ではありません。一連の特徴があります。これらの特徴は、非常に予測に役立ちます。観測することはできませんが、高品質のマッチングの予測では非常に強力です。(項目ベースの協調フィルタリング)。つのバッチタスクが、すべてのアクティブなユーザーの潜在的な特徴の計算を担当します。した特徴は、すべてのユーザーに対して何百日ものマッチングの履歴を分析することによって学習されます。潜在的な特徴を取得した結果を示しています。つのコマンドで、ユーザーの潜在的な特徴を読み込むことができます。(たとえば、配列の最初の値は、すべてのユーザーに対して同じ属性を表しています)。そのユーザーが気に入った最後のマッチングに似ている相手のユーザーを見つけることです。いう名前の男性が、サンフランシスコで女性を探しています。まハイキングやテニスをするのが好きであり、彼が「気に入った」履歴は明らかにこの好みを反映しています。件の相手は野外活動好きでスポーツをしていました。人の女性にできるだけ似ている女性の候補者をデータベースで検索します。この操作の結果は、関連性によってソートされたリコメンデーションの候補リストです。リストの先頭には、おそらく野外活動好きであるか、スポーツを楽しんでいる女性が並んでいるでしょう。人のユーザー間の類似度を計算することができます。人のユーザーの任意の組み合わせの間の類似性を効率的に見つけることができます。データストアに保持します。実装の簡単さソフトウェアエンジニアとして、ほんの数行のコードで些細ではない操作を実行できることはとても助けになります。非常に単純であり、非常に基本的なデータ構造で機能するため、隠れた罠が少なくなり、コードが単純になります。事実上、スキーマ、結合、インデックス、クエリについて考える必要はありません。ここで単純さを強調する理由は、非常に単純でよく知られているデータ構造を扱うことによって、コードが最小限になるからです。ランダムな読み取り/書き込みの効率的な処理いつでも、どんな日でも、私たちのインフラストラクチャは、ユーザーのために絶えずリコメンデーションを更新しています。キーを読み書きする順番は、決定論的ではありません。このシナリオでは、ディスクベースのデータストアを使用している誰かが、いつでもディスクのランダムで隣接していない部分にアクセスしたり、常にメモリからキャッシュを削除したりしてパフォーマンスを低下させます。インメモリにあり、この問題の影響を受けません。計算された後は、単なる数のリストであることです。潜在的な特徴は依存関係を持たず、依存関係を使用する必要もありません。以前に誰かをパスした場合、おそらく同じ人をまたパスするからです。これは事実上、親子関係の問題です。つの方法は、毎回新しいマッチングが表示されるようにセットを更新することです。除外リストに追加しました。見ているか確認したい場合は、次のようにします。ヒットしませんでした。削除することができます。このアプローチから生じる最大の問題は、二次空間を保存しなければならなくなることです。実際には、オーガニックなユーザーの増加によって除外リストの数が増えると、どのセットにも含まれる項目の数が増えます。n_usersブルームフィルターを使用して表示済みリコメンデーションをフィルタリングするブルームフィルターは、親子関係を効率的にチェックできる確率的データ構造です。セットと比較すると、偽陽性のリスクがあります。このシナリオでの偽陽性とは、ブルームフィルターが、実際にはセットに入っていないときに何かがセット内にあると知らせる可能性があることを意味します。これは、ここでのシナリオでは許容できる妥協です。冒してもやむをえません。内部的には、すべてのブルームフィルターはビットベクトルによって支えられています。ブルームフィルターに追加した各項目について、いくつかのハッシュを計算します。設定したビットを指しています。等しいかどうかをチェックします。正しくない可能性があります。そのままではブルームフィルターをサポートしていませんが、キーの特定のビットを設定するコマンドを提供しています。使用してそれらを実装する方法です。新しいブルームフィルターの作成この操作は、アプリで新しいユーザーが作成されるたびに行われます。ブルームフィルターとして選択しました。すべてのユースケースは、空間と偽陽性の要件が異なります。除外リストに追加する必要があるたびに行われます。開いてマッチングのリストをスクロールするたびに行われます。"""プロファイルを除外に追加する。マップされるビットインデックスを表す整数のリストを返します。パイプライン処理を使用します。queries」を参照してください。ブルームフィルターのメンバーシップをチェックするこの操作は、特定のプロファイルに対して候補のマッチングのリストがあり、すでに表示されたすべての候補を除外したい場合に必ず行います。表示された候補はすべてブルームフィルターに正しく挿入されていると仮定します。コレクションの場合、これはブルームフィルターにないものだけを返します。除外する可能性があります。filtered_idsこの最後の操作は他の操作よりも少し複雑なので、何が起こっているのかを段階的に見てみましょう。ブルームフィルターは単なるビットベクトルです。内ですべてのフィルターの一括操作を実行します。設定されているかどうかを確認するために、前述のチェックが行われます。設定されていない場合は、その項目がブルームフィルターに存在しないことが確実にわかります。使用してブルームフィルターを保存すると、次のような利点があります。操作を使用すると、ブルームフィルターに項目を追加することは非常に効率的で簡単です。回しかないため、一括フィルタリングの実行も非常に効率的です。ミリ秒で何万もの候補を効率的にフィルタリングすることができます。私たちのブルームフィルターはサイズが固定されているので、ユーザーベースが拡大しても、二次成長について心配する必要はありません。クラスターを使用すると、データを分割してもブルームフィルターをメモリに保持できます。使用する欠点は何か?主な欠点は、コードの複雑さです。部分は非常に単純ですが、ブルームフィルターの実際の実装は複雑になる可能性があります。ブルームフィルターはデバッグがかなり難しいので、できれば有名なライブラリを入手するようにしてください。ブルームフィルターのサポートを提供できるモジュールがあります。Redis」を参照してください。ファーストクラスのデータベースであると考えています。スクリプトの組み合わせを使って実装されています。どのように考えているかについて説明になれば幸いです。シニア機械学習エンジニアです。業界のリーダーと活気に満ちたベイエリアコミュニティを結びつけようと活動しています。データチームのリーダーです。彼は、当社のユーザーの間に有意義なつながりを作り出すことに向けて組織を推進する責任を負っています。機会均等法を順守しています。平等に採用しています。