我有一个应用程序可以从MySQL数据库访问大约200万条推文。具体来说,其中一个字段包含一条文本推文(最大长度为140个字符)。我正在将每条推文分成ngram的单词ngrams,其中1< = n< = 3.例如,考虑一下句子:
I am a boring sentence.
相应的nGrams是:
I
I am
I am a
am
am a
am a boring
a
a boring
a boring sentence
boring
boring sentence
sentence
有大约200万条推文,我正在生成大量数据。无论如何,我很惊讶从Java获得堆错误:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.mysql.jdbc.MysqlIO.nextRowFast(MysqlIO.java:2145)
at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:1922)
at com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:3423)
at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:483)
at com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:3118)
at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:2288)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2709)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2728)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2678)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1612)
at twittertest.NGramFrequencyCounter.FreqCount(NGramFrequencyCounter.java:49)
at twittertest.Global.main(Global.java:40)
以下是Netbeans的上述输出所给出的问题代码声明(第49行):
results = stmt.executeQuery("select * from tweets");
所以,如果我的内存不足,那一定是它试图立即返回所有结果然后将它们存储在内存中。解决这个问题的最佳方法是什么?具体来说,我有以下问题:
results
而不是整套?随意添加任何建议,如果您需要更多信息,请与我们联系。
修改
而不是select * from tweets
我将表格划分为大小相等的子集,大小约为总大小的10%。然后我尝试运行该程序。看起来它工作正常,但它最终给了我相同的堆错误。这对我来说很奇怪,因为我过去运行过相同的程序,成功发布了610,000条推文。现在我有大约2,000,000条推文或大约3倍的数据。因此,如果我将数据拆分为三分之一,它应该可以工作,但我更进一步将子集拆分为10%的大小。
有些记忆没有被释放吗?以下是代码的其余部分:
results = stmt.executeQuery("select COUNT(*) from tweets");
int num_tweets = 0;
if(results.next())
{
num_tweets = results.getInt(1);
}
int num_intervals = 10; //split into equally sized subets
int interval_size = num_tweets/num_intervals;
for(int i = 0; i < num_intervals-1; i++) //process 10% of the data at a time
{
results = stmt.executeQuery( String.format("select * from tweets limit %s, %s", i*interval_size, (i+1)*interval_size));
while(results.next()) //for each row in the tweets database
{
tweetID = results.getLong("tweet_id");
curTweet = results.getString("tweet");
int colPos = curTweet.indexOf(":");
curTweet = curTweet.substring(colPos + 1); //trim off the RT and retweeted
if(curTweet != null)
{
curTweet = removeStopWords(curTweet);
}
if(curTweet == null)
{
continue;
}
reader = new StringReader(curTweet);
tokenizer = new StandardTokenizer(Version.LUCENE_36, reader);
//tokenizer = new StandardFilter(Version.LUCENE_36, tokenizer);
//Set stopSet = StopFilter.makeStopSet(Version.LUCENE_36, stopWords, true);
//tokenizer = new StopFilter(Version.LUCENE_36, tokenizer, stopSet);
tokenizer = new ShingleFilter(tokenizer, 2, 3);
charTermAttribute = tokenizer.addAttribute(CharTermAttribute.class);
while(tokenizer.incrementToken()) //insert each nGram from each tweet into the DB
{
insertNGram.setInt(1, nGramID++);
insertNGram.setString(2, charTermAttribute.toString().toString());
insertNGram.setLong(3, tweetID);
insertNGram.executeUpdate();
}
}
}
答案 0 :(得分:1)
您始终可以使用-Xmx参数增加JVM可用的堆大小。您应该阅读所有可用的旋钮(例如perm gen size)。 Google可提供其他选项或阅读this SO answer.
对于32位计算机,您可能无法解决此类问题。你需要64位和大量的RAM。
另一种选择是将其视为地图缩减问题。使用Hadoop和Mahout在集群上解决它。
答案 1 :(得分:1)
不要从表中获取所有行。尝试选择部分 通过设置查询限制,根据您的要求生成数据。您正在使用MySQL数据库,您的查询将从推文限制0,10中选择*。这里0是起始行id,10表示从开始起10行。
答案 2 :(得分:0)
您是否考虑过流式传输结果集?页面中间是结果集的一部分,它解决了你的问题(我想?)将n克写入文件,然后处理下一行?或者,我是否误解了你的问题? http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-implementation-notes.html