Scala 大文本文件

Posted

技术标签:

【中文标题】Scala 大文本文件【英文标题】:Scala Large Text file 【发布时间】:2013-01-07 15:26:03 【问题描述】:

我是 Scala 编程的新手。

我必须处理 NLP 任务。

我在 Scala处理大型文本文件时遇到问题。

我已经将一个 100+ M.B 文件的整个文本读入内存(读入一个字符串)并且必须对其进行处理(我相信处理大型文本文件是自然语言处理中的一项常见任务)。

目标是计算给定字符串中唯一子字符串/单词的数量(即整个文件)。

我想在 List 对象中使用 "distinct" 方法,但是将字符串转换为列表 使用 ".split ”方法引发内存不足错误(“java.lang.OutOfMemoryError: Java heap space”错误)。

我想知道我是否可以在不使用 Scala 中使用字符串或正则表达式方法的列表的情况下完成这项任务?

【问题讨论】:

相关:***.com/questions/4255021/… 我试过了。逐行处理需要永远阅读。 虽然如果文件变得非常大,你肯定会遇到问题,但取决于你有多少内存,你可以尝试这里的一些建议来增加 JVM 可用的内存:***.com/questions/1441373/… 我使用 200+ MB 的文件进行了一些类似的工作来训练多层神经网络,而您必须提高可用的默认内存是不争的事实。我的笔记本电脑上有足够的内存,所以我通常为 JVM 使用以下命令行参数:-Xmx6g -XX:MaxPermSize=256m Raul,请举例说明您要解决的问题,即示例输入字符串和示例输出。例如"Twinkle twinkle little star" 作为输入必须给出 ("twinkle" -> 2, "little" -> 1, "star" -> 1) 作为输出。 【参考方案1】:

Have a look at this blog 讨论您的问题以及解决问题的不同方法。

【讨论】:

这很有帮助。但为时已晚。 :)【参考方案2】:

我假设,您的文件作为 List[String] 在内存中,并且列表中的每个条目都是文件的一行。

val textStream = text.toStream
val wordStream = textStream.view.flatMap(s => s.split(" "))
val distinctWordStream = wordStream.foldLeft(Stream.empty[String])((stream, string) =>
  if (stream.contains(string)) stream else string #:: stream
)

首先,您创建一个 Stream,因此您不必处理整个 String。下一步是创建一个视图并对其进行映射,因此每个字符串中只有一个单词而不是一行。最后你逐字折叠结果。如果一个词被包含,它将被删除。除了折叠,你也可以使用这一行:

val wordSet = wordStream.toSet

此时获取不同单词的数量应该是微不足道的。您只需为 Set 调用 lengthsize

【讨论】:

【参考方案3】:

默认的 JVM 堆大小肯定会增加。我非常怀疑使用拆分或任何其他基于 RE 的方法对于这么大的输入是否容易处理。同样,如果您将输入转换为List[Char] 以利用精彩的集合库,您将看到内存需求过度增加;尺寸膨胀将至少是十进制数量级。

鉴于相对简单的分解(由空格或标点符号分隔的单词),我认为可能需要一个更平淡的解决方案。强制迭代字符串的字符(但不是通过隐式转换为任何类型的Seq[Char])并找到单词,将它们转储到mutable.Set[String]。一方面,这将消除重复。也许使用Buffer[Char] 来累积每个单词的字符,然后再将它们变成String 以添加到Set[String]

这里有一点:

package rrs.scribble

object  BigTextNLP 
  def btWords(bt: String): collection.mutable.Set[String] = 
    val btLength = bt.length
    val wordBuffer = collection.mutable.Buffer[Char]()
    val wordSet = collection.mutable.Set[String]()

    /* Assuming btLength > 0 */

    import bt.charAt => chr
    import java.lang.Character.isLetter => l

    var inWord = l(chr(0))

    (0 until btLength) foreach  i =>
      val c = chr(i)
      val lc = l(c)

      if (inWord)
        if (lc)
          wordBuffer += c
        else 
          wordSet += wordBuffer.mkString
          wordBuffer.clear
          inWord = false
        
      else
        if (lc) 
          inWord = true
          wordBuffer += c
        
    

    wordSet
  

在 REPL 中:

scala> import rrs.scribble.BigTextNLP._
import rrs.scribble.BigTextNLP._

scala> btWords("this is a sentence, maybe!")
res0: scala.collection.mutable.Set[String] = Set(this, maybe, sentence, is, a)

【讨论】:

+1 平淡无奇 - 很酷的词,与解决实际问题有很好的关系;-) 您还可以在累积到 Set 之前过滤掉停用词以及规范化大小写。这段代码有一个更大的问题,即缩略词(例如,“don't”)会被拆分(分成“don”和“t”)。警告程序员

以上是关于Scala 大文本文件的主要内容,如果未能解决你的问题,请参考以下文章

在大文本文件中查找文本数据的快速方法是啥?

替换大文本文件中的长列表单词

读取大文本文件(约 20m 行),将函数应用于行,写入新文本文件

python 输出大文本文件

C#读取大文本文件

Java读写大文本文件(2GB以上)