Scala 无法从Sqoop创建的Spark中的序列文件创建数据帧

Scala 无法从Sqoop创建的Spark中的序列文件创建数据帧,scala,apache-spark,hadoop,sqoop,sequencefile,Scala,Apache Spark,Hadoop,Sqoop,Sequencefile,我想读取订单数据并从中创建RDD,该数据作为序列文件存储在cloudera的hadoop fs中vm。以下是我的步骤: 1) 将订单数据导入为序列文件: sqoop import --connect jdbc:mysql://localhost/retail_db --username retail_dba --password cloudera --table orders -m 1 --target-dir /ordersDataSet --as-sequencefile 2) 正

我想读取
订单
数据并从中创建RDD,该数据作为
序列
文件存储在
cloudera的hadoop fs中
vm
。以下是我的步骤:

1) 将订单数据导入为序列文件:

sqoop import --connect jdbc:mysql://localhost/retail_db --username retail_dba --password cloudera  --table orders -m 1 --target-dir /ordersDataSet --as-sequencefile   
2) 正在spark scala中读取文件:

Spark 1.6

val sequenceData=sc.sequenceFile("/ordersDataSet",classOf[org.apache.hadoop.io.Text],classOf[org.apache.hadoop.io.Text]).map(rec => rec.toString())  
3) 当我尝试从上面的RDD读取数据时,它抛出以下错误:

Caused by: java.io.IOException: WritableName can't load class: orders
    at org.apache.hadoop.io.WritableName.getClass(WritableName.java:77)
    at org.apache.hadoop.io.SequenceFile$Reader.getValueClass(SequenceFile.java:2108)
    ... 17 more
Caused by: java.lang.ClassNotFoundException: Class orders not found
    at org.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:2185)
    at org.apache.hadoop.io.WritableName.getClass(WritableName.java:75)
    ... 18 more
我不知道为什么它说找不到订单。我哪里做错了

我也参考了这两个链接中的代码,但运气不好:
1)

2) sqoop与此无关,下面是一个更现实的场景示例,其中saveAsSequenceFile始终假定k,v对-这可能会帮助您:

import org.apache.hadoop.io._

val RDD = sc.parallelize( List( (1, List("A", "B")) , (2, List("B", "C")) , (3, List("C", "D", "E")) ) )
val RDD2 = RDD.map(x => (x._1, x._2.mkString("/")))
RDD2.saveAsSequenceFile("/rushhour/seq-directory/2")

val sequence_data = sc.sequenceFile("/rushhour/seq-directory/*", classOf[IntWritable], classOf[Text])
                  .map{case (x, y) => (x.get(), y.toString().split("/")(0), y.toString().split("/")(1))}

sequence_data.collect
返回:

res20: Array[(Int, String, String)] = Array((1,A,B), (2,B,C), (3,C,D), (1,A,B), (2,B,C), (3,C,D))

我不确定您是否需要RDD或DF,但将RDD转换为DF当然很简单。

我找到了解决我自己问题的方法。好吧,我将写一个冗长的解决方案,但我希望它会有一些意义

1) 当我试图使用
SQOOP
读取在
HDFS
中导入的数据时,由于以下原因,它给出了一个错误:

A) 序列文件是关于
键值对的。因此,当我使用sqoop导入它时,导入的数据不在键值对中,这就是为什么在读取它时抛出错误的原因。
B) 如果您尝试读取
几个字符
,从中可以找出在读取序列文件时作为输入传递所需的
两个类
,您将获得如下数据:

[cloudera@quickstart ~]$ hadoop fs -cat /user/cloudera/problem5/sequence/pa* | head -c 300
SEQ!org.apache.hadoop.io.LongWritableorders�;�M��c�K�����@���-OCLOSED@���PENDING_PAYMENT@���/COMPLETE@���"{CLOSED@���cat: Unable to write to output stream.  
[cloudera@quickstart ~]$ hadoop fs -cat /user/cloudera/problem5/sequence/part-00000 | head -c 300
SEQorg.apache.hadoop.io.Textorg.apache.hadoop.io.Text^#%���8P���11  1374735600000   11599   CLOSED&2#2  1374735600000   256 PENDING_PAYMENT!33  1374735600000   12111   COMPLETE44  1374735600000   8827    CLOSED!55   1374735600000   11318   COMPLETE 66 1374cat: Unable to write to output stream.  

