2017-05-04 2 views
0

Ich habe eine Protokolldatei, die einige Informationen enthält, die ich über Spark verarbeiten möchte. Das einzige Problem ist, dass die gesamte Datei selbst nicht richtig formatiert ist. Also ich versuche, es ordentlich zu formatieren und nur die Daten zu greifen, die ich brauche.Format Protokoll mit Spark/Scala

Jetzt habe ich schon bemerkt, dass die meisten nützlichen Informationen ein "INFO" -Tag enthalten. Also habe ich beschlossen, nach dem gefiltert werden, dass die Verwendung:

val testje = realdata.filter (line => line.contains ("INFO"))

Aber jetzt will ich die resultierenden Daten an einen SqlContext bis i verarbeiten kann die Daten visualisieren (in Zeppelin);

  • Die resultierende RDD hat immer noch viel Müll, den ich wahrscheinlich nicht brauche.
  • Wenn ich versuche, dies mit einer Fallklasse zu formatieren, bekomme ich immer einen ArrayOutofBounds Fehler. Wahrscheinlich, weil die Junk-Information länger ist, als ich in der Klasse definiert habe.

Hier ist ein (sehr kleine) Beispiel dafür, was wie jetzt die Daten aus:

2016-03-08 14:55:29,637 INFO [ajp-nio-8009-exec-1] n.t.f.s.FloorService [FloorService.java:281] Snoozing. Wait 569 more milliseconds. Time passed : 4431 
2016-03-08 14:55:29,964 INFO [ajp-nio-8009-exec-3] n.t.f.c.FloorUpdateController [FloorUpdateController.java:67] Floor test received update from tile: 1, data = [false, false, false, false, false, false, false, false] 
2016-03-08 14:55:30,582 INFO [ajp-nio-8009-exec-2] n.t.f.c.FloorUpdateController [FloorUpdateController.java:67] Floor test received update from tile: 1, data = [false, false, false, false, false, false, true, false] 
2016-03-08 14:55:30,592 INFO [ajp-nio-8009-exec-2] n.t.f.s.FloorService [FloorService.java:284] delta time : 5387 
2016-03-08 14:55:30,595 INFO [ajp-nio-8009-exec-2] n.t.f.s.ActivityService [ActivityService.java:31] Activity added for floor with id: test 
2016-03-08 14:55:30,854 INFO [ajp-nio-8009-exec-4] n.t.f.c.FloorUpdateController [FloorUpdateController.java:67] Floor test received update from tile: 1, data = [false, false, false, false, false, false, false, false] 

Alles, was ich wirklich brauchen, sind das Datum, Uhrzeit, Kachel-ID und die Boolesche Werte.

Gibt es eine Möglichkeit, dies richtig zu formatieren, ohne alle Junk-Daten zu berücksichtigen?

Hier ist, was ich jetzt bin versucht (Disclaimer, sie ist in diesem recht neu und ich bin es irgendwie alata ^^ '):

import org.apache.commons.io.IOUtils 
import java.net.URL 
import java.nio.charset.Charset 

val realdata = sc.textFile("/media/application.txt") 

case class testClass(date: String, time: String, level: String, unknown1: String, unknownConsumer: String, unknownConsumer2: String, vloer: String, tegel: String, msg: String, bool1: String, bool2: String, bool3: String, bool4: String, bool5: String, bool6: String, bool7: String, bool8: String, batchsize: String, troepje1: String, troepje2: String) 

//val testje = realdata.filter(line => line.contains("INFO")) 
val mapData = realdata.map(s => s.split(" ")).filter(line => line.contains("INFO")).map(
    s => testClass(s(0), 
     s(1), 
     s(2), 
     s(3), 
     s(4), 
     s(5), 
     s(6), 
     s(7), 
     s(8), 
     s(9), 
     s(10), 
     s(11), 
     s(12), 
     s(13), 
     s(14), 
     s(15), 
     s(16), 
     s(17), 
     s(18), 
     s(19) 
     ) 
    ).toDF() 
    mapData.registerTempTable("test") 

Antwort

1

Ich empfehle Ihnen, mit data und nicht INFO zu filtern, da die Zeilen, die Sie teilen und in Dataframe konvertieren möchten, data enthält.
Ich habe Ihren Code ein wenig modifiziert Ihre case class anpassen und Sie können mehr nach Ihrem Bedarf

val mapData = realdata 
.filter(line => line.contains("data")) 
.map(s => s.split(" ").toList) 
.map(
    s => testClass(s(0), 
    s(1).split(",")(0), 
    s(1).split(",")(1), 
    s(3), 
    s(4), 
    s(5), 
    s(6), 
    s(7), 
    s(8), 
    s(15), 
    s(16), 
    s(17), 
    s(18), 
    s(19), 
    s(20), 
    s(21), 
    s(22), 
    "", 
    "", 
    "" 
) 
) 
.toDF() 
mapData.show(false) 

Hoffe, es hilft

+0

Das ist in der Tat hilfreich. Ich habe immer noch Probleme, dass einige der Daten nicht in die Klasse passen, aber ich denke, das ist nur eine Frage der Anpassung der Klasse, bis sie übereinstimmt. – Jdeboer

+0

Das hat funktioniert, danke! Die Durchführung von Suchanfragen auf dem DF über Zeppelin ist jedoch extrem langsam. (wie in, es lädt einfach ständig) – Jdeboer

1

Ich würde versuchen, so etwas zu tun :

val regex = """^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}),(\d{0,3}) INFO .+Floor test received update from tile: (\d+), data = (\[((false|true)(,){0,1})+\])$""".r 
final case class LogLine(date: Instant, tileId: String, data: Seq[Boolean]) 
realdata.flatMap({ 
    case regex(date, time, millis, tileId, data, _*) => 
    val mapper = new ObjectMapper() with ScalaObjectMapper 
    mapper.registerModule(DefaultScalaModule) 

    Seq(LogLine(
     Instant.parse(s"${date}T$time.${millis}Z"), 
     tileId, 
     mapper.readValue[Seq[Boolean]](data) 
    )) 
    case _ => Nil 
}) 

Die Fallklasse wäre mehrdimensional, aber das ist etwas, das Sie wahrscheinlich in diesem Fall wollen. Sie können es nachher immer abflachen, wenn Sie es wirklich brauchen.

Wenn Sie die Leistung verbessern möchten, können Sie mapPartitions anstelle von flatMap verwenden und den ObjectMapper wiederverwenden.

+0

Dank Nils, und sorry für die späte Antwort bearbeiten. Ich war ziemlich krank. Ich habe versucht, mit dieser aber die Spark-Shell wirft einen Fehler auf den Instant-Typ: : 11: Fehler: nicht gefunden: Typ Instant Ich denke, das ist, weil ich eine Abhängigkeit importieren muss, aber ich kann nicht finden, welche . – Jdeboer

+1

Stellen Sie sicher, dass Sie Java 8 verwenden, in diesem Fall ist es java.time.Instant. Wenn Sie java.util.Date oder einfach einen String verwenden möchten, können Sie dies stattdessen tun. Wenn Sie eine Zeichenfolge als Datum verwenden, dann fügen Sie nur s "$ {date} T $ time. $ {Millis} Z" oder in einem anderen Format ein, das Sie möchten. – Nils