Spark SQL在JSON中自动推断模式的正确日期/日期时间格式是什么



Spark SQL支持从JSON输入源自动推断模式(每行都是一个独立的JSON文件)-它通过扫描整个数据集来创建模式,但它仍然很有用。(我说的是1.2.1,而不是新的1.3,所以可能会有一些变化)

我看到一些关于它被支持/不被支持的相互矛盾的帖子,但我认为它是最近添加的(在1.2中)

我的问题是,在Spark SQL的自动模式推理机制中,用JSON格式化Date/Datetime/Timestamp以识别它的正确方法是什么?

可以使用您选择的格式(我使用的是Date.toJSON格式)推断日期,只需稍作修改,而且性能合理。

获取最新的维护分支:

git clone https://github.com/apache/spark.git
cd spark
git checkout branch-1.4

替换InferSchema中的以下块:

  case VALUE_STRING if parser.getTextLength < 1 =>
    // Zero length strings and nulls have special handling to deal
    // with JSON generators that do not distinguish between the two.
    // To accurately infer types for empty strings that are really
    // meant to represent nulls we assume that the two are isomorphic
    // but will defer treating null fields as strings until all the
    // record fields' types have been combined.
    NullType
  case VALUE_STRING => StringType

带有以下代码:

  case VALUE_STRING =>
    val len = parser.getTextLength
    if (len < 1) {
      NullType
    } else if (len == 24) {
      // try to match dates of the form "1968-01-01T12:34:56.789Z"
      // for performance, only try parsing if text is 24 chars long and ends with a Z
      val chars = parser.getTextCharacters
      val offset = parser.getTextOffset
      if (chars(offset + len - 1) == 'Z') {
        try {
          org.apache.spark.sql.catalyst.util.
            DateUtils.stringToTime(new String(chars, offset, len))
          TimestampType
        } catch {
          case e: Exception => StringType
        }
      } else {
        StringType
      }
    } else {
      StringType
    }

根据您的设置构建Spark。我用过:

mvn -Pyarn -Phadoop-2.6 -Dhadoop.version=2.6.0 -DskipTests=true clean install

要进行测试,请在顶层创建一个名为datedPeople.json的文件,其中包含以下数据:

{"name":"Andy", "birthdate": "2012-04-23T18:25:43.511Z"}
{"name":"Bob"}
{"name":"This has 24 characters!!", "birthdate": "1988-11-24T11:21:13.121Z"}
{"name":"Dolla Dolla BillZZZZZZZZ", "birthdate": "1968-01-01T12:34:56.789Z"}

读取文件。请确保在使用sqlContext之前设置了conf选项,否则它将不起作用。日期!

.binspark-shell.cmd
scala> sqlContext.setConf("spark.sql.json.useJacksonStreamingAPI", "true")
scala> val datedPeople = sqlContext.read.json("datedPeople.json")
datedPeople: org.apache.spark.sql.DataFrame = [birthdate: timestamp, name: string]
scala> datedPeople.foreach(println)
[2012-04-23 13:25:43.511,Andy]
[1968-01-01 06:34:56.789,Dolla Dolla BillZZZZZZZZ]
[null,Bob]
[1988-11-24 05:21:13.121,This has 24 characters!!]

JSON类型推断永远不会推断日期类型。非零长度字符串总是被推断为字符串。源代码:

private[sql] object InferSchema {
  // ...
  private def inferField(parser: JsonParser): DataType = {
    import com.fasterxml.jackson.core.JsonToken._
    parser.getCurrentToken match {
      // ...
      case VALUE_STRING => StringType
      // ...
    }
  }
  // ...
}

为了进行自动检测,必须在适当的时候将其更改为查看实际字符串(parser.getValueAsString)并基于格式返回DateType

作为第二步,只采用普通的自动生成模式并转换日期类型可能更简单。

另一种选择是读取一小部分数据样本(不使用Spark),然后自己推断模式。然后使用您的模式创建DataFrame。这也避免了一些计算。

自Spark 3.0以来,如果字符串值与JSON选项timestampFormat定义的模式匹配,JSON数据源将从字符串值推断TimestampType

选项inferTimestamp可以设置为false以禁用这种类型推断。

要在此处提供2021的更新,此时可以将字符串推断为TimestampType,但不能推断为DateType。请参阅:https://spark.apache.org/docs/latest/api/java/org/apache/spark/sql/DataFrameReader.html#json-scala.collection.Seq-

您可以在spark.read.format("json")from_json()中设置一个选项来处理解析为时间戳的格式。该选项为timestampFormat,如下所述:https://spark.apache.org/docs/latest/api/java/org/apache/spark/sql/DataFrameReader.html#json-scala.collection.Seq-

相关内容

  • 没有找到相关文章

最新更新