Scala Преобразует шестнадцатеричную подстроку столбца в десятичную — Dataframe org.apache.spark.sql.catalyst.parser.Исключение ParseException:

#scala #dataframe #apache-spark-sql #substring #pyspark-dataframes

#scala #dataframe #apache-spark-sql #подстрока #pyspark

Вопрос:

    val DF = Seq("310:120:fe5ab02").toDF("id")

 ----------------- 
|       id        |
 ----------------- 
| 310:120:fe5ab02 |
 ----------------- 


 ----------------- ------------- -------- 
|       id        |      id1    |   id2  |
 ----------------- ------------- -------- 
| 310:120:fe5ab02 |      2      | 1041835| 
 ----------------- ------------- -------- 
  

Мне нужно преобразовать две подстроки строки из столбца из шестнадцатеричной в десятичную и создать два новых столбца в Dataframe.

 id1->   310:120:fe5ab02 ->x.(split(":")(2)) -> fe5ab02 -> substring(5) -> 02 -> ParseInt(x,16) ->  2
id2->   310:120:fe5ab02 ->x.(split(":")(2)) -> fe5ab02 -> substring(0,5) -> fe5ab -> ParseInt(x,16) ->  1041835
  

Из «310: 120:fe5ab02» мне нужен «fe5ab02», который я получаю, выполняя x.split(«:»)(2)
, а затем мне нужны две подстроки «fe5ab» и «02», которые я получаю с помощью x.substring(0,5), x.substring(5)
Затем мне нужно преобразовать их в десятичную, которую я получаю с помощью Integer.parseInt(x,16)

Они хорошо работают по отдельности, но мне они нужны в одном операторе withColumn, как показано ниже

 val DF1 = DF
.withColumn("id1", expr("""Integer.parseInt((id.split(":")(2)).substring(5), 16)"""))
.withColumn("id2", expr("""Integer.parseInt((id.split(":")(2)).substring(0, 5), 16)"""))

display(DF1)
  

Я получаю исключение синтаксического анализа.

Ответ №1:

 case class SplitId(part1: Int, part2: Int)

def splitHex: (String => SplitId) = { s => {
    val str: String = s.split(":")(2)
    SplitId(Integer.parseInt(str.substring(5), 16), Integer.parseInt(str.substring(0,5), 16))
  }
}

import org.apache.spark.sql.functions.udf

val splitHexUDF = udf(splitHex)

df.withColumn("splitId", splitHexUDF(df("id"))).withColumn("id1", $"splitId.part1").withColumn("id2",  $"splitId.part2").drop($"splitId").show()
 --------------- --- ------- 
|             id|id1|    id2|
 --------------- --- ------- 
|310:120:fe5ab02|  2|1041835|
 --------------- --- ------- 
  

В качестве альтернативы, вы можете использовать приведенный ниже фрагмент без UDF

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

val df2 = df.withColumn("splitId", split($"id", ":")(2))
  .withColumn("id1", $"splitId".substr(lit(6), length($"splitId")-1).cast("int"))
  .withColumn("id2", conv(substring($"splitId", 0, 5), 16, 10).cast("int"))
  .drop($"splitId")

df2.printSchema
root
 |-- id: string (nullable = true)
 |-- id1: integer (nullable = true)
 |-- id2: integer (nullable = true)

df2.show()
 --------------- --- ------- 
|             id|id1|    id2|
 --------------- --- ------- 
|310:120:fe5ab02|  2|1041835|
 --------------- --- ------- 
  

Комментарии:

1. Есть ли способ сделать это без использования UDF? UDF не работают в моем ноутбуке scala в Databricks. Я получаю «java.lang. Исключение SecurityException: ваш администратор запретил запускать Scala UDFs в этом кластере» ошибка

2. @VenkateshGotimukul, ознакомьтесь с обновленным ответом выше.