当前位置: 首页 > 知识库问答 >
问题:

将CSV读入具有时间戳和日期类型的Spark Dataframe

姜博
2023-03-14

它是带火花1.6的CDH。

$ hadoop fs -cat test.csv
a,b,c,2016-09-09,a,2016-11-11 09:09:09.0,a
a,b,c,2016-09-10,a,2016-11-11 09:09:10.0,a

我使用databricks-csv jar。

val textData = sqlContext.read
    .format("com.databricks.spark.csv")
    .option("header", "false")
    .option("delimiter", ",")
    .option("dateFormat", "yyyy-MM-dd HH:mm:ss")
    .option("inferSchema", "true")
    .option("nullValue", "null")
    .load("test.csv")

我使用inferSchema为生成的DataFrame创建模式。printSchema()函数为上面的代码提供了以下输出:

scala> textData.printSchema()
root
 |-- C0: string (nullable = true)
 |-- C1: string (nullable = true)
 |-- C2: string (nullable = true)
 |-- C3: string (nullable = true)
 |-- C4: string (nullable = true)
 |-- C5: timestamp (nullable = true)
 |-- C6: string (nullable = true)

scala> textData.show()
+---+---+---+----------+---+--------------------+---+
| C0| C1| C2|        C3| C4|                  C5| C6|
+---+---+---+----------+---+--------------------+---+
|  a|  b|  c|2016-09-09|  a|2016-11-11 09:09:...|  a|
|  a|  b|  c|2016-09-10|  a|2016-11-11 09:09:...|  a|
+---+---+---+----------+---+--------------------+---+

C3列具有字符串类型。我想要C3有日期类型。为了将其设置为日期类型,我尝试了以下代码。

val textData = sqlContext.read.format("com.databricks.spark.csv")
    .option("header", "false")
    .option("delimiter", ",")
    .option("dateFormat", "yyyy-MM-dd")
    .option("inferSchema", "true")
    .option("nullValue", "null")
    .load("test.csv")

scala> textData.printSchema
root
 |-- C0: string (nullable = true)
 |-- C1: string (nullable = true)
 |-- C2: string (nullable = true)
 |-- C3: timestamp (nullable = true)
 |-- C4: string (nullable = true)
 |-- C5: timestamp (nullable = true)
 |-- C6: string (nullable = true)

scala> textData.show()
+---+---+---+--------------------+---+--------------------+---+
| C0| C1| C2|                  C3| C4|                  C5| C6|
+---+---+---+--------------------+---+--------------------+---+
|  a|  b|  c|2016-09-09 00:00:...|  a|2016-11-11 00:00:...|  a|
|  a|  b|  c|2016-09-10 00:00:...|  a|2016-11-11 00:00:...|  a|
+---+---+---+--------------------+---+--------------------+---+

这段代码与第一个块之间唯一的区别是dateFormat选项行(我使用“yyyy-mm-dd”而不是“yyyy-mm-dd hh:mm:ss”)。但是对于C5,忽略了HH::MM:SS部分,并在数据中显示为零。

理想情况下,我希望C3是date类型,C5是timestamp类型,并且不忽略它的hh:mm:ss部分。我现在的解决方案是这样的。我通过从我的数据库中并行提取数据来生成csv。我确保将所有日期都拉为时间戳(不理想)。因此,测试csv现在如下所示:

$ hadoop fs -cat new-test.csv
a,b,c,2016-09-09 00:00:00,a,2016-11-11 09:09:09.0,a
a,b,c,2016-09-10 00:00:00,a,2016-11-11 09:09:10.0,a

这是我最后的工作代码:

val textData = sqlContext.read.format("com.databricks.spark.csv")
    .option("header", "false")
    .option("delimiter", ",")
    .option("dateFormat", "yyyy-MM-dd HH:mm:ss")
    .schema(finalSchema)
    .option("nullValue", "null")
    .load("new-test.csv")
scala> finalSchema
res4: org.apache.spark.sql.types.StructType = StructType(StructField(C0,StringType,true), StructField(C1,StringType,true), StructField(C2,StringType,true), StructField(C3,DateType,true), StructField(C4,StringType,true), StructField(C5,TimestampType,true), StructField(C6,StringType,true))

