Konsequentes Erfassen von Informationen und Big-Data-Analyse mit Hadoop
Seite 4: Analyse und Zusammenfassung
Analyse
Nun sind die gespeicherte Log-Daten im HDFS und lassen sich analysieren. Grundsätzlich verwendet man dazu Map/Reduce-Jobs, die innerhalb der Map-Phase die Daten transformieren und in der Reduce-Phase aus diesen das gewünschte Resultat berechnen. Diese Jobs können das Hadoop-API verwenden, falls sie in JVM-basierten Programmiersprachen erstellt wurden. Will man andere Sprachen verwenden, zum Beispiel PHP, ist das über das Hadoop Streaming Framework möglich. Es stellt eine Datenschnittstelle über stdin/stdout bereit und ermöglicht dadurch in der Map- beziehungsweise Reduce-Phase das Anbinden beliebiger Prozesse. Ein solches Framework zur Erstellung von Map-Reduce-Jobs über das Hadoop Streaming Framework mit PHP hat David Zülke veröffentlicht. Dabei sind auch einige Beispielskripte, die sich einfach ausprobieren lassen und die grundlegenden Funktionen des Systems erklären.
Das Hadoop Streaming Framework ist in der Lage, reine Textdaten zeilenweise zu splitten und auf multiple Map-Tasks zu verteilen. Im Falle von komprimierten Daten lässt sich ohne Weiteres jedoch nur ein einziger Map-Task pro Datei verwenden. Durch das oben beschriebene Zusammenfassen der Daten wird zwar eine optimale Nutzung des HDFS erreicht, bei Kompression mit einem Standardcodec wie gzip lassen sich aber CPU-Resourcen nicht mehr optimal in Map/Reduce-Jobs ausnutzen. Lösen kann man das Problem durch Verwenden des LZO-Codecs für die Kompression. LZO komprimiert die Daten in Blöcken und das hadoop-lzo-Paket bietet die Möglichkeit, die komprimierten LZO-Blöcke einer Datei zu indizieren, sodass sie sich über mehrere Map-Tasks hinweg verteilen lassen. Aus lizenzrechtlichen Gründen wird LZO nicht direkt mit der Hadoop-Distribution ausgeliefert, die Integration des Codecs erfolgt allerdings genau so einfach, wie mit allen anderen von Hadoop unterstützten Codecs auch. Weitere Informationen zur LZO-Kompression, inklusive einem Vergleich mit bzip2 und gzip, finden sich im Cloudera-Blog.
Selbstgeschriebene Map/Reduce-Jobs in beliebigen Programmiersprachen bieten sehr umfangreiche Möglichkeiten der Datenauswertung. Häufig nutzt man Log-Daten allerdings nur für einfachere Datenanfragen von entwicklungsfernen Personengruppen. Die sollen ebenfalls eine flexible Möglichkeit erhalten, auf die Daten zuzugreifen. Entsprechende Änderungen an den Abfragen sollen möglichst wenige Entwicklungsresourcen abrufen, damit sich eine Abfrageanforderung kostengünstig umsetzen lässt. Mit Hive ist es möglich, über eine SQL-ähnliche Abfragesprache auf die Daten zuzugreifen, ohne sie nochmals speichern oder verändern zu müssen. Hive erlaubt die Ad-hoc-Erzeugung verschiedener Sichten auf die Daten und generiert die dafür nötigen Map/Reduce-Jobs automatisch und für den Nutzer transparent im Hintergrund.
Zur Auswertung der im Verzeichnis /icans/[PLATTFORM]/icans.content/[JAHR]/[MONAT]/[TAG] gespeicherten Content-bezogenen Log-Daten mit Hive muss man eine extern verwaltete Tabelle erzeugen und auf das entsprechende Verzeichnis verweisen. Da die Daten bereits nach Datum partitioniert ablegt sind, kann man die Hive-Tabelle entsprechend partitioniert verwalten:
// Partitionierte Tabelle "content" anlegen. Sie enthält nur eine Spalte
// namens "json", in der die JSON-kodierten Log-Messages enthalten sind:
CREATE EXTERNAL TABLE content (json string) PARTITIONED BY (year string,
month string, day string);
// Hinzufügen einer Partition. Dieser Befehl muss je Partition einmal
// ausgeführt werden.
ALTER TABLE content ADD PARTITION(year='[JAHR]',
month='[MONAT]', day='[TAG]')
LOCATION '/icans/[PLATTFORM]/icans.content/[JAHR]/[MONAT]/[TAG]/';
Nun lassen sich die initial gestellten Fragen zum erstellten Content beantworten.
Wer schrieb die Artikel, die am häufigsten gelesen wurden ?
SELECT
get_json_object("$.author") as author,
count(*) as view_count
FROM
content
WHERE (get_json_object(json, '$.handle') = 'icans.content.view')
GROUP BY get_json_object(json, ‘$.rawData.id’)
ORDER BY view_count DESC;
Hive ermöglicht SQL-ähnliche Abfragen auch auf mit JSON formatierte Daten. Es besteht die Möglichkeit, mit einer Query gezielt das gewünschte Feld aus der JSON-Struktur zu extrahieren. Das erfolgt im obigen Beispiel durch die mit Hive mitgelieferte Funktion get_json_object. Weitere Möglichkeiten, um mit Hive auf JSON-kodierten Daten zu arbeiten sind:
- Verwenden eines Deserialisierers (dazu muss man allerdings eine Hive-Tabelle mit den entsprechenden Spaltennamen definieren. Falls mehrere JSON-Dokumente mit unterschiedlichen Feldern zu speichern sind, ist dieses Vorgehen eher ungeeignet).
- das Erzeugen einer View auf die Tabelle durch die Hive-Funktion json_tuple, mit der Einschränkung, dass sich alle Felder auf derselben Hierarchieebene befinden müssen.
Im Beispiel kann es nur einen einzigen Autoren pro Content geben, da der Autor immer ein einzelner authentifizierter Nutzer der Systeme ist. Weiterhin gibt es zu jeder Content-View eine Log Message. Das macht es einfach, die Autoren der meistgelesenen Artikel zu ermitteln. Es genügt, lediglich die Views pro Content zu zählen und zusammen mit dem jeweiligen Autor auszugeben.
Wer sind die Top 10 Autoren mit dem einflussreichsten Content?
SELECT a.author, count(*) as referenced_count FROM
( SELECT extract_author_links(get_json_object("$.rawData.body"))
as (author, referenced_uri) FROM content ) a
GROUP BY a.author
ORDER BY referenced_count DESC
LIMIT 10;
Um nun den einflussreichsten (hier: den meistverlinkten) Content zu identifizieren, muss man den Content selbst analysieren und pro Content alle enthaltenen Links extrahieren. Das Beispiel extrahiert dafür zuerst ein Content-Element (wie eine HTML-Seite) aus der JSON-kodierten Log-Message. Diese HTML-Seite wird dann wiederum der Funktion extract_author_links übergeben. Die Funktion bezeichnet eine fiktive, nicht in Hive vorhandene, nutzerdefinierte Funktion (User-defined Function, UDF). Genauer gesagt stellt die Funktion eine UDTF (User-defined Table-generation Function) dar. UDTFs erlauben es, aus einem "Datum", hier eine HTML-Seite, mehrere Datensätze zu erzeugen. In einem gewissen Sinne also eine Tabelle. Dieser Schritt spiegelt die Map-Phase wieder, das heißt, eine UDTF erlaubt es, eigene Mapper in Hive zu verwenden. Im Beispiel erzeugt extract_author_links damit eine neue Tabelle mit den Spalten author und referenced_uri. Sie gibt an, welche URIs (inklusive des Autors) in der entsprechenden HTML-Seite verlinkt wurden. Nachdem die Tabelle über alle Content-Elemente hinweg erzeugt wurde, ist es einfach, die Anzahl der Verlinkungen pro Autor zu zählen, um die 10 einflussreichsten Autoren zu ermitteln.
Die von den Autoren intern verwendete Lösung hat außerdem noch weitere Anforderungen und muss intern-definierte Embedding Tags auswerten können. Eine allgemeine UDTF, um Links aus HTML-Seiten zu extrahieren, findet der Leser in der UDF/UDTF-Sammlung "smoker".
Eine weitere sinnvolle Anwendung nutzerdefinierter Funktionen in diesem Beispiel besteht darin, nicht in jeder Log Message den Content selbst zu speichern, sondern nur eine Id. Die Log Messages lassen sich dann über einen JOIN in Hive mit den Content-Daten verbinden, falls diese ebenfalls in Hive vorliegen. Falls nicht, kann man eine UDF verwenden, um den Content über die Id aus einem anderen Datenspeicher abzufragen. In dem Fall sollte der Datenspeicher allerdings sehr viele parallele Read-Requests performant bearbeiten können.
Zusammenfassung
Log Everything! Zu Beginn noch eine diffuse, scheinbar unerreichbare Anforderung, ist mit den vorgestellten Techniken relativ einfach umzusetzen. Alle dazu nötigen Systemteile lassen sich mit quelloffener Software kosteneffizient aufbauen und in aktuelle Webtechnologien wie dem Symfony2-Framework integrieren. Bei der Erfüllung der gestellten Anforderung spielt Hadoop die zentrale Rolle. Nicht nur als Möglichkeit, große Datenmengen zu speichern, auszuwerten und dabei beliebig skalieren zu können, sondern vor allem auch wegen der vielfältigen Entwicklerszene und den Tools um Hadoop herum. Sie steuern einen Großteil zu dessen Flexibilität und Vielseitigkeit bei, in ihrem Umfeld entstehen viele neue kommerzielle Produkte, um allgemeine Aufgaben zu lösen. Gleichzeitig kann man auch immer den speziellen Anforderungen Einzelner nachkommen.
Die Autoren haben gezeigt, wie sich mit Hadoop und angrenzenden Tools eine Lösung aufbauen lässt, die so mächtig ist, dass mit ihr auch sehr komplexe Aufgaben bewältigt werden können. Auf der anderen Seite ist der Ansatz flexibel genug, damit auch in Zukunft ganz unterschiedliche Techniken anbinden und gegebenenfalls ausgefallene Anforderungen einzelner Kunden berücksichtigen zu können.
Es soll allerdings nicht verschwiegen werden, dass der Einsatz von Hadoop eine Investition bedeutet und viel Spezialwissen für dessen Betrieb und die Umsetzung individueller Lösungen erfordert. Außerdem ist es eine sehr junge Technologie, die im Wesentlichen aus den Anforderungen des Internets in Bezug auf große Datenmengen und damit verbundenen Anwendungsfällen hervorgegangen ist. Verfahren, die eher traditionelle Datenbanksysteme im Blick haben oder deutlich härtere Anforderungen an Transaktionszeiten stellen, gewinnen eher nicht durch den Einsatz von Hadoop. In diesen Bereichen ist Big Data allerdings auch schon lange etabliert. Die große Stärke von Hadoop liegt heute darin, Big Data zu demokratisieren und damit auch kleinen Startups ohne den Einsatz großer Geldmittel das Arbeiten mit Big Data zu ermöglichen.
Stefan Schadwinkel
arbeitet als Analytics Engineer bei der Icans GmbH. Sein Hauptinteresse gilt dabei intelligenten Data-Mining Tools, Big Data mit Hadoop und anderen NoSQL-Technologien.
Mike Lohmann
arbeitet als Software-Architect bei der Icans GmbH. Sein Interesse gilt der Konzeption von Systemen zur Umsetzung von Big Data- und High-Performance-Anforderungen mit PHP.
()