使用Spark/Scala格式化日志

使用Spark/Scala格式化日志,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我有一个日志文件,其中包含一些我想通过Spark处理的信息。唯一的问题是整个文件本身的格式不是很正确。 所以我正试图将其格式化,只获取我需要的数据 现在我已经注意到,大多数有用的信息都包含一个“INFO”标记。因此,我决定使用以下方法进行过滤: val testje = realdata.filter(line => line.contains("INFO")) 但是现在我想将结果数据处理到SQLContext中,这样我就可以可视化数据(在齐柏林飞艇中) 由此产生的RDD仍然有很多我可

我有一个日志文件,其中包含一些我想通过Spark处理的信息。唯一的问题是整个文件本身的格式不是很正确。 所以我正试图将其格式化,只获取我需要的数据

现在我已经注意到,大多数有用的信息都包含一个“INFO”标记。因此,我决定使用以下方法进行过滤:

val testje = realdata.filter(line => line.contains("INFO"))
但是现在我想将结果数据处理到SQLContext中,这样我就可以可视化数据(在齐柏林飞艇中)

  • 由此产生的RDD仍然有很多我可能不需要的垃圾
  • 当我尝试用case类格式化时,我总是得到一个ArrayOutofBounds错误。可能是因为垃圾信息 比我在课堂上定义的时间长
下面是一个(非常小的)数据现在看起来像什么的示例:

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]
我真正需要的是日期、时间、磁贴ID和布尔值

有没有什么方法可以在不考虑所有垃圾数据的情况下正确格式化这些数据

以下是我现在正在尝试的(免责声明,我在这方面是相当新的,我有点随机应变^^'):


我会尝试这样做:

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
})
case类将是多维的,但在本例中,这可能是您想要的。如果你真的需要,你可以在事后把它弄平


如果您想提高性能,可以使用mapPartitions而不是flatMap并重用ObjectMapper。

我会尝试这样做:

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
})
case类将是多维的,但在本例中,这可能是您想要的。如果你真的需要,你可以在事后把它弄平


如果您想提高性能,可以使用mapPartitions而不是flatMap,并重用ObjectMapper。

我建议您使用
数据而不是
信息进行筛选,因为要拆分并转换为dataframe的行包含
数据

我对您的代码进行了一些修改,以适合您的
案例类
,您可以根据需要编辑更多内容

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)

希望对您有所帮助

我建议您使用
数据
而不是
信息
进行筛选,因为您要拆分并转换为数据帧的行包含
数据

我对您的代码进行了一些修改,以适合您的
案例类
,您可以根据需要编辑更多内容

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)

希望能有所帮助

谢谢Nils,很抱歉回复太晚。我病得很厉害。我尝试使用它,但spark shell在Instant类型::11:error:not found:type Instant上抛出了一个错误。我想这是因为我需要导入依赖项,但我找不到哪一个。请确保您使用的是java 8,在这种情况下,它是java.time.Instant。如果您想使用java.util.Date或只是一个字符串,您可以这样做。如果使用字符串作为日期,则只能插入s“${date}T$time.${millis}Z”或任何其他您想要的格式。谢谢Nils,很抱歉回复太晚。我病得很厉害。我尝试使用它,但spark shell在Instant类型::11:error:not found:type Instant上抛出了一个错误。我想这是因为我需要导入依赖项,但我找不到哪一个。请确保您使用的是java 8,在这种情况下,它是java.time.Instant。如果您想使用java.util.Date或只是一个字符串,您可以这样做。如果使用字符串作为日期,则只插入s“${date}T$time.${millis}Z”或任何其他您想要的格式。这确实很有帮助。我仍然有一些问题,一些数据不适合类,但我想这只是调整类直到它匹配的问题。这很有效,谢谢!但是,通过齐柏林飞艇对DF执行查询的速度非常慢。(如中所述,它只是永久加载)这确实是有帮助的。我仍然有一些问题,一些数据不适合类,但我想这只是调整类直到它匹配的问题。这很有效,谢谢!但是,通过齐柏林飞艇对DF执行查询的速度非常慢。(如中所示,它只是永久加载)