如何在 spark 2.4.1 中将 jdbc/partitionColumn 类型设置为日期
How to set jdbc/partitionColumn type to Date in spark 2.4.1
我正在尝试使用 spark-sql-2.4.1 版本从 oracle 检索数据。
我尝试将 JdbcOptions 设置如下:
.option("lowerBound", "31-MAR-02");
.option("upperBound", "01-MAY-19");
.option("partitionColumn", "data_date");
.option("numPartitions", 240);
但是报错:
java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
at java.sql.Timestamp.valueOf(Timestamp.java:204)
at org.apache.spark.sql.execution.datasources.jdbc.JDBCRelation$.toInternalBoundValue(JDBCRelation.scala:179)
然后尝试如下
.option("lowerBound", "2002-03-31"); //changed the date format
.option("upperBound", "2019-05-02");
.option("partitionColumn", "data_date");
.option("numPartitions", 240);
仍然没有运气。
那么将日期传递为 "lower/upperBound" 的正确方法是什么?
有没有办法specify/set选项参数数据类型?
第 2 部分
正确检查选项。
在执行查询之前,它们在两者之间被覆盖。
所以更正了。 ...现在错误已解决。
但对于以下选项:
.option("lowerBound", "2002-03-31 00:00:00");
.option("upperBound", "2019-05-01 23:59:59");
.option("timestampFormat", "yyyy-mm-dd hh:mm:ss");
查询字符串:
query -> ( SELECT * FROM MODEL_VALS ) T
它抛出另一个错误:
java.sql.SQLException: ORA-12801: error signaled in parallel query server P022, instance nj0005
ORA-01861: literal does not match format string
给定参数的类型为时间戳,但您提供的是唯一的日期。时间戳的格式为 yyyy-mm-dd hh:mm:ss
,因此您需要相应地提供 2002-03-31 00:00:00
和 2019-05-01 23:59:59
的日期...
必须以这种方式设置以下所有选项才能使其正常工作:
spark.read
.option("header", true)
.option("inferSchema", true)
.option("timestampFormat", "MM/dd/yyyy h:mm:ss a")
.csv("PATH_TO_CSV")
我在解决类似问题时偶然发现了这个问题。
但在这种情况下,Spark 2.4.2 以 'yyyy-MM-dd HH:mm:ss.ssss' 格式向 Oracle 发送日期,并按预期返回 "Not a valid month" 'dd-MMM-yy HH:mm:ss.ssss'。
为了解决这个问题,我遵循了:Spark GitHub Link
,它说:
Override beforeFetch method in OracleDialect to finish the following
two things:
Set Oracle's NLS_TIMESTAMP_FORMAT to "YYYY-MM-DD HH24:MI:SS.FF" to
match java.sql.Timestamp format. Set Oracle's NLS_DATE_FORMAT to
"YYYY-MM-DD" to match java.sql.Date format.
它解决了这个问题。希望对你有帮助。
如果您使用的是 Oracle,请参阅 https://github.com/apache/spark/blob/master/external/docker-integration-tests/src/test/scala/org/apache/spark/sql/jdbc/OracleIntegrationSuite.scala#L441
val df1 = spark.read.format("jdbc")
.option("url", jdbcUrl)
.option("dbtable", "datetimePartitionTest")
.option("partitionColumn", "d")
.option("lowerBound", "2018-07-06")
.option("upperBound", "2018-07-20")
.option("numPartitions", 3)
// oracle.jdbc.mapDateToTimestamp defaults to true. If this flag is not disabled, column d
// (Oracle DATE) will be resolved as Catalyst Timestamp, which will fail bound evaluation of
// the partition column. E.g. 2018-07-06 cannot be evaluated as Timestamp, and the error
// message says: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff].
.option("oracle.jdbc.mapDateToTimestamp", "false")
.option("sessionInitStatement", "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'")
.load()
我正在尝试使用 spark-sql-2.4.1 版本从 oracle 检索数据。 我尝试将 JdbcOptions 设置如下:
.option("lowerBound", "31-MAR-02");
.option("upperBound", "01-MAY-19");
.option("partitionColumn", "data_date");
.option("numPartitions", 240);
但是报错:
java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
at java.sql.Timestamp.valueOf(Timestamp.java:204)
at org.apache.spark.sql.execution.datasources.jdbc.JDBCRelation$.toInternalBoundValue(JDBCRelation.scala:179)
然后尝试如下
.option("lowerBound", "2002-03-31"); //changed the date format
.option("upperBound", "2019-05-02");
.option("partitionColumn", "data_date");
.option("numPartitions", 240);
仍然没有运气。 那么将日期传递为 "lower/upperBound" 的正确方法是什么? 有没有办法specify/set选项参数数据类型?
第 2 部分 正确检查选项。 在执行查询之前,它们在两者之间被覆盖。 所以更正了。 ...现在错误已解决。
但对于以下选项:
.option("lowerBound", "2002-03-31 00:00:00");
.option("upperBound", "2019-05-01 23:59:59");
.option("timestampFormat", "yyyy-mm-dd hh:mm:ss");
查询字符串:
query -> ( SELECT * FROM MODEL_VALS ) T
它抛出另一个错误:
java.sql.SQLException: ORA-12801: error signaled in parallel query server P022, instance nj0005
ORA-01861: literal does not match format string
给定参数的类型为时间戳,但您提供的是唯一的日期。时间戳的格式为 yyyy-mm-dd hh:mm:ss
,因此您需要相应地提供 2002-03-31 00:00:00
和 2019-05-01 23:59:59
的日期...
必须以这种方式设置以下所有选项才能使其正常工作:
spark.read
.option("header", true)
.option("inferSchema", true)
.option("timestampFormat", "MM/dd/yyyy h:mm:ss a")
.csv("PATH_TO_CSV")
我在解决类似问题时偶然发现了这个问题。 但在这种情况下,Spark 2.4.2 以 'yyyy-MM-dd HH:mm:ss.ssss' 格式向 Oracle 发送日期,并按预期返回 "Not a valid month" 'dd-MMM-yy HH:mm:ss.ssss'。 为了解决这个问题,我遵循了:Spark GitHub Link ,它说:
Override beforeFetch method in OracleDialect to finish the following two things:
Set Oracle's NLS_TIMESTAMP_FORMAT to "YYYY-MM-DD HH24:MI:SS.FF" to match java.sql.Timestamp format. Set Oracle's NLS_DATE_FORMAT to "YYYY-MM-DD" to match java.sql.Date format.
它解决了这个问题。希望对你有帮助。
如果您使用的是 Oracle,请参阅 https://github.com/apache/spark/blob/master/external/docker-integration-tests/src/test/scala/org/apache/spark/sql/jdbc/OracleIntegrationSuite.scala#L441
val df1 = spark.read.format("jdbc")
.option("url", jdbcUrl)
.option("dbtable", "datetimePartitionTest")
.option("partitionColumn", "d")
.option("lowerBound", "2018-07-06")
.option("upperBound", "2018-07-20")
.option("numPartitions", 3)
// oracle.jdbc.mapDateToTimestamp defaults to true. If this flag is not disabled, column d
// (Oracle DATE) will be resolved as Catalyst Timestamp, which will fail bound evaluation of
// the partition column. E.g. 2018-07-06 cannot be evaluated as Timestamp, and the error
// message says: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff].
.option("oracle.jdbc.mapDateToTimestamp", "false")
.option("sessionInitStatement", "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'")
.load()