我们说我有这些代码。据我所知,下面的代码运行就好,如果我有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
});
答案 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,那么你将打败问题本身的目的。