[英]How to process MultiLine input log file in Spark using Java
我是Spark的新手,对我来说似乎很困惑。 我已经浏览了Java API的spark文档但是无法找到解决问题的方法。 我必须在spark-Java中处理一个日志文件,并且只剩下很少的时间。 以下是包含多行设备记录(设备ID,描述,IP地址,状态)跨度的日志文件。 它还包含一些我不会烦恼的其他日志信息。 如何从这个巨大的日志文件中获取设备信息日志。 任何帮助深表感谢。
输入日志数据:
!
!
!
device AGHK75
description "Optical Line Terminal"
ip address 1.11.111.12/10
status "FAILED"
!
device AGHK78
description "Optical Line Terminal"
ip address 1.11.111.12/10
status "ACTIVE"
!
!
context local
!
no ip domain-lookup
!
interface IPA1_A2P_1_OAM
description To_A2P_1_OAM
ip address 1.11.111.12/10
propagate qos from ip class-map ip-to-pd
!
interface IPA1_OAM_loopback loopback
description SE1200_IPA-1_OAM_loopback
ip address 1.11.111.12/10
ip source-address telnet snmp ssh radius tacacs+ syslog dhcp-server tftp ftp icmp-dest-unreachable icmp-time-exceed netop flow-ip
到目前为止我所做的是:
Java代码
JavaRDD<String> logData = sc.textFile("logFile").cache();
List<String> deviceRDD = logData.filter(new Function<String, Boolean>() {
Boolean check=false;
public Boolean call(String s) {
if(s.contains("device") ||(check == true && ( s.contains("description") || s.contains("ip address"))))
check=true;
else if(check==true && s.contains("status")){
check=false;
return true;
}
else
check=false;
return check; }
}).collect();
电流输出:
device AGHK75
description "Optical Line Terminal"
ip address 1.11.111.12/10
status "FAILED"
device AGHK78
description "Optical Line Terminal"
ip address 1.11.111.12/10
status "ACTIVE"
预期产出是:
AGHK75,"Optical Line Terminal",1.11.111.12/10,"FAILED"
AGHK78,"Optical Line Terminal",1.11.111.12/10,"ACTIVE"
您可以使用sc.wholeTextFiles("logFile")
将数据作为键,值对,其中键将作为文件名,值作为数据。
然后你可以使用一些字符串操作来按照单个日志数据的开始和结束分隔符“!”分割数据。 并首先进行过滤,以检查第一个单词是否为device,然后在其上执行flatMap
,这将使其成为singleLog文本RDD。
然后使用地图从中获取数据。
请尝试一下,让我知道这个逻辑是否适合你。
在Spark Scala中添加了代码:
val ipData = sc.wholeTextFiles("abc.log")
val ipSingleLog = ipData.flatMap(x=>x._2.split("!")).filter(x=>x.trim.startsWith("device"))
val logData = ipSingleLog.map(x=>{
val rowData = x.split("\n")
var device = ""
var description = ""
var ipAddress = ""
var status = ""
for (data <- rowData){
if(data.trim().startsWith("device")){
device = data.split("device")(1)
}else if(data.trim().startsWith("description")){
description = data.split("description")(1)
}else if(data.trim().startsWith("ip address")){
ipAddress = data.split("ip address")(1)
}else if(data.trim().startsWith("status")){
status = data.split("status")(1)
}
}
(device,description,ipAddress,status)
})
logData.foreach(println)
Spark将使用sc.textFile
将每一行作为单独的项目。 您可以使用sc.hadoopConfiguration().set("textinputformat.record.delimiter", "!")
将其拆分为不同的char。
@Test
public void test() throws ParseException, IOException {
hadoop.write("/test.txt", "line 1\nline 2\n!\nline 3\nline 4");
JavaSparkContext sc = spark.getContext();
sc.hadoopConfiguration().set("textinputformat.record.delimiter", "!");
System.out.println(sc.textFile(hadoop.getMfs().getUri() + "/test.txt").collect());
assertThat(sc.textFile(hadoop.getMfs().getUri() + "/test.txt").count(), is(2L));
}
我相信无处不在的唯一正确方法是
Configuration hadoopConf = new Configuration();
hadoopConf.set("textinputformat.record.delimiter", "delimiter");
JavaPairRDD<LongWritable, Text> input = jsc.newAPIHadoopFile(path,
TextInputFormat.class, LongWritable.class, Text.class, hadoopConf);
hadoop相关代码存在问题。 根据输入文件的大小,它会生成其他记录: MAPREDUCE-6549 , MAPREDUCE-5948 。 它肯定适用于2.7.2。
即使mlk建议使用spark上下文完美地工作,但如果你尝试使用相同的spark上下文读取具有不同分隔符的另一个文件,它将会失败。 默认情况下,分隔符是新的行符号,一旦应用此选项,它将立即更改。
原因是spark上下文共享hadoopConfiguration对象并且很难理解,这究竟需要这个值。 作为一种解决方法,可能会实现RDD并对其进行缓存,但仍然可能会重新计算相同的RDD。
给定的方式可以在任何地方使用,因为每次它使用新的配置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.