Quelle est la différence entre les méthodes DataFrame repartition()
et DataFrameWriter partitionBy()
?
J'espère que les deux sont habitués à "partitionner les données en fonction de la colonne dataframe"? Ou y a-t-il une différence?
Si vous exécutez repartition(COL)
, vous modifiez le partitionnement pendant les calculs - vous obtiendrez des partitions spark.sql.shuffle.partitions
(Par défaut: 200). Si vous appelez ensuite .write
, Vous obtiendrez un répertoire avec plusieurs fichiers.
Si vous exécutez .write.partitionBy(COL)
, vous obtiendrez autant de répertoires que de valeurs uniques dans COL. Cela accélère la lecture des données (si vous filtrez par colonne de partitionnement) et économise de l'espace sur le stockage (la colonne de partitionnement est supprimée des fichiers de données).
UPDATE : Voir la réponse de @ conradlee. Il explique en détail non seulement comment sera la structure des répertoires après l'application de différentes méthodes, mais également quel sera le nombre de fichiers en résultant dans les deux scénarios.
Attention: je crois que la réponse acceptée n'est pas tout à fait juste! Je suis heureux que vous posiez cette question, car le comportement de ces fonctions portant le même nom diffère de manière importante et inattendue qui n’est pas bien documentée dans la documentation officielle spark.
La première partie de la réponse acceptée est correcte: appeler df.repartition(COL, numPartitions=k)
créera un cadre de données avec des partitions k
à l'aide d'un partitionneur basé sur un hachage. COL
définit ici la clé de partitionnement - il peut s'agir d'une colonne unique ou d'une liste de colonnes. Le partitionneur basé sur le hachage prend la clé de partition de chaque ligne d'entrée et la sépare dans un espace de k
partitions via quelque chose comme partition = hash(partitionKey) % k
. Cela garantit que toutes les lignes avec la même clé de partition se retrouvent dans la même partition. Cependant, les lignes de plusieurs clés de partition peuvent également se retrouver dans la même partition (lorsqu'une collision entre les clés de partition se produit) et certaines partitions peuvent être vides.
En résumé, les aspects non intuitifs de df.repartition(COL, numPartitions=k)
sont les suivants:
k
peuvent être vides, alors que d'autres peuvent contenir des lignes provenant de plusieurs clés de partitionLe comportement de df.write.partitionBy
Est très différent, d'une manière inattendue pour de nombreux utilisateurs. Supposons que vous souhaitiez que vos fichiers de sortie soient partitionnés par date et que vos données s'étendent sur 7 jours. Supposons également que df
ait 10 partitions pour commencer. Lorsque vous exécutez df.write.partitionBy('day')
, combien de fichiers de sortie devez-vous espérer? La réponse est "ça dépend". Si chaque partition de vos partitions de départ dans df
contient des données de chaque jour, la réponse est 70. Si chacune de vos partitions de départ dans df
contient des données de exactement un jour, la réponse est: dix.
Comment pouvons-nous expliquer ce comportement? Lorsque vous exécutez df.write
, Chacune des partitions d'origine dans df
est écrite indépendamment. Autrement dit, chacune de vos 10 partitions d'origine est subdivisée séparément dans la colonne "jour" et un fichier distinct est écrit pour chaque sous-partition.
Je trouve ce comportement plutôt gênant et j'espère qu'il existe un moyen de procéder à un repartitionnement global lors de l'écriture de cadres de données.