【问题标题】:Why can't Impala read parquet files after Spark SQL's write?为什么 Spark SQL 写入后 Impala 无法读取 parquet 文件?
【发布时间】:2017-10-31 23:15:45
【问题描述】:

Spark 解释 parquet 列的方式存在一些问题。

我有一个确认架构的 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,该表将仅读取 parquet 文件。

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?

parquet 消息类型已记录但无法访问?

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

我能想到的唯一解决方案是创建表,测试它是否返回,如果不删除并将十进制字段一一替换为 BIGINT,每次测试。

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

【问题讨论】:

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


    【解决方案1】:

    来自Apache Spark官方文档中Parquet FilesConfiguration部分:

    spark.sql.parquet.writeLegacyFormat(默认:false

    如果为 true,数据将以 Spark 1.4 及更早版本的方式写入。例如,十进制值将以 Apache Parquet 的固定长度字节数组格式写入,Apache Hive 和 Apache Impala 等其他系统使用该格式。如果为 false,将使用 Parquet 中较新的格式。例如,小数将以基于 int 的格式写入。如果 Parquet 输出旨在用于不支持这种新格式的系统,请设置为 true。

    官方文档更新前给出的答案

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

    要点是使用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 财产的历史):

    我们在 SPARK-6777 中实施 Parquet 向后兼容规则时引入了 SQL 选项“spark.sql.parquet.followParquetFormatSpec”。它指示我们是应该使用 Spark 1.4 及之前版本采用的遗留 Parquet 格式还是 parquet-format 规范中定义的标准格式。但是,这个选项的名称有点令人困惑,因为我们不应该遵循规范并不是超级直观的。将其重命名为“spark.sql.parquet.writeLegacyFormat”并反转其默认值会很好(它们具有相反的含义)。请注意,此选项不是“public”(isPublic 为 false)。

    【讨论】:

      猜你喜欢
      • 2019-10-28
      • 1970-01-01
      • 2020-12-14
      • 2018-10-04
      • 1970-01-01
      • 2020-10-28
      • 1970-01-01
      • 1970-01-01
      • 2021-04-19
      相关资源
      最近更新 更多