3.7 埋め込み検索と LambdaMART を組み合わせるニュース推薦の詳解

はじめに: このチュートリアルで何を学ぶか

このチュートリアルは、ユーザープロファイルとニュース記事を用いて、パーソナライズド推薦を作るための基本的な二段構成を学ぶものである。前半では、文章の embedding と cosine 類似度を使い、大量の記事から関心を持ちそうな候補を高速に取得する。後半では、候補ごとの特徴を LambdaMART へ渡し、限られた表示枠でどの記事を先に見せるべきかを学習する。

教科書の実験は、Faker で生成したユーザープロファイル、BBC ニュース記事、LLM が生成した興味ラベルを用いる。そのため、実際の行動ログを扱う推薦システムの完全な再現ではない。しかし、候補検索、ラベル付け、Learning to Rank、評価という推薦パイプラインの接続を理解する題材として有用である。

本ノートでは、次の点を順に説明する。

  1. embedding 検索が候補をどのように取得し、何を保証しないか。

  2. LLM が作る興味ラベルが何を意味し、実行動ラベルとどう異なるか。

  3. LambdaMART が cosine 類似度だけの順位付けをどう改善し得るか。

  4. Precision@k、Recall@k、NDCG@k を候補集合との関係でどう読むか。

  5. この設計を Hulu の暗黙的フィードバックへ置き換える際に、何を変更すべきか。

まず、以降の説明で混同しやすい役割分担と、結果を解釈するときの前提を確認する。

最初に押さえる要点

このチュートリアルは、推薦を二段に分ける基本形を扱っている。第一段は、ユーザープロファイルと記事の embedding を比較して、数の多い記事から「関心がありそうな候補」を広く取得する処理である。第二段は、候補ごとの特徴量を LambdaMART へ入力して、「候補のなかでどれを先に出すか」を学習する処理である。

embedding の cosine 類似度だけで順位を決める方法は、ユーザーと記事の意味が近いかという一つの軸だけを使う。これに対して LambdaMART は、ユーザー embedding の各次元、記事 embedding の各次元、両者から作った類似度を組み合わせ、上位に正例を置くように非線形な規則を学べる。そのため、教師ラベルの定義に対しては、単一の cosine 類似度より高い順位品質を得られ得る。

ただし、表 3.2 の数値は「実際のニュース閲覧行動」を予測した成績ではない。Faker で作られたプロファイルと、LLM が付与した興味ラベルを用いた合成実験の成績である。また、評価対象は embedding 検索であらかじめ取得した上位候補に限られる。したがって、 Precision@10 =0.90=0.90 を「実サービスで 10 件出せば 9 件が視聴される」と読んではならない。この結果が示すのは、指定された候補集合と LLM 教師ラベルの条件下で、LambdaMART が cosine 類似度より教師ラベルをよく順位付けした、ということである。

Hulu の暗黙的フィードバックへ移すときは、LLM ラベルを最終的な正解として置き換えるのではなく、将来の視聴行動を時点固定で作った学習ラベルを主目的にするべきである。LLM は、作品属性の補完、コールドスタート時の意味特徴、少量の評価用ラベルに使う。視聴の有無、露出、配信可否、既視聴、鮮度は、最終的な順位を決める別の重要な信号である。

段階 このチュートリアルでの処理 解く問い 出力 Hulu での主な置換
アイテム理解 記事本文を embedding 化する 記事は何について書かれているか 記事ベクトル 作品カードからのテキスト・映像 embedding
ユーザー表現 プロファイル文を embedding 化する この人の関心をどう表すか ユーザーベクトル 過去の 25% 以上視聴作品を時点固定で集約したベクトル
候補検索 cosine 上位 50 件を取る 何をランカーへ渡すか 候補集合 ANN と複数の候補経路をマージした集合
ラベル LLM が興味あり・なしを付ける 何を正例とするか 二値ラベル 将来の視聴、できれば impression 後の視聴。LLM は補助的に使う
ランキング LambdaMART で候補を並べる 候補内で何を上に出すか 順序付きリスト 行動・文脈・作品・交互作用特徴を使う学習ランカー
評価 ユーザー単位の hold-out で @k 指標を測る 上位表示の品質はどうか P/R/NDCG@k 時系列 split、露出を考慮した offline 評価、online 実験

1. まず、「検索」と「ランキング」を混同しない

