2

私は Scala プログラミングの初心者です。

NLPタスクに対処する必要があります。

Scalaで大きなテキスト ファイルを処理するのに問題があります。

100 MB 以上のファイルのテキスト全体をメモリに (文字列に) 読み込んで処理する必要があります (大きなテキスト ファイルの処理は、自然言語処理では一般的なタスクだと思います)。

目標は、指定された文字列(ファイル全体) 内の一意の部分文字列/単語の数をカウントすることです。

Listオブジェクトで「 distinct」メソッドを使用したかったのですが、「. split 」メソッドを使用して文字列をリストに変換すると、メモリ不足エラー (「java.lang.OutOfMemoryError: Java heap space」エラー) が発生します。

Scala で文字列または正規表現メソッドを使用して、リストを使用せずにこのタスクを達成できるかどうか疑問に思っていました。

4

3 に答える 3

5

デフォルトの JVM ヒープ サイズをおそらく増やす必要があることは確かです。スプリットやその他のREベースのアプローチを使用することが、その大きな入力に対して扱いやすいかどうかは大いに疑問です。List[Char]同様に、素晴らしいコレクション ライブラリを利用するために入力を に変換すると、メモリ要件が過度に増加することがわかります。サイズの膨張は、最小で 10 進数の桁数になります。

比較的単純な分解 (空白または句読点で区切られた単語) を考えると、より平凡な解決策が必要になる可能性があると思います。文字列の文字を命令的に反復し (ただし、任意の種類の への暗黙的な変換を介してではありませんSeq[Char])、単語を見つけて にダンプしますmutable.Set[String]。一つには、それは重複を排除します。おそらく、 a を使用し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)
于 2013-01-24T02:27:20.607 に答える
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
)

最初にストリームを作成するので、文字列全体を処理する必要はありません。次のステップは、ビューを作成してマッピングすることです。これにより、すべての文字列に1行ではなく1つの単語しか含まれなくなります。最後に、結果を単語ごとに折ります。単語がまだ含まれている場合、その単語は削除されます。折りたたむ代わりに、次の行を使用することもできます。

val wordSet = wordStream.toSet

個別の単語の数を取得することは、この時点では簡単なはずです。あなたはただ電話するlengthsize、セットを求める必要があります。

于 2013-01-24T09:07:57.243 に答える
1

あなたの問題とそれに対するさまざまなアプローチについて議論しているこのブログを見てください。

于 2013-01-24T19:45:48.130 に答える