我在java spark应用程序中对过滤器和类型化数据集的映射使用lambda函数时遇到问题。
我收到此运行时错误
ERROR CodeGenerator: failed to compile: org.codehaus.commons.compiler.CompileException: File 'generated.java', Line 130, Column 126: No applicable constructor/method found for actual parameters "org.apache.spark.unsafe.types.UTF8String"; candidates are: "public static java.sql.Date org.apache.spark.sql.catalyst.util.DateTimeUtils.toJavaDate(int)"
我正在使用以下类和spark 2.2.0。 https://gitlab.com/opencell/test-bigdata
中提供了包含样本数据的完整示例Dataset<CDR> cdr = spark
.read()
.format("csv")
.option("header", "true")
.option("inferSchema", "true")
.option("delimiter", ";")
.csv("CDR_SAMPLE.csv")
.as(Encoders.bean(CDR.class));
long v = cdr.filter(x -> (x.timestamp != null && x.getAccess().length()>0)).count();
System.out.println("validated entries :" + v);
CDR文件定义为gitlab link
修改
val cdrCSVSchema = StructType(Array(
StructField("timestamp", DataTypes.TimestampType),
StructField("quantity", DataTypes.DoubleType),
StructField("access", DataTypes.StringType),
StructField("param1", DataTypes.StringType),
StructField("param2", DataTypes.StringType),
StructField("param3", DataTypes.StringType),
StructField("param4", DataTypes.StringType),
StructField("param5", DataTypes.StringType),
StructField("param6", DataTypes.StringType),
StructField("param7", DataTypes.StringType),
StructField("param8", DataTypes.StringType),
StructField("param9", DataTypes.StringType),
StructField("dateParam1", DataTypes.TimestampType),
StructField("dateParam2", DataTypes.TimestampType),
StructField("dateParam3", DataTypes.TimestampType),
StructField("dateParam4", DataTypes.TimestampType),
StructField("dateParam5", DataTypes.TimestampType),
StructField("decimalParam1", DataTypes.DoubleType),
StructField("decimalParam2", DataTypes.DoubleType),
StructField("decimalParam3", DataTypes.DoubleType),
StructField("decimalParam4", DataTypes.DoubleType),
StructField("decimalParam5", DataTypes.DoubleType),
StructField("extraParam", DataTypes.StringType)))
我使用此命令加载CSV文档
val cdr = spark.read.format("csv").option("header", "true").option("delimiter", ";").schema(cdrCSVSchema).csv("CDR_SAMPLE.csv")
然后尝试使用此命令编码并运行lambda函数,但我仍然收到错误
cdr.as[CDR].filter(c => c.timestamp != null).show
答案 0 :(得分:1)
TL; DR 明确定义架构,因为输入数据集没有用于推断(java.sql.Date
字段)类型的值。
对于您的情况,使用无类型数据集API可能是一种解决方案(也许是一种解决方法,老实说我建议它避免从内部行格式进行不必要的反序列化):
cdr.filter(!$"timestamp".isNull).filter(length($"access") > 0).count
(它的Scala和我正在将它翻译成Java作为家庭练习)。
问题在于您使用inferSchema
选项,输入CDR_SAMPLE.csv
文件中的大多数字段都不可用,这些字段构成String类型的大多数字段(当没有可用于推断更具体的值时,这是默认类型类型)。
这使得java.sql.Date
类型的字段,即dateParam1
最多为dateParam5
,类型为String。
import org.opencell.spark.model.CDR
import org.apache.spark.sql.Encoders
implicit val cdrEnc = Encoders.bean(classOf[CDR])
val cdrs = spark.read.
option("inferSchema", "true").
option("delimiter", ";").
option("header", true).
csv("/Users/jacek/dev/sandbox/test-bigdata/CDR_SAMPLE.csv")
scala> cdrs.printSchema
root
|-- timestamp: timestamp (nullable = true)
|-- quantity: integer (nullable = true)
|-- access: string (nullable = true)
|-- param1: string (nullable = true)
|-- param2: string (nullable = true)
|-- param3: string (nullable = true)
|-- param4: string (nullable = true)
|-- param5: string (nullable = true)
|-- param6: string (nullable = true)
|-- param7: string (nullable = true)
|-- param8: string (nullable = true)
|-- param9: string (nullable = true)
|-- dateParam1: string (nullable = true)
|-- dateParam2: string (nullable = true)
|-- dateParam3: string (nullable = true)
|-- dateParam4: string (nullable = true)
|-- dateParam5: string (nullable = true)
|-- decimalParam1: string (nullable = true)
|-- decimalParam2: string (nullable = true)
|-- decimalParam3: string (nullable = true)
|-- decimalParam4: string (nullable = true)
|-- decimalParam5: string (nullable = true)
|-- extraParam: string (nullable = true)
请注意,感兴趣的字段,即dateParam1
到dateParam5
,都是字符串。
|-- dateParam1: string (nullable = true)
|-- dateParam2: string (nullable = true)
|-- dateParam3: string (nullable = true)
|-- dateParam4: string (nullable = true)
|-- dateParam5: string (nullable = true)
当你&#34;假装&#34;通过使用CDR
类中定义的编码器来说明字段的类型是不同的:
private Date dateParam1;
private Date dateParam2;
private Date dateParam3;
private Date dateParam4;
private Date dateParam5;
这是问题的根本原因。 Spark可以从课堂上推断出什么是不同的。没有转换,代码就会起作用,但是因为你坚持......
cdrs.as[CDR]. // <-- HERE is the issue = types don't match
filter(cdr => cdr.timestamp != null).
show // <-- trigger conversion
您在filter
运算符中访问的字段并不重要。问题是转换会导致执行错误(以及整个Java代码生成)。
我怀疑Spark可以做很多事情,因为你请求inferSchema
的数据集没有用于类型推断的值。最好的办法是明确定义架构并使用schema(...)
运算符进行设置。