Dies ist eines der Forschungsprojekte, die ich derzeit durchlaufe. Die Anforderung entspricht fast genau Ihrer, und wir haben nette Algorithmen entwickelt, um das Problem zu lösen.
Die Eingabe
Die Eingabe ist ein endloser Strom englischer Wörter oder Phrasen (wir bezeichnen sie als tokens
).
Die Ausgabe
- Geben Sie die Top-N-Token aus, die wir bisher gesehen haben (von allen Token, die wir gesehen haben!).
- Geben Sie die Top-N-Token in einem historischen Fenster aus, z. B. am letzten Tag oder in der letzten Woche.
Eine Anwendung dieser Forschung besteht darin, das aktuelle Thema oder die aktuellen Trends des Themas in Twitter oder Facebook zu finden. Wir haben einen Crawler, der auf der Website crawlt und einen Strom von Wörtern generiert, der in das System eingespeist wird. Das System gibt dann die Wörter oder Phrasen der höchsten Frequenz entweder insgesamt oder historisch aus. Stellen Sie sich vor, in den letzten Wochen würde der Satz "Weltmeisterschaft" in Twitter viele Male vorkommen. So auch "Paul der Tintenfisch". :) :)
String in Ganzzahlen
Das System hat für jedes Wort eine Ganzzahl-ID. Es gibt zwar fast unendlich viele mögliche Wörter im Internet, aber nach dem Sammeln einer großen Anzahl von Wörtern wird die Möglichkeit, neue Wörter zu finden, immer geringer. Wir haben bereits 4 Millionen verschiedene Wörter gefunden und jedem eine eindeutige ID zugewiesen. Dieser gesamte Datensatz kann als Hash-Tabelle in den Speicher geladen werden und benötigt ungefähr 300 MB Speicher. (Wir haben unsere eigene Hash-Tabelle implementiert. Die Implementierung von Java erfordert einen enormen Speicheraufwand.)
Jede Phrase kann dann als Array von ganzen Zahlen identifiziert werden.
Dies ist wichtig, da das Sortieren und Vergleichen von Ganzzahlen viel schneller ist als bei Zeichenfolgen.
Daten archivieren
Das System speichert Archivdaten für jedes Token. Im Grunde sind es Paare von (Token, Frequency)
. Die Tabelle, in der die Daten gespeichert sind, ist jedoch so groß, dass wir die Tabelle physisch partitionieren müssen. Sobald das Partitionsschema auf ngrammen des Tokens basiert. Wenn das Token ein einzelnes Wort ist, ist es 1 Gramm. Wenn das Token aus zwei Wörtern besteht, ist es 2 Gramm. Und das geht weiter. Ungefähr bei 4 Gramm haben wir 1 Milliarde Datensätze mit einer Tischgröße von etwa 60 GB.
Eingehende Streams verarbeiten
Das System absorbiert eingehende Sätze, bis der Speicher voll ausgelastet ist (Ja, wir benötigen einen MemoryManager). Nachdem Sie N Sätze genommen und im Speicher gespeichert haben, hält das System inne und beginnt, jeden Satz in Wörter und Phrasen zu unterteilen. Jeder Token (Wort oder Satz) wird gezählt.
Bei sehr häufigen Token werden sie immer gespeichert. Bei weniger häufigen Token werden sie nach IDs sortiert (denken Sie daran, dass wir den String in ein Array von Ganzzahlen übersetzen) und in eine Festplattendatei serialisiert.
(Da Sie jedoch nur Wörter zählen, können Sie für Ihr Problem nur alle Wortfrequenzkarten im Speicher ablegen. Eine sorgfältig entworfene Datenstruktur würde nur 300 MB Speicher für 4 Millionen verschiedene Wörter belegen. Einige Hinweise: Verwenden Sie ASCII-Zeichen für Strings darstellen), und dies ist sehr akzeptabel.
In der Zwischenzeit wird ein weiterer Prozess aktiviert, sobald eine vom System generierte Festplattendatei gefunden und zusammengeführt wird. Da die Datenträgerdatei sortiert ist, würde das Zusammenführen einen ähnlichen Vorgang wie das Zusammenführen von Sortierungen erfordern. Auch hier muss auf einige Designs geachtet werden, da wir zu viele zufällige Festplattensuchen vermeiden möchten. Die Idee ist, das gleichzeitige Lesen (Zusammenführungsprozess) / Schreiben (Systemausgabe) zu vermeiden und den Zusammenführungsprozess beim Schreiben auf eine andere Festplatte von einer Festplatte lesen zu lassen. Dies ähnelt der Implementierung einer Sperre.
Ende des Tages
Am Ende des Tages werden auf dem System viele häufige Token mit einer im Speicher gespeicherten Häufigkeit und viele andere weniger häufige Token in mehreren Datenträgerdateien gespeichert (und jede Datei wird sortiert).
Das System leert die In-Memory-Map in eine Festplattendatei (sortiert sie). Jetzt wird das Problem darin bestehen, eine Reihe sortierter Datenträgerdateien zusammenzuführen. Mit einem ähnlichen Verfahren würden wir am Ende eine sortierte Datenträgerdatei erhalten.
Die letzte Aufgabe besteht dann darin, die sortierte Datenträgerdatei in der Archivdatenbank zusammenzuführen. Abhängig von der Größe der Archivdatenbank funktioniert der Algorithmus wie folgt, wenn er groß genug ist:
for each record in sorted disk file
update archive database by increasing frequency
if rowcount == 0 then put the record into a list
end for
for each record in the list of having rowcount == 0
insert into archive database
end for
Die Intuition ist, dass nach einiger Zeit die Anzahl der Einfügungen immer kleiner wird. Immer mehr Operationen werden nur beim Aktualisieren ausgeführt. Und diese Aktualisierung wird nicht durch den Index bestraft.
Hoffe, diese ganze Erklärung würde helfen. :) :)
what is the most frequent item in the subsequence [2; 2; 3; 3; 3; 4; 4; 4; 4; 5; 5] of your sequence?