从数据库中获取Java Stream Group by Row

时间:2018-05-18 14:58:59

标签: java java-stream

我们说我有这些代码。据我所知,下面的代码运行就好,如果我有10个查询并同时运行它们,并且每个查询返回10M结果,我必须等待从数据库中取出的100M行才能启动组功能。

我的问题,因为Country和City笛卡尔积的基数很低,而且我必须从数据库中获取的行数是巨大的。我想从数据库中获取一行时立即计算组结果。我怎么能用Java Stream做到这一点?

  myqueries
 .parallelstream()
 .map( m-> { 
    //queryresult is a stream which return database rows
    return queryresult;
 })
 .flatMap(fm-> fm)
 .collect(Collectors.groupingBy(g-> {
                    List<Object> objects = Arrays.<Object>asList(
                    g.getCountry(),
                    g.getCity());
                    return objects;
                }, Collectors.toList()))


                .entrySet().stream().map(m-> {
                    MyResultClass item = new MyResultClass();
                    item.setCountry((String) m.getKey().get(0));
                    item.setCity((String) m.getKey().get(1));
                    item.setSumField1(m.getValue().stream().mapToDouble(m2-> m2.getSumField1()).sum());
                    item.setSumField2(m.getValue().stream().mapToDouble(m2-> m2.getSumField2()).sum());
                    item.setSumField3(m.getValue().stream().mapToDouble(m2-> m2.getSumField3()).sum());                 
                    return item;
                 }).forEach(f-> {

                //print the MyResultClass fields
        });

1 个答案:

答案 0 :(得分:1)

您的解决方案的问题是,您正在将所有数据收集到列表中,只是为了进一步减少。因此它会将所有数据累积到内存中。您可以使用toMap将这两种缩减合并为单一缩减:

myqueries
 .parallelstream()
 .flatMap( m-> { 
    //queryresult is a stream which return database rows
    return queryresult;
 })
 .collect(Collectors.toMap(
               g-> Arrays.<Object>asList(g.getCountry(), g.getCity()),
               v -> { 
                      MyResultClass item = new MyResultClass();
                      item.setCountry(v.getCountry());
                      item.setCity(v.getCity());
                      return item;
                    },
                (t, u) -> {
                       t.setSumField1(t.getSumField1() + u.getSumField1());
                       t.setSumField2(t.getSumField2() + u.getSumField3());
                       t.setSumField3(t.getSumField3() + u.getSumField3());
                       return t;
                      }
                 )
                .values().forEach(f-> {

                //print the MyResultClass fields
                });

另外,请注意,在此处使用parallelStream时,并不意味着所有查询都将并行运行。并行性取决于查询数量,计算机内核数量和运行时环境。如果要控制并发查询行为,请更好地使用ExecutorService

另一点需要注意的是,执行还将取决于您首先从查询结果创建Stream的方式。如果你等到你得到所有结果,然后创建Stream,那么你将打败问题本身的目的。