我有一个基本的方法,它从硬盘驱动器中读取大约1000行,每行约10,000行。另外,我有一个名为String
的{{1}}数组,其中包含用户的所有“描述词”。我创建了一个HashMap,其数据结构为userDescription
,对应HashMap<String, HashMap<String, Integer>>
。
该文件组织为:
HashMap<eachUserDescriptionWords, HashMap<TweetWord, Tweet_Word_Frequency>>
我的方法是:
<User=A>\t<Tweet="tweet...">\n
<User=A>\t<Tweet="tweet2...">\n
<User=B>\t<Tweet="tweet3...">\n
....
此处,方法for (File file : tweetList) {
if (file.getName().endsWith(".txt")) {
System.out.println(file.getName());
BufferedReader in;
try {
in = new BufferedReader(new FileReader(file));
String str;
while ((str = in.readLine()) != null) {
// String split[] = str.split("\t");
String split[] = ptnTab.split(str);
String user = ptnEquals.split(split[1])[1];
String tweet = ptnEquals.split(split[2])[1];
// String user = split[1].split("=")[1];
// String tweet = split[2].split("=")[1];
if (tweet.length() == 0)
continue;
if (!prevUser.equals(user)) {
description = userDescription.get(user);
if (description == null)
continue;
if (prevUser.length() > 0 && wordsCount.size() > 0) {
for (String profileWord : description) {
if (wordsCorr.containsKey(profileWord)) {
HashMap<String, Integer> temp = wordsCorr
.get(profileWord);
wordsCorr.put(profileWord,
addValues(wordsCount, temp));
} else {
wordsCorr.put(profileWord, wordsCount);
}
}
}
// wordsCount = new HashMap<String, Integer>();
wordsCount.clear();
}
setTweetWordCount(wordsCount, tweet);
prevUser = user;
}
} catch (IOException e) {
System.err.println("Something went wrong: "
+ e.getMessage());
}
}
}
计算单个用户的所有推文的单词频率。方法是:
setTweetWord
方法addValues检查private void setTweetWordCount(HashMap<String, Integer> wordsCount,
String tweet) {
ArrayList<String> currTweet = new ArrayList<String>(
Arrays.asList(removeUnwantedStrings(tweet)));
if (currTweet.size() == 0)
return;
for (String word : currTweet) {
try {
if (word.equals("") || word.equals(null))
continue;
} catch (NullPointerException e) {
continue;
}
Integer countWord = wordsCount.get(word);
wordsCount.put(word, (countWord == null) ? 1 : countWord + 1);
}
}
是否包含已存在于巨型HashMap wordsCorr中的单词。如果是,则会增加原始HashMap wordCount
中单词的计数。
现在,我的问题是无论我做什么,程序都非常慢。我在我的服务器上运行了这个版本,它有相当不错的硬件但是它已经28小时了,扫描的文件数量只有~450。我试着看看我是否反复做了一些可能没必要的事,我纠正了其中的一些。但程序仍然很慢。
另外,我已经将堆大小增加到1500米,这是我可以达到的最大值。
有什么我可能做错了吗?
感谢您的帮助!
编辑:分析结果
首先,我真的要感谢你们的评论。我已经改变了程序中的一些东西。我现在已经预编译了正则表达式而不是直接wordsCorr
和其他优化。但是,在分析后,我的String.split()
方法花费的时间最长。所以,这是addValues
的代码。有什么我应该优化的吗?哦,我也改变了我的addValues
方法。
startProcess
EDIT2:即使在尝试使用它之后,该程序也没有按预期运行。我完成了“慢速方法” private HashMap<String, Integer> addValues(
HashMap<String, Integer> wordsCount, HashMap<String, Integer> temp) {
HashMap<String, Integer> merged = new HashMap<String, Integer>();
for (String x : wordsCount.keySet()) {
Integer y = temp.get(x);
if (y == null) {
merged.put(x, wordsCount.get(x));
} else {
merged.put(x, wordsCount.get(x) + y);
}
}
for (String x : temp.keySet()) {
if (merged.get(x) == null) {
merged.put(x, temp.get(x));
}
}
return merged;
}
的所有优化,但它没有用。所以我开始创建单词字典并首先为每个单词分配索引,然后进行处理。让我们看看它去哪里。谢谢你的帮助!
答案 0 :(得分:2)
我想到了两件事:
答案 1 :(得分:1)
一个建议(我不知道你会从中获得多少改进)是基于curTweet
永远不会被修改的观察。无需创建副本。即。
ArrayList<String> currTweet = new ArrayList<String>(
Arrays.asList(removeUnwantedStrings(tweet)));
可以替换为
List<String> currTweet = Arrays.asList(removeUnwantedStrings(tweet));
或者您可以直接使用数组(速度稍快)。即。
String[] currTweet = removeUnwantedStrings(tweet);
此外,
word.equals(null)
根据{{1}}合同的定义,总是false
。正确的无效检查方法是:
equals
此外,如果执行此操作,则不需要null-pointer-exception try-catch。异常处理在发生时很昂贵,因此如果你的单词数组往往会返回大量的空值,这可能会减慢代码的速度。
更一般地说,这是您应该分析代码并找出实际瓶颈在哪里(如果存在瓶颈)而不是寻找优化广告的情况之一特别
答案 2 :(得分:1)
您可以从更多优化中获益:
static final Pattern ptnTab = Pattern.compile( "\\t" ), ptnEquals = Pattern.compile( "=" );
并致电,例如ptnTab.split( str )
。结果表现应该接近StringTokenizer。word.equals( "" ) || word.equals( null )
。这里有很多浪费的周期。如果你实际上看到空单词,那么你正在捕捉NPE,这是非常昂贵的。请参阅上面@trutheality的回复。答案 3 :(得分:0)
split()使用正则表达式,它们不是“快”。尝试使用StringTokenizer或其他东西。
答案 4 :(得分:0)
您是否考虑过使用db而不是Java。使用数据库工具,您可以使用表中数据库附带的数据加载工具加载数据,然后可以从中进行设置处理。我看到的一个挑战是在表格中加载数据,因为字段不是用“'”或“:”这样的常见分隔符分隔的。
答案 5 :(得分:0)
您可以像这样重写addValues
以加快速度 - 一些注意事项:
HashMap
替换了所有Map
s,这对你没有任何影响,但稍后会让代码更容易更改private Map<String, Integer> addValues(Map<String, Integer> wordsCount, Map<String, Integer> temp) {
Map<String, Integer> merged = new HashMap<String, Integer>(wordsCount); //puts everyting in wordCounts
for (Map.Entry<String, Integer> e : temp.entrySet()) {
Integer countInWords = merged.get(e.getKey()); //the number in wordsCount
Integer countInTemp = e.getValue();
int newCount = countInTemp + (countInWords == null ? 0 : countInWords); //the sum
merged.put(e.getKey(), newCount);
}
return merged;
}