web-dev-qa-db-fra.com

Comment partitionner RDD par clé dans Spark?

Étant donné que les documents HashPartitioner disent:

[HashPartitioner] implémente un partitionnement basé sur le hachage en utilisant Object.hashCode de Java.

Disons que je veux partitionner DeviceData par son kind.

case class DeviceData(kind: String, time: Long, data: String)

Serait-il correct de partitionner un RDD[DeviceData] En écrasant la méthode deviceData.hashCode() et en utilisant uniquement le hashcode de kind?

Mais étant donné que HashPartitioner prend un certain nombre de paramètres de partitions, je ne sais pas si j'ai besoin de connaître le nombre de types à l'avance et que se passe-t-il s'il y a plus de types que de partitions?

Est-il exact que si j'écris des données partitionnées sur le disque, elles resteront partitionnées lors de la lecture?

Mon objectif est d'appeler

  deviceDataRdd.foreachPartition(d: Iterator[DeviceData] => ...)

Et avoir seulement DeviceData de la même valeur kind dans l'itérateur.

11
BAR

Que diriez-vous simplement de faire un groupByKey en utilisant kind. Ou une autre méthode PairRDDFunctions.

Vous me semblez que vous ne vous souciez pas vraiment du partitionnement, juste que vous obtenez tout d'un type spécifique dans un flux de traitement?

Les fonctions de paire permettent ceci:

rdd.keyBy(_.kind).partitionBy(new HashPartitioner(PARTITIONS))
   .foreachPartition(...)

Cependant, vous pouvez probablement être un peu plus en sécurité avec quelque chose de plus comme:

rdd.keyBy(_.kind).reduceByKey(....)

ou mapValues ou un certain nombre d'autres fonctions de paire qui garantissent que vous obtenez les pièces dans leur ensemble

9
Justin Pihony

Serait-il correct de partitionner un RDD [DeviceData] en écrasant la méthode deviceData.hashCode () et en utilisant uniquement le hashcode de kind?

Ce ne serait pas. Si vous consultez la documentation Java Object.hashCode, Vous trouverez les informations suivantes sur le contrat général de hashCode:

Si deux objets sont égaux selon la méthode equals (Object), l'appel de la méthode hashCode sur chacun des deux objets doit produire le même résultat entier.

Donc, à moins que la notion d'égalité basée uniquement sur un kind de périphérique corresponde à votre cas d'utilisation, et j'en doute sérieusement, bricoler avec HashCode pour obtenir le partitionnement souhaité est une mauvaise idée. Dans le cas général, vous devriez implémenter votre propre partitionneur mais ici ce n'est pas obligatoire.

Puisque, à l'exclusion des scénarios spécialisés dans SQL et GraphX, partitionBy n'est valide que sur PairRDD, il est logique de créer RDD[(String, DeviceData)] et d'utiliser plain HashPartitioner

deviceDataRdd.map(dev => (dev.kind, dev)).partitionBy(new HashPartitioner(n))

Gardez à l'esprit que dans une situation où kind a une faible cardinalité ou une distribution très asymétrique, l'utiliser pour le partitionnement peut ne pas être une solution optimale.

9
zero323