J'ai un jeu de données qui contient des lignes au format (séparées par des tabulations):
Title<\t>Text
Maintenant, pour chaque mot dans Text
, je veux créer une paire (Word,Title)
. Par exemple:
ABC Hello World
donne moi
(Hello, ABC)
(World, ABC)
En utilisant Scala, j'ai écrit ce qui suit:
val file = sc.textFile("s3n://file.txt")
val title = file.map(line => line.split("\t")(0))
val wordtitle = file.map(line => (line.split("\t")(1).split(" ").map(Word => (Word, line.split("\t")(0)))))
Mais cela me donne la sortie suivante:
[Lscala.Tuple2;@2204b589
[Lscala.Tuple2;@632a46d1
[Lscala.Tuple2;@6c8f7633
[Lscala.Tuple2;@3e9945f3
[Lscala.Tuple2;@40bf74a0
[Lscala.Tuple2;@5981d595
[Lscala.Tuple2;@5aed571b
[Lscala.Tuple2;@13f1dc40
[Lscala.Tuple2;@6bb2f7fa
[Lscala.Tuple2;@32b67553
[Lscala.Tuple2;@68d0b627
[Lscala.Tuple2;@8493285
Comment résoudre ce problème?
Lectures complémentaires
Ce que je veux réaliser est de compter le nombre de Words
qui se produisent dans un Text
pour un Title
particulier.
Le code suivant que j'ai écrit est:
val wordcountperfile = file.map(line => (line.split("\t")(1).split(" ").flatMap(Word => Word), line.split("\t")(0))).map(Word => (Word, 1)).reduceByKey(_ + _)
Mais ça ne marche pas. N'hésitez pas à donner votre avis à ce sujet. Merci!
Alors ... Dans spark, vous travaillez en utilisant une structure de données distribuée appelée RDD. Ils fournissent des fonctionnalités similaires aux types de collection scala.
val fileRdd = sc.textFile("s3n://file.txt")
// RDD[ String ]
val splitRdd = fileRdd.map( line => line.split("\t") )
// RDD[ Array[ String ]
val yourRdd = splitRdd.flatMap( arr => {
val title = arr( 0 )
val text = arr( 1 )
val words = text.split( " " )
words.map( Word => ( Word, title ) )
} )
// RDD[ ( String, String ) ]
// Now, if you want to print this...
yourRdd.foreach( { case ( Word, title ) => println( s"{ $Word, $title }" ) } )
// if you want to count ( this count is for non-unique words),
val countRdd = yourRdd
.groupBy( { case ( Word, title ) => title } ) // group by title
.map( { case ( title, iter ) => ( title, iter.size ) } ) // count for every title
Voici comment résoudre ce problème à l’aide de la nouvelle API Dataframe . Commencez par lire les données en utilisant "\ t" comme délimiteur:
val df = spark.read
.option("delimiter", "\t")
.option("header", false)
.csv("s3n://file.txt")
.toDF("title", "text")
Ensuite, split
la colonne text
de l'espace et explode
pour obtenir un mot par ligne.
val df2 = df.select($"title", explode(split($"text", " ")).as("words"))
Enfin, groupez sur la colonne title
et comptez le nombre de mots pour chacun.
val countDf = df2.groupBy($"title").agg(count($"words"))
Une autre version avec DataFrame API
// read into DataFrame
val viewsDF=spark.read.text("s3n://file.txt")
// Split
val splitedViewsDF = viewsDF.withColumn("col1", split($"value", "\\t").getItem(0)).withColumn("col2", split($"value", "\\s+").getItem(1)).drop($"value"))
scala> val viewsDF=spark.read.text("spark-labs/data/wiki-pageviews.txt")
viewsDF: org.Apache.spark.sql.DataFrame = [value: string]
scala> viewsDF.printSchema
root
|-- value: string (nullable = true)
scala> viewsDF.limit(5).show
+------------------+
| value|
+------------------+
| aa Main_Page 3 0|
| aa Main_page 1 0|
| aa User:Savh 1 0|
| aa Wikipedia 1 0|
|aa.b User:Savh 1 0|
+------------------+
scala> val splitedViewsDF = viewsDF.withColumn("col1", split($"value", "\\s+").getItem(0)).withColumn("col2", split($"value", "\\s+").getItem(1)).withColumn("col3", split($"value", "\\s+").getItem(2)).drop($"value")
splitedViewsDF: org.Apache.spark.sql.DataFrame = [col1: string, col2: string ... 1 more field]
scala>
scala> splitedViewsDF.printSchema
root
|-- col1: string (nullable = true)
|-- col2: string (nullable = true)
|-- col3: string (nullable = true)
scala> splitedViewsDF.limit(5).show
+----+---------+----+
|col1| col2|col3|
+----+---------+----+
| aa|Main_Page| 3|
| aa|Main_page| 1|
| aa|User:Savh| 1|
| aa|Wikipedia| 1|
|aa.b|User:Savh| 1|
+----+---------+----+
scala>