Leistungssteigerung bei der Textverarbeitung

8

Ich habe ein Programm geschrieben, das alle Instanzen einer gewünschten Wortklasse in einem Text anzeigt. So mache ich es:

  • Erstellt ein Array von Wörtern aus dem gesamten Text

  • Iterate dieses Array. Suche für jedes Wort, was sein erster Buchstabe ist.

    • Springe zum entsprechenden Array in einem Objekt aller Wörter der ausgewählten Wortklasse (z. B. 'S') und iteriere es. Brechen Sie, wenn das Wort gefunden wird und schieben Sie es in ein Array von Übereinstimmungen.
  • Nachdem alle Wörter markiert sind, wiederhole das Array der Übereinstimmungen und markiere jedes einzelne im Text.

Ein Text, der aus 240000 Wörtern besteht, wird in 100 Sekunden in Bezug auf Substantive und ungefähr 4,5 Sekunden in Bezug auf Präpositionen auf meiner Maschine verarbeitet.

Ich suche nach einer Möglichkeit, die Leistung zu verbessern, und das sind die Ideen, die ich mir vorstellen konnte:

  • Ordne die Elemente in jedem Block meiner Wortliste neu an. Sortiere sie so, dass, wenn das Wort mit einer Stimme beginnt, alle Elemente, die einen Konsonanten als zweites Zeichen haben, zuerst kommen und umgekehrt. (in der Annahme, dass Wörter mit Doppelgesang oder Konsonanten selten sind)
  • Strukturieren Sie den Text in Kapitel und bearbeiten Sie nur das aktuell angezeigte Kapitel.

Sind das solide Ideen und gibt es noch weitere Ideen oder bewährte Techniken, um diese Art der Verarbeitung zu verbessern?

    
Sprottenwels 20.03.2015, 15:17
quelle

6 Antworten

9

Nutzen Sie die Kraft von Javascript.

Es manipuliert Wörterbücher mit String-Schlüsseln als grundlegende Operation. Erstellen Sie für jede Wortklasse ein Objekt, wobei jedes mögliche Wort ein Schlüssel und ein einfacher Wert wie true oder 1 ist. Dann wird jedes Wort einfach überprüft typeof(wordClass[word]) !== "undefined" . Ich erwarte, dass das viel schneller geht.

Reguläre Ausdrücke sind ein weiterer stark optimierter Bereich von Javascript. Sie können das Ganze wahrscheinlich als einen massiven regulären Ausdruck für jede Wortklasse verwenden. Wenn Ihre Hervorhebung in HTML ist, können Sie auch einfach eine Ersetzung im RE verwenden, um das Ergebnis zu erhalten. Diese Arbeit hängt wahrscheinlich davon ab, wie groß Ihre Wortsätze sind.

    
DrC 20.03.2015, 15:27
quelle
5

Die von mir vorgeschlagene Lösung ist die Implementierung einer trie Datenstruktur. Es erfordert mehr Aufwand zu implementieren, hat aber mehrere Vorteile gegenüber einer Hash-Tabelle (Wörterbuch).

Nachschlagen von Daten in einem Trie dauert höchstens 0 ( k ) Zeit, wobei k die Länge der Suchzeichenfolge ist. Mit einer Hash-Tabelle könnte das Speichern jedes Wortes als Schlüssel funktionieren, aber was speichern Sie als Wert für diesen Schlüssel in der Tabelle? Hashtabellen scheinen mir für dieses Problem nicht sehr effizient zu sein.

Darüber hinaus kann ein Trie alphabetisch Ihre Schlüsseleinträge nativ über Vorbestellungs-Traversal bereitstellen. Eine Hash-Tabelle kann nicht. Um seine Schlüssel zu sortieren, müssten Sie selbst eine Sortierfunktion implementieren, die nur mehr Zeit und Platz hinzufügt.

Wenn Sie weiter in Versuche lesen, werden Sie Suffixbäume und Radix-Bäume , die genau auf das Problem ansprechen, das Sie lösen möchten. In gewisser Weise erfindest du das Rad neu, aber ich behaupte nicht, dass das eine schlechte Sache ist. Das Lernen dieses Materials macht dich zu einem besseren Programmierer.

Wir können einen einfachen Trie als eine Menge verbundener Knoten implementieren, die drei Informationen speichern: 1) ein Symbol (Zeichen), 2) einen Zeiger auf das erste Kind dieses Knotens und 3) einen Zeiger auf den Elternknoten das nächste Kind des Knotens.

%Vor%

Sie können dann ein Netz von Wörtern aufbauen, die durch jeden Buchstaben im Wort miteinander verbunden sind. Wörter, die das gleiche Präfix haben, werden nativ über den Kind- und den nächsten Zeiger miteinander verknüpft, so dass die Suche ziemlich schnell ist. Ich ermutige Sie, weiter in Versuche zu schauen. Sie sind ordentlich Datenstrukturen und ich denke, dass es am besten zu Ihrem Problem passt.

    
Brett 18.08.2016 15:10
quelle
4

