我使用Spark 1.2.1(在local
模式下)从文件中提取和处理日志信息。
文件大小可能超过100Mb。该文件包含很长的单行,因此我使用正则表达式将此文件拆分为日志数据行。
MyApp.java
JavaSparkContext sc = new JavaSparkContext(conf);
JavaRDD<String> txtFileRdd = sc.textFile(filename);
JavaRDD<MyLog> logRDD = txtFileRdd.flatMap(LogParser::parseFromLogLine).cache();
LogParser.java
public static Iterable<MyLog> parseFromLogLine(String logline) {
List<MyLog> logs = new LinkedList<MyLog>();
Matcher m = PATTERN.matcher(logline);
while (m.find()) {
logs.add(new MyLog(m.group(0)));
}
System.out.println("Logs detected " + logs.size());
return logs;
}
已处理文件的实际大小约为100 Mb,实际上包含323863
个日志项。
当我使用Spark从文件中提取我的日志项时,我得到455651
[logRDD.count()
]日志项不正确。
我认为这是因为文件分区,检查输出我看到以下内容:
Logs detected 18694
Logs detected 113104
Logs detected 323863
总和为455651
!
所以我看到我的分区彼此合并,保留了重复的项目,我想阻止这种行为。
解决方法是使用repartition(1)
,如下所示:
txtFileRdd.repartition(1).flatMap(LogParser::parseFromLogLine).cache();
这确实给了我想要的结果323863
,但我怀疑它对表现有好处。
如何更好地处理性能?
答案 0 :(得分:3)
默认情况下,分区是基于行的。看来,当有一条非常长的线时,这会以一种有趣的方式失败。你可以考虑为此提交一个错误(也许已经有了)。
拆分由Hadoop文件API执行,特别是TextInputFormat
类。一种选择是指定您自己的InputFormat
(可能包括整个解析器)并使用sc.hadoopFile
。
另一种选择是通过textinputformat.record.delimiter
:
// Use space instead of newline as the delimiter.
sc.hadoopConfiguration.set("textinputformat.record.delimiter", " ")