5 Punkte von GN⁺ 2025-05-02 | 1 Kommentare | Auf WhatsApp teilen
  • Beim Aufbau von hn.unlurker.com wurde in den HN-API-Client eine scan-Funktion eingebaut, die alle Items der Reihe nach abruft, und die gesamten Hacker-News-Daten wurden lokal heruntergeladen
  • Während der Ausführung von hn scan --no-cache --asc -c- -o full.json blieb der Download mehrmals stehen, doch dank des fortsetzbaren Scans lag nach einigen Stunden eine 20-GiB-JSON-Datei vor
  • Nachdem JSON mit DuckDBs read_json_auto in eine Tabelle umgewandelt wurde, wurden mit text ILIKE und SQL für einen gleitenden 12-Wochen-Durchschnitt die Erwähnungsanteile von Python, JavaScript, Java, Ruby und Rust aggregiert
  • Schon mit einfachem grep ließ sich feststellen, dass die Phrase „correct horse battery staple“ auf Hacker News 231-mal vorkommt; DuckDB wirkt für einmalige Analysen in dieser Größenordnung gut geeignet
  • Liegen alle Daten lokal vor, lassen sich historische Inhalte von Hacker News auf viele Arten analysieren; dieses Projekt endet jedoch hier, und der nächste Schritt bleibt anderen überlassen

Alle Items von Hacker News herunterladen

  • Für den Aufbau von hn.unlurker.com wurde ein HN-API-Client geschrieben
    • Es gab bereits mehrere Clients, aber in einem neuen Projekt sollten aktuelle Go-Features und Linter ausprobiert werden
    • In der HN API werden Kommentare und Storys als Items bezeichnet
  • Der Client kann aktive Items, Item-Listen und Ähnliches abrufen
    • Für das eigentliche Projekt wurden nur aktuelle Items benötigt, aber der Vollständigkeit halber wurde eine scan-Funktion hinzugefügt
    • scan lädt Items der Reihe nach von 0 bis zum neuesten oder in umgekehrter Richtung herunter
  • Der komplette Download wurde nicht auf zehntausende GiB, sondern auf etwa einige Dutzend GiB JSON geschätzt, daher wurde der Versuch gestartet
hn scan --no-cache --asc -c- -o full.json
  • Der Download blieb mehrmals stehen und wurde mit CTRL-C abgebrochen, aber da scan fortsetzbar ist, war er einige Stunden später abgeschlossen
  • Das Ergebnis ist eine 20-GiB-JSON-Datei mit allem, was auf Hacker News passiert ist
  • Wenn derselbe Befehl erneut ausgeführt wird, kann sie wieder mit den neuesten Daten aufgefüllt werden

Lokale Daten mit DuckDB analysieren

  • Zunächst wurde einfach mit grep gesucht
    • Die Phrase „correct horse battery staple“ kommt auf Hacker News 231-mal vor
    • Das letzte Vorkommen war zum Zeitpunkt des Schreibens ein Item, das „heute“ veröffentlicht wurde
  • Danach wurde eine Analyse mit DuckDB ausprobiert
    • DuckDB ist eine einbettbare, schnelle Analytical Execution Engine und auch als Kommandozeilentool verfügbar
    • Dank der neuen UI war sie auch für Einsteiger leicht zu nutzen, und ein LLM half beim Schreiben der SQL-Abfragen
  • Die JSON-Daten werden in DuckDB auf folgende Weise importiert
CREATE TABLE items AS
SELECT *
FROM read_json_auto('/home/jason/full.json', format='nd', sample_size=-1);
  • Die Beispielabfrage gruppiert Items nach Wochen und berechnet den Anteil der Items, die ein bestimmtes Wort enthalten
    • python, javascript, java, ruby und rust werden mit text ILIKE gesucht
    • Für jeden Anteil wird ein gleitender 12-Wochen-Durchschnitt berechnet
  • Auf dieselbe Weise wurden auch datenbankbezogene Begriffe visualisiert
    • Die Beispielgrafik enthält die Erwähnungsanteile als gleitenden 12-Wochen-Durchschnitt für mysql, postgres, mongo, redis und sqlite
  • DuckDB wirkte sehr gut geeignet, um ein Dataset dieser Größe zu analysieren
  • Obwohl nun eine lokale Kopie des gesamten Hacker-News-Inhalts vorliegt, soll das Projekt hier enden

