Parallel processing 来自JPA存储库的Java8流

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的查询没有提供另一个实体时,我没有找到终止流程的方法 任何指针?一个简单的例子可

我想从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));
    }