Как понять выходные данные, когда foldLeft применяется к dataFrame? - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь удалить символы новой строки из столбцов строки Dataframe, используя foldLeft & regex_replace в Scala. Кадр данных создается после чтения таблицы RDBMS: public.test_sid на postgres. В таблице 4 столбца: id, id1, id2, id3 и id3 содержат новый символ строки. Вот как я написал логику:

var conf  = new SparkConf().setAppName("Spark-JDBC").set("spark.executor.heartbeatInterval","120s").set("spark.network.timeout","12000s").set("spark.default.parallelism", "20")
val conFile       = "testconnection.properties"
val properties    = new Properties()
properties.load(new FileInputStream(conFile))
val connectionUrl = properties.getProperty("gpDevUrl")
val devUserName   = properties.getProperty("devUserName")
val devPassword   = properties.getProperty("devPassword")
val driverClass   = properties.getProperty("gpDriverClass")
try {
  Class.forName(driverClass).newInstance()
} catch {
  case cnf: ClassNotFoundException =>
    System.exit(1)
  case e: Exception =>
    System.exit(1)
}
def main(args: Array[String]): Unit = {
  val spark = SparkSession.builder().config(conf).master("yarn").enableHiveSupport().getOrCreate()
  import spark.implicits._
  val spColsDF = spark.read.format("jdbc").option("url",connectionUrl).option("dbtable", "(select * from public.test_sid) as sampleTab").option("user", devUserName).option("password", devPassword).load()
  val strCols = spColsDF.schema.fields.filter(_.dataType==StringType).map(_.name)
  val finalDF = strCols.foldLeft(spColsDF){ (tempdf, colName) => tempdf.withColumn(colName, regexp_replace(col(colName), "\\n", " ")) }
  println("----------------------------------------------------------------------------------")
  spColsDF.show()
  println("----------------------------------------------------------------------------------")
  finalDF.show()
  println("----------------------------------------------------------------------------------")
}

В выходном журнале Из dataFrame: spColsDF я вижу данные в том формате, в котором они были вставлены.

+--------------------+--------------------+----+---+
|                  id|                 id1| id2|id3|
+--------------------+--------------------+----+---+
|1.000000000000000000|1.000000000000000000|   a|
a|
+--------------------+--------------------+----+---+

Но данные в finalDF выходят в странном формате. Значение из последнего столбца: id3 находится в начале кадра данных, и первая цифра первого столбца: идентификатор усекается и представляется как «000000000000000000» вместо «1.000000000000000000».

+--------------------+--------------------+----+---+
|                  id|                 id1| id2|id3|
+--------------------+--------------------+----+---+
 a|000000000000000000|1.000000000000000000|   a|
+--------------------+--------------------+----+---+

Данные столбца: id3 на первом месте

Если я просто получу доступ к этому конкретному столбцу: id3 из finalDF, я получу данные, как показано ниже:

scala> finalDF.select(finalDF("id3")).show
+---+
|id3|
+---+
 a|
+---+

scala> finalDF.select(finalDF("id")).show
+--------------------+
|                  id|
+--------------------+
|1.000000000000000000|
+--------------------+

Это просто проблема с консолью при печати данных или в коде есть изъян? Может кто-нибудь сообщить мне, если что-то не так в коде, который я написал выше.

1 Ответ

0 голосов
/ 27 августа 2018

Похоже на проблему CRLF (a.k.a. \ r \ n).

Исторически, один используется для указания консоли вернуться в начало строки, а другой - для создания новой строки.

Здесь, кажется, вы подавили создание новой строки, но все еще имеете часть "вернуться в начало".

Поэтому я предлагаю вам заменить оба \r и \n.

См. Википедия о CR

Возврат каретки, иногда известный как возврат картриджа и часто сокращенный до CR, или возврат, является управляющим символом или механизмом, используемым для сброса положения устройства в начале строки текста. Он тесно связан с концепциями перевода строки и новой строки, хотя его можно рассматривать отдельно по отдельности.

Чтобы увидеть его в действии, давайте создадим тестовый фрейм данных:

scala> val dataframe = Seq(
     ("normal", "normal"), 
     ("withLF", "normal\n"), 
     ("withCRLF", "normal\r\n")).toDF("id", "value")
dataframe: org.apache.spark.sql.DataFrame = [id: string, value: string]

scala> dataframe.show
+--------+--------+
|      id|   value|
+--------+--------+
|  normal|  normal|
|  withLF| normal
|
|withCRLF|normal
|
+--------+--------+

Здесь мы видим, что у наших строк с "\ r \ n" и "\ n" есть проблема, с которой вы столкнулись в начале вашего поста. Теперь, если я использую, вы замените функцию:

dataframe.withColumn("value", regexp_replace($"value", "\n", "")).show
+--------+-------+
|      id|  value|
+--------+-------+
|  normal| normal|
|  withLF| normal|
|withCRLF|normal
+--------+-------+

Мы видим, что решили ситуацию "\ n", но не "\ r \ n". Так что если вы действительно хотите использовать регулярное выражение для поиска / замены, вы должны объявить CR и LF для замены:

scala> dataframe.withColumn("value", regexp_replace($"value", "[\r\n]+", " ")).show
+--------+-------+
|      id|  value|
+--------+-------+
|  normal| normal|
|  withLF|normal |
|withCRLF|normal |
+--------+-------+

(Возможные улучшения: не использовать регулярное выражение для замены одного символа. Не выводить пустой символ в конце строки вывода, ...).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...