VarcharType несоответствие данных Spark - PullRequest
0 голосов
/ 22 января 2020

Я пытаюсь изменить схему кадра данных. каждый раз, когда у меня есть столбец строкового типа, я хочу изменить его тип на VarcharType (max), где max - это максимальная длина строки в этом столбце. я написал следующий код. (Я хочу экспортировать фрейм данных позже на sql сервер, и я не хочу иметь nvarchar на sql сервере, поэтому я пытаюсь ограничить его на стороне искры)

val df = spark.sql(s"SELECT * FROM $tableName")

var l : List [StructField] = List()

val schema = df.schema
schema.fields.foreach(x => {

  if (x.dataType == StringType) {
    val dataColName = x.name
    val maxLength = df.select(dataColName).reduce((x, y) => {
      if (x.getString(0).length >= y.getString(0).length) {
        x
      } else {
        y
      }
    }).getString(0).length

    val dataType = VarcharType(maxLength)
    l = l :+ StructField(dataColName, dataType)
  } else {
    l = l :+ x
  }
})

val newSchema = StructType(l)
val newDf = spark.createDataFrame(df.rdd, newSchema)

Однако когда запустив его, я получаю эту ошибку.

  20/01/22 15:29:44 ERROR ApplicationMaster: User class threw exception: scala.MatchError: 
  VarcharType(9) (of class org.apache.spark.sql.types.VarcharType)
  scala.MatchError: VarcharType(9) (of class org.apache.spark.sql.types.VarcharType)

Может ли столбец данных иметь тип VarcharType (n)?

1 Ответ

1 голос
/ 22 января 2020

Отображение данных из базы данных в / из фрейма данных происходит в классе диалекта. Для сервера MS SQL класс org.apache.spark.sql.jdbc.MsSqlServerDialect. Вы можете наследовать от этого и переопределить getJDBCType, чтобы влиять на отображение типов данных из кадра данных в таблицу. Затем зарегистрируйте свой диалект, чтобы он вступил в силу.

Я сделал это для Oracle (не sqlserver), однако это можно сделать аналогичным образом.

//Change this
  override def getJDBCType(dt: DataType): Option[JdbcType] = dt match {
    case TimestampType => Some(JdbcType("DATETIME", java.sql.Types.TIMESTAMP))
    case StringType => Some(JdbcType("NVARCHAR(MAX)", java.sql.Types.NVARCHAR))
    case BooleanType => Some(JdbcType("BIT", java.sql.Types.BIT))
    case _ => None
  }

Вы не можете использовать VarcharType, потому что это не DataType. Также вы не можете проверить длину фактических данных, потому что они не отображаются. У вас есть доступ только к «dt: DataType», поэтому вы можете установить размер по умолчанию для NVARCHAR, если max не приемлемо.

...