カタログに MM 本の記事があり、各ユーザーに対して全記事を精密なモデルで採点することを考える。ユーザー数を UU とすれば、全組合せは UMU M である。記事が数十万件、ユーザーが数百万人なら、リクエストごとに全組合せを重いモデルで評価することは、計算量とレイテンシの両面から現実的ではない。

そこで推薦は通常、次のように分ける。

  1. 候補検索(retrieval)では、速い計算で数十万件から数百件程度まで絞る。この段階は、後段で上位にできる正解をできるだけ落とさないこと、すなわち候補の Recall を重視する。

  2. ランキング(ranking)では、検索済み候補に追加特徴を使って精密なスコアを与え、上位数件から数十件を並べる。この段階は、限られた表示枠の Precision と順位品質を重視する。

  3. 必要なら再ランキング(reranking)で、多様性、既視聴除外、年齢制約、配信権、同一シリーズの重複といったリスト全体の制約を満たす。

この章の cosine 類似度は主として候補検索のスコアである。一方、LambdaMART は候補集合に対するランキングモデルである。LambdaMART が非常に優秀でも、候補検索で関連する記事を取得できなければ、その記事を上位に出すことはできない。逆に、候補が十分に良くても、cosine のみで固定的に並べると、上位枠を最適に使えないことがある。

この依存関係は次のように表せる。

catalogretrievalC(u)rankerπurerankerdisplayed list\text{catalog} \xrightarrow{\text{retrieval}} C(u) \xrightarrow{\text{ranker}} \pi_u \xrightarrow{\text{reranker}} \text{displayed list}

ここで C(u)C(u) はユーザー uu の候補集合、 πu\pi_u は候補の順位である。最終表示に正例があるためには、まず正例が C(u)C(u) に含まれていなければならない。したがって、ランキング指標だけではなく、候補検索の Recall も別に測る必要がある。

2. チュートリアルのデータは何を表しているか

2.1 ユーザープロファイルは行動履歴ではない

チュートリアルのユーザープロファイルには、職種、スキル、趣味、概要などが入る。例えば、次のような自然言語文を想定すればよい。

データ分析に従事する。AI、宇宙開発、サッカーに関心があり、技術革新と国際情勢をよく読む。

この文は、ユーザーの自己申告的な興味を一つのテキストとして与える。ニュース記事のタイトルと概要も同じようにテキストであるため、両者を同一の文 embedding 空間へ写し、意味的な近さを測れる。

しかし、これは通常の動画サービスで観測される行動ログとは異なる。動画推薦で観測できることが多いのは「作品 A を一定割合以上見た」「検索結果で作品 B を表示した」「作品 C をクリックした」といった行動であり、ユーザーが関心を文章として明示するとは限らない。また、視聴は好意だけでなく、家族が使った、話題だから試した、途中で離脱した、次話の自動再生だった、といった事情も含む。

このため、ニュースのプロファイル文は「ユーザーの関心を損失なく表した理想的な入力」に近い合成設定である。実務では、行動履歴から、時刻と利用可能情報を守ってユーザー表現を推定する必要がある。

2.2 記事 embedding は「記事の真の意味」そのものではない

all-MiniLM-L6-v2 のような SentenceTransformer は、入力文を固定長のベクトルへ変換する。記事のタイトル、概要、カテゴリを連結した文書をモデルへ入力すれば、出力を記事 embedding ei\mathbf{e}_i と書ける。

ei=E(titlei,summaryi,categoryi)\mathbf{e}_i=E(\text{title}_i,\text{summary}_i,\text{category}_i)

同様に、プロファイル文の embedding を eu\mathbf{e}_u とする。

eu=E(profileu)\mathbf{e}_u=E(\text{profile}_u)

embedding が近いとは、「モデルが読み取った入力テキストの意味や使用文脈が近い」ことを意味する。記事の事実性、鮮度、社会的な重要度、本人が今読むか、というすべてを表すわけではない。例えば「AI 規制」の記事と「AI 企業の決算」の記事は embedding 上近いことがあるが、規制に強い関心があり投資には関心がない人にとっては同じ魅力度ではない。

また、入力テンプレートは embedding の意味を変える。タイトルだけを入力する場合、短い固有名詞や曖昧な見出しの影響を受けやすい。タイトル、概要、カテゴリを明示的な項目名とともに入力する場合は、記事の主題をより安定して表現しやすい。学習時と配信時で項目、言語、正規化、embedding モデルのバージョンを変えると、ベクトル空間の一貫性が崩れる。

3. embedding 検索の計算と役割

3.1 cosine 類似度

