В pyspark почему `limit` с последующим` repartition` создают абсолютно равные размеры разделов? - PullRequest
0 голосов
/ 23 февраля 2019

Согласно документации pyspark , repartition должен использовать хеш-разбиение, что даст несколько неравные размеры разделов.Тем не менее, я обнаружил, что если ему предшествует limit, то получится точно равного размера раздела.Это можно показать, запустив в оболочке pyspark следующее:

df = spark.createDataFrame([range(5)] * 100)

def count_part_size(part_iter):
    yield len(list(part_iter))

print(df.repartition(20).rdd.mapPartitions(count_part_size).collect())
# [4, 4, 4, 5, 4, 4, 5, 4, 5, 6, 6, 6, 7, 5, 5, 5, 5, 6, 5, 5]

print(df.limit(100).repartition(20).rdd.mapPartitions(count_part_size).collect())
# [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

Если repartition использует разделитель хеша, почему в этом случае он получит абсолютно равные размеры разделов?И если он не использует хеш-разделитель, какой тип разделителя он использует?

Кстати, я использую python версии 2.7.15 и spark версии 2.0.2

1 Ответ

0 голосов
/ 23 февраля 2019

Здесь есть четыре фактора:

  • Если выражение разделения не указано, repartition не использует HashPartitioning или, если быть точным, не использует егонепосредственно.Вместо этого он использует RoundRobinPartitioning, , который (как вы, вероятно, можете догадаться)

    Равномерно распределяет элементы по выходным разделам, начиная со случайного раздела.

    Внутренне он генерирует последовательность scala.Int на каждом разделе, начиная со случайной точки .Только эти значения передаются через HashPartitioner.

  • Это работает так, потому что Int hashCode - это просто тождество - другими словами

    ∀x∈Int x = hashCode (x)

    (кстати, такое же поведение, как у CPython hash в диапазоне Scala Int - от -2147483648 до 2147483647. Эти хеши просто не предназначены длябыть криптографически защищенным) В результате применение HashPartitioner к серии значений Int приводит к фактическому назначению Round Robin.

    Так что в этом случае HashPartitioner работает просто как оператор по модулю.

  • Вы применяете LIMIT перед перераспределением, поэтому все значения сначала перетасовываются на один узел.Поэтому используется только одна последовательность значений Int.

  • Количество разделов является делителем размера набора данных.Благодаря этому данные могут быть равномерно распределены по разделам.

В целом это комбинация предполагаемого поведения (каждый раздел должен быть равномерно распределен по выходным разделам), свойств конвейера (есть толькоодин входной раздел) и данные (набор данных может быть распределен равномерно).

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