int[] records = job.getTargetSearchIDs();
topology.applyMatcherSearchWeight(records);
int[] mIDs = topology.getMatcherIds();
SystemResponse[] sysResponse = new SystemResponse[mIDs.length];
Map<Integer, SearchCommand> mrCmdsMap = new HashMap<Integer, SearchCommand>();
mID的长度为250,记录的长度为750万个整数。我希望这个循环能够在不到3秒的时间内在具有8核Intel Xeon X5355处理器,64位Linux(Ubuntu)和32位Java的服务器上运行。
for (long mID : mIDs) {
List<Integer> recIDsToMatch = new LinkedList<Integer>();
Matcher matcher = topology.getMatcherById(mID);
for (long record : records) {
if (matcher.getRange().isInRange(record))
recIDsToMatch.add(record);
}
if (recIDsToMatch.size() > 0) {
SearchCommand command = new SearchCommand(job.getMatchParameters(),
job.getRequestType(),
job.getId(),
job.getMatchParameters().getEngineProperties(),
recIDsToMatch);
command.setTimeout(searchTimeout, TimeUnit.SECONDS);
mrCmdsMap.put(mID, command);
}
}
当您阅读此代码段时会想到哪些改进?可以进行哪些数据结构和/或算法改进?
答案 0 :(得分:3)
如果isInRange()
实际检查给定的整数是否在特定范围内,那么将记录放入以更有效的方式执行此操作的数据结构中可能会更好。
例如,尝试将记录放入TreeSet
,然后使用subSet
查找范围内的记录。
另一种方法是构建类似TreeMap<Integer, List<Matcher>>
的内容,其中value是Matcher
的列表,涵盖当前密钥和后续密钥之间的范围。它可能更好,因为Matcher
的数量小于记录的数量。
答案 1 :(得分:2)
单个循环没有利用多核的优势......如果你可以在子集中打破这个循环迭代,创建线程会更好。
例如:将你的数组分成6块,每块一个线程。
答案 2 :(得分:1)
如果你有大型数据集并且想要速度和简单性,可以考虑使用像Lucene这样的文本搜索引擎,它可以在几毫秒内使用相当复杂的匹配参数索引数百万个文档并检索命中。
答案 3 :(得分:0)
您正在尝试迭代某些集合(而不是搜索集合中的元素),这意味着您将至少运行 O [n ]时间复杂度(即线性时间复杂度),您还有一个嵌套的for循环,这会使您的时间复杂度达到 O [n ^ 2]时间复杂度(即二次方程式)时间复杂度)。
检查以确保您没有在循环内执行任何剩余操作,并且如果可能的话,尽可能在循环外移动(任何初始化等)。
如果你只想迭代整个集合然后遍历集合中该元素的成员子集,那么你没有做太多事情就是你没有做过。
答案 4 :(得分:0)
您让我们猜测问题背后的数据结构,但有三种可能性:
您正在做的事情实际上需要在3秒内完成400亿条记录(13G记录/秒)。我不认为你的内存系统可以处理这个带宽;如果确实如此,你需要更多的硬件。 (但我打赌不是。)
您只是想查看一个数字是否在一组4000万个范围内,而且大多数数字都不在该范围内。然后你需要一个interval tree。你可以找到各种各样的实现;不幸的是,Apache Commons和Guava都没有。
您只是想看看4000个不同范围内的4000万中的哪些数字。对4000万个数字(一次)进行排序,然后二次搜索到范围的端点(对于每个范围)。介于两者之间的所有东西都在。
如果2.或3.描述您的问题,则在单个核心上只需要几分之一秒。