Избегание нескольких объединений в конкретном случае c с несколькими столбцами с одинаковым доменом в кадрах данных apache spark sql - PullRequest
1 голос
/ 10 марта 2020

Меня попросили сделать что-то в apache spark sql (java api) через фреймы данных, что, я думаю, стоило бы очень дорого, если бы оно выполнялось по наивному подходу (я все еще работаю в наивном подход, но я думаю, что это будет стоить дорого, поскольку потребуется как минимум 4 вида соединений).

Я получил следующий кадр данных:

+----+----+----+----+----+----------+------+
|  C1|  C2|  C3|  C4|  C5|UNIQUE KEY|points|
+----+----+----+----+----+----------+------+
|   A|   A|null|null|null|      1234|     2|
|   A|null|null|   H|null|      1235|     3|
|   A|   B|null|null|null|      1236|     3|
|   B|null|null|null|   E|      1237|     1|
|   C|null|null|   G|null|      1238|     1|
|   F|null|   C|   E|null|      1239|     2|
|null|null|   D|   E|   G|      1240|     1|
+----+----+----+----+----+----------+------+

C1, C2, C3, C4 и C5 имеют одинаковые доменные значения, уникальный ключ - это уникальный ключ, точки - это целое число, которое следует рассматривать только один раз для каждого отдельного значения его соответствующих C столбцов (например, для первой строки A, A, null, null, null , ключ, 2 - это то же самое, что и A, ноль, ноль, ноль, ноль, ключ, 2 или A, A, A, A, нуль, ключ, 2)

Меня попросили "для каждого существующего C значение получить общее количество точек ".

Таким образом, вывод должен быть:

+----+------+
|  C1|points|
+----+------+
|   A|     8|
|   B|     4|
|   C|     3|
|   D|     1|
|   E|     4|
|   F|     2| 
|   G|     2|
|   H|     3|
+----+------+

Я собирался разделить фрейм данных на несколько маленьких (1 столбец для столбец C и 1 столбец для точек) через простые .select("C1","point"), .select("C2","point") и т. д. Но я полагаю, что если объем данных будет действительно большим, это будет стоить очень дорого, я считаю, что с помощью сокращения карт должен быть какой-то трюк, но я сам не смог его найти, поскольку я все еще новичок во всем этом. Мир. Я думаю, что мне не хватает некоторых понятий о том, как применить уменьшение карты.

Я также думал об использовании функции explode, я подумал собрать воедино [C1, C2, C3, C4, C5] в затем столбец с помощью разнесения, так что я получаю 5 строк для каждой строки, а затем просто группирую по ключу ... но я считаю, что это увеличит объем данных в какой-то момент, и если мы говорим о ГБ, это может быть неосуществимо ... .. Надеюсь, вы сможете найти трюк, который я ищу.

Спасибо за ваше время.

1 Ответ

1 голос
/ 10 марта 2020

Использование explode, вероятно, будет способом к go здесь. Это не увеличит объем данных и будет намного более вычислительно эффективным по сравнению с использованием нескольких join (обратите внимание, что одна join сама по себе является дорогостоящей операцией).

В этом случае Вы можете преобразовать столбцы в массив, сохраняя только уникальные значения для каждой отдельной строки. Этот массив затем может быть взорван и все нули отфильтрованы На данный момент, простой groupBy и сумма даст вам желаемый результат.

В Scala:

df.select(explode(array_distinct(array("C1", "C2", "C3", "C4", "C5"))).as("C1"), $"points")
  .filter($"C1".isNotNull)
  .groupBy($"C1)
  .agg(sum($"points").as("points"))
  .sort($"C1") // not really necessary

Это даст вам желаемый результат:

+----+------+
|  C1|points|
+----+------+
|   A|     8|
|   B|     4|
|   C|     3|
|   D|     1|
|   E|     4|
|   F|     2| 
|   G|     2|
|   H|     3|
+----+------+
...