我正在努力寻找更好的方法,因为它可能需要数年才能计算出来!我需要计算一个太大而不适合内存的映射,所以我试图按如下方式使用IO。
我有一个包含Ints列表的文件,大约有100万个。我有另一个文件,其中包含有关我(500,000)文档集的数据。我需要为第一个文件中的每个Int计算一个计数函数,它显示了多少文档(第二行中的行)。让我举一个例子:
File1:
-1
1
2
etc...
file2的:
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)
})
})
必须有更快的方法来做到这一点,有人能想到办法吗?
答案 0 :(得分:7)
根据我对您的代码的理解,您试图在文档列表中找到字典中的每个单词。 因此,您正在进行N * M比较,其中N是单词的数量(在带有整数的字典中),M是文档列表中的文档数。实例化您的值,您正在尝试计算10 ^ 6 * 5 * 10 ^ 5比较,即5 * 10 ^ 11。是不可行的。
为什么不创建一个可变映射,其中字典中的所有整数都是键(内存中的1000000个int大约是我的测量值的3.8M)并且只通过文档列表一次,每个文档都提取整数和增量地图中的相应计数值(整数是关键字)。
这样的事情:
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...
结果是一个地图,其键是dict中的数字,值是它在文档列表中出现的次数
这是过于简单的
这样你只需要传递一次文件,这使得任务再次可行。