Gorp.NET ist eine neue Bibliothek zum Erstellen umkehrbarer Vorlagen zum Extrahieren von Daten aus strukturiertem Text auf der Grundlage der vorhandenen Salesforce Gorp- Codebasis.In dieser Veröffentlichung werde ich ein wenig darüber sprechen, wie die Bibliothek zum Analysieren von strukturiertem Text mit dem Namen
Gorp verwendet wird (eines der Beispiele für Tools, die manchmal als
rückentwickelte Vorlagensysteme bezeichnet werden).
Was ist eine
umkehrbare Vorlage im Allgemeinen? Angenommen, wir haben ein bestimmtes System, mit dem wir den benötigten Text auf der Grundlage der von uns ermittelten Anfangsdaten nach strengen Regeln generieren können, die in der Syntax der Vorlagen festgelegt sind. Stellen wir uns nun eine Aufgabe mit umgekehrter Bedeutung vor: Wir haben einen Text mit einer strukturellen Integrität, die durch die Verwendung eines Systems erzielt werden könnte, das auf den Vorlagen aus dem vorherigen Beispiel basiert. Unser Ziel ist es, aus diesem Text die Quelldaten zu extrahieren, auf deren Grundlage sie erstellt wurden. Wenn wir versuchen, eine bestimmte verallgemeinerte Syntax zur Lösung dieses Problems zu finden, die dem entsprechenden Parser bereitgestellt wird, der den Eingabetext in separate Elemente zerlegt, ist dies ein Beispiel für die Syntax zur Implementierung des Konzepts umkehrbarer Vorlagen.
Warum habe ich mich entschieden, speziell über
Gorp zu schreiben? Tatsache ist, dass ich mich entschlossen habe, dieses System als Grundlage für die Fertigstellung meines eigenen Projekts zu verwenden - die Geschichte des Projekts selbst, einschließlich einiger Details zu allen Änderungen, die ich am ursprünglichen
Gorp- Projekt vorgenommen habe, finden Sie
im vorherigen Artikel . Hier konzentrieren wir uns genau auf den technischen Teil, einschließlich der Verwendung einer modifizierten Version des Motors. Der
Einfachheit halber werde ich es weiterhin
Gorp.NET nennen , obwohl es in Wirklichkeit keine Version von
Gorp ist, die nicht auf .NET portiert ist, sondern nur eine leicht polierte und finalisierte Version davon, alle in demselben Java. Eine andere Sache ist, dass das Add-On für die
Gorp- Bibliothek
selbst (in meiner Version) in Form einer verwalteten DLL namens
BIRMA.NET eine eigene spezielle Assembly verwendet -
genau das
Gorp.NET , das Sie leicht selbst erhalten können, wenn Sie den Quelltext ausführen ( Die Adresse seines Repositorys lautet
https://github.com/S-presso/gorp/ ) über das Dienstprogramm
IKVM.NET .
Ich werde jetzt bemerken, dass für alle Arten von Aufgaben zum Extrahieren von Daten aus strukturiertem Text die
Gorp.NET- Tools selbst für
Sie ausreichen werden - zumindest, wenn Sie ein wenig Java beherrschen oder zumindest wissen, wie Sie Methoden aus externen Java-Modulen in Ihren Projekten aufrufen .NET Framework sowie verschiedene Typen aus den dortigen Standard-JVM-Bibliotheken (dies habe ich über das gleiche
IKVM.NET erreicht , das jedoch bereits den Status eines nicht unterstützten Projekts hat). Nun, und was werden Sie als nächstes mit den extrahierten Daten tun - dies ist, wie sie sagen, Ihre persönliche Angelegenheit.
Gorp und
Gorp.NET alleine bieten nur ein nacktes Framework. Einige Grundlagen für die Weiterverarbeitung all dieser Daten enthält das bereits erwähnte
BIRMA.NET . Die Beschreibung der
BIRMA.NET- Funktionalität an
sich ist jedoch bereits ein Thema für eine separate Veröffentlichung (obwohl ich in meinem vorherigen
vergleichenden historischen Überblick über BIRMA-Technologien bereits etwas erwähnt habe). Mit Blick auf die Zukunft werde ich mir eine etwas kühne Aussage erlauben, dass die Technologie zur Beschreibung der in
Gorp.NET (und dementsprechend in
BIRMA.NET ) verwendeten umkehrbaren Vorlagen etwas Einzigartiges unter anderen Handwerken dieser Art ist (ich sage “ Kunsthandwerk “, wie ich es noch nicht gesehen habe, wenn große Unternehmen ihre eigenen Frameworks für diese Zwecke bewarben - nun ja, vielleicht nur
Salesforce selbst mit seiner ursprünglichen Implementierung von
Gorp ).
Für die vollständige Offenlegung des Konzepts und der technischen Aspekte, die dem in Gorp verwendeten Vorlagenbeschreibungssystem zugrunde liegen, lasse ich hier nur einen Link zur
Originaldokumentation in englischer Sprache . Alles, was darin angegeben ist, können Sie sicher in Bezug auf
Gorp.NET anwenden . Und jetzt erzähle ich Ihnen etwas über die Essenz.
Die Beschreibung der Vorlage ist also eine Art Textdokument (möglicherweise sogar als einzelne große Zeile dargestellt, die zur Verarbeitung an die entsprechende Methode übergeben werden kann). Es besteht aus drei Teilen, die sequentielle Beschreibungen der drei wichtigsten Elemente enthalten:
Muster ,
Muster und
Beispiele (Auszüge).
Der Block der untersten Ebene sind hier
Muster - sie können nur aus regulären Ausdrücken und Verweisen auf andere Muster bestehen. Auf der nächsten Hierarchieebene befinden sich
Vorlagen , deren Beschreibung auch Verknüpfungen zu benennbaren Mustern sowie Einschlüsse in Form von Textliteralen, Verknüpfungen zu verschachtelten Vorlagen und Extraktoren enthält. Es gibt auch
parametrische Muster , auf die ich im Moment nicht eingehen werde (in der Quelldokumentation gibt es nur wenige Beispiele für deren Verwendung). Nun, und schließlich gibt es
Beispiele , die bestimmte Syntaxregeln angeben, die
benannte Muster bestimmten Vorkommen im Quelltext zuordnen.
Nach meinem Verständnis bestand das ursprüngliche Ziel, das sich die Entwickler von
Gorp gesetzt hatten, darin,
die in den Berichtsdateien (oder Protokolldateien) enthaltenen
Datensequenzen zu
analysieren . Betrachten Sie ein einfaches Beispiel für eine bestimmte Anwendung des Systems.
Angenommen, wir haben einen Bericht mit der folgenden Zeile:
<86> 2015-05-12T20: 57: 53.302858 + 00: 00 10.1.11.141 RealSource: "10.10.5.3"
Lassen Sie uns eine Beispielvorlage für das Parsen mit den
Gorp- Werkzeugen
erstellen :
pattern %phrase \\S+
pattern %num \\d+\n
pattern %ts %phrase
pattern %ip %phrase
extract interm {
template <%num>$eventTimeStamp(%ts) $logAgent(%ip) RealSource: "$logSrcIp(%ip)"
}
Beachten Sie, dass der Vorlagenzuweisungsblock hier sogar weggelassen wird, da alle erforderlichen Vorlagen bereits in der endgültigen Auswahl enthalten sind. Alle hier verwendeten Vorlagen sind benannt, ihr Inhalt wird nach ihrem Namen in Klammern angegeben. Als Ergebnis wird ein Textdatensatz mit den Namen
eventTimeStamp ,
logAgent und
logSrcIp erstellt .
Wir werden nun ein einfaches Programm zum Extrahieren der notwendigen Daten schreiben. Angenommen, die von uns erstellte Vorlage ist bereits in einer Datei mit dem Namen
extractions.xtr enthalten .
import com.salesforce.gorp.DefinitionReader; import com.salesforce.gorp.ExtractionResult; import com.salesforce.gorp.Gorp;
Ein weiteres Beispiel für eine einfache Parsing-Vorlage:
# Patterns
pattern %num \d+
pattern %hostname [a-zA-Z0-9_\-\.]+
pattern %status \w+
# Templates
@endpoint $srcHost(%hostname): $srcPort(%num)
# Extraction
extract HostDefinition {
template @endpoint $status(%status)
}
Nun, ich denke der Punkt ist klar. Es ist auch nicht falsch zu erwähnen, dass es für die
Extraktionsmethode auch eine Definition mit zwei Eingabeparametern gibt, von denen der zweite einen logischen Typ hat. Wenn Sie den Wert auf
true setzen , durchläuft die Methode bei der Ausführung alle potenziellen Datensätze, bis sie auf einen geeigneten
Wert stößt (Sie können den Methodenaufruf auch durch
extractSafe ersetzen - bereits ohne den zweiten Parameter). Der Standardwert ist
false , und die Methode kann bei der Diskrepanz zwischen den Eingabedaten und der verwendeten Vorlage "schwören".
Gleichzeitig
stelle ich fest, dass
Gorp.NET auch eine neue erweiterte Implementierung der Methode
extract eingeführt hat : Jetzt gibt es eine Version mit zwei nachfolgenden Parametern eines logischen Typs. Mit einem abgekürzten Aufruf der
Sicht extractAllFound setzen wir beide standardmäßig auf true. Der positive Wert des dritten Parameters gibt uns noch mehr Spielraum für Variationen: Ab sofort können wir den Text mit beliebigen Zeicheneinschlüssen in den Intervallen zwischen den gewünschten, bereits strukturierten Stichproben (mit Sätzen extrahierter Daten) analysieren.
Es ist also an der Zeit, die Frage zu beantworten: Was genau kann an dieser Modifikation der Basisversion von
Gorp einzigartig sein, abgesehen von der Erweiterung der Extraktionsmethode?
Tatsache ist, dass ich bereits vor einigen Jahren eine Art eigenes Tool zum Extrahieren der erforderlichen Daten aus Text erstellt habe (das auch auf der Verarbeitung bestimmter Vorlagen mit einer eigenen spezifischen Syntax beruhte), das nach etwas anderen Grundsätzen arbeitete. Der Hauptunterschied zu dem in
Gorp implementierten Ansatz und allen abgeleiteten Frameworks besteht darin, dass jedes zu extrahierende Textelement einfach durch Auflisten seiner linken und rechten Ränder festgelegt wurde (von denen jedes entweder Teil des Elements selbst sein oder es einfach trennen kann alle nachfolgenden oder vorherigen Texte). Gleichzeitig wurde im allgemeinen Fall die Struktur des Ausgangstextes selbst nicht wie bei
Gorp analysiert, sondern nur die notwendigen Teile herausgegriffen. Der Inhalt des Textes, der zwischen ihnen eingeschlossen ist, hätte keiner strukturellen Analyse unterliegen können (es könnte sich durchaus um inkohärente Zeichensätze handeln).
Kann man in
Gorp einen ähnlichen Effekt erzielen? In der ursprünglichen Version - vielleicht nicht (korrigieren Sie mich, wenn ich mich irre). Wenn wir einfach einen Ausdruck wie
(. *) Schreiben, unmittelbar gefolgt von der Maske, um den linken Rand des nächsten zu durchsuchenden Elements anzugeben, wird mithilfe des Quantifizierers "Habgier" der gesamte nachfolgende Text erfasst. Und wir können in vorhandenen
Gorp- Implementierungen keine regulären Regeln mit "nicht gieriger" Syntax verwenden.
Mit Gorp.NET können
Sie dieses Problem problemlos umgehen, indem Sie zwei spezielle
Mustertypen einführen:
(% all_before) und
(% all_after) . Die erste ist eine Alternative zur "nicht gierigen" Version
(. *) , Die zum Kompilieren eigener Vorlagen geeignet ist. Wie bei
(% all_after) wird auch der Quelltext bis zum ersten Auftreten des nächsten Teils des beschriebenen Musters betrachtet, wobei jedoch bereits das Suchergebnis des vorherigen Musters herangezogen wird. Alles, was sich zwischen ihnen befindet, fällt auch in die extrahierbare Teilzeichenfolge des aktuellen Elements. In gewisser
Weise "schaut"
(% all_after) zurück und "schaut"
(% all_before) im Gegenteil nach vorne. Ich
stelle fest, dass ein eindeutiges Analogon für
(% all_before) in der ersten Version von
BIRMA der fehlende linke Rand in der Beschreibung des Elements war und analog zu
(% all_after) eine Leerstelle anstelle des rechten Randes war. Wenn beim Beschreiben des nächsten Elements nicht beide Grenzen gesetzt sind, erfasst der Parser offensichtlich den gesamten nachfolgenden Text! All diese damalige Implementierung von
BIRMA hat jetzt jedoch eine rein historische Bedeutung (mehr dazu
in meinem damaligen Bericht ).
Versteckter TextDie Quellcodes wurden wegen ihrer extrem geringen Qualität noch nie irgendwo ausgelegt - in Wahrheit könnten sie als Denkmal für das schlechte Design von Softwaresystemen dienen.
Betrachten wir die Funktionen der Verwendung von
Dienstmustern (% all_before) und
(% all_after) am Beispiel der Aufgabe, bestimmte Benutzerdaten von einer bestimmten Website zu extrahieren. Wir analysieren die Amazon-Website und speziell diese Seite:
https://www.amazon.com/B06-Plus-Bluetooth-Receiver-Streaming/product-reviews/B078J3GTRK/ ).
Versteckter TextEin Beispiel stammt aus einer Testaufgabe für ein Stellenangebot eines Entwicklers mit einer Spezialisierung auf Datenanalyse, die von meinem Unternehmen gesendet wurde und die leider nicht auf meine vorgeschlagene Lösung des Problems reagiert hat. Richtig, sie haben mich nur gebeten, den allgemeinen Prozess der Lösung zu beschreiben - ohne einen bestimmten Algorithmus anzugeben. Als Reaktion darauf habe ich bereits versucht, auf Gorp-Vorlagen zu verweisen, während meine eigenen Erweiterungen zu dieser Zeit nur "auf Papier" existierten. ".
Aus Gründen der Neugier werde ich mir erlauben, ein Fragment aus meinem Antwortschreiben zu zitieren, bei dem es sich anscheinend um die erste Erwähnung von
Gorp.NET handelt , wenn auch privater Natur.
„Um die obige Liste der regulären Ausdrücke, die ich zur Lösung dieses Problems verwende, anschaulicher zu gestalten, habe ich eine vorgefertigte Vorlage zusammengestellt (die dem Brief beigefügt ist), mit der ich alle erforderlichen Daten extrahieren kann, indem ich meine eigene Entwicklung universellerer Natur anwende entwickelt, um diese Art von Problem zu lösen. Der Code basiert auf dem Projekt
github.com/salesforce/gorp. Auf derselben Seite finden Sie eine allgemeine Beschreibung der Regeln zum Kompilieren solcher Vorlagen. Im Allgemeinen impliziert eine solche Beschreibung an sich die Zuweisung sowohl konkreter regulärer Ausdrücke als auch der Logik ihrer Verarbeitung. Der schwierigste Punkt hierbei ist, dass wir für jedes Datenmuster die gesamte Struktur des Textes, der sie enthält, und nicht nur die einzelnen Elemente selbst vollständig durch Regulars beschreiben müssen (wie dies beim Schreiben unseres eigenen Programms möglich ist, das nacheinander in einer Schleife wie I sucht) zuvor beschrieben). ”
Die ursprüngliche Aufgabe bestand darin, die folgenden Daten von der obigen Seite zu sammeln:
- Benutzername
- Bewertung
- Titel überprüfen
- Das Datum
- Text
Nun, jetzt gebe ich Ihnen nur eine von mir kompilierte Vorlage, mit der Sie diese Aufgabe schnell und effizient erledigen können. Ich denke, die allgemeine Bedeutung sollte ziemlich offensichtlich sein - vielleicht können Sie selbst eine präzisere Lösung anbieten.
Versteckter TextAn diesem Beispiel habe ich im Allgemeinen die Funktionalität meiner eigenen Erweiterungen für Gorp getestet (bereits ohne Beschäftigungsziel, sondern basierend auf der Ideologie des „Proof of Concept“).
pattern %optspace ( *)
pattern %space ( +)
pattern %cap_letter [AZ]
pattern %small_letter [az]
pattern %letter (%cap_letter|%small_letter)
pattern %endofsentence (\.|\?|\!)+
pattern %delim (\.|\?|\!\,|\:|\;)
pattern %delim2 (\(|\)|\'|\")
pattern %word (%letter|\d)+
pattern %ext_word (%delim2)*%word(%delim)*(%delim2)*
pattern %text_phrase %optspace%ext_word(%space%ext_word)+
pattern %skipped_tags <([^>]+)>
pattern %sentence (%text_phrase|%skipped_tags)+(%endofsentence)?
pattern %start <div class=\"a-fixed-right-grid view-point\">
pattern %username_start <div class=\"a-profile-content\"><span class=\"a-profile-name\">
pattern %username [^\s]+
pattern %username_end </span>
pattern %user_mark_start <i data-hook=\"review-star-rating\"([^>]+)><span class=\"a-icon-alt\">
pattern %user_mark [^\s]+
pattern %user_mark_end ([^<]+)</span>
pattern %title_start data-hook=\"review-title\"([^>]+)>(%skipped_tags)*
pattern %title [^<]+
pattern %title_end </span>
pattern %span class <span class=\"[^\"]*\">
pattern %date_start <span data-hook="review-date"([^>]+)>
pattern %date ([^<]+)
pattern %date_end </span>
pattern %content_start <span data-hook=\"review-body\"([^>]+)>(%skipped_tags)*
pattern %content0 (%sentence)+
pattern %content (%all_after)
pattern %content_end </span>
template @extractUsernameStart (%all_before)%username_start
template @extractUsername $username(%username)%username_end
template @extractUserMarkStart (%all_before)%user_mark_start
template @extractUserMark $user_mark(%user_mark)%user_mark_end
template @extractTitleStart (%all_before)%title_start
template @extractTitle $title(%title)%title_end
template @extractDateStart (%all_before)%date_start
template @extractDate $date(%date)%date_end
template @extractContentStart (%all_before)%content_start
template @extractContent $content(%content)%content_end
extract ToCEntry {
template @extractUsernameStart@extractUsername@extractUserMarkStart@extractUserMark@extractTitleStart@extractTitle@extractDateStart@extractDate@extractContentStart@extractContent
}
Das ist wahrscheinlich alles für heute. Zu den von mir implementierten Tools von Drittanbietern, an denen dieses Framework bereits vollständig beteiligt war, darf ich Ihnen ein anderes Mal mitteilen.