ユーザーと記事の近さとして、チュートリアルは cosine 類似度を使う。ユーザー embedding を eu\mathbf{e}_u 、記事 embedding を ei\mathbf{e}_i とすると、スコアは次である。

su,i=euTeieu2ei2s_{u,i} = \frac{\mathbf{e}_u^{\mathsf{T}}\mathbf{e}_i} {\lVert\mathbf{e}_u\rVert_2\lVert\mathbf{e}_i\rVert_2}

これは二ベクトルの長さではなく向きの近さを測る。あらかじめ各ベクトルを L2 正規化しておけば、cosine 類似度は内積と一致する。

e~=ee2su,i=e~uTe~i\tilde{\mathbf{e}}=\frac{\mathbf{e}}{\lVert\mathbf{e}\rVert_2} \qquad s_{u,i}=\tilde{\mathbf{e}}_u^{\mathsf{T}}\tilde{\mathbf{e}}_i

この性質により、大規模カタログでは正規化済み記事ベクトルに対する最大内積検索として、ANN index を利用できる。

3.2 小さな数値例

説明を単純にするため、二次元かつ正規化済みのユーザー embedding を次のように置く。

eu=(0.8,0.6)\mathbf{e}_u=(0.8,0.6)

三記事の embedding が次であるとする。

eA=(0.8,0.6),eB=(0,1),eC=(0.6,0.8)\mathbf{e}_A=(0.8,0.6),\quad \mathbf{e}_B=(0,1),\quad \mathbf{e}_C=(-0.6,0.8)

このとき cosine 類似度は内積で求められ、それぞれ 1.01.00.60.60.00.0 となる。検索段階だけを見るなら、順序は ABCA \succ B \succ C である。

ただし、現実の embedding は数百次元であり、各次元に人が理解しやすい名前は通常付かない。さらに 0.800.800.780.78 の差が、どのユーザー、どの話題、どの言語でも同じ意味を持つわけではない。そのため「 0.750.75 以上なら興味あり」のような固定閾値を、検証なしに意味ラベルや視聴ラベルへ変換してはならない。

3.3 上位 KK 件取得は何を保証し、何を保証しないか

各ユーザーに対して、スコアの大きい順に上位 K=50K=50 件を取り出すとする。

CK(u)=TopKiI  su,iC_K(u)=\operatorname{TopK}_{i\in I}\;s_{u,i}

この処理は、50 件が「ユーザーが読むべき 50 件」であることを保証しない。「この embedding と cosine の観点では近い 50 件」であることを保証するだけである。検索セットには、次の誤差が残る。

  • embedding が意味的に近いが、ユーザーの意図に合わない記事が入る。

  • 重要な固有名詞、鮮度、地域性、否定表現を embedding が十分区別できず、関連記事を落とすことがある。

  • ランカーが好みそうな記事でも、cosine が低く 50 件に入らなければ救済できない。

  • 50 件だけへラベルを付けると、学習データは「retriever が選んだ領域」に条件付けられる。ランカーはカタログ全体の好みではなく、その領域内の優先順位を学ぶ。

この最後の点は特に重要である。ランキングモデルの Recall@10 が高くても、候補検索の Recall@50 が低ければ、カタログ全体に対する最終推薦の Recall は低いままである。概念的には、最終システムの到達可能な Recall は候補検索の Recall を超えない。

4. LLM による興味ラベルは、何を教師にしているか

4.1 prompt が定義する「Interested」

提示された prompt は、ユーザープロファイルと記事を一組ずつ示し、興味ありを 1、興味なしを 0 として返すようモデルに求めている。このラベルを yu,iy_{u,i} と書く。

yu,i{0,1}y_{u,i}\in\{0,1\}

ここでの yu,i=1y_{u,i}=1 は、「この LLM が、この入力と指示に基づけば、そのプロファイルの人は記事に興味を持つと判断した」という意味である。クリック、記事完読、滞在時間、購読継続といった実行動を観測したラベルではない。

この違いは本質的である。例えば、ある人がプロファイルに「サッカーが趣味」と書いていても、その人が移籍市場の記事を毎日読むとは限らない。一方、LLM はプロフィールと記事の話題が合うため 1 を返しやすい。これは LLM が誤っているというより、「意味的な関心」と「実際の行動」という異なる目的を測っているためである。

4.2 合成ラベルの利点