Ich denke, die Schritte, die eine hohe Rechenzeit kosten, wären:

  • Suche nach einem bestimmten Wort im Container der Weltklasse.
  • Hervorhebung der Treffer im Quelldokument.

Somit würde ich eine effizientere Datenstruktur vorschlagen, um Ihren Wortklassencontainer und die Übereinstimmungen Liste zu speichern. So läuft die Suche und Suche schneller.

Wenn ich Ihr Problem richtig verstanden habe, möchten Sie nur die Wörter hervorheben, die in der Weltklassenliste enthalten sind . Also würde ich Bloom Filter vorschlagen, der diesen Job sehr hervorragend macht.

Ссылка

Bloom Filter ist ein Set-Container, in dem Sie beliebige Elemente (Wörter) ablegen und prüfen können, ob bereits ein neues Wort in diesem Set enthalten ist. Die Geschwindigkeit ist rasend schnell und eignet sich gut für die Verarbeitung großer Datenmengen.

Die Anwendungsfälle wären:

  • Sie speichern die Wortklassen in einem Bloom-Filter, nennen wir es bfWordClass .
  • Iterate durch die Liste der extrahierten Wörter, überprüfe, ob jedes Wort ein Mitglied von bfWordClass ist (Diese Operation ist extrem schnell und 100% genau).
  • Wenn das Wort zu bfWordClass gehört, suchen Sie den Text und markieren ihn. Sie können eine andere Datenstruktur in Betracht ziehen, um die eindeutigen Wörter, die aus dem Dokument extrahiert wurden, und alle im Dokument gefundenen Indizes zur schnelleren Bezugnahme zu speichern.
Tao P. R. 20.03.2015 15:50
quelle
2
  • Verwenden Sie die ersten 3 Zeichen als Schlüssel, nicht das erste Zeichen.
  • Laden Sie Ihre Arbeit auf viele Hintergrund-Threads herunter
  • Verarbeite Text zuerst
Ginden 19.08.2016 09:40
quelle
2

2,40,000 Wörter sind in der Tat eine große Datenmenge, die auf der Client-Seite verarbeitet werden muss, dies wird Performance-Probleme in Javascript sowie DOM-Manipulation verursachen, wenn Sie den Text markieren. Sie sollten versuchen, einen kleineren Satz zu verarbeiten, wie Seiten, Absätze oder Abschnitte.

Wenn Sie Ihre aktiven Wörter reduzieren können oder nicht, hier sind einige Optimierungen, die Sie für Ihre Textverarbeitung ausprobieren können:

Speichern des Textes in DOM

Sie können hier zwei Ansätze ausprobieren:

  1. Einzelnes DOM-Element, das den gesamten Text enthält, d. h. 240.000 Wörter
  2. Mehrere DOM-Elemente, die jeweils N Wörter enthalten, sagen 240 Elemente mit je 1000 Wörtern.

Sie müssen Tools wie jsPerf verwenden, um zu sehen, wie schnell innerHTML-Änderungen in beiden Ansätzen sind, dh ein großes ersetzen innerHTML oder Text in einem einzelnen DOM-Element gegenüber dem Ersetzen mehrerer innerHTMLs übereinstimmender DOM-Elemente.

Übereinstimmende Wörter werden hervorgehoben, wenn sie vollständig eingegeben wurden

Sie möchten beispielsweise "Javascript" und "Text" in Ihrem Text markieren, nachdem sie vollständig eingegeben wurden. In diesem Fall, wie @DrC erwähnt, wäre die Vorverarbeitung Ihres Textes zum Speichern von Schlüssel vs Daten eine gute Sache. Generieren Sie einen Schlüssel für das Wort (Sie können den Schlüssel normalisieren, falls Sie die Groß- / Kleinschreibung nicht berücksichtigen oder Sonderzeichen usw. ignorieren möchten, dh 'nosql' ist der Schlüssel für 'NoSQL' oder 'NOSQL' oder 'No-SQL ". Ihr Nachschlageobjekt wird dann wie folgt aussehen:

%Vor%

Wenn ein Wort durchsucht wird, generieren Sie den Schlüssel zum Suchen von Indizes aller Übereinstimmungen und markieren den Text.

Übereinstimmende Wörter werden hervorgehoben, während sie eingegeben werden Für diesen Ansatz benötigen Sie eine trie basierte Struktur, die im JavaScript-Objekt erstellt wurde. Ein anderer Ansatz wäre das Erzeugen und Kompilieren von Regex basierend auf aktuelle typisierte Zeichenfolge, z. B. wenn der Benutzer 'jav' eingegeben hat, wäre die Regex \jav\gi und führt eine Regex-Übereinstimmung für den gesamten Text aus. Beide Ansätze würden einen Leistungsvergleich benötigen

    
DhruvPathak 19.08.2016 11:31
quelle
-3

Ich würde so etwas tun.

HTML

%Vor%

JavaScript

%Vor%     
Henrik Albrechtsson 18.08.2016 09:54
quelle