使用Scala在Apache Spark中拆分字符串

时间:2015-04-23 10:19:11

标签: string scala apache-spark

我有一个数据集,其中包含格式的行(制表符分隔):

Title<\t>Text

现在,对于Text中的每个字词,我想创建一个(Word,Title)对。 例如:

ABC      Hello World

给了我

(Hello, ABC)
(World, ABC)

使用Scala,我写了以下内容:

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)))))

但这给了我以下输出:

[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

我该如何解决这个问题?

进一步阅读

我想要实现的是计算特定Words的{​​{1}}中Text的数量。

我写的后续代码是:

Title

但它不起作用。请随时提供您的意见。谢谢!

4 个答案:

答案 0 :(得分:7)

所以......在Spark中你使用名为RDD的分布式数据结构。它们提供类似于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

答案 1 :(得分:2)

使用较新的数据框API 可解决此问题。首先使用“\ t”作为分隔符读取数据:

val df = spark.read
  .option("delimiter", "\t")
  .option("header", false)
  .csv("s3n://file.txt")
  .toDF("title", "text")

然后,split空格text列和explode每行一个字。

val df2 = df.select($"title", explode(split($"text", " ")).as("words"))

最后,在title列上进行分组,并计算每个字词的数量。

val countDf = df2.groupBy($"title").agg(count($"words"))

答案 2 :(得分:0)

具有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>

答案 3 :(得分:0)

上面证明的答案还不够好。 .map( line => line.split("\t") )可能导致:

  

org.apache.spark.SparkException:由于阶段失败而导致作业中止:阶段18.0中的任务0失败4次,最近一次失败:阶段18.0中的任务0.3丢失(TID 1485,ip-172-31-113-181 .us-west-2.compute.internal,执行程序10):java.lang.RuntimeException:编码时出错:java.lang.ArrayIndexOutOfBoundsException:14

如果最后一列为空。 最好的结果在这里解释- Split 1 column into 3 columns in spark scala