在spark Dataframe中使用arraytype

时间:2018-05-28 15:07:33

标签: scala apache-spark apache-spark-sql

我的要求是将DataFrame中的所有Decimal数据类型转换为String。逻辑工作正常,类型简单但不适用于ArrayType。 这是逻辑: -

var df = spark.sql("select * from test_1")
for(dt <- df.dtypes) {
  if(dt._2.substring(0,7) == "Decimal"){
    df = df.withColumn(dt._1,df(dt._1).cast("String"))  
  }
}

但arrayType中的列保持不变,但它们是十进制类型。请帮助,我如何循环嵌套元素并将其转换为字符串。 这是我的数据帧的架构:

  

阶&GT; df.schema res77:org.apache.spark.sql.types.StructType =   StructType(StructField(mstr_prov_id,StringType,真)   StructField(prov_ctgry_cd,StringType,真)   StructField(prov_orgnl_efctv_dt,TimestampType,真)   StructField(prov_trmntn_dt,TimestampType,真)   StructField(prov_trmntn_rsn_cd,StringType,真)   StructField(npi_rqrd_ind,StringType,真)   StructField(prov_stts_aray_txt,数组类型(StructType(StructField(PROV_STTS_KEY,DecimalType(22,0),真)   StructField(PROV_STTS_EFCTV_DT,TimestampType,真)   StructField(PROV_STTS_CD,StringType,真)   StructField(PROV_STTS_TRMNTN_DT,TimestampType,真)   StructField(PROV_STTS_TRMNTN_RSN_CD,StringType,TRUE)),真),真))

3 个答案:

答案 0 :(得分:0)

您还可以投射复杂类型,例如如果你有像这个架构的数据框:

root
 |-- arr: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- i: decimal(22,0) (nullable = true)
 |    |    |-- j: double (nullable = false)

您可以通过执行以下操作来强制转换所有十进制类型的数组元素(在此示例中为字段i):

df
  .select($"arr".cast("array<struct<i:string,j:double>>"))
  .printSchema()

root
 |-- arr: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- i: string (nullable = true)
 |    |    |-- j: double (nullable = true)

编辑: 如果您事先不知道架构,则可以使用decimal替换原始架构中的string

val arraySchema = df.schema.fields(0).dataType.simpleString
val castedSchema = arraySchema.replaceAll("decimal\\(.*\\)","string")

df
  .select($"arr".cast(castedSchema))
  .show()

答案 1 :(得分:0)

如果您使用的是Spark 2.1及以上版本,那么以下投射应该适合您

val newSchema = DataType.fromJson(df.schema.json.replaceAll("(decimal\\(\\d+,\\d+\\))", "string")).asInstanceOf[StructType]
df.select(newSchema.map(field => col(field.name).cast(field.dataType)): _*)

应将所有小数类型转换为字符串类型。

但是如果你使用的spark版本低于上面提到的版本,并且因为结构列中有 timestamp 数据类型,你会遇到

  
    

TimestampType (of class org.apache.spark.sql.types.TimestampType$) scala.MatchError: TimestampType (of class org.apache.spark.sql.types.TimestampType$)

  

它是casting structs fails on Timestamp fields并已解决cast struct with timestamp field fails

答案 2 :(得分:0)

尝试一下(您与==的比较可能不是您想要的)

var df = spark.sql("select * from test_1")
for(dt <- df.dtypes) {
  if("Decimal".equalsIgnoreCase(dt._2.substring(0,Math.min(7, dt._2.length)))){
    df = df.withColumn(dt._1,df(dt._1).cast("String"))  
  }
}