scala> val sequenceData=sc.sequenceFile("/user/cloudera/problem5/sequence",classOf[org.apache.hadoop.io.Text],classOf[org.apache.hadoop.io.Text]).map(rec=>rec.toString)
sequenceData: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[26] at map at <console>:30
scala> sequenceData.take(4).foreach(println)
(1,1    1374735600000   11599   CLOSED)
(2,2    1374735600000   256 PENDING_PAYMENT)
(3,3    1374735600000   12111   COMPLETE)
(4,4    1374735600000   8827    CLOSED)
上面您只能看到
一个类,即
org.apache.hadoop.io.LongWritable
,当我在读取序列数据时传递这个时,它会抛出一个错误,这在文章中提到

val sequenceData=sc.sequenceFile("/ordersDataSet",classOf[org.apache.hadoop.io.LongWritable],classOf[org.apache.hadoop.io.LongWritable]).map(rec => rec.toString())  
我不认为
B
点是该错误的主要原因,但我非常确定
A
点是该错误的真正罪魁祸首

2) 下面是我解决问题的方法

我使用
SQOOP
将数据作为
avro
数据
文件导入到其他目标中。然后,我使用以下方法从avro创建了数据帧:

scala> import com.databricks.spark.avro._;
scala> val avroData=sqlContext.read.avro("path")  
现在我创建了
键值对
,并将其保存为
序列
文件

avroData.map(p=>(p(0).toString,(p(0)+"\t"+p(1)+"\t"+p(2)+"\t"+p(3)))).saveAsSequenceFile("/user/cloudera/problem5/sequence")  
现在,当我尝试读取上面编写的文件中的
几个
字符时,它会给我
两个类
,我在读取文件时需要它们,如下所示:

[cloudera@quickstart ~]$ hadoop fs -cat /user/cloudera/problem5/sequence/pa* | head -c 300
SEQ!org.apache.hadoop.io.LongWritableorders�;�M��c�K�����@���-OCLOSED@���PENDING_PAYMENT@���/COMPLETE@���"{CLOSED@���cat: Unable to write to output stream.  
[cloudera@quickstart ~]$ hadoop fs -cat /user/cloudera/problem5/sequence/part-00000 | head -c 300
SEQorg.apache.hadoop.io.Textorg.apache.hadoop.io.Text^#%���8P���11  1374735600000   11599   CLOSED&2#2  1374735600000   256 PENDING_PAYMENT!33  1374735600000   12111   COMPLETE44  1374735600000   8827    CLOSED!55   1374735600000   11318   COMPLETE 66 1374cat: Unable to write to output stream.  

scala> val sequenceData=sc.sequenceFile("/user/cloudera/problem5/sequence",classOf[org.apache.hadoop.io.Text],classOf[org.apache.hadoop.io.Text]).map(rec=>rec.toString)
sequenceData: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[26] at map at <console>:30
scala> sequenceData.take(4).foreach(println)
(1,1    1374735600000   11599   CLOSED)
(2,2    1374735600000   256 PENDING_PAYMENT)
(3,3    1374735600000   12111   COMPLETE)
(4,4    1374735600000   8827    CLOSED)

最后但并非最不重要的一点,感谢大家的努力。干杯

scala>import org.apache.hadoop.io.Text scala>import org.apache.hadoop.io.intwriteable请导入这些并重试。基本语法是:scala>val result=sc.sequenceFile(“/filepath/filename”,classOf[Text],classOf[intwriteable])。map{case(x,y)=>(x.toString,y.get())}您必须使用Sqoop吗?为什么不使用SparkSQL JDBC?如何实现?ORC类型的数据也是如此。它应该保存在键值对格式中,也可以通过df writer保存。