java - 如何在 java 中有效地处理数百万元组的集合?

标签 java vector collections arraylist

我正在开发一个 java 程序,它实际上从 postgresql 数据库中检索元组并使用它们做一些工作。我将每个元组表示为 StringVector,并将完整的元组集 (resultSet) 表示为元组的 vector 。

Vector<String>         tuple;
Vector<Vector<String>> resultSet;

在我的应用程序中,我需要处理数百万个元组。这是一个简单的基准测试,它通过简单地读取结果集中的 X 个元组然后打印结果集大小、第一个和最后一个元组来模拟我的程序。

benchmark 考虑使用 vector 和 arrayList 来表示元组

List<String>       tuple;
List<List<String>> resultSet;

基准程序代码

import java.util.Vector;
import java.util.List;
import java.util.ArrayList;

public class VectorVSarrayList {

  public static void loadDataInVector(Integer size){

    Vector<Vector<String>> r     = new Vector<Vector<String>>();
    Vector<String>         tuple = new Vector<String>();

    startTimer();  

    for(Integer i = 0; i < size; i++){

      tuple = new Vector<String>();

      for(int j = 0; j < 3; j ++)
        tuple.add(i.toString() + " tuple "+j);

      r.add(tuple);

    }

    endTimer("vector size " + r.size() + " first element : " + r.get(0).get(0) + ", and     last element : " + r.get(r.size()-1).get(0)); 

    r.clear();

  }

  public static void loadDataInArrayList(Integer size){

    List<List<String>> r     = new ArrayList<List<String>>();
    List<String>       tuple = new ArrayList<String>();


    startTimer();    

    for(Integer i = 0; i < size; i++){

      tuple = new ArrayList<String>();

      for(int j = 0; j < 3; j ++)
        tuple.add(i.toString() + " tuple "+j);

     r.add(tuple);
    }

    endTimer("array  size " + r.size() + " first element : " + r.get(0).get(0) + ", and  last element : " + r.get(r.size()-1).get(0)); 

    r.clear();       
  }

  public static void main(String [] args){

    Integer size = Integer.parseInt(args[0]);

    loadDataInArrayList(size);
    loadDataInVector(size);

    loadDataInArrayList(size);
    loadDataInVector(size);
  }

  private static long startTime = 0;
  private static long endTime   = 0;

  public static void startTimer(){
    startTime = System.currentTimeMillis();
  }

  public static void endTimer(String log){
        endTime = System.currentTimeMillis();
        System.out.println(log + ", " + (endTime - startTime) + ", ms");
 }


}

我已经运行了基准测试来处理 1 和 1000 万个元组,Java 堆大小扩展到 2G,这是结果

> time java -Xmx2g VectorVSarrayList 1000000
array  size 1000000 first element : 0 tuple 0, and last element : 999999 tuple 0, 1642, ms
vector size 1000000 first element : 0 tuple 0, and last element : 999999 tuple 0, 1075, ms
array  size 1000000 first element : 0 tuple 0, and last element : 999999 tuple 0, 1625, ms
vector size 1000000 first element : 0 tuple 0, and last element : 999999 tuple 0, 308, ms

real    0m4.829s
user    0m14.849s
sys     0m0.500s


> time java -Xmx2g VectorVSarrayList 10000000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at VectorVSarrayList.loadDataInArrayList(VectorVSarrayList.java:72)
    at VectorVSarrayList.main(VectorVSarrayList.java:28)

real    6m12.708s
user    22m57.662s
sys     0m6.200s

这些结果表明,即使只有 1000 万个元组,我也将花费至少 6 分钟(而 100 万个元组需要 4 秒)并最终运行 OutOfMemory

OS         : Ubuntu 12.04
RAM        : 6 GB
processor  : Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz

是否有更好的方法(更好的集合类型或更好的实践)来完成此类工作?

最佳答案

根据“一些工作”的含义,您可以优化这个问题,我将其理解为对数据库中的结果进行分组

显然,您可以使用更高效的数据结构,这样不会使您的堆溢出。但是每次数据更改(相关)时,这些都需要维护。在上述情况下,创建初始大小为 3 的 ArrayList 或更好地使用 LinkedList。

另一种方法是让数据库已经准备好数据,以便此准备支持您的操作。喜欢

  • 按您的组键排序数据(在数据库中)
  • 迭代器遍历数据,只要组键相同就填充A vector
  • 当组键更改时,对分组序列进行一些处理(例如存储或打印出第一个、最后一个和大小或其他任何内容)并仅存储该序列的相关事实。
  • 数据完成后,处理每个序列的结果,比如聚合它们

这种方法称为 MapReduce,这里映射是在数据库中(虚拟地)完成的,而缩减是在您的程序中完成的。

关于java - 如何在 java 中有效地处理数百万元组的集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22854086/

相关文章:

java - 用 this 调用实例方法

java - 使用字符串键和对象引用值创建映射

c++ - 通过 Lambda 删除 vector 项

collections - 在 Kotlin 中维护重复值的两个列表的交集

java - 更新记录时如何使用替换方法?

lambda - 使用 java 8 流对列表项进行分组和求和

java - Maven编译: package does not exist

r - R 中的自定义属性传播

C++ - 迭代 vector 的替代方法

java - Activity 不调用 onActivityResult