scala之大数据慢IO

你猜 阅读:69 2024-08-28 10:21:53 评论:0

我正试图找到一种更好的方法来执行此操作,因为它可能需要数年时间才能计算出来!我需要计算一个太大而无法放入内存的 map ,因此我尝试按如下方式使用 IO。

我有一个包含整数列表的文件,其中大约有 100 万个。我有另一个文件,其中包含有关我的 (500,000) 个文档集合的数据。我需要为第一个文件中的每个 Int 计算它出现在多少文档(第二个行)中的计数函数。让我举个例子:

文件 1:

-1 
1 
2 
etc... 

文件2:

E01JY3-615,  CR93E-177 , [-1 -> 2,1 -> 1,2 -> 2,3 -> 2,4 -> 2,8 -> 2,... // truncated for brevity]  
E01JY3-615,  CR93E-177 , [1 -> 2,2 -> 2,4 -> 2,5 -> 2,8 -> 2,... // truncated for brevity] 
etc... 

这是我目前的尝试

def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) { 
    val p = new java.io.PrintWriter(new BufferedWriter((new FileWriter(f)))) 
    try { 
      op(p) 
    } finally { 
      p.close() 
    } 
  } 
 
  def binarySearch(array: Array[String], word: Int):Boolean = array match { 
    case Array() => false 
    case xs      => if (array(array.size/2).split("->")(0).trim().toInt == word) { 
      return true 
    } else if (array(array.size/2).split("->")(0).trim().toInt > word){ 
      return binarySearch(array.take(array.size/2), word) 
    } else { 
      return binarySearch(array.drop(array.size/2 + 1), word) 
    } 
  } 
 
  var v = Source.fromFile("vocabulary.csv").getLines() 
 
  printToFile(new File("idf.csv"))(out => { 
    v.foreach(word =>{ 
      var docCount: Int = 0 
      val s = Source.fromFile("documents.csv").getLines() 
      s.foreach(line => { 
        val split = line.split("\\[") 
        val fpStr = split(1).init 
        docCount = if (binarySearch(fpStr.split(","), word.trim().toInt)) docCount + 1 else docCount 
      }) 
      val output = word + ", " + math.log10(500448 / (docCount + 1)) 
      out.println(output) 
      println(output) 
    }) 
  }) 

必须有更快的方法来做到这一点,谁能想到办法?

请您参考如下方法:

根据我对您的代码的理解,您正试图在文档列表中的词典中查找每个单词。 因此,您正在进行 N*M 比较,其中 N 是单词数(在字典中为整数),M 是文档列表中的文档数。实例化您的值,您正在尝试计算 10^6 * 5*10^5 比较,即 5*10^11。不可行。

为什么不创建一个可变映射,将字典中的所有整数作为键(根据我的测量,内存中的 1000000 个整数大约是 380 万)并且仅通过文档列表一次,其中对于每个文档,您提取整数并递增映射中的各个计数值(整数是关键)。

像这样:

import collection.mutable.Map 
import scala.util.Random._ 
 
val maxValue = 1000000 
 
val documents = collection.mutable.Map[String,List[(Int,Int)]]() 
 
// util function just to insert fake input; disregard 
def provideRandom(key:String) ={ (1 to nextInt(4)).foreach(_ => documents.put(key,(nextInt(maxValue),nextInt(maxValue)) :: documents.getOrElse(key,Nil)))} 
 
// inserting fake documents into our fake Document map  
(1 to 500000).foreach(_ => {val key = nextString(5); provideRandom(key)}) 
 
// word count map 
val wCount = collection.mutable.Map[Int,Int]() 
 
// Counting the numbers and incrementing them in the map 
documents.foreach(doc => doc._2.foreach(k => wCount.put(k._1, (wCount.getOrElse(k._1,0)+1)))) 
 
scala> wCount 
res5: scala.collection.mutable.Map[Int,Int] = Map(188858 -> 1, 178569 -> 2, 437576 -> 2, 660074 -> 2, 271888 -> 2, 721076 -> 1, 577416 -> 1, 77760 -> 2, 67471 -> 1, 804106 -> 2, 185283 -> 1, 41623 -> 1, 943946 -> 1, 778258 -> 2... 

结果是一个映射,它的键是字典中的一个数字,值是它在文档列表中出现的次数

这是过于简单化了

  • 我不验证数字是否存在于字典中,尽管您只需要使用值初始化映射,然后在最终映射中递增该值(如果它具有该键);
  • 我不做 IO,这会加快整个过程

这样一来,您只需遍历文档一次,这使得任务再次变得可行。


标签:大数据
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号