我是新来的火花。因此,我正在努力训练自己,以便通过遵循一些教程和小任务来熟悉火花和分布式系统。 在某些任务中,下面是让我在这里提出问题以找到更好的解决方案的任务。
以下是我的示例数据。
EEL A CAT LOC1 EEX 13|42|45|67 EEL A CAT LOC2 EEX 24|32 ....
我的目标是转换以上数据。
EEL A CAT LOC1 EEX 13 EEL A CAT LOC1 EEX 42 EEL A CAT LOC1 EEX 45 EEL A CAT LOC1 EEX 67 EEL A CAT LOC2 EEX 24 EEL A CAT LOC2 EEX 32
我的代码如下所示,它适用于10MB以下的数据大小。但是,如果我输入一个大型数据集(超过3GB),则需要大约10~15分钟才能在多节点平台上完成。
请注意,我使用的是一个spark-master节点和四个数据节点,它们分别具有16核和16GB内存。
考虑到我的计算机规格,我认为这个简单的转换任务不应该花费太多时间,我也认为有一种更有效的方法来缩短运行时间。
我知道spark是基于内存系统的,我坚信它可以帮助我轻松处理这样一个迭代和简单的任务,但结果对我来说有点失望。
以下是我的完整代码。我跳过了详细的解释,因为它非常简单。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;
public class DataTransformation {
public static JavaRDD<String> DataTransformation_V01(String input,JavaSparkContext sc){
JavaRDD<String> lines = sc.textFile(input);
JavaRDD<String> line = lines.flatMap(new FlatMapFunction<String, String>() {
public Iterator<String> call(String s) throws Exception {
return Arrays.asList(s.split("\n")).iterator();
}
});
JavaRDD<String> newLine = line.flatMap(new FlatMapFunction<String, String>() {
public Iterator<String> call(String s) throws Exception {
List<String> ret = new ArrayList<String>();
List<String> ls = Arrays.asList(s.split("\t"));
String values = ls.get(ls.size()-1);
List<String> value = Arrays.asList(values.split("\\|"));
for(int i=0;i<value.size();++i){
String ns = ls.get(0)+"\t"+ls.get(1)+"\t"+ls.get(2)+"\t"+ls.get(3)+"\t"+ls.get(4)+"\t"+ls.get(5);
ns = ns + "\t" + value.get(i);
ret.add(ns);
}
return ret.iterator();
}
});
return newLine;
}
public static void main(String[] args) throws Exception{
String inputFile = args[0];
String outputFile = args[1];
SparkConf conf = new SparkConf().setAppName("Data Transformation")
.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")
JavaSparkContext sc = new JavaSparkContext(conf);
JavaPairRDD<String,String> result = DataTransformation_V01(inputFile,sc);
System.out.println(result.count());
result.saveAsTextFile(outputFile);
sc.stop();
sc.close();
}
}
感谢。
答案 0 :(得分:1)
尝试使用Dataframes API代替RDD进行此计算。以下代码段(使用scala简洁)将满足您的要求。
scala> import sqlContext.implicits._
import sqlContext.implicits._
scala> val df = sc.textFile("/user/test/files/spark_test.txt").map(_.split(',')).map(x => (x(0),x(1),x(2),x(3),x(4),x(5))).toDF("c1","c2","c3","c4","c5","c6")
df: org.apache.spark.sql.DataFrame = [c1: string, c2: string, c3: string, c4: string, c5: string, c6: string]
scala> df.explode("c6","c7")((x:String) => x.split('|')).drop("c6").show()
{"level": "INFO ", "timestamp": "2017-01-30 01:13:09,138", "classname": "com.hadoop.compression.lzo.GPLNativeCodeLoader", "body": "Loaded native gpl library"}
{"level": "INFO ", "timestamp": "2017-01-30 01:13:09,141", "classname": "com.hadoop.compression.lzo.LzoCodec", "body": "Successfully loaded & initialized native-lzo library [hadoop-lzo rev 2cedc48fab9e2e10a84b909b4c198053ff379ac7]"}
+---+---+---+----+---+---+
| c1| c2| c3| c4| c5| c7|
+---+---+---+----+---+---+
|EEL| A|CAT|LOC1|EEX| 13|
|EEL| A|CAT|LOC1|EEX| 42|
|EEL| A|CAT|LOC1|EEX| 45|
|EEL| A|CAT|LOC1|EEX| 67|
|EEL| A|CAT|LOC2|EEX| 24|
|EEL| A|CAT|LOC2|EEX| 32|
+---+---+---+----+---+---+
我在这里假设我们有csv文件,如下所示
EEL,A,CAT,LOC1,EEX,13|42|45|67
EEL,A,CAT,LOC2,EEX,24|32
数据帧比RDD更高性能,因为它可以利用Catalyst优化器并避免JVM对象序列化/反序列化以及相关的GC开销。 有关here的更多详情。
其他明显的性能考虑因素是使用镶木地板文件而不是纯文本文件。由于镶木地板文件是柱状的,并且运动效果更好,因此可以显着减少IO。另外,您可以将镶木地板文件直接读入数据框,并完全跳过昂贵的RDD阶段。