web-dev-qa-db-fra.com

PySpark - Création d'un bloc de données à partir d'un fichier texte

J'ai un simple fichier texte, qui contient des "transactions".

La première ligne correspond aux noms de colonne, par exemple "START_TIME", "END_TIME", "SIZE" .. environ ~ 100 noms de colonne.

Les noms de colonne dans le fichier sont sans guillemets.

Je veux utiliser Spark, pour convertir ce fichier en un bloc de données, avec des noms de colonnes,

puis supprimez toutes les colonnes du fichier MAIS certaines colonnes spécifiques.

J'ai un peu de mal à convertir le fichier texte en bloc de données.

Voici mon code jusqu'à présent:

from pyspark import SparkContext
from pyspark.sql import SQLContext
from pyspark.sql.types import *

# Load relevant objects
sc = SparkContext('local')
log_txt = sc.textFile("/path/to/text/file.txt")
sqlContext = SQLContext(sc)

# Construct fields with names from the header, for creating a DataFrame
header = log_txt.first()
fields = [StructField(field_name, StringType(), True)
      for field_name in header.split(',')]

# Only columns\fields 2,3,13,92 are relevant. set them to relevant types
fields[2].dataType = TimestampType()    # START_TIME in yyyymmddhhmmss format
fields[3].dataType = TimestampType()    # END_TIME in yyyymmddhhmmss
fields[13].dataType = IntegerType()     # DOWNSTREAM_SIZE, in bytes
fields[92].dataType = BooleanType()     # IS_CELL_CONGESTED, 0 or 1
schema = StructType(fields)             # Create a schema object

# Build the DataFrame
log_txt = log_txt.filter(lambda line: line != header) # Remove header from the txt file
temp_var = log_txt.map(lambda k: k.split("\t"))

log_df = sqlContext.createDataFrame(temp_var, schema) # PROBLEMATIC LINE

Le problème que j'ai est avec la dernière ligne, je crains de manquer quelques étapes avant ces dernières étapes.

Pouvez-vous m'aider à déterminer les étapes manquantes?

La dernière ligne de code produit beaucoup d'erreurs. Les mettra à jour dans le message si nécessaire.

Le format de fichier est (exemple de 2 lignes)

TRANSACTION_URL,RESPONSE_CODE,START_TIME,END_TIME,.... <more names>
http://www.google.com<\t seperator>0<\t seperator>20160609182001<\t seperator>20160609182500.... <more values>
http://www.cnet.com<\t seperator>0<\t seperator>20160609192001<\t seperator>20160609192500.... <more values>

De plus, quelqu'un peut-il m'aider à supprimer les colonnes inutiles du bloc de données une fois qu'il est construit?

Merci

5
Adiel

Je pense que vous y pensez un peu trop. Imaginez que nous ayons quelque chose de moins complexe, exemple ci-dessous

`cat sample_data.txt`
field1\tfield2\tfield3\tfield4
0\tdog\t20160906182001\tgoogle.com
1\tcat\t20151231120504\tamazon.com

pyspark ouvert

sc.setLogLevel("WARN")
#setup the same way you have it
log_txt=sc.textFile("/path/to/data/sample_data.txt")
header = log_txt.first()

#filter out the header, make sure the rest looks correct
log_txt = log_txt.filter(lambda line: line != header)
log_txt.take(10)
  [u'0\\tdog\\t20160906182001\\tgoogle.com', u'1\\tcat\\t20151231120504\\tamazon.com']

temp_var = log_txt.map(lambda k: k.split("\\t"))

#here's where the changes take place
#this creates a dataframe using whatever pyspark feels like using (I think string is the default). the header.split is providing the names of the columns
log_df=temp_var.toDF(header.split("\\t"))
log_df.show()
+------+------+--------------+----------+
|field1|field2|        field3|    field4|
+------+------+--------------+----------+
|     0|   dog|20160906182001|google.com|
|     1|   cat|20151231120504|Amazon.com|
+------+------+--------------+----------+
#note log_df.schema
#StructType(List(StructField(field1,StringType,true),StructField(field2,StringType,true),StructField(field3,StringType,true),StructField(field4,StringType,true)))

# now lets cast the columns that we actually care about to dtypes we want
log_df = log_df.withColumn("field1Int", log_df["field1"].cast(IntegerType()))
log_df = log_df.withColumn("field3TimeStamp", log_df["field1"].cast(TimestampType()))

log_df.show()
+------+------+--------------+----------+---------+---------------+
|field1|field2|        field3|    field4|field1Int|field3TimeStamp|
+------+------+--------------+----------+---------+---------------+
|     0|   dog|20160906182001|google.com|        0|           null|
|     1|   cat|20151231120504|Amazon.com|        1|           null|
+------+------+--------------+----------+---------+---------------+
log_df.schema
StructType(List(StructField(field1,StringType,true),StructField(field2,StringType,true),StructField(field3,StringType,true),StructField(field4,StringType,true),StructField(field1Int,IntegerType,true),StructField(field3TimeStamp,TimestampType,true)))

#now let's filter out the columns we want
log_df.select(["field1Int","field3TimeStamp","field4"]).show()
+---------+---------------+----------+
|field1Int|field3TimeStamp|    field4|
+---------+---------------+----------+
|        0|           null|google.com|
|        1|           null|Amazon.com|
+---------+---------------+----------+

Une trame de données doit avoir un type pour chaque champ qu'elle rencontre, que vous l'utilisiez ou non, cela dépend de vous. Vous devrez utiliser l'une des fonctions spark.SQL pour convertir les dates de la chaîne en horodatages réels, mais cela ne devrait pas être trop difficile.

J'espère que cela t'aides

PS: pour votre cas spécifique, pour faire la trame de données initiale, essayez: log_df=temp_var.toDF(header.split(','))

10
James Tobin