web-dev-qa-db-fra.com

pyspark: TypeError: IntegerType ne peut pas accepter d'objet de type <type 'unicode'>

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 ?

7
Hello lad

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.

6
zero323

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."

0
Giovanni Bruner