1 Kommentare

 
GN⁺ 2025-05-02
Kommentare auf Hacker News
  • Ich kenne zwei Datenbanken mit aktualisierten Hacker-News-Tabellen, mit denen man Analysen ausführen kann, ohne sie vorher herunterzuladen.
    BigQuery erfordert ein Google-Cloud-Konto; Abfragen sind vermutlich im kostenlosen Kontingent möglich, und man kann bigquery-public-data.hacker_news.full verwenden.
    ClickHouse erfordert keine Registrierung, und Abfragen lassen sich direkt im Browser ausführen: https://play.clickhouse.com/play?user=play#U0VMRUNUICogRlJPT...

  • Ich habe früher einmal etwas Ähnliches mit dem @fesshole-Twitter-/Bluesky-Account gemacht. Ich habe das gesamte Archiv heruntergeladen und ein Modell feinabgestimmt, damit es noch abgedrehtere Geständnisse erzeugt.
    Darauf war ich ziemlich stolz, bis mir klar wurde, dass ich einer unschuldigen Maschine letztlich nur Masturbation und Scheidung beigebracht hatte.
    Es fühlte sich an wie in einem Science-Fiction-Film, in dem Aliens oder eine superintelligente KI die Menschheitsgeschichte im Schnelldurchlauf sehen und entscheiden, dass wir es nicht wert sind, gerettet zu werden.

    • Zu der Stelle „einer unschuldigen Maschine Masturbation und Scheidung“: Angenommen, man findet einen USB-Stick einer längst verschwundenen Zivilisation und trainiert mit dessen Textdaten ein Modell.
      Wenn es keinerlei Verbindung zur Außenwelt zu diesen Daten gibt, wie sollten ein Mensch oder ein Modell dann wissen, dass auf diesem USB-Stick Daten über Masturbation und Scheidung enthalten sind?
    • Ich verstehe nicht, was an Masturbation und Scheidung problematisch sein soll. Beides sind Wege, wie Menschen glücklicher und selbstständiger leben können, bzw. Wege, aus unpassenden Situationen herauszukommen.
      Ich halte beides insgesamt für positiv und bin dankbar, in einer Gesellschaft zu leben, in der solche Dinge normalisiert sind.
  • Eine Java-Abfrage enthält auch alle Vorkommen von JavaScript, daher wird Java überrepräsentiert.

    • Genauso würde eine Rust-Abfrage jede Menge Wörter wie trust, antitrust und frustration enthalten.
    • Stimmt … dann ist es vielleicht sogar noch unerwarteter, dass ein Abwärtstrend zu sehen ist.
  • Dass es auf Hacker News eine 20-GiB-JSON-Datei mit allem gab, was je passiert ist, wirkt überraschend groß, wenn man bedenkt, dass es eine reine Textseite ist.
    Bedeutet das, dass die Leute in den 18 Jahren, in denen HN existiert, mehr als 20 Milliarden Byte Text gepostet haben? Das wären im Schnitt über 2 MB pro Tag, etwa 7,5 KB pro Sekunde.

    • 2 MB pro Tag wirken nicht besonders viel. Vor allem seit dem Reddit-Debakel und dem jüngsten und größten „Ewigen September“ dürfte die Zahl der Beiträge über die Jahre exponentiell gewachsen sein.
      Außerdem dürfte ein beträchtlicher Teil davon nicht von Menschen stammen. /newest ist voller Bot-Spam.
    • 7,5 KB/s, also 7.500 Zeichen pro Sekunde, klang unrealistisch, deshalb habe ich nachgerechnet[0]: Tatsächlich sind es eher etwa 34 Byte pro Sekunde, also 0,03 KB/s.
      Da darin auch JSON-Metadaten und -Syntax enthalten sind, dürfte die tatsächliche Textmenge noch geringer sein. Die Rechnung „über 2 MB pro Tag“ stimmte.
      [0] Eigentlich hat ChatGPT gerechnet, aber es sieht richtig aus: https://chatgpt.com/share/68124afc-c914-800b-8647-74e7dc4f21...
    • Das komplette Reddit-Archiv lag kurz vor der Abschaffung der API bei rund 4 TB komprimiert. Früher wurde es bei the-eye gehostet, und wenn man möchte, gibt es immer noch Orte, an denen man die Dateien per Torrent bekommen kann.
      Vieles davon ist Müll, aber besonders die frühen Daten vor 2018–2019, bevor die intelligenteren Bots auftauchten, dürften einen Blick wert sein.
    • 20 GB JSON ist erstaunlich. Ich habe eine SQLite-Datei mit allen HN-Daten, und die ist 20 GB groß; als JSON hätte ich erwartet, dass sie deutlich größer ist.
    • Die Gesamtgröße wirkt eher klein. Sie ist das Ergebnis von fast 20 Jahren mit Hunderttausenden aktiven Mitgliedern und insgesamt Millionen Beitragenden.
      Nach Maßstäben vor Facebook wäre HN wohl ein ziemlich großes soziales Netzwerk gewesen, und weil es überschaubar groß und aktiv moderiert ist, ist es auch vergleichsweise wertvoll.
      2019, als Google+ eingestellt wurde, habe ich einmal modelliert, wie viele Textdaten zu dieser Site beigetragen worden waren.
      Mit Textdaten meine ich dabei ohne Medien wie Bilder, Audio und Video sowie ohne zusätzliches Seitengerüst wie HTML, CSS und JS.
      Angesichts der sehr niedrigen Beteiligungsrate und einer durchschnittlichen Beitragslänge von etwa 120 Zeichen kamen selbst sieben Jahre mit zig Millionen aktiven Konten nur auf ein paar GiB. Es gab über 4 Milliarden registrierte Profile, aber die tatsächliche Aktivität war viel geringer.
      Das Archive Team arbeitete zwar mit dem Internet Archive zusammen, führte die Google+-Archivierung aber separat durch, mit gemischtem Ergebnis. Viel Inhalt wurde gesichert, aber noch viel mehr fehlte; Kommentare blieben kaum erhalten, Threads wurden auf die etwa zehn neuesten Einträge gekürzt, und ohne Suche war das Ganze weitgehend wenig nützlich. „Vanity Accounts“, die statt eines zufälligen Hashs einen gewählten Kontonamen verwendeten, waren noch schlechter zugänglich.
      Zudem versuchte man, vollständige Seiten zu scrapen, um die online sichtbare Form zu reproduzieren; dadurch stiegen die Speicheranforderungen stark, während vieles von dem, was die Site eigentlich interessant machte, übersehen wurde.
      Selbst wenn man die Textbeiträge großer Bevölkerungsgruppen speichern will, sind die Speicheranforderungen ziemlich moderat. Nimmt man zum Beispiel im Schnitt 45 Minuten Onlinezeit pro Tag, 45 wpm Tippgeschwindigkeit und nur die Hälfte der Onlinezeit fürs Schreiben statt Lesen, ergibt das pro Person etwa 1.000 Wörter pro Tag, also rund 6 KiB. Das sind 6 MiB pro 1.000 Personen, 6 GiB pro Million und etwa 6 PiB pro Milliarde Menschen.
      Die tatsächlichen Werte sind fast sicher niedriger. Die Schreibzeit ist überschätzt und liegt real eher bei 10 %, und die Eingabegeschwindigkeit auf Mobilgeräten dürfte eher bei 20–30 wpm liegen. Auf Facebook etwa werden pro Tag rund 2,45 Milliarden „Content Pieces“ hochgeladen, und die Hälfte davon ist Video. Geht man von 120 Zeichen pro Beitrag aus, liegt die Textdatenmenge bei deutlich unter 300 GiB pro Tag – überraschend wenig.
      Der Großteil der heutigen Datensammlung und der Systeme des Überwachungskapitalismus entfällt auf Daten, die Menschen nicht direkt eingeben, etwa Standort, Video, Online-Interaktionen und Handel.
  • Was ist die richtige Netiquette, wenn man HN herunterlädt? Sollte man zuerst dang fragen, bevor man die Server belastet?
    Oder kann man davon ausgehen, dass milliardenschwere Tech-Unternehmen das ohnehin schon mehrfach getan haben und es gar nicht auffallen würde?

    • Wie im Artikel erwähnt, hat HN eine API, sogar ohne Rate Limit. Alle Daten werden bei Firebase gehostet, einem YC-Unternehmen, also sollte das in Ordnung sein.
    • Es gibt buchstäblich eine öffentliche Datenbank.
      https://console.cloud.google.com/marketplace/product/y-combi...
    • Man darf auch nicht ausschließen, dass Drei-Buchstaben-Behörden HN-Aliasnamen mit echten Namen verknüpfen.
    • Der Name ist Hacker News, also ist zumindest Hacking im guten Sinne fair game.
    • Was im öffentlichen Web steht, wird bereits von Tausenden Bots gescrapt.
  • Ich habe etwas Ähnliches gemacht. Ich habe einen Trick mit dem BigQuery-Datensatz genutzt; aus irgendeinem Grund wurde er weiter aktualisiert. Ich habe die Daten als Parquet exportiert, heruntergeladen und dann mit DuckDB abgefragt.

    • Das ist kein Trick, sondern einfach eine pragmatische Entscheidung.
  • „Jetzt, da ich alle Inhalte von Hacker News lokal heruntergeladen habe, kann ich Hunderte LLM-basierte Bots trainieren, sie als Beitragende einsetzen und langsam, aber unausweichlich sämtlichen menschlichen Text durch die Ausgabe eines Chinese-Room-Vibrators ersetzen, der die Vergangenheit für immer widerhallen lässt und recycelt“ – das ist zwar ein Witz, aber ich fürchte, irgendwann wird es jemand versuchen.
    Ich hoffe, dass das nicht passiert, aber wenn doch: Könnte man es verhindern?

    • Ich glaube immer mehr an eine alte Idee, die mit der Zeit immer wichtiger wird: ein Vertrauensnetz zwischen Menschen aufzubauen, bei dem ein Account über einen Pfad verifiziert wird – jemand, den ich nicht kenne, wird von jemandem vertraut, der wiederum von jemandem vertraut wird, den ich kenne, und diese Person vertraue ich.
      Es gibt viele zu lösende Probleme, Privatsphäre ist eines davon. Die Verbindungen müssen den Nutzern nicht offengelegt werden, aber bei einer naiven Implementierung bleiben sie auf dem Server erhalten.
      Man könnte auch Pfade des Misstrauens mit negativem Gewicht hinzufügen. Wenn man jemandem direkt oder indirekt misstraut, sinkt der Wert der Vertrauenskette zwischen mir und dieser Person.
      Da es ein Netzwerk ist, könnte sich das System gegen Manipulationsversuche selbst anpassen, aber wie robust es wäre, bleibt offen.
    • Woher wissen wir, dass das nicht schon passiert?
      Lange, substanzielle Kommentare kann man meist unterscheiden, aber es ist viel schwieriger geworden als noch vor ein oder zwei Jahren. Bei kurzen Kommentaren aus ein oder zwei Sätzen sind LLMs inzwischen gut genug, um als menschlich durchzugehen, denke ich.
    • Unsere LLMs können nur Ergebnisse liefern, die aus mehreren Quellen bestätigt sind, und geben daher nur die durchschnittliche menschliche Antwort aus.
      Viele Kommentare auf HN sind dagegen ziemlich einzigartige Einsichten, die vom durchschnittlichen populären Denken abweichen. Wenn ein LLM versucht, das nachzuahmen, wird es nur Unsinn produzieren.
      Wenn man darauf einen Filter setzt, der nur vernünftige und sinnvoll klingende Antworten durchlässt, werden die Antworten langweilig und bleiben trotzdem nahe am Unsinn.
      Damit Antworten korrekt, präzise und einzigartig werden, muss man etwas anderes als ein LLM verwenden.
    • HN hat bereits ein ziemlich gutes Immunsystem gegen diese Art von Dingen. Low-effort- und repetitive Kommentare werden schnell downgevotet, gemeldet und rate-limited.
      Die Karma- und Geschwindigkeitsheuristiken der Site sind im Vergleich zu schickem Machine Learning grob, aber sie funktionieren, weil die Community kleiner ist als Reddit oder Twitter und die Betreiber direkt eingreifen.
      Damit eine Gruppe von LLM-Fake-Accounts menschliche Texte „ersetzen“ kann, müsste sie ständig Beiträge posten, die Menschen tatsächlich interessant finden. Andernfalls würde sie lange vorher eingeschränkt oder still entfernt.
      Selbst ein paar KI-Accounts am Leben zu halten, hat hohe Grenzkosten. Rund um die Uhr Inferenz auf Dutzende neuer Threads laufen zu lassen, ist nicht kostenlos, und es ist überraschend schwer, die Ausgabe davon abzuhalten, in gewöhnlichen SEO-Müll abzurutschen.
      Auch der Ertrag ist praktisch nicht vorhanden. HN-Traffic lässt sich nicht monetarisieren, und Karma ist für Bot-Betreiber eine miserable Währung.
      Könnte man einen hartnäckigen böswilligen Akteur mit Ressourcen aufhalten? Wahrscheinlich ja, aber die Gegenmaßnahmen wären dieselben wie heute: striktes Rate-Limiting, strengere Limits für neue Accounts, Prüfung durch menschliche Moderatoren und vielleicht etwas Stilanalyse.
      Für legitime neue Nutzer wäre das lästig, aber nicht fatal. Am Ende überlebt HN, weil die Menschen hier Texte anderer Menschen lesen wollen. Wenn Kommentare anfangen, wie stochastische Papageien zu klingen, werden Leser sie ignorieren oder melden, und die Bots werden miteinander reden.
      Verfasst von GPT-3o
    • Es gibt bereits Dinge, die diese Entwicklung vorweggenommen haben, etwa das Metal-Gear-Franchise[0] oder die Dead-Internet-Theorie[1].
      „In Metal Gear Solid 2 wurde Hideo Kojimas ambitioniertes Skript teils als eines der ersten Beispiele eines postmodernen Videospiels bewertet und auch dafür gelobt, Konzepte wie Post-Truth-Politik, Fake News, Echokammern und alternative Fakten vorweggenommen zu haben.“
      [0] https://en.wikipedia.org/wiki/Metal_Gear
      [1] https://en.wikipedia.org/wiki/Dead_Internet_theory
  • Ich glaube, in den nächsten Jahren werden viele APIs einfach anfangen, eine Option anzubieten, eine DuckDB-Datei zurückzugeben.
    Wenn man JSON ohnehin in eine Datenbank lädt, gibt es keinen Grund, nicht gleich eine Datenbank als Antwort zu bekommen.

    • zstd Parquet, aus einer DuckDB-1.2-Datei exportiert, komprimiert 2- bis 3-mal besser.
  • Ich wünschte, man würde keine gestapelten Diagramme verwenden. Ich halte es für fast unmöglich, den Eindruck der Leser damit nicht zu verzerren.
    Es ist sehr schwer, die Höhe eines bestimmten Datenpunkts im Rauschen abzuschätzen, und es suggeriert Abhängigkeiten, die wahrscheinlich nicht existieren.

    • Das war auch mein erster Gedanke. Der Autor von uPlot hat eine Demo, die die Fallstricke gut zeigt: https://leeoniya.github.io/uPlot/demos/stacked-series.html
    • Stimmt :( Aber wenn man dieselben Daten als Liniendiagramm zeichnet, überlappt so viel, dass man kaum noch etwas erkennen kann.
      Für das nächste Mal denke ich darüber nach, mehrere Liniendiagramme übereinander anzuordnen, jeweils mit nur einer Reihe pro Region.
    • Ein 3D-Ansatz ist der Punkt, an dem dieses Problem gelöst wird. Stapeln, aber mit etwas Versatz – es gibt kaum etwas Besseres, um Game-Engine-Technik für echte Business Intelligence einzusetzen und große Datenmengen auf einmal zu verstehen.
      Sieh dir die Arbeit von https://flowimmersive.com/ an.
    • Was haltet ihr von gestapelten Plots mit logarithmischer y-Achse? Manche physikalischen Experimente machen das ständig so[1], aber ich finde es ziemlich unintuitiv.
      [1]: https://atlas.web.cern.ch/Atlas/GROUPS/PHYSICS/PUBNOTES/ATL-...
  • Ich hatte früher mal etwas Ähnliches gebaut, https://github.com/ashish01/hn-data-dumps, und es war ziemlich interessant.
    Eine coole Funktion bei der Implementierung wäre, zu berücksichtigen, dass neuere Einträge mit der Zeit häufiger aktualisiert werden und daher kürzlich heruntergeladene Einträge schneller zu einem stale cache werden als ältere.

    • Es ist wirklich großartig, dass HN so eine API bereitstellt und sie nicht wie viele andere Websites dichtmacht.
      Ich habe eine altersbasierte Funktion verwendet, um zu bestimmen, wann etwas veraltet ist. Anfangs gilt es ab 1–2 Minuten nach der Erstellung als veraltet, wird dann einige Tage lang häufig aktualisiert und nach der ersten Woche schnell zurückgefahren, sodass es nach etwa zwei Wochen als unveränderlich behandelt wird.
      // DefaultStaleIf marks stale at 60 seconds after creation, then frequently for the first few days after an item is
      // created, then quickly tapers after the first week to never again mark stale items more than a few weeks old.
      const DefaultStaleIf = "(:now-refreshed)>" +
      "(60.0*(log2(max(0.0,((:now-Time)/60.0))+1.0)+pow(((:now-Time)/(24.0*60.0*60.0)),3)))"
      https://github.com/jasonthorsness/unlurker/blob/main/hn/core...