Apache spark 如何使用模式推断将RDD[String]写入拼花地板文件?

Apache spark 如何使用模式推断将RDD[String]写入拼花地板文件?,apache-spark,apache-spark-sql,spark-streaming,spark-dataframe,Apache Spark,Apache Spark Sql,Spark Streaming,Spark Dataframe,我的Spark Streaming作业需要处理RDD[String],其中String对应于csv文件的一行。我事先不知道模式,所以我需要从RDD推断模式,然后将其内容写入一个拼花文件。如果我从磁盘读取csv文件,我可以通过模式推理将所有内容加载到DataFrame中,并直接将其写入拼花地板。然而,在我的场景中,我的起点是作为流的结果得到的RDD[String]。您需要将RDD[String]转换为RDD[Row],然后您可以传递模式以将RDD[Row]转换为DataFrame 请参考这个 当您

我的
Spark Streaming
作业需要处理
RDD[String]
,其中String对应于
csv
文件的一行。我事先不知道模式,所以我需要从RDD推断模式,然后将其内容写入一个
拼花文件。如果我从磁盘读取
csv
文件,我可以通过模式推理将所有内容加载到
DataFrame
中,并直接将其写入拼花地板。然而,在我的场景中,我的起点是作为流的结果得到的
RDD[String]

您需要将
RDD[String]
转换为
RDD[Row]
,然后您可以传递模式以将
RDD[Row]
转换为
DataFrame

请参考这个


当您有一个
RDD[String]
时,您还应该有一个字符串格式(或任何形式——您可以解析)的模式

那么现在呢,

// If we just thing of TWO FIELDS
val schema = "f1;f2"

// Generate the schema based on the string of schema
val f = schema.split(";").map(fn => StructField(fn, StringType))
val schema = StructType(f)

// Convert records of the RDD[String] to Rows
// Assuming each row in CSV have -comma- as delimiter
val rowRDD = <rdd>.map(_.split(",")).map(array => Row(array(0), array(1)))

// Apply the schema to the RDD
val df = spark.createDataFrame(rowRDD, schema)
//如果我们只需要两个字段
val schema=“f1;f2”
//根据模式字符串生成模式
val f=schema.split(“;”).map(fn=>StructField(fn,StringType))
val schema=StructType(f)
//将RDD[String]的记录转换为行
//假设CSV中的每一行都有-逗号-作为分隔符
val rowRDD=.map(u.split(“,”).map(数组=>行(数组(0),数组(1)))
//将模式应用于RDD
val df=spark.createDataFrame(rowRDD,schema)

现在可以使用
df
实例将其保存为拼花地板格式。

在Spark 1.6.x中可以这样做,因为from Datatricks支持使用csv解析器转换
RDD[字符串]
的方法。在Spark版本>=2.0中,此支持已合并到主项目中,并且此方法已从接口中删除。此外,许多方法都是私有的,因此很难绕过,但可能值得探索其底层

通过在Spark 1.6.1上使用Databricks的Spark CSV支持,我们可以执行以下操作:

import com.databricks.spark.csv.CsvParser

val sqlContext = new SQLContext(sparkContext)
val parser = new CsvParser().withInferSchema(true)

val rdd = sparkContext.textFile("/home/maasg/playground/data/sample-no-header.csv")
rdd.take(1) // show a sample data 
// Array[String] = Array(2000,JOHN,KINGS,50)

val df = parser.csvRdd(sqlContext, rdd)
df.schema() // let's inspect the inferred schema
// org.apache.spark.sql.types.StructType = StructType(StructField(C0,IntegerType,true), StructField(C1,StringType,true), StructField(C2,StringType,true), StructField(C3,IntegerType,true))
df.write.parquet("/tmp/sample.parquet") // write it to parquet

在一个
foreachRDD{rdd=>…}
调用中,在Spark Streaming中集成这样的代码应该很简单。

谢谢,但我事先不知道模式,因为我写过,我需要通过从磁盘读取文件来推断模式。我将在我的问题中更清楚地说明。@AndreaT.Bonanno:即使您必须阅读CSV文件,您也需要将列名作为CSV文件的第一行传递,然后只有Spark可以将其转换为DF。当您通过Spark流媒体进行消费时,您不会将架构或列名作为行之一。因此,你应该通过某种方式拥有图式;或者至少,如果您知道每行的列数,您可以定义自己的列名,如
col1;col2;col3
。但是,最后一句话是:你们应该知道你们收到了什么。或者首先编写一个程序来解析RDD[String]中的几行,以便在开始时识别列名;然后通过应用该模式将其转换为DATAFRAME;在您的情况下,提供模式为
str1;str2;str3
;(通过从RDD获取列数)或者,编写您自己的程序(可能是机器学习)来定义列名。如果模式在行之间发生变化,您会期望什么?另外,如果模式未知,您希望拼花地板上有什么样的列结构?你能举例说明吗?