2014-11-04 2 views
1

저는 파이썬에서 통계를 처리하는 데 사용됩니다. 예를 들어, 큰 파일에는 수천만 개의 ID가 포함되어 있습니다.스칼라에서 큰 목록을 처리하는 방법은 무엇입니까?

$ cat report_ids | head 
3788065 
7950319 
140494477 
182851142 
120757318 
160033281 
78087029 
42591118 
104363873 
212143796 
... 

IPython에서 다음 줄은 항상 올바르게 작동합니다.

In [1]: lines = [line.strip() for line in open('./report_ids').readlines()] 

In [2]: from collections import Counter 

In [3]: d = Counter(lines) 

In [4]: d[lines[0]] 
Out[4]: 9 

스칼라에서 같은 것을 시도하면 메모리 부족 오류가 발생합니다.

val lines = scala.io.Source.fromFile("./report_ids").getLines.toList 
lines: List[String] = List(3788065, 7950319, 140494477, 182851142, 120757318, 160033281, 78087029, 42591118, 104363873, 212143796, 175644298, 112703123, 213308679, 109649718, 11947300, 214660563, 83402867, 162877289, 83030111, 78231639, 45129180, 11635655, 34778452, 46604760, 142519099, 213261965, 137812002, 167057636, 119258917, 212722777, 177979907, 13754217, 156769524, 40682536, 202195379, 91879046, 22766751, 6656279, 11972540, 76929862, 91616020, 110579570, 143849021, 27239477, 65146692, 142968764, 153891284, 182405787, 153038108, 50714639, 113386401, 96657813, 75908413, 32215626, 175000692, 154337083, 113754207, 165109267, 3788065, 42285876, 171004203, 109802388, 92956305, 46690091, 103638776, 15141632, 110579570, 120984867, 183167775, 86841540, 60465849, 27239477, 91760184, 213464... 

scala> val g = lines.groupBy(e => e).mapValues(x => x.length) 
java.lang.OutOfMemoryError: GC overhead limit exceeded 
    at scala.collection.immutable.HashMap$HashTrieMap.updated0(HashMap.scala:328) 
    at scala.collection.immutable.HashMap$HashTrieMap.updated0(HashMap.scala:326) 
    at scala.collection.immutable.HashMap.$plus(HashMap.scala:57) 
    at scala.collection.immutable.HashMap.$plus(HashMap.scala:36) 
    at scala.collection.mutable.MapBuilder.$plus$eq(MapBuilder.scala:28) 
    at scala.collection.mutable.MapBuilder.$plus$eq(MapBuilder.scala:24) 
    at scala.collection.TraversableLike$$anonfun$groupBy$3.apply(TraversableLike.scala:334) 
    at scala.collection.TraversableLike$$anonfun$groupBy$3.apply(TraversableLike.scala:333) 
    at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:772) 
    at scala.collection.mutable.HashMap$$anonfun$foreach$1.apply(HashMap.scala:98) 
    at scala.collection.mutable.HashMap$$anonfun$foreach$1.apply(HashMap.scala:98) 
    at scala.collection.mutable.HashTable$class.foreachEntry(HashTable.scala:226) 
    at scala.collection.mutable.HashMap.foreachEntry(HashMap.scala:39) 
    at scala.collection.mutable.HashMap.foreach(HashMap.scala:98) 
    at scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:771) 
    at scala.collection.TraversableLike$class.groupBy(TraversableLike.scala:333) 
    at scala.collection.AbstractTraversable.groupBy(Traversable.scala:105) 
    at .<init>(<console>:8) 
    at .<clinit>(<console>) 
    at .<init>(<console>:7) 
    at .<clinit>(<console>) 
    at $print(<console>) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734) 
    at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983) 
    at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:573) 
    at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604) 
    at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568) 
    at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:760) 

그때 나는 그것 여전히 작동하지 않는, 스칼라의 게으른 방법을 시도했다.

scala> lazy val lines = scala.io.Source.fromFile("./report_ids").getLines.toList 
lines: List[String] = <lazy> 