合成ラベルは、実行動ラベルをまだ持てない段階で、パイプラインの形を検証するために有用である。

  • 各段階の入出力、失敗時の処理、group ranking の実装を早く確認できる。

  • 専門家に全ペアをラベル付けしてもらう前に、どのような特徴量が必要かを探索できる。

  • プロファイルと記事が明らかに不整合なペアを発見し、embedding 検索の定性的な品質を点検できる。

一方で、合成ラベルだけを学習・評価に使うと、作ったモデルは本質的に「教師 LLM の関心判断を再現するモデル」になる。教師モデルと同じ種類の文章情報を embedding として使う場合、両者の判断が整合しやすいこともある。その高い整合性は、実利用者の満足や視聴を保証しない。

4.3 ラベル付与を堅牢にする最低条件

元の prompt は出力形式を強く制約しており、バッチ処理と parser の観点で良い出発点である。ただし、実験として再現可能にするには、少なくとも次を保存する必要がある。

保存するもの 必要な理由
対象の user ID、item ID、入力本文の version 後からどの情報で判定したかを再現するため
prompt version と rubric 「興味あり」の定義が変わったことを検出するため
モデル名、モデル version、温度、生成日時 同じ prompt でも出力が変化し得るため
生の応答、parse 成否、再試行回数 形式違反を黙って 0 と扱わないため
人手監査結果 LLM の判断と意図した基準のずれを測るため

また、「興味あり」を何で判定するかを prompt に明示する必要がある。職業・趣味との主題一致だけを見るのか、初心者にも読めるか、政治的なセンシティブさを避けるか、鮮度を重視するかによって、同じプロファイル・記事ペアでもラベルは変わる。自由文の常識へ任せるほど、ラベルの境界は不安定になる。

5. LambdaMART は何を学習するのか

5.1 点ごとの二値分類ではなく、ユーザー内の順序を学ぶ

検索済み候補 CK(u)C_K(u) の各記事に対し、特徴量ベクトル xu,i\mathbf{x}_{u,i} を作る。教科書の最小構成では、ユーザー embedding、記事 embedding、cosine 類似度を連結する。

xu,i=[eu;ei;su,i]\mathbf{x}_{u,i} = \left[ \mathbf{e}_u;\, \mathbf{e}_i;\, s_{u,i} \right]

ここで [;][\cdot;\cdot] はベクトルの連結を表す。embedding の次元を dd とすると、特徴量数は 2d+12d+1 である。

LambdaMART は木のアンサンブルでスコア関数 ff を学習する。

r^u,i=f(xu,i)\hat r_{u,i}=f(\mathbf{x}_{u,i})

予測スコアが大きい記事を先に表示する。

πu=sortiCK(u)  r^u,iin descending order\pi_u=\operatorname{sort}_{i\in C_K(u)}\;\hat r_{u,i}\quad\text{in descending order}

重要なのは、学習単位が候補一件ではなく「一ユーザーに対する候補リスト」である点である。あるユーザーについて、興味ありの記事 ii を興味なしの記事 jj より上に置くことを学びたい。別のユーザーの候補と混ぜて比較する必要はない。LightGBM や XGBoost で LambdaMART を使うときに、同一ユーザーの候補行数を group として渡す理由はここにある。

5.2 Lambda の直感

NDCG を直接最適化しようとすると、「順位を入れ替える」という離散操作が含まれるため、通常の微分をそのまま適用しにくい。LambdaRank は、正例 ii と負例 jj の順序を逆転させたときの NDCG の変化量を重みとした勾配のような信号、すなわち lambda を作る。

概念的には、 yu,i>yu,jy_{u,i}>y_{u,j} であるにもかかわらず r^u,ir^u,j\hat r_{u,i}\leq\hat r_{u,j} なら、 ii のスコアを上げ、 jj のスコアを下げる更新を強くする。その強さは、二つを入れ替えたときの ΔNDCG\lvert\Delta\operatorname{NDCG}\rvert が大きいほど大きい。

λi,jΔNDCGi,j11+exp(r^u,ir^u,j)\lvert\lambda_{i,j}\rvert \propto \left\lvert\Delta\operatorname{NDCG}_{i,j}\right\rvert \cdot \frac{1}{1+\exp\left(\hat r_{u,i}-\hat r_{u,j}\right)}

例えば 1 位と 2 位の入替えは、50 位と 51 位の入替えより表示品質への影響が大きい。LambdaMART はこの性質を使い、決定木を勾配ブースティングで追加していく。従って、単に 0/1 を当てる二値分類器より、上位 kk の順序を重視した学習に適する。

5.3 cosine 類似度を渡す意味

