为了说明问题,我采用了testset csv文件。但在实际案例中,问题必须处理的不仅仅是TeraByte数据。
我有一个CSV文件,其中的列用引号括起来(“col1”)。但是当数据导入完成时。一列包含换行符(\ n)。当我想将它们保存为Hive表时,这会导致很多问题。
我的想法是用“|”替换\ n字符火花管。
我到目前为止取得了成就:
1. val test = sqlContext.load(
"com.databricks.spark.csv",
Map("path" -> "test_set.csv", "header" -> "true", "inferSchema" -> "true", "delimiter" -> "," , "quote" -> "\"", "escape" -> "\\" ,"parserLib" -> "univocity" ))#read a csv file
2. val dataframe = test.toDF() #convert to dataframe
3. dataframe.foreach(println) #print
4. dataframe.map(row => {
val row4 = row.getAs[String](4)
val make = row4.replaceAll("[\r\n]", "|")
(make)
}).collect().foreach(println) #replace not working for me
样本集:
(17 , D73 ,525, 1 ,testing\n , 90 ,20.07.2011 ,null ,F10 , R)
(17 , D73 ,526, 1 ,null , 89 ,20.07.2011 ,null ,F10 , R)
(17 , D73 ,529, 1 ,once \n again, 10 ,20.07.2011 ,null ,F10 , R)
(17 , D73 ,531, 1 ,test3\n , 10 ,20.07.2011 ,null ,F10 , R)
预期结果集:
(17 , D73 ,525, 1 ,testing| , 90 ,20.07.2011 ,null ,F10 , R)
(17 , D73 ,526, 1 ,null , 89 ,20.07.2011 ,null ,F10 , R)
(17 , D73 ,529, 1 ,once | again, 10 ,20.07.2011 ,null ,F10 , R)
(17 , D73 ,531, 1 ,test3| , 10 ,20.07.2011 ,null ,F10 , R)
对我有用的是什么:
val rep = "\n123\n Main Street\n".replaceAll("[\\r\\n]", "|") rep: String = |123| Main Street|
但为什么我无法以元组为基础?
val dataRDD = lines_wo_header.map(line => line.split(";")).map(row => (row(0).toLong, row(1).toString,
row(2).toLong, row(3).toLong,
row(4).toString, row(5).toLong,
row(6).toString, row(7).toString, row(8).toString,row(9).toString))
dataRDD.map(row => {
val wert = row._5.replaceAll("[\\r\\n]", "|")
(row._1,row._2,row._3,row._4,wert,row._6, row._7,row._8,row._9,row._10)
}).collect().foreach(println)
Spark --version 1.3.1
答案 0 :(得分:2)
如果您可以使用Spark SQL 1.5或更高版本,则可以考虑使用可用于列的functions。假设您不知道(或没有)列的名称,您可以执行以下代码段:
val df = test.toDF()
import org.apache.spark.sql.functions._
val newDF = df.withColumn(df.columns(4), regexp_replace(col(df.columns(4)), "[\\r\\n]", "|"))
如果您知道列的名称,则可以在两次出现时将df.columns(4)
替换为其名称。
我希望有所帮助。 欢呼声。
答案 1 :(得分:0)
我的想法是用“|”替换\ n字符火花管。
我尝试了 replaceAll 方法,但它无效。以下是实现相同目标的替代方案:
val test = sq.load(
"com.databricks.spark.csv",
Map("path" -> "file:///home/veda/sample.csv", "header" -> "false", "inferSchema" -> "true", "delimiter" -> "," , "quote" -> "\"", "escape" -> "\\" ,"parserLib" -> "univocity" ))
val dataframe = test.toDF()
val mapped = dataframe.map({
row => {
val str = row.get(0).toString()
var fnal=new StringBuilder(str)
//replace newLine
var newLineIndex=fnal.indexOf("\\n")
while(newLineIndex != -1){
fnal.replace(newLineIndex,newLineIndex+2,"|")
newLineIndex = fnal.indexOf("\\n")
}
//replace carriage returns
var cgIndex=fnal.indexOf("\\r")
while(cgIndex != -1){
fnal.replace(cgIndex,cgIndex+2,"|")
cgIndex = fnal.indexOf("\\r")
}
(fnal.toString()) //tuple modified
}
})
mapped.collect().foreach(println)
注意:您可能希望将重复的代码移动到单独的函数中。
答案 2 :(得分:0)
CSV的多行支持在Spark版本2.2 JIRA中添加,而spark 2.2尚未发布。
我遇到了同样的问题并通过帮助我们的hadoop输入格式和阅读器来解决它。
从git复制InputFormat和reader类,并执行如下:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
//implementation
JavaPairRDD<LongWritable, Text> rdd =
context.
newAPIHadoopFile(path, FileCleaningInputFormat.class, null, null, new Configuration());
JavaRDD<String> inputWithMultiline= rdd.map(s -> s._2().toString())
另一种解决方案 - 使用Apache crunch中的CSVInputFormat
读取CSV文件,然后使用opencsv解析每个CSV行:
sparkContext.newAPIHadoopFile(path, CSVInputFormat.class, null, null, new Configuration()).map(s -> s._2().toString());
Apache crunch maven依赖:
<dependency>
<groupId>org.apache.crunch</groupId>
<artifactId>crunch-core</artifactId>
<version>0.15.0</version>
</dependency>