我在spark-shell中使用Spark 2.1.1和Scala 2.11.8。
我的输入数据集类似于:
2017-06-18 00:00:00 , 1497769200 , z287570731_serv80i:7:175 , 5:Re
2017-06-18 00:00:00 , 1497769200 , p286274731_serv80i:6:100 , 138
2017-06-18 00:00:00 , 1497769200 , t219420679_serv37i:2:50 , 5
2017-06-18 00:00:00 , 1497769200 , v290380588_serv81i:12:800 , 144:Jo
2017-06-18 00:00:00 , 1497769200 , z292902510_serv83i:4:45 , 5:Re
2017-06-18 00:00:00 , 1497769200 , v205454093_serv75i:5:70 , 50:AK
它保存为CSV文件,使用sc.textFile("input path")
经过几次转换后,这就是我所拥有的RDD的输出:
(String, String) = ("Re ",7)
我通过执行
得到这个val tid = read_file.map { line =>
val arr = line.split(",")
(arr(3).split(":")(1), arr(2).split(":")(1))
}
我的输入RDD是:
( z287570731_serv80i:7:175 , 5:Re )
( p286274731_serv80i:6:100 , 138 )
( t219420679_serv37i:2:50 , 5 )
( v290380588_serv81i:12:800 , 144:Jo )
( z292902510_serv83i:4:45 , 5:Re )
可以观察到,在第一个第2栏中,我有
5:Re
我正在获得输出
("Re ",7)
然而,当我到达第二行时,根据格式,第2列是138,应该是
138:null
但在执行
时给出了ArrayIndexOutOfBoundsExceptiontid.collect()
如何更正此值,以便分别为第二行和第三行显示138和5?我试着这样做:
tid.filter(x => x._1 != null )
答案 0 :(得分:3)
问题是你希望这个位置至少有两个部分,而你可能只有一个部分。
以下是导致问题的一行。
{var arr = line.split(","); (arr(3).split(":")(1),arr(2).split(":")(1))});
完成line.split(",")
之后的arr(3).split(":")(1)
以及arr(2).split(":")(1)
。
对于这种格式肯定有太多的假设,并被缺失的值所打败。
但在执行
时给出了ArrayIndexOutOfBoundsException
这是因为您访问了3
和2
元素,但只有2个(!)
scala> sc.textFile("input.csv").
map { line => line.split(",").toSeq }.
foreach(println)
WrappedArray(( z287570731_serv80i:7:175i , 5:Re ))
WrappedArray(( p286274731_serv80i:6:100 , 138 ))
问题几乎与Spark无关。它是一个常规的Scala问题,数据不在您预期的位置。
scala> val arr = "hello,world".split(",")
arr: Array[String] = Array(hello, world)
请注意,上面的内容只是纯粹的Scala。
给出以下数据集......
2017-06-18 00:00:00 , 1497769200 , z287570731_serv80i:7:175 , 5:Re
2017-06-18 00:00:00 , 1497769200 , p286274731_serv80i:6:100 , 138
2017-06-18 00:00:00 , 1497769200 , t219420679_serv37i:2:50 , 5
2017-06-18 00:00:00 , 1497769200 , v290380588_serv81i:12:800 , 144:Jo
2017-06-18 00:00:00 , 1497769200 , z292902510_serv83i:4:45 , 5:Re
2017-06-18 00:00:00 , 1497769200 , v205454093_serv75i:5:70 , 50:AK
......我执行以下操作:
val solution = sc.textFile("input.csv").
map { line => line.split(",") }.
map { case Array(_, _, third, fourth) => (third, fourth) }.
map { case (third, fourth) =>
val Array(_, a @ _*) = fourth.split(":")
val Array(_, right, _) = third.split(":")
(a.headOption.orNull, right)
}
scala> solution.foreach(println)
(Re,7)
(null,6)
(Re,4)
(null,2)
(AK,5)
(Jo,12)
我强烈建议使用Spark SQL进行此类数据转换。正如你所说,你是Spark的新手,所以为什么不从正确的Spark SQL SQL开始。
val solution = spark.
read.
csv("input.csv").
select($"_c2" as "third", $"_c3" as "fourth").
withColumn("a", split($"fourth", ":")).
withColumn("left", $"a"(1)).
withColumn("right", split($"third", ":")(1)).
select("left", "right")
scala> solution.show(false)
+----+-----+
|left|right|
+----+-----+
|Re |7 |
|null|6 |
|null|2 |
|Jo |12 |
|Re |4 |
|AK |5 |
+----+-----+
答案 1 :(得分:2)
如果您的数据如下文件
( z287570731_serv80i:7:175 , 5:Re )
( p286274731_serv80i:6:100 , 138 )
( t219420679_serv37i:2:50 , 5 )
( v290380588_serv81i:12:800 , 144:Jo )
( z292902510_serv83i:4:45 , 5:Re )
然后你可以使用
val tid = sc.textFile("path to the input file")
.map(line => line.split(","))
.map(array => {
if (array(1).contains(":")) (array(1).split(":")(1).replace(")", "").trim, array(0).split(":")(1))
else (null, array(0).split(":")(1))
})
tid.foreach(println)
应该输出为
(Re,7)
(null,6)
(null,2)
(Jo,12)
(Re,4)
但如果您有数据
2017-06-18 00:00:00 , 1497769200 , z287570731_serv80i:7:175 , 5:Re
2017-06-18 00:00:00 , 1497769200 , p286274731_serv80i:6:100 , 138
2017-06-18 00:00:00 , 1497769200 , t219420679_serv37i:2:50 , 5
2017-06-18 00:00:00 , 1497769200 , v290380588_serv81i:12:800 , 144:Jo
2017-06-18 00:00:00 , 1497769200 , z292902510_serv83i:4:45 , 5:Re
2017-06-18 00:00:00 , 1497769200 , v205454093_serv75i:5:70 , 50:AK
2017-06-18 00:00:00 , 1497769200 , z287096299_serv80i:19:15000 , 39:Re
然后你需要做
val tid = sc.textFile("path to the input file")
.map(line => line.split(","))
.map(array => {
if (array(3).contains(":")) (array(3).split(":")(1).replace(")", "").trim, array(2).split(":")(1))
else (null, array(2).split(":")(1))
})
tid.foreach(println)
你应该输出
(Re,7)
(null,6)
(null,2)
(Jo,12)
(Re,4)
(AK,5)
(Re,19)
答案 2 :(得分:1)
ArrayIndexOutOfBounds
正在发生,因为如果元组的第二个元素中不存在:
,则元素将不存在。
您可以检查每个元组的第二个元素中是否存在:
。然后使用map为您提供一个中间RDD,您可以在其上运行当前查询。
val rdd = sc.parallelize(Array(
( "z287570731_serv80i:7:175" , "5:Re" ),
( "p286274731_serv80i:6:100" , "138" ),
( "t219420679_serv37i:2:50" , "5" ),
( "v290380588_serv81i:12:800" , "144:Jo" ),
( "z292902510_serv83i:4:45" , "5:Re" )))
rdd.map { x =>
val idx = x._2.lastIndexOf(":")
if(idx == -1) (x._1, x._2+":null")
else (x._1, x._2)
}
显然有更好的(更少的代码行)方法来完成你想要完成的任务但是作为初学者,最好在单个命令中布置每个步骤,以便易于阅读和理解,特别是scala
用一行代码就可以阻止全球变暖。