使用 spark.read.format("com.crealytics.spark.excel") 的 inferSchema 推断日期类型列的双精度

Posted

技术标签:

【中文标题】使用 spark.read.format("com.crealytics.spark.excel") 的 inferSchema 推断日期类型列的双精度【英文标题】:inferSchema using spark.read.format("com.crealytics.spark.excel") is inferring double for a date type column 【发布时间】:2017-08-16 12:35:12 【问题描述】:

我正在使用 PySpark(Python 3.6 和 Spark 2.1.1)并尝试使用 spark.read.format("com.crealytics.spark. excel"),但它推断日期类型列的双精度。

例子:

输入 -

 df = spark.read.format("com.crealytics.spark.excel").\
     option("location", "D:\\Users\\ABC\\Desktop\\TmpData\\Input.xlsm").\
     option("spark.read.simpleMode","true"). \
     option("treatEmptyValuesAsNulls", "true").\
     option("addColorColumns", "false").\ 
     option("useHeader", "true").\  option("inferSchema", "true").\
     load("com.databricks.spark.csv")

结果:

Name | Age | Gender | DateOfApplication
________________________________________
X    | 12  |   F    |  5/20/2015

Y    | 15  |   F    |  5/28/2015

Z    | 14  |   F    |  5/29/2015

打印模式 -

df.printSchema()

root
 |-- Name: string (nullable = true)
 |-- Age: double (nullable = true)
 |-- Gender: string (nullable = true)
 |-- DateOfApplication: double (nullable = true)

正在做.show -

df.show()

Name | Age | Gender | DateOfApplication
________________________________________
X    | 12.0  |   F    |   42144.0

Y    | 15.0  |   F    |   16836.0

Z    | 14.0  |   F    |   42152.0

在读取数据集时,日期或任何其他数值被转换为双精度(日期的特殊问题是它完全改变了难以恢复到原始日期的值。

我可以帮忙吗?

【问题讨论】:

【参考方案1】:

插件的作者在这里:)

推断列类型是done in the plugin itself。 那个代码是taken from spark-csv。从代码中可以看出,目前只能推断出 String、Numeric、Boolean 和 Blank 单元格类型。

最好的选择是创建一个使用the corresponding DateUtil API 正确推断日期列的 PR。

第二好的选择是手动指定模式,类似于@addmeaning 的描述。请注意,我刚刚发布了 makes some required parameters optional 和 changes the way the path to the file needs to be specified 的 0.9.0 版本。

yourSchema = StructType()
                     .add("Name", StringType(), True)
                     .add("Age", DoubleType(), True)
                     .add("Gender", StringType(), True)
                     .add("DateOfApplication", DateType(), True)

df = spark.read.format("com.crealytics.spark.excel").
         schema(yourSchema).
         option("useHeader", "true").\
         load("D:\\Users\\ABC\\Desktop\\TmpData\\Input.xlsm")

【讨论】:

您能否详细说明插件如何从具有这种特定格式('5/29/2015')的 excel 文件中的列推断 DateType? 嘿夜景,所以你说我可以使用新发布的 0.9 插件而不是使用 com.crealytics:spark-excel_2.11:0.8.4 并避免使用 inferSchema=true 和它会工作?我会试着让你知道。否则,我将尝试使用 DateUtil 将双精度转换回 Date 类型。会及时通知你。非常感谢! @addmeaning AFAIK,Excel 在内部将日期编码为双精度值。字符串“5/29/2015”只是内部编码的用户可见表示。该插件目前不会将此推断为日期列,因为尚未添加相应的功能。 @AakashBasu 新发布的 0.9 版本默认 inferSchema=false,所以如果你不希望它自动推断 schema,你不需要指定这个选项。无论如何,手动指定的架构将优先于推断的架构,因此您应该能够执行上述示例中的操作。 我评论了我最终选择的解决方案,并且在 0.9.0 版本中还发现了一个新问题,请查看它 - github.com/crealytics/spark-excel/pull/13【参考方案2】:

Spark 无法推断日期类型。您可以手动指定架构并将 DateOfApplication 读取为字符串,然后将其转换为日期。以这种方式阅读您的 df:

    yourSchema = StructType()
                         .add("Name", StringType(), True)
                         .add("Age", DoubleType(), True)
                         .add("Gender", StringType(), True)
                         .add("DateOfApplication", StringType(), True)

    df = spark.read.format("com.crealytics.spark.excel").
             schema(yourSchema).
             option("location", "D:\\Users\\ABC\\Desktop\\TmpData\\Input.xlsm").\
             option("spark.read.simpleMode","true"). \
             option("treatEmptyValuesAsNulls", "true").\
             option("addColorColumns", "false").\ 
             option("useHeader", "true").\  //no infer schema
             load("com.databricks.spark.csv")

【讨论】:

谢谢哥们,但是,我有一个非常广泛的数据集,如大约 30 多列,我是否手动指定架构并将其与输入集连接?没有其他更简单的解决方案? 我只想要数据集中的10列,我可以直接为这10列创建架构并在读取文件时直接选择它们吗? 如果我在读取数据集时避免使用 inferSchema 选项,则会收到此错误(似乎是强制要求)- py4j.protocol.Py4JJavaError: An error occurred while calling o72.load. :java.lang.IllegalArgumentException:选项中缺少参数“inferSchema”。你能帮忙吗? 您可以将文件读取为 rdd 并选择只需要的列,然后将 rdd 转换为 DF 您是否知道任何有助于读取 RDD 的 Excel (.xlsm) 文件的 JAR?你觉得我应该怎么做?【参考方案3】:

指定架构可能会解决此问题。

from pyspark.sql.types import *

schema = StructType([StructField("Name", StringType(), False),
                    StructField("Age", DoubleType(), False),
                    StructField("Gender", StringType(), False),
                    StructField("DateOfApplication", DateType(), True)]) 

将架构添加到 spark.read。

df_excel= spark.read.
                   format("com.crealytics.spark.excel").
                   schema(schema).
                   option("useHeader", "true").
                   option("treatEmptyValuesAsNulls", "false").
                   option("inferSchema", "false"). 
                   option("addColorColumns", "false").
                   load(file_path)

display(df_excel)

【讨论】:

以上是关于使用 spark.read.format("com.crealytics.spark.excel") 的 inferSchema 推断日期类型列的双精度的主要内容,如果未能解决你的问题,请参考以下文章

限制 spark.read pyspark 的分区数

Spark数据框加入问题

使用 Spark 从 Oracle 导入数据

spark sql 性能调优

Spark JDBC:DataFrameReader 无法读取数据类型为 ROWID 的 Oracle 表

Spark - 多次使用数据框而无需多次卸载