ユーザー embedding と記事 embedding の全次元を渡しているなら、理論上はモデルが両者の関係を学ぶ余地がある。それでも cosine 類似度を明示的に追加するのには理由がある。

  • cosine は、embedding 空間における既知の強い類似性シグナルを一列に要約した特徴である。

  • 木モデルは個々の次元に対するしきい値分割を積み上げるため、多数次元の内積や正規化を効率良く再構成するとは限らない。

  • ランカーは「cosine が高いなら常に上位」の規則ではなく、「特定のユーザー・記事領域では cosine を強く信頼し、それ以外では弱める」という規則を学べる。

ただし、embedding 全次元の生の連結だけでは、表現が冗長でサンプル数に対して特徴量が多くなり得る。実運用では、次のような交互作用特徴も候補になる。

euei,euei,euTei\mathbf{e}_u\odot\mathbf{e}_i, \qquad \left\lvert\mathbf{e}_u-\mathbf{e}_i\right\rvert, \qquad \mathbf{e}_u^{\mathsf{T}}\mathbf{e}_i

ただし、特徴を増やすこと自体は改善を保証しない。時点固定の validation で、候補検索、ランキング、最終指標のそれぞれに改善があるかを確認するべきである。

5.4 ランカーが cosine より良くなり得る具体例

あるユーザーが技術、宇宙、サッカーに興味を持つとする。cosine は「AI 企業の資金調達」と「宇宙望遠鏡の成果」を高く評価し、「代表戦の戦術分析」をやや低くするかもしれない。もし教師ラベルが、スポーツ関心を重く見て代表戦の記事も正例にするなら、LambdaMART は profile embedding の特定領域と記事 embedding の組合せから、その例外を学習できる可能性がある。

反対に、経済記事一般は embedding 上は技術投資記事と近くても、このユーザーへの教師ラベルでは負例かもしれない。ランカーは cosine の高低だけでなく、記事ベクトルの局所的なパターンを条件として、順位を下げられる。このような非線形な条件分岐が、学習型ランキングの価値である。

ただし、この説明は「木モデルが文章の意味を新たに理解する」という意味ではない。モデルが利用できるのは既存 embedding と学習ラベルに現れた関係だけである。未知の話題、未知の行動文脈、急なニュースの鮮度は、別の特徴やデータがなければ扱えない。

6. 評価指標を、候補集合を明示して読む

テストユーザー uu の候補集合を CK(u)C_K(u) とし、そのなかの正例集合を RuR_u とする。ランカーが上位 kk に置いた記事集合を Lu@kL_u@k とする。

6.1 Precision@k

Precision@k は、表示した上位 kk 件のうち何件が正例だったかを表す。

Precision@k(u)=Lu@kRuk\operatorname{Precision@k}(u) = \frac{\left\lvert L_u@k\cap R_u\right\rvert}{k}

例えば上位 10 件中 9 件が LLM の興味ありなら、 Precision@10 は 0.90.9 である。これは上位枠の純度を表すが、候補外にどれだけ正例を落としたかは表さない。

6.2 Recall@k

Recall@k は、評価対象の正例のうち上位 kk へ回収できた割合である。

Recall@k(u)=Lu@kRuRu\operatorname{Recall@k}(u) = \frac{\left\lvert L_u@k\cap R_u\right\rvert}{\left\lvert R_u\right\rvert}

ここで分母 RuR_u が「上位 50 件の候補内にある正例」なのか、「カタログ全体の正例」なのかを必ず確認する必要がある。チュートリアルの流れからは、ラベルを付けた retrieval set 内の正例を分母にしていると読むのが自然である。この場合の Recall@10 =0.541=0.541 は、「retrieval set 内の興味あり記事の約 54.1% を上位 10 件へ置けた」ことを意味する。検索で取り逃したカタログ全体の正例は、この数値に含まれない。

6.3 NDCG@k

NDCG は、正例を含むだけでなく、それをより上位へ置いたかを測る。二値関連度 yu,iy_{u,i} に対する DCG は、次のように書ける。

DCG@k(u)=p=1k2yu,πu(p)1log2(p+1)\operatorname{DCG@k}(u) = \sum_{p=1}^{k} \frac{2^{y_{u,\pi_u(p)}}-1}{\log_2(p+1)}

ここで πu(p)\pi_u(p) は順位 pp の記事である。理想順序での DCG を IDCG@k(u)\operatorname{IDCG@k}(u) とすれば、正規化した NDCG は次である。

