我是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"
答案 0 :(得分:2)
您可以使用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)
答案 1 :(得分:1)
Spark将每行作为sc.textFile
的单独项目。您可以使用sc.hadoopConfiguration().set("textinputformat.record.delimiter", "!")
将其拆分为不同的字符。
@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));
}
答案 2 :(得分:0)
我相信无处不在的唯一正确方法是
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。
给定的方式可以在任何地方使用,因为每次它都使用新的配置。