Можно ли использовать coalesce с pivot / count для отображения нулей в нули в spark sql? - PullRequest
0 голосов
/ 01 сентября 2018

В ходе изучения разворота в Spark Sql я нашел простой пример с подсчетом, что привело к строкам с нулями.

Из оболочки искры, если вы сделаете это ->

val visits = Seq(
  (0, "Warsaw", 2015),
  (1, "Warsaw", 2016),
  (2, "Boston", 2017)
).toDF("id", "city", "year")

val withNulls = visits.groupBy("city").pivot("year", Seq("2015", "2016", "2017")).count()
withNulls.show()

вы получите этот вывод:

+------+----+----+----+
|  city|2015|2016|2017|
+------+----+----+----+
|Warsaw|   1|   1|null|
|Boston|null|null|   1|
+------+----+----+----+

Я могу преобразовать нули в нули с помощью еще одного шага с помощью функции 'na', например:

val noNulls = withNulls .na.fill(0)
 noNulls.show()

И результат - то, что я хочу:

+------+----+----+----+
|  city|2015|2016|2017|
+------+----+----+----+
|Warsaw|   1|   1|   0|
|Boston|   0|   0|   1|
+------+----+----+----+

Я бы предположил, что было бы более эффективно, если бы я мог сделать это за один шаг. Но я не смог придумать хорошее одношаговое решение. Ниже приведена одна неудачная попытка, которая оставила нулевые значения на месте и изменила мои (действительные) значения 1 на нули (что вовсе не правильно!).

visits.groupBy("city").pivot("year", Seq("2015", "2016", "2017")).agg(expr("coalesce(count(),0)")).show()

Может быть, один из экспертов Spark Sql мог бы подсказать мне, как сделать это правильно? Я почти уверен, что coalesce будет полезен, но любое одношаговое решение, даже без coalesce , будет приветствоваться!

Обновление:

Я собираюсь принять ответ Чандана (спасибо, Чандан!) И заключу, что самый ясный и эффективный способ сделать это с помощью na.fill (0)

Глядя вглубь принятого решения, мне кажется, что было бы дополнительное задание запущено, чтобы получить список столбцов (в форме одного оператора case на столбец), который используется в select это решение.

Я проверил это через пользовательский интерфейс spark. Когда я выполнил это заявление:

scala> val cols = visits.groupBy("city").pivot("year").count.columns.map(i => when(col(i).isNull,0).otherwise(col(i)).alias(i))

Я видел статистику для дополнительной работы в пользовательском интерфейсе .... это имеет смысл, так как в решении Чандана есть два «счета», каждое из которых является действием, которое может привести к запуску работы. Еще одна интересная вещь, которую я отметил о принятых Решение заключается в том, что значение cols представляет собой список операторов case, по одному на каждый столбец, и именно эти операторы case фактически применяет логику преобразования «if null-> then zero».

cols: Array[org.apache.spark.sql.Column] = Array(CASE WHEN (city IS NULL) THEN 0 ELSE city END AS `city`, CASE WHEN (2015 IS NULL) THEN 0 ELSE 2015 END AS `2015`, CASE WHEN (2016 IS NULL) THEN 0 ELSE 2016 END AS `2016`, CASE WHEN (2017 IS NULL) THEN 0 ELSE 2017 END AS `2017

1 Ответ

0 голосов
/ 02 сентября 2018

внутри agg api невозможно.

Вы можете использовать na.fill, как вы упомянули, или найти подход ниже.

visits.groupBy("city").pivot("year").count.select(visits.groupBy("city").pivot("year").count.columns.map(i => when(col(i).isNull,0).otherwise(col(i)).alias(i)):_*).show
...