Wie funktioniert die Beitragsverfolgung in Discourse

Discourse verfolgt die Lesezeit für jeden Beitrag, den Benutzer auf dem Bildschirm sehen. Dieses System hat sich über die Jahre weiterentwickelt, und ich stelle oft fest, dass ich auf den Code zurückgreifen muss, um herauszufinden, wie dies funktioniert und warum es existiert.

Dieser Beitrag behandelt die schmerzhaften technischen Details der aktuellen Implementierung.

Wie der Discourse-Client die Zeit verfolgt

Die Verfolgung der Beitragszeit wird in screen-track.js.es6 implementiert. Dieses Modul ist dafür verantwortlich, zu verfolgen, wie lange ein Beitrag auf dem Bildschirm war und wie lange das Thema auf dem Bildschirm war.

Wenn eine Themenseite „scrollt", teilt sie dem Screen-Tracker mit, welche Beiträge im Sichtfeld sind UND welche dieser Beiträge gelesen wurden. Beiträge, die nur teilweise im Sichtfeld sind, gelten als „im Sichtfeld".

Der Screen-Tracker feuert dann jede Sekunde ein „Tick", das entscheidet, welche Daten an den Server gesendet werden müssen.

Der Screen-Tracker verwaltet mehrere Listen:

a. Eine Liste von (Beitrag/Zeit, die mit dem Lesen des Beitrags verbracht wurde), die noch nicht an den Server gesendet wurde
b. Eine Liste von Beiträgen, von denen wir wissen, dass sie gelesen wurden
c. Eine Liste von Beiträgen, von denen wir wissen, dass sie sich gerade auf dem Bildschirm befinden

Zu Beginn eines Ticks (jede Sekunde), wenn wir Beiträge in (a) haben, werden wir prüfen, ob wir sie an den Server senden:

  • Wenn die Site-Einstellung flush_timing_secs (Standard 60 Sekunden) seit dem letzten Senden von Daten an den Server vergangen ist.

  • Wenn einer der Beiträge vom Benutzer als „ungelesen" markiert ist, senden wir die gesamte Liste sofort.

Am Ende eines Ticks, wenn Discourse den Fokus hat:

Wenn wir „Beiträge auf dem Bildschirm" haben, protokollieren wir für jeden Beitrag „1 Tick" Zeit.

Wenn wir zu einem beliebigen Zeitpunkt das Thema verlassen (zu einer anderen Stelle in Discourse navigieren):

Wir senden sofort alles, was „in der Luft" ist in (a), an den Server.

Grenzen

  • Jedes Mal, wenn Sie ein Thema ansehen, protokollieren wir maximal 6 Minuten Lesezeit pro Beitrag (dies wird zurückgesetzt, wenn Sie weg- und wieder zum Beitrag navigieren).

  • Wenn 3 Minuten vergehen, ohne dass Sie gescrollt haben, deaktivieren wir dieses Subsystem, bis erneut gescrollt wird.

  • Wir protokollieren die Zeit für bis zu 5 Themen für anonyme Benutzer (was beim Registrieren des Benutzers in die Tabelle posts_timing umgewandelt wird).

Wichtige Beobachtung

  1. Obwohl die Tabelle post_timings bis auf die Millisekunde verfolgt, haben wir pro Beitrag zwischen „0–1000 ms" „nicht protokollierte" Zeit, je nachdem, wann der Tick feuert.

  2. Jede „Sitzung" des Ansehens eines Themas kann bis zu 6 Minuten Lesezeit pro Beitrag protokollieren. Es gibt keine Obergrenze für die Lesezeit pro Beitrag; ein Beitrag kann über Tage hinweg von einem Benutzer gelesen werden, wenn der Benutzer zu einem Thema zurückkehrt.

Was machen wir mit diesen Daten?

Der wichtigste Informationswert, den wir verwenden, ist „Hat Benutzer X Beitrag Y gelesen?". Dies bestimmt die Anzahl der ungelesenen Beiträge im Thema und viele andere kritische Daten.

Abgesehen von der binären Verwendung verwenden wir die in post_timings protokollierte Zeit, um avg_time für einen Beitrag zu berechnen.

Die durchschnittliche Zeit für einen Beitrag wird als Exponent des Durchschnitts des natürlichen Logarithmus der Zeit berechnet (d. h. geometrisches Mittel).

Zum Beispiel:

Beitrag 1: sam, 10 Sekunden
Beitrag 2: jane, 1 Stunde

avg_time = exp((log(3600000) + log(10000)) / 2)
=~ exp((15,09 + 9,2) / 2)
=~ 189094
=~ 189 Sekunden

Diese avg_time wird dann im Score-Rechner als eine Komponente für den „Beitrags-Score" verwendet.

Score = 5 * reply_count + 15 * like_score + 5 * incoming link count + 2 * bookmark_count + 0,05 * avg_time + 0,2 * post reads.

Im obigen Fall entsprechen 189 Sekunden durchschnittlicher Lesezeit pro Beitrag 37 Punkten. Das sind also… ungefähr 2 Likes und etwas mehr. Oder 72 Lesevorgänge.

Der „Beitrags-Score" wird dann für „Best of" verwendet, um herauszufinden, welche Beiträge in einem Thema die besten sind.

24 „Gefällt mir“

Isn’t this read data the backing store for these numbers, total read time?

3 „Gefällt mir“

Yes the “topic read time” I will update the OP to explain about that, I touched on it very lightly.

The topic_users table has a column called total_msecs_viewed. This number is updated independent of post_timings in the same controller action. We can not “rebuild” that number from post timings cause we have no idea about overlapping times.

The “topic timing” piece has no 6 minute limit like post timing does. The number is flushed with the same post timing batch according to the same rules.

I think I was so focused on talking about post tracking that I missed out on explaining the topic tracking part.

4 „Gefällt mir“

Whoa… we do? Do we really need to do this? It feels unnecessary?

What do you mean by “overlapping times”?

1 „Gefällt mir“

I have not tested this recently, but yes the code is all there to do it. I guess it means you can get to TL1 a bit faster.

Say you we know about my timings:

Post 1: 10 seconds
Post 2: 12 seconds
Post 3: 17 seconds

The time I spent reading the topic can be anywhere between 17 seconds and 39 seconds.

So we can not use the data in the posts timing table to figure out what the number in topic users should be. So we are forced to track that other number independently.

It is not a huge deal and makes no big diff, but there is no way to “run an inventory” and check that the number in topic user is 100% correct.

3 „Gefällt mir“