对于 1989Dec31 和 31Dec1989 等日期,pyspark 无法识别 spark.read.load() 中的 MMM dateFormat 模式
pyspark doesn't recognize MMM dateFormat pattern in spark.read.load() for dates like 1989Dec31 and 31Dec1989
我在 macOS Sierra 上使用 pyspark
时遇到了一个非常奇怪的问题。我的目标是解析 ddMMMyyyy
格式的日期(例如:31Dec1989
)但会出错。我 运行 Spark 2.0.1,Python 2.7.10 和 Java 1.8.0_101。我也尝试使用 Anaconda 4.2.0(它附带 Python 2.7.12),但也出现错误。
具有相同 Java 版本和 Python 2.7.9 的 Ubuntu 服务器 15.04 上的相同代码可以正常工作。
关于 spark.read.load()
的 official documentation 指出:
dateFormat
– sets the string that indicates a date format. Custom date
formats follow the formats at java.text.SimpleDateFormat
. This applies
to date type. If None is set, it uses the default value value,
yyyy-MM-dd
.
official Java documentation 谈到 MMM
是解析月份名称(如 Jan
、Dec
等的正确格式,但它会抛出很多以以下开头的错误java.lang.IllegalArgumentException
。
文档指出 LLL
也可以使用,但 pyspark
无法识别并抛出 pyspark.sql.utils.IllegalArgumentException: u'Illegal pattern component: LLL'
.
我知道 dateFormat
的另一种解决方案,但这是解析数据的最快方法,也是最简单的编码方法。我在这里错过了什么?
为了运行以下示例,您只需将test.csv
和test.py
放在同一目录中,然后运行<spark-bin-directory>/spark-submit <working-directory>/test.py
。
我的测试用例使用 ddMMMyyyy
格式
我有一个名为 test.csv
的纯文本文件,其中包含以下两行:
col1
31Dec1989
代码如下:
from pyspark.sql import SparkSession
from pyspark.sql.types import *
spark = SparkSession \
.builder \
.appName("My app") \
.config("spark.some.config.option", "some-value") \
.getOrCreate()
struct = StructType([StructField("column", DateType())])
df = spark.read.load( "test.csv", \
schema=struct, \
format="csv", \
sep=",", \
header="true", \
dateFormat="ddMMMyyyy", \
mode="FAILFAST")
df.show()
我收到错误。我也尝试在日期和年份之前或之后移动月份名称(例如:1989Dec31
和 yyyyMMMdd
)但没有成功。
使用 ddMMyyyy
格式的工作示例
除日期格式外,此示例与上一个示例相同。 test.csv
现在包含:
col1
31121989
以下代码打印test.csv
的内容:
from pyspark.sql import SparkSession
from pyspark.sql.types import *
spark = SparkSession \
.builder \
.appName("My app") \
.config("spark.some.config.option", "some-value") \
.getOrCreate()
struct = StructType([StructField("column", DateType())])
df = spark.read.load( "test.csv", \
schema=struct, \
format="csv", \
sep=",", \
header="true", \
dateFormat="ddMMyyyy", \
mode="FAILFAST")
df.show()
输出如下(我省略了各种冗长的行):
+----------+
| column|
+----------+
|1989-12-31|
+----------+
UPDATE1
我做了一个简单的 Java class 使用 java.text.SimpleDateFormat
:
import java.text.*;
import java.util.Date;
class testSimpleDateFormat
{
public static void main(String[] args)
{
SimpleDateFormat format = new SimpleDateFormat("yyyyMMMdd");
String dateString = "1989Dec31";
try {
Date parsed = format.parse(dateString);
System.out.println(parsed.toString());
}
catch(ParseException pe) {
System.out.println("ERROR: Cannot parse \"" + dateString + "\"");
}
}
}
此代码不适用于我的环境并抛出此错误:
java.text.ParseException: Unparseable date: "1989Dec31"
但在另一个系统上运行完美 (Ubuntu 15.04)。这似乎是一个 Java 问题,但我不知道如何解决。我安装了 Java 的最新可用版本并且我的所有软件都已更新。
有什么想法吗?
UPDATE2
我找到了如何通过指定 Locale.US
:
使其在纯 Java 下工作
import java.text.*;
import java.util.Date;
import java.util.*;
class HelloWorldApp
{
public static void main(String[] args)
{
SimpleDateFormat format = new SimpleDateFormat("yyyyMMMdd", Locale.US);
String dateString = "1989Dec31";
try {
Date parsed = format.parse(dateString);
System.out.println(parsed.toString());
}
catch(ParseException pe) {
System.out.println(pe);
System.out.println("ERROR: Cannot parse \"" + dateString + "\"");
}
}
}
现在,问题变成了:如何在 pyspark
中指定 Java 的语言环境?
您已经将问题确定为 Spark 的 JVM 中的语言环境之一。您可以在启动 spark shell 后转到 http://localhost:4040/environment/ 来检查您的 Spark JVM 使用的默认国家和语言设置。在系统属性部分下搜索 "user.language" 和 user.country"。它应该是 US 和 en。
如果需要,您可以像这样更改它们。
选项 1:编辑 {SPARK_HOME}/conf 文件夹中的 spark-defaults.conf 文件。添加以下设置:
spark.executor.extraJavaOptions -Duser.country=US -Duser.language=en
spark.driver.extraJavaOptions -Duser.country=US -Duser.language=en
选项 2:将选项作为命令行选项传递给 pyspark
$pyspark --conf spark.driver.extraJavaOptions="-Duser.country=US,-Duser.language=en" spark.executor.extraJavaOptions="-Duser.country=US,-Duser.language=en"
选项 3:更改 Mac OS 中的语言和地区。例如 - What settings in Mac OS X affect the `Locale` and `Calendar` inside Java?
P.S。 - 我只验证了选项 1 有效。我还没有尝试过其他 2 个。有关 Spark 配置的更多详细信息在此处 - http://spark.apache.org/docs/latest/configuration.html#runtime-environment
可能值得注意的是,这已于 2016 年 10 月 24 日在 Spark mailing list 上解决。根据原始发帖人:
This worked without setting other options: spark/bin/spark-submit --conf "spark.driver.extraJavaOptions=-Duser.language=en" test.py
并在 Spark 2.0.1 中被报告为 SPARK-18076(将 DateFormat、NumberFormat 中使用的默认区域设置修复为 Locale.US)并在 Spark 2.1.0 中得到解决。
此外,如果使用 Spark 2.1.0,提交者提出的特定问题不再需要上述解决方法(传入 --conf "spark.driver.extraJavaOptions=-Duser.language=en"
),但一个显着的副作用是 Spark 2.1.0用户,如果您想解析非英语日期,则不能再传递 --conf "spark.driver.extraJavaOptions=-Duser.language=fr"
之类的内容,例如"31mai1989".
事实上,从 Spark 2.1.0 开始,当使用 spark.read()
加载 csv 时,我认为不再可能使用 dateFormat
选项来解析日期,例如 "31mai1989 ",即使您的默认语言环境是法语。我什至将 OS 中的默认区域和语言更改为法语,并传入了我能想到的几乎所有区域设置排列,即
JAVA_OPTS="-Duser.language=fr -Duser.country=FR -Duser.region=FR" \
JAVA_ARGS="-Duser.language=fr -Duser.country=FR -Duser.region=FR" \
LC_ALL=fr_FR.UTF-8 \
spark-submit \
--conf "spark.driver.extraJavaOptions=-Duser.country=FR -Duser.language=fr -Duser.region=FR" \
--conf "spark.executor.extraJavaOptions=-Duser.country=FR -Duser.language=fr -Duser.region=FR" \
test.py
无济于事,导致
java.lang.IllegalArgumentException
at java.sql.Date.valueOf(Date.java:143)
at org.apache.spark.sql.catalyst.util.DateTimeUtils$.stringToTime(DateTimeUtils.scala:137)
但同样,这只会影响在 Spark 2.1.0 中解析非英语日期。
我还没有测试过这个,但我会尝试以下方法:
--conf spark.executor.extraJavaOptions="-Duser.timezone=America/Los_Angeles"
--conf spark.driver.extraJavaOptions="-Duser.timezone=America/Los_Angeles"
我在 macOS Sierra 上使用 pyspark
时遇到了一个非常奇怪的问题。我的目标是解析 ddMMMyyyy
格式的日期(例如:31Dec1989
)但会出错。我 运行 Spark 2.0.1,Python 2.7.10 和 Java 1.8.0_101。我也尝试使用 Anaconda 4.2.0(它附带 Python 2.7.12),但也出现错误。
具有相同 Java 版本和 Python 2.7.9 的 Ubuntu 服务器 15.04 上的相同代码可以正常工作。
关于 spark.read.load()
的 official documentation 指出:
dateFormat
– sets the string that indicates a date format. Custom date formats follow the formats atjava.text.SimpleDateFormat
. This applies to date type. If None is set, it uses the default value value,yyyy-MM-dd
.
official Java documentation 谈到 MMM
是解析月份名称(如 Jan
、Dec
等的正确格式,但它会抛出很多以以下开头的错误java.lang.IllegalArgumentException
。
文档指出 LLL
也可以使用,但 pyspark
无法识别并抛出 pyspark.sql.utils.IllegalArgumentException: u'Illegal pattern component: LLL'
.
我知道 dateFormat
的另一种解决方案,但这是解析数据的最快方法,也是最简单的编码方法。我在这里错过了什么?
为了运行以下示例,您只需将test.csv
和test.py
放在同一目录中,然后运行<spark-bin-directory>/spark-submit <working-directory>/test.py
。
我的测试用例使用 ddMMMyyyy
格式
我有一个名为 test.csv
的纯文本文件,其中包含以下两行:
col1
31Dec1989
代码如下:
from pyspark.sql import SparkSession
from pyspark.sql.types import *
spark = SparkSession \
.builder \
.appName("My app") \
.config("spark.some.config.option", "some-value") \
.getOrCreate()
struct = StructType([StructField("column", DateType())])
df = spark.read.load( "test.csv", \
schema=struct, \
format="csv", \
sep=",", \
header="true", \
dateFormat="ddMMMyyyy", \
mode="FAILFAST")
df.show()
我收到错误。我也尝试在日期和年份之前或之后移动月份名称(例如:1989Dec31
和 yyyyMMMdd
)但没有成功。
使用 ddMMyyyy
格式的工作示例
除日期格式外,此示例与上一个示例相同。 test.csv
现在包含:
col1
31121989
以下代码打印test.csv
的内容:
from pyspark.sql import SparkSession
from pyspark.sql.types import *
spark = SparkSession \
.builder \
.appName("My app") \
.config("spark.some.config.option", "some-value") \
.getOrCreate()
struct = StructType([StructField("column", DateType())])
df = spark.read.load( "test.csv", \
schema=struct, \
format="csv", \
sep=",", \
header="true", \
dateFormat="ddMMyyyy", \
mode="FAILFAST")
df.show()
输出如下(我省略了各种冗长的行):
+----------+
| column|
+----------+
|1989-12-31|
+----------+
UPDATE1
我做了一个简单的 Java class 使用 java.text.SimpleDateFormat
:
import java.text.*;
import java.util.Date;
class testSimpleDateFormat
{
public static void main(String[] args)
{
SimpleDateFormat format = new SimpleDateFormat("yyyyMMMdd");
String dateString = "1989Dec31";
try {
Date parsed = format.parse(dateString);
System.out.println(parsed.toString());
}
catch(ParseException pe) {
System.out.println("ERROR: Cannot parse \"" + dateString + "\"");
}
}
}
此代码不适用于我的环境并抛出此错误:
java.text.ParseException: Unparseable date: "1989Dec31"
但在另一个系统上运行完美 (Ubuntu 15.04)。这似乎是一个 Java 问题,但我不知道如何解决。我安装了 Java 的最新可用版本并且我的所有软件都已更新。
有什么想法吗?
UPDATE2
我找到了如何通过指定 Locale.US
:
import java.text.*;
import java.util.Date;
import java.util.*;
class HelloWorldApp
{
public static void main(String[] args)
{
SimpleDateFormat format = new SimpleDateFormat("yyyyMMMdd", Locale.US);
String dateString = "1989Dec31";
try {
Date parsed = format.parse(dateString);
System.out.println(parsed.toString());
}
catch(ParseException pe) {
System.out.println(pe);
System.out.println("ERROR: Cannot parse \"" + dateString + "\"");
}
}
}
现在,问题变成了:如何在 pyspark
中指定 Java 的语言环境?
您已经将问题确定为 Spark 的 JVM 中的语言环境之一。您可以在启动 spark shell 后转到 http://localhost:4040/environment/ 来检查您的 Spark JVM 使用的默认国家和语言设置。在系统属性部分下搜索 "user.language" 和 user.country"。它应该是 US 和 en。
如果需要,您可以像这样更改它们。
选项 1:编辑 {SPARK_HOME}/conf 文件夹中的 spark-defaults.conf 文件。添加以下设置:
spark.executor.extraJavaOptions -Duser.country=US -Duser.language=en
spark.driver.extraJavaOptions -Duser.country=US -Duser.language=en
选项 2:将选项作为命令行选项传递给 pyspark
$pyspark --conf spark.driver.extraJavaOptions="-Duser.country=US,-Duser.language=en" spark.executor.extraJavaOptions="-Duser.country=US,-Duser.language=en"
选项 3:更改 Mac OS 中的语言和地区。例如 - What settings in Mac OS X affect the `Locale` and `Calendar` inside Java?
P.S。 - 我只验证了选项 1 有效。我还没有尝试过其他 2 个。有关 Spark 配置的更多详细信息在此处 - http://spark.apache.org/docs/latest/configuration.html#runtime-environment
可能值得注意的是,这已于 2016 年 10 月 24 日在 Spark mailing list 上解决。根据原始发帖人:
This worked without setting other options:
spark/bin/spark-submit --conf "spark.driver.extraJavaOptions=-Duser.language=en" test.py
并在 Spark 2.0.1 中被报告为 SPARK-18076(将 DateFormat、NumberFormat 中使用的默认区域设置修复为 Locale.US)并在 Spark 2.1.0 中得到解决。
此外,如果使用 Spark 2.1.0,提交者提出的特定问题不再需要上述解决方法(传入 --conf "spark.driver.extraJavaOptions=-Duser.language=en"
),但一个显着的副作用是 Spark 2.1.0用户,如果您想解析非英语日期,则不能再传递 --conf "spark.driver.extraJavaOptions=-Duser.language=fr"
之类的内容,例如"31mai1989".
事实上,从 Spark 2.1.0 开始,当使用 spark.read()
加载 csv 时,我认为不再可能使用 dateFormat
选项来解析日期,例如 "31mai1989 ",即使您的默认语言环境是法语。我什至将 OS 中的默认区域和语言更改为法语,并传入了我能想到的几乎所有区域设置排列,即
JAVA_OPTS="-Duser.language=fr -Duser.country=FR -Duser.region=FR" \
JAVA_ARGS="-Duser.language=fr -Duser.country=FR -Duser.region=FR" \
LC_ALL=fr_FR.UTF-8 \
spark-submit \
--conf "spark.driver.extraJavaOptions=-Duser.country=FR -Duser.language=fr -Duser.region=FR" \
--conf "spark.executor.extraJavaOptions=-Duser.country=FR -Duser.language=fr -Duser.region=FR" \
test.py
无济于事,导致
java.lang.IllegalArgumentException
at java.sql.Date.valueOf(Date.java:143)
at org.apache.spark.sql.catalyst.util.DateTimeUtils$.stringToTime(DateTimeUtils.scala:137)
但同样,这只会影响在 Spark 2.1.0 中解析非英语日期。
我还没有测试过这个,但我会尝试以下方法:
--conf spark.executor.extraJavaOptions="-Duser.timezone=America/Los_Angeles"
--conf spark.driver.extraJavaOptions="-Duser.timezone=America/Los_Angeles"