Die Vorschläge-Karte rechnet einmal für alle statt dreimal pro Leser (v7.231.3) - #1326
Merged
Conversation
…(v7.231.3) Die "Vorschläge"-Karte im Feed hat ihre Kandidaten pro Leser neu ermittelt, und zwar bis zu dreimal: eine Leiter aus drei Stufen (fremde Autoren aus den letzten 14 Tagen, dann fremde Autoren jeden Alters, dann alle außer mir selbst aus 14 Tagen), jede Stufe ein eigener Scan über posts plus Like-Rollup, gruppiert auf einen Post pro Autor. Der teure Teil dieser Frage ist für jeden Leser derselbe: welche öffentlichen Posts dieser Sprache kamen gut an, einer pro Autor, bester zuerst. Persönlich ist nur die letzte Meile, also nicht meine eigenen Posts, niemand, den ich stumm gestellt oder blockiert habe, und Leute, denen ich noch nicht folge, vor denen, denen ich schon folge. Der geteilte Teil wandert deshalb in einen Snapshot. Vutuv.Posts.PopularPosts folgt genau dem Muster von Vutuv.Social.PopularUsers (der Schwesterkarte "Wem folgen?" im selben Rail) und Vutuv.Posts.TopPosters: alle zehn Minuten eine Rangliste pro konfigurierter Sprache in eine read_concurrency-ETS-Tabelle, :miss fällt auf die bisherige Leiter zurück. Eine Ranglisten-Abfrage pro Sprache für die ganze Installation, unabhängig davon, wie viele Leute lesen. Das lohnt mehr, als eine Zahl pro Seitenaufruf vermuten lässt: das Rail zeichnet sich alle fünf Minuten selbst neu, die alte Rechnung skalierte also mit offenen Tabs, nicht mit Lesern. Die drei Stufen werden dabei zu einer Sortierung, was sie immer waren: ein CASE im ORDER BY der Ziehung statt drei Suchen. Nebenbei stimmt damit die Richtung wieder. Stufe 1 und 2 schließen alle aus, denen der Leser folgt, also bezahlten gut vernetzte Mitglieder bisher zwei Ziehungen, die die Karte gar nicht füllen konnten, bevor die dritte die Arbeit machte. Die Regel, auf der das Ganze ruht: der Pool schlägt vor, die Datenbank entscheidet. Ein Snapshot ist Minuten alt, Moderation ist es nicht, also enthält er nur Kandidaten-IDs, und die Ziehung legt das volle anonyme Sichtbarkeits-Gate plus Blocks und Mutes des Lesers erneut an. Bezahlbar ist das genau deshalb, weil es auf ein paar hundert bekannte IDs begrenzt ist statt auf die posts-Tabelle. Ein veralteter Pool kann damit einen leicht veralteten Vorschlag kosten, nie einen Post, den jemand nicht sehen darf. Gemessen auf einer Kopie der Produktionsdaten: 4,35 ms und 8,59 ms DB-Zeit für die Leiter, 1,13 ms und 2,03 ms für den Snapshot-Pfad, dazu 3,2 ms alle zehn Minuten für alle Sprachen zusammen. Der wichtigste Testblock heißt "a stale pool never leaks a hidden post" und hat einen Fall pro Art, wie sich die Welt nach dem Snapshot bewegen kann. Gefangen hat die Suite außerdem einen echten Fehler der ersten Fassung: sie mischte die Kandidaten über die ganze Menge statt innerhalb einer Stufe und warf damit still die Bevorzugung fremder Autoren weg. Diesen Text hat ein KI-Agent in meinem Namen geschrieben, ungeprüft von mir. Die Arbeit dahinter ist meine, nur das Aufschreiben habe ich delegiert.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Die "Vorschläge"-Karte im Feed hat ihre Kandidaten bisher pro Leser neu ermittelt, und zwar bis zu dreimal: eine Leiter aus drei Stufen (fremde Autoren aus den letzten 14 Tagen → fremde Autoren jeden Alters → alle außer mir selbst, wieder aus 14 Tagen), jede Stufe ein eigener Scan über
postsplus Like-Rollup, gruppiert auf einen Post pro Autor.Der teure Teil dieser Frage ist aber für jeden Leser derselbe: welche öffentlichen Posts dieser Sprache kamen gut an, einer pro Autor, bester zuerst. Persönlich ist nur die letzte Meile — nicht meine eigenen Posts, niemand, den ich stumm gestellt oder blockiert habe, und Leute, denen ich noch nicht folge, vor denen, denen ich schon folge.
Was sich ändert
Der geteilte Teil wandert in einen Snapshot.
Vutuv.Posts.PopularPostsist ein GenServer nach genau demselben Muster wieVutuv.Social.PopularUsers(die Schwesterkarte "Wem folgen?" im selben Rail) undVutuv.Posts.TopPosters: alle zehn Minuten eine Rangliste pro konfigurierter Sprache in eineread_concurrency-ETS-Tabelle,:missfällt auf die bisherige Abfrage zurück. Eine Ranglisten-Abfrage pro Sprache für die ganze Installation, egal wie viele Leute gerade lesen.Das lohnt sich mehr, als eine Zahl pro Seitenaufruf vermuten lässt:
feed.exzeichnet das Rail alle fünf Minuten neu (@suggestions_refresh), also skalierte die alte Rechnung mit offenen Tabs, nicht mit Lesern.Die drei Stufen werden eine Sortierung. Sie waren immer eine Rangfolge über eine Kandidatenmenge, keine drei Suchen. Jetzt sind sie ein
CASEimORDER BYder Ziehung. Nebenbei behebt das die Richtung: Stufe 1 und 2 schließen alle aus, denen der Leser folgt, also bezahlten gut vernetzte Mitglieder bisher zwei Ziehungen, die die Karte gar nicht füllen konnten, bevor die dritte die Arbeit machte.Der Pool schlägt vor, die Datenbank entscheidet. Ein Snapshot ist Minuten alt, Moderation ist es nicht. Deshalb enthält er nur Kandidaten-IDs, und die Ziehung legt das volle anonyme Sichtbarkeits-Gate plus Blocks und Mutes des Lesers erneut an. Bezahlbar ist das genau deshalb, weil es auf ein paar hundert bekannte IDs begrenzt ist statt auf die posts-Tabelle. Veralteter Pool kann also einen leicht veralteten Vorschlag kosten, nie einen Post, den jemand nicht sehen darf.
Gemessen (Kopie der Produktionsdaten)
Dazu 3,2 ms alle zehn Minuten für alle Sprachen zusammen, einmal für die ganze Installation. Die Abfragezahl sinkt nur um zwei, weil der Rest Preloads sind; die drei Ranglisten-Scans sind durch eine ID-gebundene Abfrage ersetzt, und deren Kosten hängen nicht mehr an der Größe der posts-Tabelle.
Tests
test/vutuv/posts/popular_posts_test.exs, 24 Fälle. Der wichtigste Block heißt "a stale pool never leaks a hidden post" und hat einen Fall pro Art, wie sich die Welt nach dem Snapshot bewegen kann: Post eingefroren, Autor eingefroren / gesperrt / deaktiviert / unerreichbar, Post nachträglich beschränkt, Autor seither blockiert oder stumm gestellt. Dazu die Rückfälle (leerer Pool auf einer frischen Installation, Leser filtert den ganzen Pool weg, Snapshot antwortet nicht) und eine Zusicherung, dass auf dem Cache-Pfad kein Ranking-Scan mehr läuft.Ein Fehler, den die Tests gefangen haben und der es wert ist, erwähnt zu werden: die erste Fassung mischte die Kandidaten über die ganze Menge statt innerhalb einer Stufe und warf damit still die Bevorzugung fremder Autoren weg. Jetzt wird pro Stufe gemischt, mit eigenem Test dafür.
Die bestehende
discover_posts/2-Suite (25 Fälle) prüft weiter die Leiter: in Tests ist der Refresh-Timer aus, also läuft dort der:miss-Pfad. Beide Wege sind damit abgedeckt.Deploy: hot, keine Migration. Neuer Prozess im Supervision-Tree und ein neuer Schalter
:refresh_popular_posts(in Tests aus, wie bei den beiden Schwester-Caches).Version: 7.231.3 (Patch: das Rail verhält sich gleich, es ist ein Refactor)
mix precommit: grün (6961 Tests).Diesen Text hat ein KI-Agent in meinem Namen geschrieben, ungeprüft von mir. Die Arbeit dahinter ist meine, nur das Aufschreiben habe ich delegiert.