我对RDD和血统图有疑问。让我用一个例子来说明: 我有一个如下所示的数据文件:
ID; parent; level; type;content; Budget;
999999 ;;a;Total;total; 313344394;
01 ;;a;Part 1;Chancellery of the President of the Republic of Poland; 171524;
02 ;;a;Part 2;Chancellery of the Sejm; 430780;
03 ;;a;Part 3;OFFICE OF THE SENATE; 176212;
04 ;;a;Part 4;SUPREME COURT; 88161;
请注意,对于上一个预算字段,有一个前导空格。 所以我读入数据,创建一个由选定列组成的RDD:
scala> val baseRDD=sc.textFile(dataFile)
baseRDD: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[103] at textFile at <console>:29
scala> val budgetRDD=baseRDD.map(_.split(";")).map(x => (x(0),x(4), x(5)))
budgetRDD: org.apache.spark.rdd.RDD[(String, String, String)] = MapPartitionsRDD[101] at map at <console>:31
现在,我过滤掉标题行并获取最后一列作为int:
scala> val headerRow=budgetRDD.first
headerRow: (String, String, String) = (ID,content,Budget)
scala> val idBudgetRDD = budgetRDD.filter(_!=headerRow).map{case(id,name,money) =>
(id,money.toInt)}
idBudgetRDD: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[105] at map at <console>:46
scala> idBudgetRDD.toDebugString
res143: String =
(2) MapPartitionsRDD[105] at map at <console>:46 []
| MapPartitionsRDD[104] at filter at <console>:46 []
| MapPartitionsRDD[101] at map at <console>:31 []
| MapPartitionsRDD[100] at map at <console>:31 []
| MapPartitionsRDD[99] at textFile at <console>:29 []
| /home/user/poland_budget_2011_small.txt HadoopRDD[98] at textFile at <console>:29 []
因此上面的血统图清楚地显示了过滤步骤。 现在我看看我的数据并得到一个错误:
scala> idBudgetRDD.take(2)
16/02/12 03:43:46 ERROR Executor: Exception in task 0.0 in stage 146.0 (TID 179)
java.lang.NumberFormatException: For input string: " 313344394"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:569)
at java.lang.Integer.parseInt(Integer.java:615)
由于预算栏中的领先空间,这是可以理解的。 因此,我编辑并删除了数据文件中的前导空格,而不是使用trim:
ID; parent; level; type;content;Budget;
999999 ;;a;Total;total;313344394;
01 ;;a;Part 1;Chancellery of the President of the Republic of Poland;171524;
02 ;;a;Part 2;Chancellery of the Sejm;430780;
03 ;;a;Part 3;OFFICE OF THE SENATE;176212;
04 ;;a;Part 4;SUPREME COURT;88161;
进行了此更改后,使用上面的沿袭图,我的期望是重新运行take
操作会重新执行沿袭图并产生所需的结果。但事实并非如此,而是我得到了另一个错误,表明未应用排除标题行的过滤步骤:
scala> idBudgetRDD.take(2)
16/02/12 03:47:03 ERROR Executor: Exception in task 0.0 in stage 147.0 (TID 180)
java.lang.NumberFormatException: For input string: "Budget"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
有人可以解释发生了什么吗?我的想法是,由于懒惰的评估和沿袭,修复数据文件并重新执行take
将导致谱系图完全重新运行。
答案 0 :(得分:0)
事实证明我上面使用的过滤器是固定的,因此在我修改文件后它不再适用。我能够通过指定一个依赖于匹配ID字符串的过滤器来解决这个问题,如下所示:
val idBudgetRDD = budgetRDD.filter(! _.0.startsWith("ID;")).map{case(id,name,money) => (id, money.toInt)}
这总是与标题行匹配,重新运行take会产生正确的结果。