我已经在Qubole(Hive)中创建了一个外部表,该表从s3中读取镶木地板(压缩的:snappy)文件,但是在执行SELECT * table_name
时,我得到除分区列之外的所有列的空值。
我尝试在SERDEPROPERTIES中使用不同的serialization.format值,但是我仍然面临相同的问题。
在删除属性'serialization.format' = '1'
时,我得到了ERROR: Failed with exception java.io.IOException:Can not read value at 0 in block -1 in file s3://path_to_parquet/
。
我检查了实木复合地板文件,并能够使用实木复合地板工具读取数据:
**file_01.snappy.parquet:**
{"col_2":1234,"col_3":ABC}
{"col_2":124,"col_3":FHK}
{"col_2":12515,"col_3":UPO}
**External table stmt:**
CREATE EXTERNAL TABLE parquet_test
(
col2 int,
col3 string
)
PARTITIONED BY (col1 date)
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
WITH SERDEPROPERTIES (
'serialization.format' = '1'
)
STORED AS PARQUET
LOCATION 's3://path_to_parquet'
TBLPROPERTIES ('parquet.compress'='SNAPPY');
Result:
col_1 col_2 col_3
5/3/19 NULL NULL
5/4/19 NULL NULL
5/5/19 NULL NULL
5/6/19 NULL NULL
Expected Result:
col_1 col_2 col_3
5/3/19 1234 ABC
5/4/19 124 FHK
5/5/19 12515 UPO
5/6/19 1234 ABC
答案 0 :(得分:0)
写下面的答案,假设该表是使用Hive创建的,并使用Spark读取的(因为该问题用apache-spark-sql
标记了)
Spark支持区分大小写的架构。
当我们使用数据框API时,可以使用区分大小写的架构进行编写。
示例:
scala> case class Employee(iD: Int, NaMe: String )
defined class Employee
scala> val df =spark.range(10).map(x => Employee(x.toInt, s"name$x")).write.save("file:///tmp/data/")
scala> spark.read.parquet("file:///tmp/data/").printSchema
root
|-- iD: integer (nullable = true)
|-- NaMe: string (nullable = true)
请注意,在上述示例中,保留了敏感性。
当我们在从Spark创建的数据之上创建Hive表时,Hive将能够正确读取它,因为它不区分大小写。
而当使用Spark读取相同的数据时,它将使用Hive中的模式(默认情况下为小写),并且返回的行为null
。
为了克服这个问题,Spark引入了一个配置spark.sql.hive.caseSensitiveInferenceMode
。
object HiveCaseSensitiveInferenceMode extends Enumeration {
val INFER_AND_SAVE, INFER_ONLY, NEVER_INFER = Value
}
val HIVE_CASE_SENSITIVE_INFERENCE = buildConf("spark.sql.hive.caseSensitiveInferenceMode")
.doc("Sets the action to take when a case-sensitive schema cannot be read from a Hive " +
"table's properties. Although Spark SQL itself is not case-sensitive, Hive compatible file " +
"formats such as Parquet are. Spark SQL must use a case-preserving schema when querying " +
"any table backed by files containing case-sensitive field names or queries may not return " +
"accurate results. Valid options include INFER_AND_SAVE (the default mode-- infer the " +
"case-sensitive schema from the underlying data files and write it back to the table " +
"properties), INFER_ONLY (infer the schema but don't attempt to write it to the table " +
"properties) and NEVER_INFER (fallback to using the case-insensitive metastore schema " +
"instead of inferring).")
.stringConf
.transform(_.toUpperCase(Locale.ROOT))
.checkValues(HiveCaseSensitiveInferenceMode.values.map(_.toString))
.createWithDefault(HiveCaseSensitiveInferenceMode.INFER_AND_SAVE.toString)
INFER_AND_SAVE
-Spark推断模式并存储在metastore中,作为表TBLEPROPERTIES
的一部分(desc extended <table name>
应该显示这一点)
如果该属性的值是INFER_AND_SAVE
或INFER_ONLY
的 NOT ,则Spark使用metastore表中的架构,并且将无法读取实木复合地板文件。
自Spark 2.2.0起,该属性的默认值为INFER_AND_SAVE
。
我们可以检查以下内容是否是与模式敏感性有关的问题:
1. spark.sql.hive.caseSensitiveInferenceMode
的值(spark.sql("set spark.sql.hive.caseSensitiveInferenceMode")
应该表明这一点)
2.如果使用Spark创建的数据
3.如果2为true,请检查Schema是否区分大小写(spark.read(<location>).printSchema
)
4.如果3使用区分大小写的模式,并且1的输出不是INFER_AND_SAVE
/ INFER_ONLY
,则设置spark.sql("set spark.sql.hive.caseSensitiveInferenceMode=INFER_AND_SAVE")
,删除表,重新创建表并尝试从Spark读取数据。