我需要编写一个读取DataSet [Row]的作业并将其转换为DataSet [CustomClass] CustomClass是protobuf类。
val protoEncoder = Encoders.bean(classOf[CustomClass])
val transformedRows = rows.map {
case Row(f1: String, f2: Long ) => {
val pbufClass = CustomClass.newBuilder()
.setF1(f1)
.setF2(f2)
pbufClass.build()}}(protoEncoder)
然而,看起来像Protobuf类并不是真正的Java Bean,我确实在下面获得了NPE
val x = Encoders.bean(classOf[CustomClass])
如何确保作业可以发出类型的数据集 DataSet [CustomClass]其中CustomClass是protobuf类。 有关为类编写自定义编码器的任何指针/示例吗?
NPE:
val encoder2 = Encoders.bean(classOf[CustomClass])
java.lang.NullPointerException
at org.spark_project.guava.reflect.TypeToken.method(TypeToken.java:465)
at org.apache.spark.sql.catalyst.JavaTypeInference$$anonfun$2.apply(JavaTypeInference.scala:126)
at org.apache.spark.sql.catalyst.JavaTypeInference$$anonfun$2.apply(JavaTypeInference.scala:125)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:186)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
at scala.collection.mutable.ArrayOps$ofRef.map(ArrayOps.scala:186)
at org.apache.spark.sql.catalyst.JavaTypeInference$.org$apache$spark$sql$catalyst$JavaTypeInference$$inferDataType(JavaTypeInference.scala:125)
at org.apache.spark.sql.catalyst.JavaTypeInference$.inferDataType(JavaTypeInference.scala:55)
at org.apache.spark.sql.catalyst.encoders.ExpressionEncoder$.javaBean(ExpressionEncoder.scala:89)
at org.apache.spark.sql.Encoders$.bean(Encoders.scala:142)
... 48 elided
Bean编码器内部使用
JavaTypeInference.serializerFor(protoClass)
如果我尝试在自定义编码器中执行相同操作,则会收到更具描述性的错误消息:
Caused by: java.lang.UnsupportedOperationException: Cannot infer type for class xxx.yyy.CustomClass because it is not bean-compliant
at org.apache.spark.sql.catalyst.JavaTypeInference$.org$apache$spark$sql$catalyst$JavaTypeInference$$serializerFor(JavaTypeInference.scala:430)
at org.apache.spark.sql.catalyst.JavaTypeInference$.serializerFor(JavaTypeInference.scala:337)
at xxx.yyy..EncoderHolder$.protoEncoder(xxx.scala:69)
at xxx.yyy..EncoderHolder$.encoder$lzycompute$1(xxx.scala:82)
at xxx.yyy..EncoderHolder$.encoder$1(xxx.scala:82)
at xxx.yyy..EncoderHolder$.liftedTree1$1(xxx.scala:84)
at xxx.yyy..EncoderHolder$.<init>(xxx.scala:81)
at xxx.yyy..EncoderHolder$.<clinit>(xxx.scala)
答案 0 :(得分:2)
要将Row转换为Protobuf类,您可以使用sparksql-protobuf
该库提供了用于处理Protobuf对象的实用程序 SparkSQL。它提供了一种读取SparkSQL编写的镶木地板文件的方法 返回作为兼容的protobuf对象的RDD。它也可以转换 将protobuf对象的RDD转换为DataFrame。
为您的for (var i = 1; i < 11; i++) {
var mydiv="#cc-"+i;
$("mydiv iframe").on('hidden.bs.modal', function (e) {
$('"#cc-' + i + ' iframe"').attr("src", $('"#cc-' + i + 'iframe"').attr("src"));
});
}
文件添加依赖关系
build.sbt
)
您可以按照库中的一些示例开始
我希望这有帮助!
答案 1 :(得分:1)
My experience with Encoders are not very promising此时我建议不要花更多的时间在这上面。
我宁愿考虑替代方案以及如何使用Spark的方式,并在最后一步将Spark计算的结果映射到protobuf生成的类。
答案 2 :(得分:0)
虽然不是一个严格的答案,但我确实得到了解决方法。如果我们使用RDD,则不需要编码器。
val rows =
spark.sql("select * from tablename").as[CaseClass].rdd
val transformedRows = rows.map {
case Row(f1: String, f2: Long ) => {
val pbufClass = CustomClass.newBuilder()
.setF1(f1)
.setF2(f2)
pbufClass.build()}}
这给了我一个可以使用的Protobuf类的RDD。
答案 3 :(得分:0)
我这样做的方式:我使用了saurfang的sparksql-protobuf库(Github上提供的代码)。您直接获得RDD [ProtoSchema],但很难转换为数据集[ProtoSchema]。我用它来获取信息,主要附加到具有用户定义函数的另一个RDD。
1:导入库
使用Maven:
String value = response.split("TOTAL CREDITS:</B>&NBSP;")[1].split("</FONT>")[0].trim();
2:以RDD [ProtoSchema]
的形式读取数据<dependencies>
<dependency>
<groupId>com.github.saurfang</groupId>
<artifactId>sparksql-protobuf_2.10</artifactId>
<version>0.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.parquet</groupId>
<artifactId>parquet-protobuf</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.5.1</version>
</dependency>
</dependencies>
...
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>bintray-saurfang-maven</id>
<name>bintray</name>
<url>https://dl.bintray.com/saurfang/maven</url>
</repository>
</repositories>
(可选)添加PathFilter(Hadoop API)
如果您想添加PathFilter类(就像您以前使用的Hadoop一样),或者激活Hadoop的其他选项,您可以这样做:
val sess: SparkSession = ...
val proto_rdd = new ProtoParquetRDD[ProtoSchema](sess.sparkContext, input_path, classOf[ProtoSchema])
但是,如果您想使用SparkSession阅读其他内容,请不要忘记清除Hadoop配置:
sess.sparkContext.hadoopConfiguration.setBoolean("mapreduce.input.fileinputformat.input.dir.recursive", true)
sess.sparkContext.hadoopConfiguration.setClass("mapreduce.input.pathFilter.class", classOf[MyPathFiltering], classOf[PathFilter])
答案 4 :(得分:0)
默认序列化也不适用于我的protobuf对象。
但是,事实证明内部火花是使用Kryo。所以如果你这样做
private var observer: NSKeyValueObservation?
// ... other code
self.observer = audioSession?.observe(\.outputVolume) { [weak self] (audioSession, _) in
guard let `self` = self else { return }
let mute = audioSession.outputVolume
var isMuted = false
if (mute == 0) && (!self.player.isMuted) {
isMuted = true
} else if (mute.isZero) && (self.player.isMuted) {
isMuted = false
}
// do what's needed here with `isMuted`
}
有效。