我有一个Scrunch Spark管道,当我尝试使用以下方法将其输出保存为Avro格式时:
data.write(to.avroFile(path))
我得到以下例外:
java.lang.ClassCastException: org.apache.crunch.types.writable.WritableType cannot be cast to org.apache.crunch.types.avro.AvroType
at org.apache.crunch.io.avro.AvroFileTarget.configureForMapReduce(AvroFileTarget.java:77) ~[crunch-core-0.14.0-SNAPSHOT.jar:0.14.0-SNAPSHOT]
at org.apache.crunch.impl.spark.SparkRuntime.monitorLoop(SparkRuntime.java:327) [crunch-spark-0.14.0-SNAPSHOT.jar:0.14.0-SNAPSHOT]
at org.apache.crunch.impl.spark.SparkRuntime.access$000(SparkRuntime.java:80) [crunch-spark-0.14.0-SNAPSHOT.jar:0.14.0-SNAPSHOT]
at org.apache.crunch.impl.spark.SparkRuntime$2.run(SparkRuntime.java:139) [crunch-spark-0.14.0-SNAPSHOT.jar:0.14.0-SNAPSHOT]
虽然这样可以正常工作:
data.write(to.textFile(path))
(在两种情况下data
都是PCollection
的相同实例和path
字符串
我理解为什么会发生错误,我尝试编写的PCollection
属于Writable
类型系列而不是Avro
类型。我不清楚的是如何在Scrunch中决定我的PCollection属于一个而不是另一个。
然而,这种机制在Crunch中似乎更为明显。根据{{3}}:
Crunch支持两种不同的类型系列,每种类型都实现了PTypeFamily接口:一个用于Hadoop的可写接口,另一个用于基于Apache Avro。还有一些类包含每个PTypeFamily的静态工厂方法,以便于导入和使用:一个用于Writable,一个用于Avros。
然后:
对于大多数管道,您将专门使用一个类型系列,因此您可以通过将Writables或Avros类中的所有方法导入到类中来减少类中的某些样板
import static org.apache.crunch.types.avro.Avros。*;
事实上,在正式回购中为Crunch提供的示例中,可以看出这是如何明确的。请参阅official Crunch documentation示例中的以下代码段:
PCollection<String> lines = pipeline.readTextFile(args[0]);
PCollection<String> words = lines.parallelDo(new DoFn<String, String>() {
public void process(String line, Emitter<String> emitter) {
for (String word : line.split("\\s+")) {
emitter.emit(word);
}
}
}, Writables.strings()); // Indicates the serialization format
PTable<String, Long> counts = words.count();
虽然等效的WordCount是这样的:
def countWords(file: String) = {
read(from.textFile(file))
.flatMap(_.split("\\W+").filter(!_.isEmpty()))
.count
}
没有明确的,或者据我所知,提供了对WritableFamily
的隐式引用。
那么Scrunch如何决定使用哪种Writable族类型?它是基于原始输入源的默认值吗? (例如,如果从文本文件中读取,它是可写的,如果来自Avro然后是Avro)如果是这种情况,那么我怎么能改变从一个源读取的类型并写入目标taht属于不同的家庭类型在Scrunch?