在Spark Scala中仅选择部分输入

在Spark Scala中仅选择部分输入,scala,apache-spark,Scala,Apache Spark,我正在从HDFS读取一个文件,我想用DataFrame结构将它保存在另一个存储库中。 我的数据示例: 05-09-2020 22:10:10,jony,abcd,usr.admin.local.teste 我想将此数据结构发送到另一个存储库: 05-09-2020 22:10:10,jony,abcd,teste 当我在spark scala中编写这段代码时,一切正常,一切正常: val read=sc.textFile(“hdfs://.../teste.csv") val select=r

我正在从HDFS读取一个文件,我想用DataFrame结构将它保存在另一个存储库中。 我的数据示例:

05-09-2020 22:10:10,jony,abcd,usr.admin.local.teste

我想将此数据结构发送到另一个存储库:

05-09-2020 22:10:10,jony,abcd,teste

当我在spark scala中编写这段代码时,一切正常,一切正常:

val read=sc.textFile(“hdfs://.../teste.csv") 
val select=read.map(u.split(“,”).map{x=>(x(0),x(1),x(2))}
val名称=序号(“日期”、“名称”、“id”)
val df=select.toDF(名称:*)
但当我做这个函数时,只是为了在最后一个参数中得到“test”,它给出了一个错误

val read = sc.textFile("hdfs://.../teste.csv")
val select = linesConsumer.map(_.split(",")).map{x => (x(0),x(1),x(2),x(3).split(",")(3).replace(".", ","))}
val names = Seq("date","name","id","teste")
val df = select.toDF(names: _*)
它给我的错误如下:

ERROR Executor:28.0阶段(TID 160)任务0.0中的异常java.lang.ArrayIndexOutOfBoundsException:4
在$line145.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.应用(:25)
在$line145.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.应用(:25)
位于scala.collection.Iterator$$anon$11.next(Iterator.scala:410)
位于scala.collection.Iterator$$anon$11.next(Iterator.scala:410)
位于org.apache.spark.sql.catalyst.expressions.GeneratedClass$GenerateEditorForCodeGenStage1.processNext(未知源)
位于org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43)
位于org.apache.spark.sql.execution.whisttagecodegenexec$$anonfun$13$$anon$1.hasNext(whisttagecodegenexec.scala:636)
位于org.apache.spark.sql.execution.SparkPlan$$anonfun$2.apply(SparkPlan.scala:255)
位于org.apache.spark.sql.execution.SparkPlan$$anonfun$2.apply(SparkPlan.scala:247)
位于org.apache.spark.rdd.rdd$$anonfun$mapPartitionsInternal$1$$anonfun$apply$24.apply(rdd.scala:836)
位于org.apache.spark.rdd.rdd$$anonfun$mapPartitionsInternal$1$$anonfun$apply$24.apply(rdd.scala:836)
位于org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:52)
在org.apache.spark.rdd.rdd.computeOrReadCheckpoint(rdd.scala:324)
位于org.apache.spark.rdd.rdd.iterator(rdd.scala:288)
位于org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:52)
在org.apache.spark.rdd.rdd.computeOrReadCheckpoint(rdd.scala:324)
位于org.apache.spark.rdd.rdd.iterator(rdd.scala:288)
位于org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:90)
位于org.apache.spark.scheduler.Task.run(Task.scala:121)
位于org.apache.spark.executor.executor$TaskRunner$$anonfun$10.apply(executor.scala:408)
位于org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1360)
位于org.apache.spark.executor.executor$TaskRunner.run(executor.scala:414)
位于java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
位于java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
在java.lang.Thread.run(Thread.java:748)20/09/05 21:57:22警告TaskSetManager:在阶段28.0中丢失任务0.0(TID 160,本地主机,执行器驱动程序):java.lang.ArrayIndexOutOfBoundsException:4
在$line145.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.应用(:25)
在$line145.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.应用(:25)
位于scala.collection.Iterator$$anon$11.next(Iterator.scala:410)
在scala.collection.Iterator$$anon$11.next(Iterator.scala:410)。。。

有人知道我做错了什么吗?

您正在用逗号拆分行,然后尝试用逗号拆分x(3);由于第一次拆分,x(3)将不包含任何逗号,因此将在除0之外的所有索引上提供ArrayIndexOutOfBounds。

您的错误发生是因为您在
拆分后执行了
替换
,而您以前可能打算这样做。这就引出了:为什么不直接在
上拆分呢?
这种方法通过执行一些简单的长度检查,并从本质上跳过无法解析的行,从而增加了弹性:

//为每个成功解析的行返回一个元组列表
val getRow=(s:String)=>{
val a=s.split(“,*”)
如果(a.length==4){
val lastList=a(3).split('.'))
val last=if(lastList.length>0){lastList(lastList.length-1)}else“”
名单((a(0)、a(1)、a(2)、最后一份))
}else List()}
val df=sc.textFile(csv_path).flatMap(getRow).toDF(“日期”、“名称”、“id”、“测试”)
假设这一输入:

05-09-2020 22:10:10, jony, abcd, usr.admin.local.teste
05-09-2020 12:10:10, vas, saga, usr.admin.local.champ
05-09-2020 20:10:10, nema, abd, usr.admin.local.mora
这将是
df.show(false)

由于日期仍然只是一个字符串,您可能需要转换它,具体取决于您将如何使用它

编辑评论中的其他问题 要省略
@'
之后的字符串,如果字符串中存在此类字符,请引入新值
lastBefore
,并使用
string
indexOf
substring
方法:

val getRow=(s:String)=>{
val a=s.split(“,*”)
如果(a.length==4){
val lastList=a(3).split('.'))
val last=if(lastList.length>0)lastList(lastList.length-1)else“”
val lastBefore=if(last.indexOf('@')>=0)last.substring(0,last.indexOf('@'))else last
列表((a(0),a(1),a(2),最后一次)
}else List()}

在x(3).split(“,”)行中,您试图以“usr.admin.local.teste”格式拆分数据,对吗?如果是这样的话,为什么要用“,”而不是“.”分开呢?我想用逗号分隔参数,但在最后一个参数中,我想得到最后一个用点分隔的参数。我试着这样做:
val all=read.map(u.split(“,”).map{x=>(x(3).split(“.split(“.3))}
但它不起作用,给出了相同的错误我想将第三个参数除以一点以得到最后一个值,但我无法做到这不是你上面的代码所做的,你正在用逗号分割第三个参数,所以这可能是你的问题!如果我的最后一个参数还有另一个分隔符,我该怎么做?如果我的输入是
05-09-2020 22:10:10,jony,abcd,usr.admin.local。teste@123
我还是想得到这个
05-09-2020 22:10:10,j
05-09-2020 22:10:10, jony, abcd, usr.admin.local.teste
05-09-2020 12:10:10, vas, saga, usr.admin.local.champ
05-09-2020 20:10:10, nema, abd, usr.admin.local.mora
+-------------------+----+----+-----+
|date               |name|id  |teste|
+-------------------+----+----+-----+
|05-09-2020 22:10:10|jony|abcd|teste|
|05-09-2020 12:10:10|vas |saga|champ|
|05-09-2020 20:10:10|nema|abd |mora |
+-------------------+----+----+-----+