为什么Impala在Spark SQL写入后不能读取镶木地板文件?

时间:2017-05-31 08:43:53

标签: java apache-spark apache-spark-sql parquet

Spark解释木条柱的方式存在一些问题。

我有一个带有已确认架构的Oracle源代码(df.schema()方法):

root
  |-- LM_PERSON_ID: decimal(15,0) (nullable = true)
  |-- LM_BIRTHDATE: timestamp (nullable = true)
  |-- LM_COMM_METHOD: string (nullable = true)
  |-- LM_SOURCE_IND: string (nullable = true)
  |-- DATASET_ID: decimal(38,0) (nullable = true)
  |-- RECORD_ID: decimal(38,0) (nullable = true)

然后保存为Parquet - df.write()。parquet()方法 - 具有相应的消息类型(由Spark确定):

  message spark_schema {
    optional int64 LM_PERSON_ID (DECIMAL(15,0));
    optional int96 LM_BIRTHDATE;
    optional binary LM_COMM_METHOD (UTF8);
    optional binary LM_SOURCE_IND (UTF8);
    optional fixed_len_byte_array(16) DATASET_ID (DECIMAL(38,0));
    optional fixed_len_byte_array(16) RECORD_ID (DECIMAL(38,0));
}

我的应用程序然后使用HashMap生成表DDL以进行类型转换,例如:

CREATE EXTERNAL TABLE IF NOT EXISTS 
ELM_PS_LM_PERSON (
LM_PERSON_ID DECIMAL(15,0)
,LM_BIRTHDATE TIMESTAMP
,LM_COMM_METHOD STRING
,LM_SOURCE_IND STRING
,DATASET_ID DECIMAL(38,0)
,RECORD_ID DECIMAL(38,0)
) PARTITIONED BY (edi_business_day STRING) STORED AS PARQUET LOCATION '<PATH>'

我的问题是Impala无法读取该表,因为它不会接受LM_PERSON_ID作为十进制字段。如果此列设置为BIGINT,则表格仅读取镶木地板文件。

Query 8d437faf6323f0bb:b7ba295d028c8fbe: 0% Complete (0 out of 1)
File 'hdfs:dev/ELM/ELM_PS_LM_PERSON/part-00000-fcdbd3a5-9c93-490e-a124-c2a327a17a17.snappy.parquet' has an incompatible Parquet schema for column 'rbdshid1.elm_ps_lm_person_2.lm_person_id'. 
Column type: DOUBLE, Parquet schema:
optional int64 LM_PERSON_ID [i:0 d:1 r:0]

我怎么知道何时用十进制字段替换BIGINT?

是否记录了镶木地板消息类型但无法访问?

两个十进制字段转换为fixed_len_byte_array(16),LM_PERSON_ID转换为int64

我能想到的唯一解决方案是创建表,测试它是否返回,如果没有丢弃,则将十进制字段逐个替换为BIGINT,每次测试。

我在这里缺少什么?我可以为镶木地板文件强制执行十进制模式吗?

1 个答案:

答案 0 :(得分:5)

非常相似SPARK-20297 Parquet Decimal(12,2) written by Spark is unreadable by Hive and Impala最近(20 / Apr / 17 01:59)被解决为非问题。

要点是使用spark.sql.parquet.writeLegacyFormat属性并以遗留格式编写镶木地板元数据(我在Configuration下的官方文档中没有看到这些内容,并报告为改进SPARK-20937)。

  

当启用spark.sql.parquet.writeLegacyFormat时,Hive和Impala可以读取Spark编写的数据。

     

它遵循较新的标准 - https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#decimal,我错过了文档。   那不就是Impala或Hive中的错误吗?

     

int32 / int64选项出现在小数规范的原始版本中,它们并没有得到广泛实施:https://github.com/Parquet/parquet-format/commit/b2836e591da8216cfca47075baee2c9a7b0b9289。所以它不是一个新的/旧版本的东西,它只是许多系统没有实现的替代表示。

SPARK-10400也可以是非常有用的阅读(关于spark.sql.parquet.writeLegacyFormat属性的历史记录):

  

我们引入了SQL选项&#34; spark.sql.parquet.followParquetFormatSpec&#34;同时致力于在SPARK-6777中实现Parquet向后兼容性规则。它表明我们是否应该使用Spark 1.4和之前版本采用的传统Parquet格式或者镶木地板格式规范中定义的标准格式。但是,这个选项的名称有点混乱,因为它不是超级直观的,为什么我们不应该遵循规范。将它重命名为&#34; spark.sql.parquet.writeLegacyFormat&#34;会很高兴。并反转其默认值(它们具有相反的含义)。请注意,此选项不是&#34; public&#34; (isPublic是假的)。