おすすめができるまでの9ステップ
おすすめは、点数だけでは決まらない。
まず、ざっくりした全体像から。Xのおすすめは、AIが1回で全部決めているのではありません。「候補を集める」→「ふるいにかける」→「AIが点数を付ける」→「上位だけ残す」と、係を順番に通していく工場のラインのような作りです。
そのラインを細かく見ると、9つの工程に分かれています。数字だけ先に出すと、こうです。
候補源の上限を単純に足すと3,000件 → 点数を付けて上位50件 → 表示できるものだけ残して、最大35件。
点数を付ける前に18個のふるいがあり、点数を付けた後にも「上位50件」の関門と表示可否のチェックがある。どこで落ちるかが分かると、伸びない理由も見えてきます。
そして、この記事の芯は1つです。「候補に入る」「順位が高い」「実際に表示される」は、全部別の話だということ。この3つを混ぜて考えると、おすすめは分からなくなります。
あなたの投稿がおすすめに載るまでに、何が起きているか。①Thunder、②Phoenix、③セマンティックID、④SimClustersと、4回かけて部品を1つずつ見てきました。今回は、その部品が「どういう順番でつながっているか」を1本の流れにします。公開コードの、おすすめを組み立てているプログラム(home-mixer)を上から順に読んだ結果です。
全体の流れ(1枚)
順番はコードに書かれた通りで、次の9ステップです。
- 1. あなたの情報を集める(17種類) —— 注文者の情報をそろえる
- 2. 候補を集める(既定で動くのは3つの係) —— 材料を集める
- 3. 候補に情報を付ける(12種類) —— 材料にラベルを貼る
- 4. ふるいにかける(18個のフィルタ) —— 条件外をはじく
- 5. AIが「どう反応するか」を予測する —— 採点係が予測値を出す
- 6. 重みを掛けて1つの点数にする —— 点数にまとめる
- 7. 並べ替えモデルにかける —— もう一度並べ直す
- 8. 上位50件だけを選ぶ —— 一次選抜
- 9. 表示可否の最終チェック → 最大35件に絞る → 画面を組み立てる —— 出荷前の最終検品
1つずつ、短く見ていきます。
① あなたの情報を集める(17種類)
候補を探す前に、まず「あなた」の情報がそろえられます。コードに並んでいるのは17種類。
- 行動履歴(順位付け用と、候補探し用の2種類)
- フォローしている人、購読している人、相互フォローの相手
- ブロック・ミュートしている人
- すでに見た投稿(インプレッションの履歴)
- 最近反応した投稿(いいね・リポスト・返信・ブックマーク・共有・自分の投稿・写真の拡大・動画視聴)
- フォロー中のトピック、スターターパック
- 国・言語などの属性、推定された性別、IP、インストール済みのアプリ
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs#L226-L276
集めただけでは意味がないので、それぞれがこの先のどこで使われるかを並べておきます。ここが分かると、残りの8工程がぐっと読みやすくなります。
【候補集め(②)で使うもの】
- フォローしている人 → Thunderが「この人たちの投稿」を持ってくる
- 行動履歴(候補探し用) → Phoenix検索が「あなたに近い投稿」を探す入口になる
- 最近反応した投稿(9種類) → SimClustersの手がかり。反応した投稿1件ずつが検索の起点になる
- フォロー中のトピック → トピックを指定したリクエストのときの検索に使う
【ふるい(④)で使うもの】
- ブロック・ミュートしている人 → その相手の投稿を落とす
- すでに見た投稿、すでに配信した投稿 → 同じものを二度出さない
- 購読している人 → 購読者限定の投稿を出してよいかの判定
- ミュートキーワード → 含む投稿を落とす
【点数付け(⑤⑥)で使うもの】
- 行動履歴(順位付け用) → Phoenixがあなたの反応を予測するための材料
- フォローしている人 → フォロー外かどうかの判定。フォロー外なら0.75倍
- 相互フォローの相手 → 返信の予測に掛ける重みが上乗せされる(公開値では返信の重みに +15.0。滞在時間側は既定0)
- 国・言語・年齢層・性別・推定性別・インストール済みのアプリ・フォロー中のトピック・スターターパック・IPから割り出した位置 → まとめて「利用者の情報」としてPhoenixに渡されます
最後の1行が、意外と重いところです。投稿の中身だけでなく、あなたの属性や環境も、予測モデルの入力に入っている。IPについては、緯度・経度や地域コードに変換されて渡されます。
なお「すでに見た投稿」の履歴は、ブルームフィルタという「たぶん見た」を高速に判定する仕組みで持っています。完全な一覧を持つより軽い代わりに、誤検知が起こりえます。コードにも誤検知率(`false_positive_rate`)の設定があり、テストでは0.01(1%)が使われています。ここでの誤検知は「見ていない投稿を、見たかもしれないと判定する」方向のことです。
② 候補を集める(既定で動くのは3つの係)
材料を集める工程です。1行でまとめると、こうなります。
Thunder 1,200 + Phoenix 1,000 + SimClusters 800 = 最大3,000件
コードには候補を集める係の枠が7つ並んでいますが、通常の「おすすめ」のリクエストで既定で動くのは、これまでの回で見てきたこの3つです。
- Thunder: フォロー中の人の投稿。最大1,200件(第1回 → 【第1回のURL】)
- Phoenix検索: 中身と投稿者で近い投稿。最大1,000件(第2回 → 【第2回のURL】、第3回 → 【第3回のURL】)
- SimClusters: 反応した投稿と、いいねした人たちの層が近い投稿。最大800件(第4回 → https://x.com/FFBuncho/status/2091314098948686194)
残り4つは、既定でオフか、条件付きです。
- TweetMixer: 別サービスから候補を受け取る枠。最大800件。既定ではオフ(`enable_tweet_mixer_source` = false)。中身は公開コードの外
- Phoenix MoE: 別モデルによる候補。最大200件。既定ではオフ
- Phoenixトピック検索: トピックを指定したリクエストのときだけ動く
- キャッシュ: 直前のリクエストで残った候補があるときだけ動く
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs#L317-L326
運用側がTweetMixerやMoEをオンにしていれば、この3,000件に最大1,000件が加わります(既定値は公開コードの値で、本番で何がオンかは分かりません)。この時点では、まだ「集めただけ」です。
③ 候補に情報を付ける(12種類)
集まった候補1件ごとに、判断材料が付けられます。
- 投稿の基本データ、引用元、メディア情報、言語
- 投稿者の情報、あなたをブロックしていないか、購読者限定か
- エンゲージメント数(いいね・返信などの現在の数)
- セマンティックID(第3回の「中身の住所」→ 【第3回のURL】)
- フォロー内かどうか、相互フォローかどうか
順番が大事で、この「情報を付ける」が終わってから、次のふるいにかけられます。情報がそろっていない候補は、次で落ちます。
④ ふるいにかける(18個)
条件外をはじく工程です。ここで、条件に合わない候補が落ちていきます。18個を性質で4つに分けると、こうなります(コードに並んでいる順番は、下のコード画像の通りです)。
【重複と古さ】
- 同じ投稿が重複しているもの(複数の候補源が同じ投稿を持ってきた場合、1つだけ残す)、基本データが取れなかったもの
- 48時間より古い投稿
- リポストの重複(同じ元投稿のリポストが複数あれば、1つだけ残す)
【あなたが見たくないもの・もう見たもの】
- 自分の投稿
- すでに見た投稿、すでに配信した投稿(3種類)
- ミュートキーワードを含む投稿
- ブロック・ミュートしている相手の投稿
【権限と安全】
- フォロー外の人のリポスト・返信
- フォロー外でNSFWのSimClusters候補
- 購読者限定で、あなたに権限がないもの
- ブラジル2026年選挙の規制対象(選挙裁判所への届出アカウント)
【条件付きの4つ】
- 動画を除外する設定のときだけ、動画を落とす
- トピックを指定したときだけ、トピック外を落とす
- 新規・復帰ユーザー向けの最低エンゲージメント(既定オフ)
- 運用実験用の間引き(既定オフ)
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs#L346-L374
18個のうち、通常の「おすすめ」で常に動くのは14個で、残り4つは条件付きか既定オフです(既定値は公開コードの値で、本番で何がオンかは分かりません)。
注目してほしいのは「48時間」です。一部の候補源では候補集めの段階から48時間の制限がかかっていて、さらに候補をまとめたあとにも共通の年齢フィルタがあります。ここを通れないので、2日より古い投稿は、どのルートからもおすすめに入りません。
ただし、この年齢フィルタが見ているのは「候補として渡ってきた投稿そのもの」の時刻です。リポストは、それ自体が新しい投稿として扱われます。元の投稿が1週間前でも、リポストされたのが1時間前なら、リポストは1時間前の投稿として判定される、ということです。引用も同じく、引用した投稿自身の時刻で判定されます。
⑤ AIが「どう反応するか」を予測する
ここから点数付けです。⑤⑥⑦は続けて起きるので、先に一言でまとめておきます。
⑤ AIが行動ごとの予測値を出す → ⑥ 重みを掛けて1つの点数にまとめる → ⑦ 別のモデルでもう一度並べ直す
まず⑤。残った候補に、Phoenixのモデルが点数を付けます。予測しているのは「この人がこの投稿に、いいねする確率」「返信する確率」「どれくらい長く読むかの予測値」など、行動ごとの予測です。いいねや返信は確率ですが、滞在時間のように「確率」ではない予測値も混ざっています。ここは第2回で詳しく書きました(→ 【第2回のURL】)。
ポイントは、この時点ではまだ「行動ごとの予測値の束」であって、1つの点数ではないことです。
⑥ 重みを掛けて1つの点数にする
予測値の束に重みを掛けて足し、1つの点数にします。ここで効くのが、投稿の中身とは関係のない2つの掛け算です。
- フォロー外の投稿は0.75倍(トピック指定時は0.5倍)
- 同じ投稿者の2件目以降は減点(著者多様性)
2つ目は仕組みが面白いので、次の節に分けます。
⑥の補足1: 同じ人の投稿が続かない理由(著者多様性)
ひとことで言うと、「同じ人の投稿ばかりが並ばないようにする仕組み」です。
④の「重複」と混同しやすいので、先に区別しておきます。④で落とすのは、同じ投稿・同じ元投稿のリポストという「文字どおりのダブり」です。こちらは、中身が別々の投稿でも、投稿者が同じなら2件目以降の点数を下げる、という話。落とすのではなく、点数を割り引きます。
1回のおすすめの選別の中で、候補を点数順に並べたとき、同じ投稿者の投稿が2件目、3件目と出てくると、順番に点数が下げられます。計算式もそのままコードにあります。
それ以前に同じ投稿者が出た回数を k とすると、倍率 = (1 - 0.25) × 0.5^k + 0.25
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/scorers/ranking_scorer.rs#L643-L645
数字にすると:
- 1件目(k=0): 1.0倍(そのまま)
- 2件目(k=1): 0.625倍
- 3件目(k=2): 0.4375倍
- 4件目(k=3): 0.34倍
- 以降: 0.25倍に近づく(下限0.25)
つまり、どれだけ強い投稿を並べても、同じアカウントの2件目は約6割、3件目は4割強まで割り引かれます。既定でオンです(`enable_author_diversity` = true)。
ただし、これは「その時のおすすめの選別の中では」の話です。減点されるのは、同じリクエストの候補の中に同じ投稿者の投稿が複数並んだとき。次のリクエストではまた最初から計算されますし、候補に1件しか入っていなければ減点はありません。連投そのものが常に不利になる、という意味ではなく、「同じタイミングで同じ人の投稿が何件も候補に並ぶと、2件目以降は割り引かれる」という作りです。連投したときに「1件しか伸びない」ことがあるのは、これと整合します。
そしてもう1つ、この作りから読めることがあります(ここは解釈です)。減点は「その1回の選別の中」だけなので、読み込み直すと順番待ちが解消されます。1回目に出た投稿は「配信済み」になって次は落ち、代わりに減点されていた2件目が「1件目」扱いに戻る。つまり、読み込むたびに同じ人の投稿が1件ずつ出てくる、ということが起こりえます。
投稿する側から見るとどういう意味になるかは、後半の「だからどうなる」で書きます。
同じように、セマンティックIDの階層ごとに「同じ話題がそれ以前に何件あったか」「前回から何順位離れているか」も計算され、次の並べ替えモデルに渡されます。ただし、著者多様性のような明示的な減点式はコードになく、この情報をモデルがどう使っているかは公開コードからは確定できません。第3回(→ 【第3回のURL】)で見た「中身の住所」が、投稿を探すときだけでなく並べ方の判断材料にも渡されている、というところまでが事実です。
⑥の補足2: 小さいアカウント向けの1枠(コールドスタート)
ひとことで言うと、「小さいアカウント向けに、1枠だけ持ち上げる処理」があります。
点数付けのところに置かれていて、フォロワーが少なく、まだ表示回数も少ない投稿の中から、1件だけ点数を引き上げます。
公開コードの既定値で使われている条件は、次の4つです。
- 投稿者のフォロワー数が1,000人以下(`cold_start_follower_cap` = 1000)
- その投稿の表示回数が1,000回未満(`cold_start_impression_threshold` = 1000)
- 返信でもリポストでもない、単独の投稿
- もともとの点数の順位が、点数が付いた候補の上位85%以内にいること
4つ目に注意してください。「下位に沈んでいる投稿を救い上げる」仕組みではありません。ある程度の点数をすでに持っている投稿が対象で、下位15%は外されます。
条件に合う候補のうち、いちばん点数の高い1件が選ばれ、その点数が「少なくとも今の16位の候補と同じ水準」まで引き上げられます(`cold_start_slot_min` = 15、`cold_start_slot_max` = 16。0から数えるので16位の点数です)。既定でオンです(`enable_viewer_cold_start_boost` = true)。
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/scorers/author_cold_start.rs#L132-L138
つまり、単純に下位の投稿を持ち上げるのではなく、「ある程度の点数を持っている小規模アカウントの候補に、1件だけ上位へ入るチャンスを与える」仕組みです。小規模アカウントにとっては数少ない追い風で、④SimClustersの「いいねが集まらないと候補にもなれない」構造とは逆向きに働きます。
なお、引き上げられるのは1回の選別につき1件だけです。
⑦ 並べ替えモデルにかける
ここで当然の疑問が出ます。⑥で点数を付けたのに、なぜその順番のまま使わないのか。
理由は、見ているものの範囲が違うからです。
- ⑥は、Phoenixの行動予測に重みを掛けて足し、フォロー外の0.75倍や著者多様性といった決められた補正を反映して、1つの点数にする
- ⑦は、その点数と「同じ投稿者が何件目か」「同じ話題が続いているか」を別のモデルに渡して、もう一度点数を付け直す
⑥の時点でも、著者多様性のように「候補の並びの中で何件目か」を見ている補正はあります。ただしそれは、決められた式で機械的に掛けるもの。⑦は、その結果もひっくるめてモデルが判断し直します。たとえば、点数の高い順に並べたら似た投稿ばかりが上位に固まってしまう、といったことを、式ではなくモデル側で調整できる形です。
点数が付いた候補は、「価値モデル」と呼ばれる別のサービスに渡されます。そのとき一緒に渡されるのが、⑥の補足1で出てきた「同じ投稿者が何件目か」「同じ話題がそれ以前に何件あったか」「前回から何順位離れているか」です。公開コードの既定では、DPP(決定的点過程)という、似たものが重ならないように選ぶ方法が指定されています。
返ってきた点数で、元の点数が置き換えられます。既定でオンです。
まとめると、⑥が「各候補の基本的な評価と、決められた補正」、⑦が「並びの文脈まで含めた再評価」。この2段構えになっています。
⑧ 上位50件だけを選ぶ
ここが、今回いちばんはっきりした数字です。
点数順に並べて、**上から50件**だけが選ばれます(`TOP_K_CANDIDATES_TO_SELECT = 50`)。
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/config.rs#L17
集めた候補は数千件。そこから50件です。しかも、この先の表示可否のチェックでさらに減ります。
冒頭に書いた芯が、ここで効いてきます。候補に入っても、点数が50位に届かなければ出ません。50位に入っても、表示可否のチェックで落ちれば出ません。「候補に入る」「順位が高い」「実際に表示される」は、それぞれ別の関門です。
⑨ 表示可否のチェック → 最大35件 → 画面へ
選ばれた50件に、表示可否(Visibility Filtering)まわりの情報が付けられ、最後のフィルタが3つかかります。
- VFフィルタ(安全性のラベルによる除外。番外編で書いた「フォロー外だけ落とす」判定もここ → 【番外編(コピペ&過剰リプ)のURL】)
- 補助のVFフィルタ
- 同じ会話の重複除去
【寄り道: そのラベルは、どう付くのか】
ここだけ少し寄り道します。表示可否を決める材料の1つとして重要なのが「ラベル」ですが、そのラベルがそもそもどう付くか、という話です。
VF自身がアカウントの信頼度(Cred)を直接読んでいるわけではありません。Credが効くのは1段手前、ラベル付与などを決めるenforcementの側です。公開コードのルールでは、信頼度が高いアカウント(`cred.is_high` または `cred.score >= 50.0`)は `pagerank_skipped` として処理が打ち切られます。フォロワー数が一定以上の場合も、同じようにこの処理をスキップする項目(`high_follower_count`)があります。
順番が大事です。検知の結果はこの手前で出ていて、ルールの後半は「検知結果にこのラベルが入っていたら、こう処理する」という形。信頼度によるスキップは、その前に置かれています。つまり検知されていても、スキップが先に成立すれば、後ろのラベル付与まで進みません。「Credが高い → 一部の処理で一部のラベルが付きにくい → 結果としてVFで落ちにくくなる場合がある」という、間接的なつながりです。
ただし `score.skip_author_credibility_prechecks` が立っている場合、このスキップは効きません(この但し書きは投稿側のルールにあり、アカウント側のルールにはありません)。どの検知でこれが立つのかは、次回の「エンゲージメント稼ぎへの対策」で扱います。
残った候補は、上から最大35件に切られます(`RESULT_SIZE = 35`)。ここまでが「投稿を選ぶ」処理で、コード上の順番は「点数付け → 上位50件を選ぶ → 表示可否の情報を付ける → 3つのフィルタ → 35件に切る」です。
【切られた分はどうなるのか】
50件のうち35件に入らなかった分や、途中で落ちた候補は、消えてなくなるわけではありません。
- 実際に最終応答へ返された投稿だけが「配信済み」として記録され、次回以降のふるい(④)で落とされます
- それ以外の候補は「配信済み」になりません。つまり、次のリクエストでまた候補になれます
- さらに、点数が付いた候補は最大750件までキャッシュに保存されます(保存は3分間)。次のリクエストがこの3分以内なら、候補集め(②)は動かず、このキャッシュから候補が供給されます
なので「35件に入らなかった投稿が優先される枠」のようなものはありません。ただ、配信済みにはならないので、同じ人が3分以内にもう一度読み込めば、前回作った候補の中から改めて選び直される。3分を過ぎれば、また②の候補集めからやり直しです(そのときも48時間以内なら、また候補になれます)。
【④のふるいと何が違うのか】
ここで「④のふるいと何が違うの?」と思った方へ。どちらも「落とす」処理ですが、見ているものが別です。
- ④(点数付けの前): その読者に出せる候補かどうか。重複、48時間、既読、ブロック・ミュート、購読の権限など、ほぼ機械的な条件です
- ⑨(上位50件のあと): その投稿を表示してよいかどうか。スパム、NSFW、暴力的な内容、悪質なURL、「増幅しない」指定など、投稿やアカウントに付いた安全性のラベルで判定します
安全に関わる判定の本体は⑨です。ただし④にも安全寄りのものが2つ混ざっています(フォロー外でNSFWのSimClusters候補、ブラジル選挙の規制対象)。「安全チェックは最後だけ」ではない、というのはその意味です。
なお、この表示可否の判定(Visibility Filtering)は、おすすめを組み立てるプログラムとは別のサービスとして切り出されています。ラベルを引くのに追加の問い合わせが必要なので、数千件の候補全部ではなく、選ばれた50件にだけかけている——という順番になっている、と読めます(ここは解釈です)。
【外側での組み立て】
このあと、外側でタイムラインが組み立てられます。広告は投稿の間に差し込まれ、既定の混ぜ方では投稿と広告の列が35件に切られます。その上に、おすすめユーザー(6番目の位置)などのモジュール(4枠)と、フレーム(最大8枠)が載るので、1回の応答全体の上限はコード上47アイテム(35+4+8)です。
数字で追いかけると
- 集める: 3,000件(既定の3つの上限の単純合計。TweetMixer・MoEがオンなら最大+1,000件)
- ふるい: 18個のフィルタ(常に動くのは14個)で条件外の候補を除外
- 点数付け: AIの予測 → 重み付け → 並べ替え
- 選抜: 上位50件
- 最終: 投稿は最大35件(投稿+広告の列も35件)。モジュールとフレームを含めた応答全体の上限は47アイテム
各候補源の上限を単純合計した3,000件と比べると、画面に出る投稿は最大35件なので、約1%という規模感です。ただし毎回3,000件が集まるわけではありませんし、重複除去や既読除外も入るので、あくまで上限同士を並べた目安です。
ここが誤解されやすい
【「候補に入った」=「表示される」ではない】
④(https://x.com/FFBuncho/status/2091314098948686194)で書いた「番組のランキング800位以内」も、あくまで候補になれるかどうかの話。そこから18個のフィルタと、上位50件の関門があります。
【フォロワー数だけで単純に加点されるわけではない】
Thunderは「フォロー中の人の投稿を運ぶ」だけで、順位を付けるのはPhoenixの予測です。⑥の重み付けにも「フォロワーが多いほど何点加算」という単純な項目はありません。
ただし、⑦の並べ替えモデルには、投稿者のフォロワー数(`author_followers_count`)が入力として渡されています。そこでどう使われているかは、公開コードからは確定できません。「フォロワー数は順位に一切関係ない」とまでは言えない、というのが正確なところです。
【連投は不利になりうる(その時の選別の中では)】
同じ投稿者の2件目以降には、はっきりした減点があります(0.625倍、0.4375倍…)。ただし効くのは、同じリクエストの候補に同じ人の投稿が複数並んだときだけ。同じ時間帯に何件も出すと、その選別では2件目以降が割り引かれた点数で競うことになります。連投が常に不利、という意味ではありません。
だからどうなる
【読む側】
おすすめに出てくる投稿は、数千件から上位50件に絞られ、さらに表示可否のチェックを通った結果です。同じ人の投稿ばかりが1画面に続かないのは、意図的に組み込まれた減点によるものです。ただし減点は1回の選別の中だけなので、読み込み直すと同じ人の別の投稿が出てくることがあります(解釈)。同じ話題の連続状況も、並べ替えモデルに渡す判断材料として組み込まれています。
【投稿する側】
- 48時間を過ぎた投稿は、どのルートからも候補になりません
- 同じ選別に同じ人の投稿が複数並ぶと、2件目以降は割り引かれます。判定の単位は投稿の間隔ではなく、その読者の1回の候補選別です。候補の年齢上限が48時間なので、間隔を空けても同じ選別に2本並ぶことはあります。「間隔を空ければ避けられる」とはコードからは言えません
- 「候補に入る」までの入口は複数あります(フォロワー経由=Thunder、中身=Phoenix、いいねの層=SimClusters)。どれか1つの候補源から拾われ、そのあと④の18個のフィルタを通れば、点数付けの土俵に乗ります
【連投は損か、という話(ここは解釈です)】
ここまでの部品を組み合わせると、こう読めます。
Thunderは、フォロー中の人の投稿を新着順に最大1,200件持ってきます。つまり連投すると、そのフォロワーの候補プールに、あなたの投稿が複数入る。ただし1回の選別では、多様性の減点があるので2件目以降はかなり不利になります。そして「配信済み」として記録されるのは、実際に出た分だけ。次にその人が読み込むと、出た分は落ちて、残っていた投稿が「1件目」扱いに戻ります。
なので、読者が何度も見に来るほど、連投した分が順番に消化されていく、という形になります。「その1回の選別では不利、でも積んだ分が無駄になるとは限らない」というのが、コードから読める姿です。
ただし前提が2つあります。1つは、最終的に表示まで残れるだけの評価を得ていること。点数の元になっているのは「その読者が各行動を起こす予測値」なので、反応の薄い相手には、候補に入っても表示までは届きません。もう1つは48時間以内であること。2日を過ぎた分は、消化されないまま候補から消えます。
【では、いつも反応してもらえる相手ならどうか】
減点は必ずかかりますが、掛け算です。元の点数が高ければ、減点されても上位に残れます。
減点そのものを打ち消すのに、どれだけ余裕が必要かを逆算するとこうなります。
- 2件目(×0.625): 1件目と同じ位置に立つには、元の点数が約1.6倍必要
- 3件目(×0.4375): 約2.3倍
- 4件目(×0.34): 約2.9倍
ただし、これは「この倍率があれば35件に残る」という意味ではありません。この後に⑦の並べ替えと⑧の上位50件、⑨の表示可否のチェックが入るので、⑥の点数から最終的な35件の境界を直接逆算することはできません。ここで言えるのは「減点を相殺するには、これだけの差が要る」というところまでです。
つまり「連投しても不利にならない」のではなく、「不利を上回る差があれば、同じ画面に2件、3件と並ぶこともある」ということです。
ここで大事なのが、その点数の中身です。⑥の点数の元になっているのは、その読者が各行動を起こす予測値で、材料はあなたの行動履歴。だから効くのは「世間的に人気かどうか」ではなく、「この読者にとって反応しやすいかどうか」です。
- 有名なアカウントでも、あなたが普段スルーしているなら予測は低く、2件目は落ちます
- フォロワーが少ないアカウントでも、あなたがいつも反応しているなら予測は高く、2件目も残りえます
- 相互フォローなら、返信の予測に掛ける重みが上乗せされます(公開値では +15.0)
「アカウントが強い」のではなく、「あなたとその人の関係が強い」。この記事で何度か出てくる「フォロワー数だけでは加点されない」と、同じことを別の角度から言っているだけです。
ただし⑦の並べ替えモデルには投稿者のフォロワー数が渡っているので、「有名であること自体は一切効かない」とまでは言い切れません。ここは公開コードからは確定できないところです。
言い換えると、この構造で効いてくるのは「投稿の本数」そのものではなく、「何度も見に来て、反応してくれる読者がどれだけいるか」です。ここまでの回で見てきた、④SimClustersの「同じ層からのいいねが集まらないと候補にもなれない」とも、向きは同じです。
まとめ
- おすすめは「係を順番に通すライン」。集める → 情報を付ける → ふるう → 予測 → 点数化 → 並べ替え → 上位50件 → 表示可否のチェック → 35件 → 画面の組み立て
- 候補集めの入口は、既定で3つ(Thunder 1,200 / Phoenix 1,000 / SimClusters 800。合計3,000件)。コード上はほかに4つの枠があるが、既定オフか条件付き
- 48時間より古い投稿は、候補にならない
- フォロー外の投稿には0.75倍。同じ選別の中で同じ投稿者の2件目以降は0.625倍、3件目は0.4375倍(下限0.25倍)。連投が常に不利という意味ではない
- フォロワー1,000人以下・表示1,000回未満・上位85%以内などの条件に合う候補から1件を選び、既定では16位の点数の水準まで引き上げる「コールドスタート」処理がある(既定オン)
- 「候補に入る」「順位が高い」「実際に表示される」は、全部別。どれか1つ通っても、次で落ちる
- ランキングで一次選抜されるのは上位50件。その後、表示可否のチェックを通った投稿が最大35件まで残る(投稿+広告の列も35件)。モジュール込みの応答全体は最大47アイテム
次回は、ここまで何度か触れてきた「エンゲージメント稼ぎへの対策」を予定しています。
参照(クリックすると該当箇所が開きます)
おすすめの組み立て全体(候補源・フィルタ・点数付け・選抜の順番):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs
利用者の情報がPhoenixに渡される部分(年齢層・性別・推定性別・トピック・スターターパック・IPの位置・インストール済みアプリ):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/util/phoenix_request.rs#L30-L75
相互フォロー相手への重みの上乗せ(返信 +15.0 / 滞在時間は既定0):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/param.rs#L317-L327
あなたの情報を集める処理(17種類):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs#L226-L276
候補を集める係(7つの枠、既定で動くのは3つ):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs#L317-L326
著者多様性の計算式(0.5の減衰・下限0.25):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/scorers/ranking_scorer.rs#L643-L645
著者多様性の既定値(decay 0.5 / floor 0.25 / 既定オン):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/param.rs#L223-L239
上位50件の選抜:
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/config.rs#L17
投稿の上限35件と、応答全体の上限47(35+4+8):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/config.rs#L17-L22
並べ替えモデル(既定の価値モデルはDPP。同じ投稿者が何件目か・同じ話題の連続も渡される):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/scorers/vm_ranker.rs
候補のキャッシュ(選ばれた分と選ばれなかった分をまとめて最大750件・3分間):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/side_effects/redis_post_candidate_cache_side_effect.rs
配信済みとして記録されるのは実際に返した分だけ:
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/side_effects/update_served_history_side_effect.rs
実行順(点数付け → 選抜 → 選抜後の情報付け → 選抜後のフィルタ → 件数で切る):
https://github.com/xai-org/x-algorithm/blob/28e414f/candidate-pipeline/candidate_pipeline.rs#L97-L131
コールドスタート(フォロワー1,000人以下・表示1,000回未満・上位85%以内・16位の水準へ):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/scorers/author_cold_start.rs
コールドスタートの既定値(follower_cap 1000 / impression_threshold 1000 / slot 15-16 / 上位85% / 既定オン):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/param.rs#L653-L695
並べ替えモデルに渡される投稿者のフォロワー数:
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/scorers/vm_ranker.rs#L188
年齢フィルタ(候補そのもののIDで判定。リポストはリポスト自身の時刻):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/filters/age_filter.rs
投稿の年齢上限48時間:
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/config.rs#L36
各候補源の上限と既定のオン/オフ(Thunder 1,200 / Phoenix 1,000 / TweetMixer 800・既定オフ / MoE 200・既定オフ):
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/param.rs#L1-L52
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/params/param.rs#L135-L162:
信頼度による審査スキップ(pagerank_skipped / high_follower_count):
https://github.com/xai-org/x-algorithm/blob/28e414f/abuse-enforcement-service/service-lib/rules/enforcement_post.yaml
https://github.com/xai-org/x-algorithm/blob/28e414f/abuse-enforcement-service/service-lib/rules/enforcement_user.yaml:
最後の安全チェックと画面の組み立て:
https://github.com/xai-org/x-algorithm/blob/28e414f/home-mixer/candidate_pipeline/for_you_candidate_pipeline.rs
この記事のもとになったX記事
Xで公開した第5回の記事を、サイト用に読みやすく再構成したものです。
ふくふく文鳥