NDCG@k(u)=DCG@k(u)IDCG@k(u)\operatorname{NDCG@k}(u) = \frac{\operatorname{DCG@k}(u)}{\operatorname{IDCG@k}(u)}

値は通常 00 から 11 の範囲で、大きいほど理想順序に近い。表 3.2 の LambdaMART の NDCG@10 =0.946=0.946 は、候補内の LLM 正例を非常に上位寄りに配置できたことを示す。一方、全候補が正例であるユーザーでは順位の良し悪しを判別できないため、NDCG の集計方法、正例ゼロのユーザーを除外したか、どの平均を取ったかも記録すべきである。

6.4 ユーザー 80/20 split の意義と限界

ユーザーの 80% を train、20% を test に分けると、同じユーザーの候補ペアが train と test の両方に入ることを防げる。未知ユーザーへの一般化を調べる group split としては、ランダムなペア単位 split より適切である。

しかし、記事は train と test で共有され得る。また、Faker プロファイルに時間変化がないため、未来情報の混入を検査する実験ではない。実際のサービスでは、訓練期間の末尾を t0t_0 、評価期間を (t0,t1](t_0,t_1] として、 t0t_0 より後に起きた視聴だけをテスト正例にする時系列 split が必要である。時系列を無視してランダムに分けると、将来見た作品を過去の興味として使うリークが起こる。

7. 表 3.2 の結果をどう解釈するか

結果表の差は、候補内の LLM ラベルに対して、LambdaMART が cosine 類似度よりも強い順位付け規則を学習したことと整合する。特に Precision@10 が 0.420.42 から 0.900.90 、 Recall@10 が 0.2120.212 から 0.5410.541 、 NDCG@10 が 0.7670.767 から 0.9460.946 へ上がっているため、単に正例数が増えただけでなく、正例を前方へ移動できた可能性が高い。

それでも、次の推論はこの表だけからはできない。

  • LambdaMART が実際の読者のクリックや長期満足を改善する。

  • embedding 検索がカタログ全体の関連記事を十分に回収している。

  • 別のニュースデータセット、別の言語、別の LLM 教師でも同程度に改善する。

  • 作品数やユーザー数を増やしても、同じ特徴量構成が過学習せずに機能する。

数値が非常に高く見えるときは、まずデータ生成過程を確認するべきである。合成ユーザーのプロファイル、記事の明確なカテゴリ、LLM による意味ラベル、上位 cosine 候補への限定という設定では、意味的一貫性を捉えるモデルが高い成績を出しやすい。これはチュートリアルの価値を下げるものではない。どの段階が何を改善するかを、短時間で理解・実装する教材として有用である。一方で、本番品質の根拠にするには、実ログと独立した評価が必要である。

8. Hulu の暗黙的フィードバックへ置き換える

8.1 データ対応

Hulu では、プロファイルの自己紹介文の代わりに、過去の視聴作品を使って関心を表現する。 hj-data-01.report.unique_viewed_series は、プロフィールごとに動画コンテンツ長の 25% 以上を視聴したシリーズを記録する。この事実は「一定の視聴があった」という比較的強い正のシグナルであり、少なくとも単なる表示や短い誤タップよりは有益である。

チュートリアルの要素 Hulu での候補 注意点
user profile 文 cutoff 時点までに 25% 以上見たシリーズの履歴 将来の last_viewing_date を絶対に混ぜない
BBC 記事文書 item_information_table のタイトル、説明、ジャンル、タグ、人物、ムード series_idservice_type の組をアイテム識別子として扱う
article embedding 作品カードの text embedding。必要なら映像 fingerprint は別塔で扱う avg_fingerprint と text embedding は同一空間とは限らない
LLM の Interested 評価期間における 25% 以上視聴、または impression 後の視聴 未視聴を即座に負例とみなさない
cosine Top-50 ANN、協調、コンテンツなど複数経路の候補 検索経路ごとの rank と score を特徴に残す

item_information_table の主なキーは series_idservice_type である。従って、内部結合や embedding index の ID を series_id 単独で作る前に、サービス種別をまたいだ衝突・配信条件を確認する必要がある。また、 publish_start_atpublish_end_atis_blacklistis_coming_soon 、年齢区分、SVOD/TVOD の利用可能性は、ランキング以前に時点 tt で判定可能な候補フィルタとして扱う。

8.2 行動履歴からユーザー embedding を作る

