计算文本中单词的出现次数--Apache Spark Scala

时间:2015-04-23 13:30:15

标签: regex scala apache-spark

我最初有以下格式的一组记录:

(Title, Text)

其中Title是图书的名称,Text是其描述。

我已计算Word字段中Text字段中Title的每个((Word, Title), WordCount) 的出现次数。它采用以下格式:

Titles

现在,我想计算Word中出现Text的不同图书((Word, Title), TitleCount) 的数量。然后将其存储为以下格式:

Count

Titles是具有此Word的{​​{1}}的数量。 我想将其存储在文件TitleCount.txt

计算TitleCount

val idfRdd = yourRdd.flatMap(title => (title, scala.math.log(N/(file.filter(_.split("\t")(1).contains(title.split(",")))))))

N = fixed number (20)

但是这段代码没有给出错误:

scala> val idfRdd = yourRdd.flatMap(title => (title, scala.math.log(N/(file.filter(_.split("\t")(1).contains(title.split(",")))))))
<console>:31: error: value split is not a member of (String, String)
       val idfRdd = yourRdd.flatMap(title => (title, scala.math.log(N/(file.filter(_.split("\t")(1).contains(title.split(",")))))))
                                                                                                                   ^

更新

我也尝试了这个:

val r = splitRdd.flatMap(arr => { 
  val title = arr(0) 
  val text = arr(1) 
  val words = text.split(" ") 
  words.map(word => ((word, title), scala.math.log(N/(file.filter(_.split("\t")(1).contains(word))).count))) })

上面的代码编译但在运行时失败。

Title可能包含",",但这将是一个简单的正则表达式修复。 为了获得每个Title的单个字数,我编写了以下代码:

val file = sc.textFile("s3n://bucket/test.txt") // RDD[ String ]
val splitRdd = file.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 ) ]

val countRdd = yourRdd.map(title => (title, 1)).reduceByKey(_ + _)
countRdd.saveAsTextFile("s3n://bucket/wordcount.txt")

进一步阅读

我想通过将两个文档中的计数字段相乘来合并文档TitleCount.txtWordCount.txt。 这给了我们:

FinalCount.txt

((Word, Title), WordCount * TitleCount)

这是一个实际的乘法,而不是出于表示目的。

有人可以帮我解决这个问题吗? 谢谢!

3 个答案:

答案 0 :(得分:2)

我在下面尝试过,效果很好。

  1. 我在/home/cloudera/上创建了一个文件。 (请你的文件位置)。
  2. 阶&GT; val rpsteam=sc.textFile("file:///home/cloudera/RPS_Cricket_team.txt");
  3. 阶&GT; val rpscricket=rpsteam.flatMap(lines=>lines.split(" ")).filter(value=>value=="Rahane").map(word=>(word,1)).reduceByKey(_+_);
  4. 阶&GT; rpscricket.collect();

答案 1 :(得分:0)

我无法猜测yourRddfile等的数据类型是什么,所以我无法真正理解您的原始示例。

一般来说,要弄清楚这些类型的问题,请拆分成多个语句并在变量上声明数据类型,特别是在lambdas的左侧(x: Int =&gt; ...) 。然后编译器或IDE会告诉你你在哪里误入歧途。如果您使用的是IDE,它可能有一个键盘快捷键,用于向变量添加类型声明。学习它。这是Intellij的alt-enter。

在这种情况下,即使我无法理解整个代码,但错误消息告诉您File.filter正在返回字符串元组的集合,而不是字符串,所以_.split无效。

答案 2 :(得分:0)

嗯,错误真的告诉了一切。定义闭包时:

val idfRdd = yourRdd.flatMap(title => (title, scala.math.log(N/(file.filter(_.split("\t")(1).contains(title.split(",")))))))
<console>:31: error: value split is not a member of (String, String)
       val idfRdd = yourRdd.flatMap(title => (title, scala.math.log(N/(file.filter(_.split("\t")(1).contains(title.split(",")))))))

特别是title => ...,您匹配yourRdd RDD中的类型。如果这是您的初始输入,那么该类型是元组(String, String),实际上没有spit方法。例如,您可以使用title._2

现在,根据文本数量及其大小,您可能希望利用spark来完成内部计数。例如,通过

// Get an RDD[title, word], then a hashmap with all counts
val split = file.flatMap(x => x._2.split(",").map(y => (x._1, y)))
val counts = split.countByKey()

如果你想要的是计算IDF(我不完全确定),请按照以下步骤操作:

  1. 获取总文件数:var numDocs = file.count()
  2. 反转分割,使单词成为关键。
  3. 使用aggregateByKey()通过[word,num_titles]获取RDD
  4. 将其映射到最终公式:.map(x => (x._1, Log(numDocs / x._2.toDouble))
  5. 在那里,你得到一个RDD [(Word,IDF)]: - )