我现有以Avro格式存储的Hive数据。无论出于何种原因,通过执行SELECT读取这些数据非常慢。我还没弄清楚原因。数据已分区,我的WHERE子句始终遵循分区列。所以我决定通过导航到分区路径并使用Spark SQLContext直接读取数据。这工作得更快。但是,我遇到的问题是读取DOUBLE值。 Avro以二进制格式存储它们。 当我在Hive中执行以下查询时:
select myDoubleValue from myTable;
我得到了正确的期望值
841.79
4435.13
.....
但是以下Spark代码:
val path="PathToMyPartition"
val sqlContext = new SQLContext(sc)
val df = sqlContext.read.avro(path)
df.select("myDoubleValue").rdd.map(x => x.getAs[Double](0))
给了我这个例外
java.lang.ClassCastException : [B cannot be cast to java.lang.Double
提供模式或将以二进制格式存储的值转换为双重格式的正确方法是什么?
答案 0 :(得分:0)
我找到了如何将Avro架构转换为Spark SQL StructType的部分解决方案。由Databricks开发的com.databricks.spark.avro.SchemaConverters在其toSqlType(avroSchema:Schema)方法中转换Avro逻辑数据类型时出错,该方法错误地转换了logicalType
{"name":"MyDecimalField","type":["null",{"type":"bytes","logicalType":"decimal","precision":38,"scale":18}],"doc":"","default":null}
到
StructField("MyDecimalField",BinaryType,true)
我在我的本地代码版本中修复了这个错误,现在它正在转换为
StructField("MyDecimalField",DecimalType(38,18),true)
现在,以下代码读取Avro文件并创建一个Dataframe:
val avroSchema = new Schema.Parser().parse(QueryProvider.getQueryString(pathSchema))
val sqlContext = new SQLContext(sc)
val df = sqlContext.read.schema(MyAvroSchemaConverter.toSqlType(avroSchema).dataType.asInstanceOf[StructType]).avro(path)
然而,当我选择我期望为小数的字段
时df.select("MyDecimalField")
我收到以下异常:
scala.MatchError: [B@3e6e0d8f (of class [B)
这是我在这个时候停留的地方,如果有人可以建议下一步做什么或其他任何工作,我将不胜感激。