programmation avec pyspark sur un cluster Spark, les données sont volumineuses et en morceaux, elles ne peuvent donc pas être chargées dans la mémoire ou vérifier facilement la santé des données
en gros ça ressemble
af.b Current%20events 1 996
af.b Kategorie:Musiek 1 4468
af.b Spesiaal:RecentChangesLinked/Gebruikerbespreking:Freakazoid 1 5209
af.b Spesiaal:RecentChangesLinked/Sir_Arthur_Conan_Doyle 1 5214
données wikipedia:
Je l'ai lu dans aws S3, puis j'essaie de construire spark Dataframe avec le code python suivant dans pyspark intepreter:
parts = data.map(lambda l: l.split())
wikis = parts.map(lambda p: (p[0], p[1],p[2],p[3]))
fields = [StructField("project", StringType(), True),
StructField("title", StringType(), True),
StructField("count", IntegerType(), True),
StructField("byte_size", StringType(), True)]
schema = StructType(fields)
df = sqlContext.createDataFrame(wikis, schema)
tout a l'air bien, seulement createDataFrame me donne une erreur
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/spark/python/pyspark/sql/context.py", line 404, in createDataFrame
rdd, schema = self._createFromRDD(data, schema, samplingRatio)
File "/usr/lib/spark/python/pyspark/sql/context.py", line 298, in _createFromRDD
_verify_type(row, schema)
File "/usr/lib/spark/python/pyspark/sql/types.py", line 1152, in _verify_type
_verify_type(v, f.dataType)
File "/usr/lib/spark/python/pyspark/sql/types.py", line 1136, in _verify_type
raise TypeError("%s can not accept object in type %s" % (dataType, type(obj)))
TypeError: IntegerType can not accept object in type <type 'unicode'>
pourquoi je ne peux pas définir la troisième colonne qui devrait être compter à IntegerType? Comment puis-je résoudre ça ?
Comme indiqué par ccheneson vous passez des types incorrects.
En supposant que data
ressemble à ceci:
data = sc.parallelize(["af.b Current%20events 1 996"])
Après la première carte, vous obtenez RDD[List[String]]
:
parts = data.map(lambda l: l.split())
parts.first()
## ['af.b', 'Current%20events', '1', '996']
La deuxième carte le convertit en Tuple (String, String, String, String)
:
wikis = parts.map(lambda p: (p[0], p[1], p[2],p[3]))
wikis.first()
## ('af.b', 'Current%20events', '1', '996')
Votre schema
indique que la 3ème colonne est un entier:
[f.dataType for f in schema.fields]
## [StringType, StringType, IntegerType, StringType]
Le schéma est le plus utilisé pour éviter une analyse complète de la table afin d'inférer des types et n'effectue aucune conversion de type.
Vous pouvez soit convertir vos données lors de la dernière carte:
wikis = parts.map(lambda p: (p[0], p[1], int(p[2]), p[3]))
Ou définissez count
en tant que StringType
et colonne cast
fields[2] = StructField("count", StringType(), True)
schema = StructType(fields)
wikis.toDF(schema).withColumn("cnt", col("count").cast("integer")).drop("count")
Notons que count
est réservé à Word dans SQL et ne doit pas être utilisé comme nom de colonne. Dans Spark, cela fonctionnera comme prévu dans certains contextes et échouera dans un autre.
Avec Apache 2.0, vous pouvez laisser spark déduire le schéma de vos données. Globalement, vous devez définir votre fonction d'analyse comme indiqué ci-dessus:
"Lorsque le schéma est Aucun, il essaiera d'inférer le schéma (noms et types de colonnes) à partir de données, qui devraient être un RDD de rangée, ou de nom nommé, ou de dict."