Как создать заголовок DataFrame со столбцом Map [String, Long] и сохранить типы? - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть фрейм данных, к которому я применил filter условие

val colNames = customerCountDF
  .filter($"fiscal_year" === maxYear && $"fiscal_month" === maxMnth)

из всех выбранных строк, я просто хочу последний столбец одной строки.

тип последнего столбца Map[String, Long].Я хочу, чтобы все ключи карты были List[String].

. Я попробовал следующий синтаксис:

val colNames = customerCountDF
  .filter($"fiscal_year" === maxYear && $"fiscal_month" === maxMnth)
  .head
  .getMap(14)
  .keySet
  .toList
  .map(_.toString)

. Я использую map(_.toString) для преобразования List[Nothing] в List[String].Я получаю ошибку:

missing parameter type for expanded function ((x$1) => x$1.toString)
[error]        val colNames = customerCountDF.filter($"fiscal_year" === maxYear && $"fiscal_month" === maxMnth).head().getMap(14).keySet.toList.map(_.toString)

df выглядит следующим образом:

+-------------+-----+----------+-----------+------------+-------------+--------------------+--------------+--------+----------------+-----------+----------------+-------------+-------------+--------------------+
|division_name|  low| call_type|fiscal_year|fiscal_month|  region_name|abandon_rate_percent|answered_calls|connects|equiv_week_calls|equiv_weeks|equivalent_calls|num_customers|offered_calls|                  pv|
+-------------+-----+----------+-----------+------------+-------------+--------------------+--------------+--------+----------------+-----------+----------------+-------------+-------------+--------------------+
|     NATIONAL|PHONE|CABLE CARD|       2016|           1|ALL DIVISIONS|                0.02|         10626|       0|             0.0|        0.0|         10649.8|            0|        10864|Map(subscribers_c...|
|     NATIONAL|PHONE|CABLE CARD|       2016|           1|      CENTRAL|                0.02|          3591|       0|             0.0|        0.0|          3598.6|            0|         3667|Map(subscribers_c...|
+-------------+-----+----------+-----------+------------+-------------+--------------------+--------------+--------+----------------+-----------+----------------+-------------+-------------+--------------------+

одна строка только что выбранного последнего столбца равна

[Map(subscribers_connects -> 5521287, disconnects_hsd -> 7992, subscribers_xfinity home -> 6277491, subscribers_bulk units -> 4978892, connects_cdv -> 41464, connects_disconnects -> 16945, connects_hsd -> 32908, disconnects_internet essentials -> 10319, disconnects_disconnects -> 3506, disconnects_video -> 8960, connects_xfinity home -> 43012)] 

Я хотел бы получить ключи последнего столбца как List[String] после применения условия фильтра и извлечения только одной строки из фрейма данных.

Ответы [ 4 ]

0 голосов
/ 14 декабря 2018

Поскольку вы получаете доступ только к одному столбцу (на 14-й позиции), почему бы не сделать жизнь вашего разработчика немного проще (и помочь людям, которые поддержат ваш код позже)?

Попробуйте выполнить следующее:

val colNames = customerCountDF
  .where($"fiscal_year" === maxYear)  // Split one long filter into two
  .where($"fiscal_month" === maxMnth) // where is a SQL-like alias of filter
  .select("pv")                       // Take just the field you need to work with
  .as[Map[String, Long]]              // Map it to the proper type
  .head                               // Load just the single field (all others are left aside)
  .keySet                             // That's just a pure Scala

Я думаю, что приведенный выше код говорит о том, что он делает таким ясным способом (и я думаю, что он должен быть самым быстрым из предоставленных решений, поскольку он просто загружает одно поле pv в JVMобъект на водителя).

0 голосов
/ 12 декабря 2018

После filter вы можете просто выбрать столбец и получить как карту, как показано ниже

first().getAs[Map[String, Long]]("pv").keySet
0 голосов
/ 12 декабря 2018

Проблему типа легко решить, явно указав параметры типа в источнике, который равен getMap(14).Поскольку вы знаете, что вы ожидаете Map из String -> Int пар ключ-значение, просто замените getMap(14) на getMap[String, Int](14).

И до тех пор, пока getMap[String, Int](14) будет пустым Map, это связано с вашими данными, и у вас просто есть пустая карта в index 14 в строке head.

Подробнее

В Scala при создании List[A]Scala выводит тип, используя доступную информацию.

Например,

// Explicitly provide the type parameter info
scala> val l1: List[Int] = List(1, 2)
// l1: List[Int] = List(1, 2)

// Infer the type parameter by using the arguments passed to List constructor,
scala> val l2 = List(1, 2)
// l2: List[Int] = List(1, 2)

Итак, что происходит, когда вы создаете пустой список,

// Explicitly provide the type parameter info
scala> val l1: List[Int] = List()
// l1: List[Int] = List()

    // Infer the type parameter by using the arguments passed to List constructor,
// but surprise, there are no argument since you are creating empty list
scala> val l2 = List()
// l2: List[Nothing] = List()

ИтакТеперь, когда Scala ничего не знает, он выберет наиболее подходящий тип, который может найти, который является «пустым» типом Nothing.

То же самое происходит, когда вы делаете toList в другой коллекции.объекты, он пытается вывести параметр типа из исходного объекта.

scala> val ks1 = Map.empty[Int, Int].keySet
// ks1: scala.collection.immutable.Set[Int] = Set()
scala> val l1 = ks1.toList
// l1: List[Int] = List()

scala> val ks2 = Map.empty.keySet
// ks: scala.collection.immutable.Set[Nothing] = Set()
scala> val l2 = ks2.toList
// l1: List[Nothing] = List()

Аналогично, getMap(14), который вы вызывали для head Row из DataFrame, выводит параметры типадля Map с использованием значений, которые он получает от Row в index 14.Таким образом, если по указанному индексу ничего не получится, возвращаемая карта будет такой же, как Map.empty, то есть Map[Nothing, Nothing].

Что означает, что ваше целое,

val colNames = customerCountDF.filter($"fiscal_year" === maxYear && $"fiscal_month" === maxMnth).head.getMap(14).keySet.toList.map(_.toString)

эквивалентно,

val colNames = Map.empty.keySet.toList.map(_.toString)

И, следовательно,

scala> val l = List()
// l1: List[Nothing] = List()

val colNames = l.map(_.toString)

Подводя итог вышесказанному, любой List[Nothing] может быть только пустым списком.

Теперь естьдве проблемы, одна о проблеме типа в List[Nothing], другая о том, что она пуста.

0 голосов
/ 12 декабря 2018

Обходной путь для получения окончательного результата в List [String].Проверьте это:

scala> val customerCountDF=Seq((2018,12,Map("subscribers_connects" -> 5521287L, "disconnects_hsd" -> 7992L, "subscribers_xfinity home" -> 6277491L, "subscribers_bulk units" -> 4978892L, "connects_cdv" -> 41464L, "connects_disconnects" -> 16945L, "connects_hsd" -> 32908L, "disconnects_internet essentials" -> 10319L, "disconnects_disconnects" -> 3506L, "disconnects_video" -> 8960L, "connects_xfinity home" -> 43012L))).toDF("fiscal_year","fiscal_month","mapc")
customerCountDF: org.apache.spark.sql.DataFrame = [fiscal_year: int, fiscal_month: int ... 1 more field]

scala> val maxYear =2018
maxYear: Int = 2018

scala> val maxMnth = 12
maxMnth: Int = 12

scala> val colNames = customerCountDF.filter($"fiscal_year" === maxYear && $"fiscal_month" === maxMnth).first.getMap(2).keySet.mkString(",").split(",").toList
colNames: List[String] = List(subscribers_connects, disconnects_hsd, subscribers_xfinity home, subscribers_bulk units, connects_cdv, connects_disconnects, connects_hsd, disconnects_internet essentials, disconnects_disconnects, disconnects_video, connects_xfinity home)

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