scala> textData.printSchema()
root
 |-- C0: string (nullable = true)
 |-- C1: string (nullable = true)
 |-- C2: string (nullable = true)
 |-- C3: date (nullable = true)
 |-- C4: string (nullable = true)
 |-- C5: timestamp (nullable = true)
 |-- C6: string (nullable = true)


scala> textData.show()
+---+---+---+----------+---+--------------------+---+
| C0| C1| C2|        C3| C4|                  C5| C6|
+---+---+---+----------+---+--------------------+---+
|  a|  b|  c|2016-09-09|  a|2016-11-11 09:09:...|  a|
|  a|  b|  c|2016-09-10|  a|2016-11-11 09:09:...|  a|
+---+---+---+----------+---+--------------------+---+

相关链接:
http://spark.apache.org/docs/latest/sql-programming-guide.html#手动-指定-选项
https://github.com/databricks/spark-csv

共有1个答案

姜楷
2023-03-14

对于非琐碎的情况,如果使用infer选项,它可能不会返回预期的结果。正如您在inferschema.scala中所看到的:

if (field == null || field.isEmpty || field == nullValue) {
  typeSoFar
} else {
  typeSoFar match {
    case NullType => tryParseInteger(field)
    case IntegerType => tryParseInteger(field)
    case LongType => tryParseLong(field)
    case DoubleType => tryParseDouble(field)
    case TimestampType => tryParseTimestamp(field)
    case BooleanType => tryParseBoolean(field)
    case StringType => StringType
    case other: DataType =>
      throw new UnsupportedOperationException(s"Unexpected data type $other")

它将只尝试用时间戳类型匹配每列,而不是日期类型,因此这种情况下的“开箱即用的解决方案”是不可能的。但根据我的经验,“更简单”的解决方案是直接用所需的类型定义模式,这将避免infer选项设置一个只匹配RDD计算的类型,而不是整个数据。您的最终模式是一个有效的解决方案。

 类似资料:
  • 我对…感到困惑。、和的类型。 > 我在Oracle 11g数据库中有两种数据类型。->, 我用Hibernate映射了这个。->, 它可以像映射到和映射到一样? 以及到和到? 那么我应该在Java代码中使用什么类型呢? Oracle DB/Hibernate/Java代码 > 日期/日期/日期或时间戳?? 时间戳/日期/日期还是时间戳? 时间戳/时间戳/日期还是时间戳? 四种情况都有可能?我很困惑

  • 本文向大家介绍Java将日期类型Date时间戳转换为MongoDB的时间类型数据,包括了Java将日期类型Date时间戳转换为MongoDB的时间类型数据的使用技巧和注意事项,需要的朋友参考一下 存了一个时间类型(Date)的数据到mongo数据库中,但是前台显示的是一串数字。继而引发了如下问题: Java里面如何把 时间戳 1477387464495 转换为 2016-10-25 17:24:2

  • 问题内容: 在MySQL客户端/控制台中输出查询结果之前,如何告诉MySQL将时间戳格式设置为可读日期? 问题答案: 像这样使用FROM_UNIXTIME:

  • 我们有带有日期字段(类型date)的表,将时间戳插入日期字段在某些oracle环境中工作(我们有多种开发环境),但在某些环境中失败。

  • 主要内容:YEAR 类型,TIME 类型,DATE 类型,DATETIME 类型,TIMESTAMP 类型MySQL 中有多处表示日期的数据类型: YEAR、 TIME、 DATE、 DTAETIME、 TIMESTAMP。当只记录年信息的时候,可以只使用 YEAR 类型。 每一个类型都有合法的取值范围,当指定确定不合法的值时,系统将“零”值插入数据库中。 下表中列出了 MySQL 中的日期与时间类型。 类型名称 日期格式 日期范围 存储需求 YEAR YYYY 1901 ~ 2155 1 个字

  • 11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 表示时间值的DATE和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。每个时间类型有一个有效值范围和一个“零”值,当指定不合法的MySQL不能表示的值时使用“零”值。TIMESTAMP类型有专有的自动更新