Parallel processing 来自JPA存储库的Java8流
我想从JPA存储库创建一个流。目标是将来自回购协议的实体(可能超过100万)映射到其他实体,这些实体将存储在另一个回购协议中 到目前为止,我构建了一个收集器,它将收集给定数量(例如1000)的实体,然后将它们存储到目标回购协议中。这将在并行流中工作。我现在需要的是一种从源Repo获取实体并根据需要将它们提供给流的好方法 到目前为止,最有希望的是实现一个Supplier(),通过generate构建流,但当对源Repo的查询没有提供另一个实体时,我没有找到终止流程的方法Parallel processing 来自JPA存储库的Java8流,parallel-processing,java-8,spring-data-jpa,java-stream,spliterator,Parallel Processing,Java 8,Spring Data Jpa,Java Stream,Spliterator,我想从JPA存储库创建一个流。目标是将来自回购协议的实体(可能超过100万)映射到其他实体,这些实体将存储在另一个回购协议中 到目前为止,我构建了一个收集器,它将收集给定数量(例如1000)的实体,然后将它们存储到目标回购协议中。这将在并行流中工作。我现在需要的是一种从源Repo获取实体并根据需要将它们提供给流的好方法 到目前为止,最有希望的是实现一个Supplier(),通过generate构建流,但当对源Repo的查询没有提供另一个实体时,我没有找到终止流程的方法 任何指针?一个简单的例子可
任何指针?一个简单的例子可能是:
@Repository
public class MyEntityRepository extends CrudRepository<MyEntity, Long> {
}
@Component
public class MyEntityService {
@Autowired
private MyEntityRepository myEntityRepository;
public void() {
// if the findAll() method returns List
Stream<MyEntity> streamFromList = myEntityRepository.findAll().stream();
// if the findAll() method returns Iterable
Stream<MyEntity> streamFromIterable = StreamSupport.stream(myEntityRepository.findAll().spliterator(), true);
}
}
@存储库
公共类MyEntityRepository扩展了Crudepository{
}
@组成部分
公共类MyEntityService{
@自动连线
私人髓鞘再生髓鞘再生;
公共空间(){
//如果findAll()方法返回List
Stream streamFromList=myEntityRepository.findAll().Stream();
//如果findAll()方法返回Iterable
Stream streamFromIterable=StreamSupport.Stream(myEntityRepository.findAll().spliterator(),true);
}
}
如果您能够将源代码表示为供应商
实现,那么您也可以实现拆分器
。而不是Supplier.get
您将实现boolean tryAdvance(Consumer)
,它不会返回新值,而是在Consumer
上调用accept
,否则返回false
。在大多数情况下,与迭代器
相比,这简化了实现,迭代器必须处理两个方法hasNext
和next
,这两个方法可以按任意顺序调用
您必须为拆分器实现更多的方法,但谢天谢地,有一些直接的方法可以实现它们
public Spliterator<T> trySplit() {
return null;// simple answer when splitting is not supported
}
public long estimateSize() {
return Long.MAX_VALUE; // the value which should be used for UNKNOWN
}
public int characteristics() {
return 0; // no flags but check out whether some flags fit
}
如果您的源代码更适合hasNext
/next
模式,您可以实现一个普通的迭代器
,并让JRE创建一个拆分器
,如Ok中所述,感谢所有的贡献。我把所说的结合起来,实现了我所需要的。也许实施会澄清我想从什么开始
我创建了两个类,RepositoryCollector和RepositorySpliterator
public class RepositorySpliterator<T> implements Spliterator<T> {
private Slice<T> slice;
private Function<Pageable, Slice<T>> getSlice;
private Iterator<T> sliceIterator;
public RepositorySpliterator(Pageable pageable, Function<Pageable, Slice<T>> getSlice) {
this.getSlice = getSlice;
this.slice = this.getSlice.apply(pageable);
this.sliceIterator = slice.iterator();
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if(sliceIterator.hasNext()) {
action.accept(sliceIterator.next());
return true;
} else if (slice.hasNext()) {
this.slice = getSlice.apply(slice.nextPageable());
this.sliceIterator = this.slice.iterator();
if(sliceIterator.hasNext()){
action.accept(sliceIterator.next());
return true;
}
}
return false;
}
public Stream<T> getStream(boolean parallel){
return StreamSupport.stream(this, parallel);
}
}
公共类RepositoryCollector实现收集器{
私有JPA存储库;
私有整数阈值;
公共二进制运算符组合器(){
返回(listTuple,itemsTuple)->{
列表=列表元组。\u 2;
列表项目=项目列表;
列表。添加所有(项目);
int sum=listuple.\u 1+itemsTuple.\u 1;
if(list.size()>=此.threshold){
this.repository.save(列表);
this.repository.flush();
列表=新的LinkedList();
}
返回新的Tuple2(总和,列表);
};
}
}
我省略了收集器所需的其他功能,因为所有相关信息都存在于组合器中。同样适用于拆分器
public class RepositorySpliterator<T> implements Spliterator<T> {
private Slice<T> slice;
private Function<Pageable, Slice<T>> getSlice;
private Iterator<T> sliceIterator;
public RepositorySpliterator(Pageable pageable, Function<Pageable, Slice<T>> getSlice) {
this.getSlice = getSlice;
this.slice = this.getSlice.apply(pageable);
this.sliceIterator = slice.iterator();
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if(sliceIterator.hasNext()) {
action.accept(sliceIterator.next());
return true;
} else if (slice.hasNext()) {
this.slice = getSlice.apply(slice.nextPageable());
this.sliceIterator = this.slice.iterator();
if(sliceIterator.hasNext()){
action.accept(sliceIterator.next());
return true;
}
}
return false;
}
public Stream<T> getStream(boolean parallel){
return StreamSupport.stream(this, parallel);
}
}
公共类RepositorySpliterator实现Spliterator{
私有切片;
私有函数getSlice;
私有迭代器;
公共存储拆分器(可分页、可分页、函数getSlice){
this.getSlice=getSlice;
this.slice=this.getSlice.apply(可分页);
this.sliceIterator=slice.iterator();
}
@凌驾
public boolean tryAdvance(Consumer我们最近在Spring Data Fowler发布系列的最新RC1版本中添加了对Spring Data JPA(和MongoDB)中的支持
据我所知,findAll将急切地获取完整的集合。我需要延迟获取。可能的供应商副本仅适用于无限流。您可以编写一个简单的旧迭代器。拆分器是我的第二个猜测。我希望得到一个更直接的解决方案。问题仍然是我不想获取完整的E集合实体,而仅仅使用存储库作为迭代器是没有好处的。您可以批量加载实体。我知道我可以进行分页。我想要的是根据需要从源存储库获取实体,并将它们输入并行流,在其中映射、累积并存储到目标存储库中。非常感谢您的参与放!嗨,托马斯,非常感谢。我实际上在博客上写了关于如何亲自见到你使事情进展顺利(德语):
public class RepositorySpliterator<T> implements Spliterator<T> {
private Slice<T> slice;
private Function<Pageable, Slice<T>> getSlice;
private Iterator<T> sliceIterator;
public RepositorySpliterator(Pageable pageable, Function<Pageable, Slice<T>> getSlice) {
this.getSlice = getSlice;
this.slice = this.getSlice.apply(pageable);
this.sliceIterator = slice.iterator();
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if(sliceIterator.hasNext()) {
action.accept(sliceIterator.next());
return true;
} else if (slice.hasNext()) {
this.slice = getSlice.apply(slice.nextPageable());
this.sliceIterator = this.slice.iterator();
if(sliceIterator.hasNext()){
action.accept(sliceIterator.next());
return true;
}
}
return false;
}
public Stream<T> getStream(boolean parallel){
return StreamSupport.stream(this, parallel);
}
}
public void start(Timestamp startTimestamp, Timestamp endTimestamp) {
new RepositorySpliterator<>(
new PageRequest(0, 10000), pageable -> sourceRepository.findAllBetween(startTimestamp, endTimestamp, pageable))
.getStream(true)
.map(entity -> mapToTarget(endTimestamp, entity))
.collect(new RepositoryCollector<>(targetRepository, 1000));
}