時点 tt より前にプロフィール uu が視聴したシリーズ集合を Hu(t)H_u(t) とする。各シリーズの content embedding を ej\mathbf{e}_j 、視聴の重みを wu,j,tw_{u,j,t} とすれば、単純なユーザー embedding は加重平均で作れる。

eu(t)=normalize(jHu(t)wu,j,tej)\mathbf{e}_u(t) = \operatorname{normalize} \left( \sum_{j\in H_u(t)}w_{u,j,t}\mathbf{e}_j \right)

最小構成では、重みを全て 1 にできる。履歴の日付が利用できるなら、最近の視聴を強くする減衰重みも候補になる。

wu,j,t=exp(γ(ttu,j))w_{u,j,t} = \exp\left(-\gamma\left(t-t_{u,j}\right)\right)

ただし、提供されている unique_viewed_series は「25% 以上を視聴したシリーズ」と最終視聴日を表すテーブルであり、impression、視聴開始、完走率、視聴分数、セッション文脈をすべて持つわけではない。したがって、この集約は「長期の内容嗜好」を表す出発点にはなるが、「今この画面で選ぶ作品」を完全には表さない。季節性、家族共用、視聴進捗、直近の探索意図は別特徴または別モデルが必要である。

8.3 作品カードとアイテム embedding

テキスト embedding の入力には、単に series_title_ja だけを渡さず、意味が安定する構造化カードを作る。例えば次の項目を用いる。

  • タイトル: series_title_ja

  • 形式・ジャンル: media_typegenresub_genre

  • 内容: descriptionsentencesockets_tagkeywords

  • 人物: castsfilm_directorsproducerswriters

  • 時間・属性: premiere_yearvideo_durationcountries_of_origin

ここで、人名だけが一致して似て見えること、広告的な文言が過大に効くこと、欠損列が多い作品で表現品質が落ちることを監査する必要がある。 avg_mood_tag は「緊張感」「内省的」といったトーンを表すため、説明文 embedding と補完的になり得る。 avg_fingerprint は動画内容から推定された別の embedding である。異なる生成元のベクトルを、同じ次元数だからといって単純平均してはならない。別々の cosine、あるいは別の候補経路・特徴量として使い、検証で有効性を確かめるべきである。

8.4 学習ラベル: 未視聴は負例ではない

時点 t0t_0 に候補を生成し、将来区間 (t0,t1](t_0,t_1] に 25% 以上視聴されたシリーズを正例とするなら、簡略化したラベルは次のように書ける。

yu,i,t0=1[i is viewed by u in (t0,t1]]y_{u,i,t_0}=\mathbb{1} \left[ i\text{ is viewed by }u\text{ in }(t_0,t_1] \right]

しかし、 yu,i,t0=0y_{u,i,t_0}=0 は「嫌い」ではない。そもそも表示されなかった、表示されたが見つけられなかった、時間がなかった、後で見るつもりだった、別プロフィールが使用した、といった理由があり得る。学習時に最も望ましい負例は、同じ表示面で実際に露出されたが視聴されなかった候補である。impression log がなければ、候補集合からの負例 sampling を使うことはできるが、ラベルの不確実性と露出バイアスを明示しなければならない。

また、 unique_viewed_series だけでは、候補を見た日時や表示順位が分からない。これを用いた offline 評価は、意味嗜好や将来視聴への相関を見る proxy としては有用だが、ホーム画面の UI 変更や順位効果を因果的に評価するものではない。最終的な優劣は、露出ログを用いた補正と online A/B テストで確かめる必要がある。

8.5 Hulu 向け LambdaMART の特徴量

最小の embedding 連結に、利用可能な時点固定特徴を足すと、例えば次の設計になる。

種別 特徴例 目的
ユーザー 履歴 embedding、最近視聴ジャンル比率、履歴長、直近視聴からの日数 長期嗜好と活性度を表す
アイテム text embedding、ジャンル、公開年、尺、ムード、公開からの日数 作品の内容と鮮度を表す
交互作用 text cosine、ジャンル一致数、出演者一致、ムード距離、履歴との最大類似度 ユーザーに対する関連度を表す
検索由来 ANN score、協調候補 score、各経路での順位、候補経路数 候補になった根拠を保つ
文脈・制約 リクエスト時刻、デバイス、表示面、SVOD/TVOD、配信残日数 今表示できるか、今選ばれやすいかを表す

この表の特徴は全てを必ず使うという意味ではない。重要なのは、各特徴について「時点 t0t_0 に本当に取得できたか」「欠損が何を意味するか」「学習と配信で同じ定義か」を確認することである。特に publish_end_at に基づく残日数は有益なことがあるが、訓練当時に知られなかった将来の権利更新情報を使えばリークになる。

