1

我正在连接一个非常不灵活的套接字 API。它将返回如下行:

NAME, CITY, STATE, JOB, MONTH

但是会有重复,因为它不做任何聚合。我需要计算重复的行(这在 SQL 中很容易,但据我所知,在 Java 中不是)。

示例源数据:

NAME,     CITY, STATE, JOB,         MONTH
John Doe, Denver, CO, INSTALLATION, 090301
John Doe, Denver, CO, INSTALLATION, 090301
John Doe, Denver, CO, INSTALLATION, 090301
Jane Doe, Phoenix, AZ, SUPPORT, 090301

故意的:

    NAME,    CITY, STATE,          JOB,  MONTH, COUNT
John Doe,  Denver,    CO, INSTALLATION, 090301,   3
Jane Doe, Phoenix,    AZ,      SUPPORT, 090301,   1

我可以轻松地为大约 100,000 个返回行执行此操作,但我在一个月内处理大约 6000 万个返回行。有任何想法吗?

编辑:不幸的是,这些行没有返回排序......也没有通过API对它们进行排序的选项。我得到了一大堆需要汇总的东西。现在我使用一个 ArrayList 并执行 indexOf(new row) 来查找该项目是否已经存在,但是越多的行它就越慢。

编辑:为澄清起见,这只需要每月运行一次,在月底。谢谢大家的回复

4

5 回答 5

3

您可以使用 HashSet 来存储具有相同内容的前一行。(假设您的 Row 对象实现了正确的 .hashValue() 和 .equals() 方法。

可能是这样的:

Set<Row> previousRows = new HashSet<Row>();
List<Row> rowsInOrder = new LinkedList<Row>();

然后在使用中(进一步假设您对 Row 类有一个 incrementCount() 方法):

Row newRow = getNextRow();
if(!previousRows.contains(newRow)){
    previousRows.put(newRow);
    rowsInOrder.add(newRow);
} 
previousRows.get(newRow).incrementCount();

如果你不关心行进来的顺序,你可以去掉 List 而只使用 Set。

于 2009-11-07T04:23:22.400 回答
1

您是否具有灵活性,或者这是一项足够重要的任务来投资于Hadoop之类的东西?有了这么大的数据,您想开始从“地图缩减”的思维方式来考虑它。

于 2009-11-07T03:32:20.147 回答
1

您是否能够一次将所有数据放入内存中?如果你把它放在一个 ArrayList 中,听起来你可以。

如果是这种情况,您可以只使用 MultiSet 的实现,例如Google 集合中的那个

然后,您可以将所有行插入到多重集中,如下所示

Multiset<Row> rowMultiset = HashMultiset.create();
for (Row row: rows) {
  rowMultiset.add(row);
}

你可以通过计数来迭代,使用类似的东西:

for (Multiset.Entry entry : rowMultiset.entrySet()) {
  System.out.println("row: "+entry.getElement()+", count: "+entry.getCount());
}

如果您不想使用外部库,您可以使用 HashMap 将行映射到整数来执行类似的操作。

如果不是所有行都适合内存,我认为最简单的方法就是将数据插入数据库并进行查询。数据库是为不适合内存的大型数据集设计和优化的。

于 2009-11-07T04:25:28.263 回答
0

返回的行是否总是排序的?IE。要分组的行总是一个接一个地返回吗?如果答案是肯定的:

1) 初始化一个计数器。

2)跟踪您刚刚阅读的上一行并将其与当前行进行比较。如果相同,请增加您的计数器。如果不同,请使用当前计数器值记录您的行并重置计数器。

3)当您到达最后一条记录时,请确保记录当前计数的行。

这种策略将允许您读取流中的大型数据集,并保持程序的内存占用较低,同时生成您所追求的更紧凑的聚合数据。

于 2009-11-07T03:35:06.070 回答
0

我可以想到四种方法来做到这一点:

  • 如果您有足够的内存在内存中保存 6000 万行的表示(较少重复),请使用 aHashMap<Row, Integer>来表示计数。

  • 将行存储在 RDB 中,然后使用 SQL 进行聚合和计数。

  • 将行写入一个大文件并使用经典的合并排序,然后再一次计算行数。

  • 使用 Hadoop 之类的东西将行分布在多台机器上。

您预计将在一个月或更长时间内累积计数这一事实表明您需要考虑您的应用程序需要重新启动的可能性。这表明需要一个 RDB 或基于文件的解决方案。

于 2009-11-07T08:39:59.403 回答