Analyse von Enron mit Solr, Spark und Fusion
Auf der Lucene/Solr Revolution in diesem Jahr habe ich einen Kurs über die Verwendung von Big Data-Technologien mit Apache Solr…
Auf der Lucene/Solr Revolution in diesem Jahr habe ich einen Kurs über die Verwendung von Big Data-Technologien mit Apache Solr und damit auch Lucidworks Fusion gehalten. Im Rahmen des Kurses haben wir den von der Carnegie Mellon University zur Verfügung gestellten Enron-Korpus eingelesen. Das Korpus besteht aus einer Vielzahl von E-Mails, von denen einige aus den Anfängen des letzten Jahrzehnts stammen und die Teil der juristischen Ermittlungsphase im Zusammenhang mit dem Flop des Energieunternehmens im Jahr 2001 waren. Mit 423 MB komprimiert handelt es sich um eine ziemlich umfangreiche Menge an unstrukturierten Daten.
Im Laufe dieses Artikels werden wir den Enron-Korpus indizieren, mit Solr durchsuchen und anschließend eine Stimmungsanalyse mit den Ergebnissen durchführen. Folgen Sie uns, nehmen Sie sich eine Kopie des Enron-Korpus und entpacken Sie sie in ein Verzeichnis auf Ihrer Festplatte. Sie können den referenzierten Code aus meinem Repository hier herunterladen.
Warum Spark und Solr?
Warum sollten Sie Solr verwenden, wenn Sie bereits Spark nutzen? Bedenken Sie dies: Wenn Sie eine große Menge an gespeicherten Daten haben, die Sie analysieren wollen, wollen Sie dann wirklich ALLE diese Daten in den Speicher laden, nur um die Teilmenge zu finden, die Sie bearbeiten wollen? Wäre es nicht sinnvoller, nur die Daten aus dem Speicher zu laden, die Sie benötigen? Dazu brauchen Sie einen intelligenteren Speicher! Sie können den Speicher indizieren, während Sie die Daten speichern oder in Stapeln irgendwann danach. Andernfalls führt jeder, der dieselbe Analyse durchführt, wahrscheinlich denselben nutzlosen „Finde es“-Prozess durch, bevor er tatsächlich mit der Analyse beginnt.
Warum sollten Sie Spark verwenden, wenn Sie bereits Solr nutzen? Solr ist erstaunlich in dem, was es tut: Es findet Nadeln oder kleine Heuhaufen in einer großen Scheune voller Heu. Es kann die Daten finden, die Sie benötigen, um die von Ihnen gestellte Anfrage zu erfüllen. Solr ist jedoch nicht in der Lage, maschinelles Lernen zu betreiben oder Analysen durchzuführen, die Sie sich wünschen. Wenn die Antwort auf Ihre Abfrage aus einer riesigen Datenmenge abgeleitet werden muss, benötigen Sie eine wirklich schnelle verteilte Verarbeitungsmaschine – wie Spark – für die algorithmische Manipulation.
Lucidworks Fusion verdankt seinen Namen der „Verschmelzung“ von Spark und Solr zu einer einzigen Lösung. Bei der Bereitstellung von Solr-Lösungen für Kunden entdeckte Lucidworks, dass Spark eine großartige Möglichkeit ist, die Fähigkeiten von Solr zu erweitern – vom maschinellen Lernen bis hin zur Verteilung der Verarbeitung von Index-Pipelines.
Die Einnahme von
2013 zeigte Erik Hatcher, wie Sie E-Mails und andere Entitäten mit Hilfe von Solr und einer gehörigen Portion Affencode einlesen können. Da es bei Lucene/Solr Revolution nicht um Ingestion, sondern um die Verwendung von Spark mit Solr ging, habe ich einfach Fusion verwendet, um die Daten in Solr aufzunehmen. Der Prozess des Ingesting der Enron-E-Mails ist einfach und die Fusion-Benutzeroberfläche macht es kinderleicht.
- Laden Sie Lucidworks Fusion herunter, installieren Sie es und führen Sie es aus.
- Rufen Sie http://localhost:8764 auf und schließen Sie den Einrichtungsprozess für Fusion ab. Überspringen Sie das Quickstart-Tutorial.
Hinweis: Die Screenshots stammen aus der kommenden Version 3.x von Fusion. Sie wurden mit der Version 2.4.x getestet, aber das Erscheinungsbild wird sich leicht unterscheiden.
- Navigieren Sie zum Bildschirm für die Fusion-Sammlung (unter 2.4 ist dies der erste Bildschirm, der angezeigt wird, unter 3.x klicken Sie auf devops)
- Klicken Sie auf Neue Sammlung, geben Sie enron ein und klicken Sie auf Speichern.
- Klicken Sie auf die neu erstellte Sammlung „enron“ und dann auf „Datenquellen“.
- Erstellen Sie eine neue Datenquelle für ein lokales Dateisystem
- Rufen Sie die Datenquelle enron-data auf und scrollen Sie nach unten
- Erweitern Sie „StartLinks“ und geben Sie den vollständigen Pfad zu dem Verzeichnis ein, in das Sie den Enron-Korpus entpackt haben (Stammverzeichnis). Dann scrollen oder erweitern Sie „Dokumente einschränken“.
- Bei der maximalen Dateigröße habe ich einfach eine 0 hinzugefügt. Einige der Dateien im enron-Korpus sind sehr groß. Scrollen Sie weiter nach unten.
- Speichern Sie die Datenquelle
- Klicken Sie auf Crawl starten
- Klicken Sie auf Auftragsverlauf und wählen Sie Ihren Auftrag aus.
- Achten Sie darauf, dass der Topf kocht. Das kann ein bisschen dauern, wenn Sie das am Laptop machen.
Es wird einige E-Mails geben, die aufgrund schlechter Form, mangelnden Inhalts oder aus anderen Gründen übersprungen werden. In einem echten Projekt würden wir die Pipeline ein wenig anpassen. Wie dem auch sei, beachten Sie, dass wir so weit gekommen sind, ohne eine Zeile Code oder die Befehlszeile zu berühren oder wirklich etwas Schweres zu tun!
Spark / Spark-Solr
Wenn Sie Solr verwenden, hat mein Kollege Tim Ihnen bereits im August letzten Jahres gezeigt, wie Sie das spark-solr Repository erhalten und erstellen können.
Wenn Sie Fusion verwenden, werden die Spark-Solr-Konnektivität und Spark selbst bereitgestellt. Sie finden sie in $FUSION_HOME/apps/libs/spark-solr-2.2.2.jar und die spark-shell in $FUSION_HOME/bin. Um die Spark-Konsole zu starten, geben Sie ein: bin/spark-shell
Scala kurz gefasst
Scala ist die Sprache, in der Spark geschrieben ist. Es handelt sich um eine typsichere funktionale Sprache, die auf der Java Virtual Machine läuft. Die Syntax ist Leuten, die mit Java oder einer C-ähnlichen Sprache vertraut sind, nicht allzu fremd. Es gibt jedoch einige deutliche Unterschiede.
object HelloWorld { def main(args: Array[String]) { println("Hello, world!") } }
Spark unterstützt auch Python und andere Sprachen (Sie können sogar in funktionalem Java schreiben). Da Spark nativ Scala ist, hat Scala immer die beste Unterstützung und es gibt Leistungseinbußen bei den meisten anderen Sprachen. Es gibt gute Gründe, Sprachen wie Python und R für Statistiken und Analysen zu verwenden, z.B. verschiedene Bibliotheken und die Vertrautheit der Entwickler, aber ein Spark-Entwickler sollte zumindest mit Scala vertraut sein.
In diesem Artikel werden wir Beispiele in Scala geben.
Spark mit Solr verbinden
Starten Sie wieder die Spark-Shell, die mit Fusion geliefert wird, indem Sie bin/spark-shell eingeben. Nun müssen wir die Sammlung, die Abfrage und die Felder angeben, die wir zurückgeben möchten. Dies tun wir in einer „options“-Variablen. Als nächstes lesen wir einen Datenrahmen aus Solr und laden die Daten. Siehe das Beispiel unten:
val options = Map( "collection" -> "enron", "query" -> "content_txt:*FERC*", "fields" -> "subject,Message_From,Message_To,content_txt" ) val dfr = sqlContext.read.format("solr"); val df = dfr.options(options).load;
Wenn Sie nicht Fusion verwenden, müssen Sie den zkHost angeben und möglicherweise auch die spark-data-Bibliothek und ihre Abhängigkeiten mit dem Argument –jars zur spark-shell hinzufügen. In Fusion haben wir dies bereits für Sie erledigt.
Die Stimmungsanalyse des armen Mannes
In dem oben erwähnten Repository finden Sie ein einfaches Skript namens sentiment.scala. Wir demonstrieren eine Verbindung zu Solr und ein einfaches Skript zur Berechnung des Sentiments. Sentiment-Analysen von E-Mails können für eine Vielzahl von Zwecken durchgeführt werden: Vielleicht wollen Sie die allgemeine Stimmung unter den Mitarbeitern herausfinden oder die Reaktionen der Kunden auf bestimmte Mitarbeiter, Themen oder Richtlinien verfolgen oder einfach nur, weil es Spaß macht!
Wir müssen etwas mit unserem DataFrame machen. Ich hatte schon immer ein Faible für Sentiment-Analysen, denn was gibt es Schöneres, als die Gefühle der Menschen (oder zumindest die, die sie in ihrer textlichen Kommunikation zu vermitteln versuchen) mathematisch zu berechnen? Dafür gibt es verschiedene Algorithmen. Der einfachste besteht darin, alle Wörter zu nehmen, Stoppwörter zu entfernen (a, der, es, er, sie usw.) und den verbleibenden Wörtern einen negativen, positiven oder neutralen Wert zuzuweisen (z.B. -5 bis +5), die Werte zu addieren und den Durchschnitt zu berechnen. Dabei gibt es Probleme, wie z.B. dass „Das ist keine schlechte Art zu arbeiten“ ziemlich negativ ausfällt, obwohl es sich eigentlich um eine positive bis neutrale Stimmung handelt.
Um dies wirklich zu tun, benötigen Sie ausgefeiltere Techniken des maschinellen Lernens und der natürlichen Sprachverarbeitung. Wir werden es einfach auf die dumme Art machen. Woher wissen wir also, was positiv oder negativ ist? Jemand hat das bereits für uns in der AFINN-Datenbank katalogisiert. Es handelt sich um eine Textdatei mit 2477 Wörtern, die mit einer Zahl zwischen -5 und +5 bewertet sind. Es gibt alternative Wortlisten, aber wir werden diese verwenden.
Auf dieser Grundlage gehen wir in einer Schleife alle Wörter durch, addieren sie und teilen dann die Wörter durch die Anzahl der Wörter. Das ist unser Durchschnitt.
Den Code verstehen
abandon -2 abandoned -2 abandons -2 abducted -2 abduction -2 ...
AFINN-111.txt erste 5 Zeilen
Der erste Schritt besteht darin, unsere afinn-Datendatei als eine Zuordnung von Wörtern zu Werten zu erhalten.
Wir definieren unseren knochentrockenen, vereinfachten Algorithmus wie folgt:
val defaultFile = "/AFINN/AFINN-111.txt" val in = getClass.getResourceAsStream(defaultFile) val alphaRegex = "[^a-zA-Zs]".r val redundantWhitespaceRegex = "[s]{2,}".r val whitespaceRegex = "s".r val words = collection.mutable.Map[String, Int]().withDefaultValue(0) for (line <- Source.fromInputStream(in).getLines()) { val parsed = line.split("t") words += (parsed(0) -> parsed(1).toInt) }
Sentiment.scala Auszug
Als nächstes stellen wir eine Verbindung zu Solr her, fragen alle Nachrichten in unserer Sammlung „enron“ ab, die sich auf die Federal Energy Regulatory Commission (FERC) beziehen, und extrahieren die relevanten Felder:
val options = Map( "collection" -> "enron", "zkhost" -> "localhost:9983", "query" -> "content_txt:*FERC*", "fields" -> "subject,Message_From,Message_To,content_txt" ) val dfr = sqlContext.read.format("solr"); val df = dfr.options(options).load;
Sentiment.scala Auszug
Die Idee ist, eine Sammlung von Absenderadressen mit dem Affinitätswert zu erhalten. Dazu müssen wir einige weitere Sammlungen erstellen und dann die Punktzahl normalisieren, indem wir die Anzahl der E-Mails teilen, in denen unser Thema „FERC“ erwähnt wird.
val peopleEmails = collection.mutable.Map[String, Int]().withDefaultValue(0) val peopleAfins = collection.mutable.Map[String, Float]().withDefaultValue(0) def peoplesEmails(email: String, sentiment: Float) = { var peopleEmail: Int = peopleEmails(email); var peopleAfin: Float = peopleAfins(email); peopleEmail += 1; peopleAfin += sentiment; peopleEmails.put(email, peopleEmail); peopleAfins.put(email, peopleAfin); } def normalize(email: String): Float = { var score: Float = peopleAfins(email); var mails: Int = peopleEmails(email); var retVal : Float = score / mails return retVal }
sentiment.scala Auszug
Schließlich führen wir unsere Algorithmen aus und drucken das Ergebnis:
df.collect().foreach( t => peoplesEmails(t.getString(1), sentiment(tokenize(t.getString(3))) ) ) for ((k,v) <- peopleEmails) println( ""+ k + ":" + normalize(k))
Sentiment.scala Auszug
Das Ergebnis sieht aus wie mehrere Zeilen von
ken@enron.com -0.0075
Da die E-Mails der Unternehmen damals eher wie Memos aussahen als die direktere Kommunikation von heute, sind die meisten Stimmungen ziemlich neutral. „Die FERC macht das“ und nicht „Diese Idioten von der FERC sind dabei, alle unsere E-Mails vorzuladen, und ich hoffe sehr, dass sie nicht an die Öffentlichkeit gelangen!!!“
Nächste Schritte
Eine Liste von Adressen und Nummern ist natürlich nur der Anfang. Ich meine, Sie können die Daten auch visualisieren.
So unterhaltsam das auch war und eine gute Möglichkeit, die Verbindung zu Solr/Fusion mit Spark zu demonstrieren, so ist es doch nicht der beste Weg für die Sentimentanalyse. Warum analysieren Sie nicht einfach die Stimmung, während Sie indexieren, und speichern die Bewertung im Index selbst? Sie könnten immer noch Spark verwenden, aber anstatt bei jeder Abfrage ein Stück Post zu analysieren, machen Sie es einmal.
Sie können auch die Dokumentation fusionieren.
Außerdem sehen wir uns die Stimmung in den Daten an. Wie sieht es mit der Stimmung Ihrer Nutzer bei ihren Konversationssuchen aus? Was ist mit anderen kontextbezogenen Informationen über ihr Verhalten, d.h. mit Signalen. Es gibt viele Möglichkeiten, die Leistung von Spark innerhalb von Fusion zu nutzen, um leistungsfähigere Analysen und relevante Informationen zu erstellen.