9. 実験を信頼できるものにする設計

チュートリアルを実サービスへ発展させるなら、次の順序が実務的である。

  1. まず候補検索だけの baseline を作る。作品 embedding と、時点固定した視聴履歴の集約を使い、候補 Recall、定性的な近傍、配信不可・既視聴除外の正しさを確認する。

  2. 各リクエスト時点の候補、特徴、露出、後続視聴をログとして保存する。学習データを後から再現できることが、特徴追加より先に必要である。

  3. cosine 順を ranking baseline にし、同じ候補集合・同じ評価時点で LambdaMART と比較する。候補集合まで変えると、改善が検索かランキングかを区別できない。

  4. 時系列 validation で、Precision@k、Recall@k、NDCG@k に加え、候補 Recall、カバレッジ、ジャンル別・新着別・履歴長別の性能を報告する。全体平均だけでは、活発なユーザーや人気作品への偏りを見落とす。

  5. offline で改善したモデルだけを、ガードレール付きの online A/B テストへ進める。短期の視聴開始だけでなく、25% 到達、総視聴時間、離脱、継続利用、TVOD なら購入・レンタルへの影響も確認する。

この流れでは、LLM は二つの補助的な役割を持つ。第一に、新着・低視聴作品の説明、タグ、テーマ、ムードを補完し、embedding とランカー特徴を改善する。第二に、人手で少量作った評価セットを補うため、候補の意味的関連性を judge する。ただし LLM judge の結果と実視聴指標は別に報告する。前者の改善だけをもって、後者の改善と結論付けてはならない。

10. このチュートリアルで起こりやすい失敗

「LambdaMART の score は視聴確率である」

二値ラベルで学習しても、LambdaMART の出力は通常、順位付けのための相対スコアである。確率として解釈したいなら、別途校正と十分な検証が必要である。特に LambdaMART は NDCG を重視するため、score の絶対値より同一リスト内の順序を主に使う。

「LLM ラベルがあるので、人間の行動ログは不要である」

LLM はコンテンツの意味整合性を評価できるが、表示位置、サムネイル、価格、視聴時間、家族利用、時刻といった実行動の要因を完全には再現しない。LLM を教師にしたモデルは、まず LLM の判断を蒸留している。視聴最適化が目的なら、実ログが主たる教師である。

「上位 50 件に正解があるかは、ランカーの問題である」

候補集合にない作品はランカーで上げられない。ランキングの改善と検索の改善を別々に測り、候補 Recall が低いなら検索経路、embedding、filter、ANN の設定を見直す必要がある。

「user split をしたのでリークはない」

ユーザーを分けても、将来の視聴履歴、将来の作品属性、ラベル生成に使った情報が特徴へ混ざるリークは起こり得る。実行時刻を基準に、特徴・候補・正解ラベルの利用可能範囲を切り分ける必要がある。

「未視聴を全部 0 にすれば二値学習できる」

暗黙的フィードバックでは、未視聴は未露出や未認知を含む。負例の作り方は、学習される順位の意味を直接変える。露出済み未視聴を優先し、露出がない場合は sampling 方針とその限界を明示するべきである。

「高い offline NDCG があれば deploy してよい」

NDCG は指定されたラベルと候補集合に対する順位品質であり、UI や配信制約、長期満足、ビジネス影響をすべて含まない。配信可能性、セグメント悪化、視聴後の離脱などのガードレールを持ち、online で検証する必要がある。

まとめ

この章の中心的な学びは、embedding と学習型ランカーを競合させることではなく、役割分担させることにある。embedding は大量カタログから意味的に有望な候補を高速に拾う。LambdaMART は、その候補内で複数の特徴を使い、上位表示に適した順序を学ぶ。LLM ラベルは、そのパイプラインを試作・評価するための意味的な教師になり得る。

一方で、合成プロファイルと LLM ラベルで高い P/R/NDCG が出ても、それは実利用者の視聴を直接証明しない。Hulu で同じ考え方を使うなら、 unique_viewed_series の 25% 以上視聴を時点固定の正シグナルとして扱い、作品メタデータと embedding を特徴にし、候補検索の Recall と候補内ランキングの品質を分けて測るべきである。さらに、未視聴の意味、露出バイアス、配信制約、時間変化を明示したうえで、offline 評価から online 実験へ進めることが必要である。