spark 以字符串形式写入并以数字形式读取分区列

spark write as string and read partition column as numeric

我发现我的业务代码有一些非法数据,调试后发现这个bug是spark partitions resolve导致的,如果不改变write partition columns如何避免这个问题

import org.apache.spark.sql.functions.lit
import spark.implicits._

val df = Seq(("122D", 2), ("122F", 2), ("122", 2))
      .toDF("no", "value")
      .withColumn("other", lit(1))

val path = "/user/my/output"

df
  .write
  .partitionBy("no","value")
  .parquet(path)

我的预期结果读起来和写的一样好

df.show()
+----+-----+-----+
|  no|value|other|
+----+-----+-----+
|122D|    2|    1|
|122F|    2|    1|
| 122|    2|    1|
+----+-----+-----+

// df.distinct.count==3

实际读取结果是这样的

val read=spark.read.parquet(path)

read.show()
+-----+-----+-----+
|other|   no|value|
+-----+-----+-----+
|    1|122.0|    2|
|    1|122.0|    2|
|    1|122.0|    2|
+-----+-----+-----+

// read.distinct.count==1

检查 output 目录结构是这样的

└─output
    ├─no=122
    │  └─value=2
    ├─no=122D
    │  └─value=2
    └─no=122F
        └─value=2

非常感谢。 我的 spark 版本是 2.4.5,scala 版本是 2.11.12

只需添加spark.conf.set("spark.sql.sources.partitionColumnTypeInference.enabled",false)

理论知识 : 所有内置文件源(包括Text/CSV/JSON/ORC/Parquet)都能够自动发现和推断分区信息。自动推断分区列的数据类型。

您可以使用 : spark.sql.sources.partitionColumnTypeInference.enabled 作为 False。

Make Sure That : 禁用类型推断时,字符串类型将用于分区列。