scala> val g = lines.groupBy(e => e).mapValues(x => x.length) 
java.lang.OutOfMemoryError: Java heap space 
    at java.util.Arrays.copyOfRange(Arrays.java:2694) 
    at java.lang.String.<init>(String.java:203) 
    at java.io.BufferedReader.readLine(BufferedReader.java:349) 
    at java.io.BufferedReader.readLine(BufferedReader.java:382) 
    at scala.io.BufferedSource$BufferedLineIterator.hasNext(BufferedSource.scala:67) 
    at scala.collection.Iterator$class.foreach(Iterator.scala:727) 
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1157) 
    at scala.collection.generic.Growable$class.$plus$plus$eq(Growable.scala:48) 
    at scala.collection.mutable.ListBuffer.$plus$plus$eq(ListBuffer.scala:176) 
    at scala.collection.mutable.ListBuffer.$plus$plus$eq(ListBuffer.scala:45) 
    at scala.collection.TraversableOnce$class.to(TraversableOnce.scala:273) 
    at scala.collection.AbstractIterator.to(Iterator.scala:1157) 
    at scala.collection.TraversableOnce$class.toList(TraversableOnce.scala:257) 
    at scala.collection.AbstractIterator.toList(Iterator.scala:1157) 
    at .lines$lzycompute(<console>:7) 
    at .lines(<console>:7) 
    at .<init>(<console>:8) 
    at .<clinit>(<console>) 
    at .<init>(<console>:7) 
    at .<clinit>(<console>) 
    at $print(<console>) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734) 
    at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983) 
    at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:573) 
    at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604) 
    at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568) 
    at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:760) 
    at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:805) 

그래서 내가 파이썬에서했던 것처럼 스칼라에서 작업하여 그룹을 완성 할 수 있습니까? 감사.

답변

8

저는 파이썬과 스칼라에서 다소 다른 것을하고 있다고 생각합니다. 의 그 첫 번째 라인을 살펴 보자 :

lines = [line.strip() for line in open('./report_ids').readlines()] 

그것은 당신이 (스칼라 기준) 여기에 반복 가능한 작업하는 나에게 보이는이 아닌 실제 목록입니다. 나는 잘못 생각할 수도 있습니다 - 기억하기에 충분할만큼 자주 파이썬을 사용하지는 않습니다 -하지만 여러분이 스칼라에서 어떻게 똑같은 것을 얻을 수 있는지를 가정 해 봅시다. 내가 스칼라 I/O가 하나되어 생각하지만, 지금

val lines = scala.io.Source.fromFile("./report_ids").getLines.toList 

, 스칼라는 표준 라이브러리의 파일 반복자를 가지고 있지 않습니다이 있었다. 여기에서, 당신은 반복자 (안 같은 일을) 얻기 위해이 작업을 수행 할 수 있습니다
val lines = scala.io.Source.fromFile("./report_ids").getLines 

은 그냥 List으로 바꿀하지 않습니다. :) 이제 iterator가 아닌 iterator이기 때문에 두 번 사용하면 실패합니다. 자 이제 이렇게 작성하겠습니다.

def lines = scala.io.Source.fromFile("./report_ids").getLines 

이제 "회선"을 여러 번 사용할 수 있습니다. 슬프게도, 당신은 파일 기술자를 누출하게됩니다 - 더 심각한 I/O 처리를 위해서 Scalaz Stream이나 Scala I/O 같은 더 심각한 I/O 라이브러리를보십시오. 또는 대출 패턴을 사용하십시오.

는 다음, 당신이 함께 Counter 코드를 대체 : 무슨

val g = lines.groupBy(e => e).mapValues(x => x.length) 

가 메모리를 많이합니다. 이런 식으로 뭔가 훨씬 더해야한다 : lines 이후

val g = scala.collection.mutable.HashMap.empty[String, Int] withDefaultValue 0 
for (line <- lines) g(line) += 1 

당신은 lines(0)을 할 수 없습니다, Iterator입니다. 첫 번째 줄의 경우 lines.next을 수행하거나 lines.toStream(0)을 사용하여 전체 파일을 메모리로 읽지 않고 색인에 액세스 할 수 있습니다.

관련 문제