Java 如何提高基于其他流过滤的处理流的性能?

Java 如何提高基于其他流过滤的处理流的性能?,java,java-stream,Java,Java Stream,在处理一个大的对象流(来自一个源)时,我面临一个性能问题,该对象流正在使用另一个大的流/集合(假设来自另一个源)的值进行过滤和映射。我正在尝试一种连接(sql) 我的机器需要11分钟以上的时间来执行它 我以前尝试过在地图上添加一个过滤器,但它使情况恶化得更多 在这件事上我该怎么做才能得到更好的结果 我将提供一个我试图实现的例子 请注意,过滤器仅使用ID,但可以用于两个流的更常见属性 import static java.util.stream.Collectors.toSet; import j

在处理一个大的对象流(来自一个源)时,我面临一个性能问题,该对象流正在使用另一个大的流/集合(假设来自另一个源)的值进行过滤和映射。我正在尝试一种连接(sql)

我的机器需要11分钟以上的时间来执行它

我以前尝试过在地图上添加一个过滤器,但它使情况恶化得更多

在这件事上我该怎么做才能得到更好的结果

我将提供一个我试图实现的例子

请注意,过滤器仅使用ID,但可以用于两个流的更常见属性

import static java.util.stream.Collectors.toSet;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Objects;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class ProcessorQuestion {

  static record Element(int id, String content) {

    public Element(int id, String content) {
      this.id = id;
      this.content = content == null ? "Data " + id : content;
    }
  }

  static record Row(int id, String content) {

    public Row(int id, String content) {
      this.id = id;
      this.content = content == null ? "Row " + id : content;
    }
  }

  static record RowVsElement(Row row, Element element) {
  }

  private static Random r = new Random();

  protected static Stream<Element> loadElementsData() {
    return IntStream.range(1, 1_000_000)
                    .mapToObj(value -> new Element(r.nextInt(235_000), null));
  }

  protected static Stream<Row> loadRowsData() {
    return IntStream.range(1, 235_000)
                    .mapToObj(value -> new Row(r.nextInt(235_000), null));
  }

  public static void main(String[] args) throws IOException {

    var init = Instant.now();

    final ProcessorQuestion processor = new ProcessorQuestion(loadElementsData());
    processor.process();

    System.err.println("Runned in " + Duration.between(init, Instant.now()).toMinutes() + " min");

  }

  private final Collection<Element> entries;

  public ProcessorQuestion(Stream<Element> entries) {
    this.entries = entries.collect(toSet());
  }

  void process() {
    //    System.out.println("rows size = " + rows.size());
    System.out.println("elements size = " + entries.size());

    loadRowsData().parallel()
                  //                    .filter(r0 -> entries.stream()
                  //                                                   .anyMatch(
                  //                                                       entry -> entry.getId() == r0.getId()))
                  .map(r1 -> entries.parallelStream()
                                    .filter(entry -> entry.id() == r1.id())
                                    .findFirst()
                                    .map(elem -> new RowVsElement(r1, elem))
                                    .orElse(null))
                  .filter(Objects::nonNull)
                  .forEachOrdered(pair -> saveOnMedia(pair.row, pair.element));

  }

  void saveOnMedia(Row row, Element element) {

    StringBuilder rsb = new StringBuilder(Integer.toString(row.id()));

    rsb.append(Integer.toString(row.id()));
    rsb.append(";");
    rsb.append(Integer.toString(element.id()));
    rsb.append(";");
    rsb.append(row.content());
    rsb.append(";");
    rsb.append(element.content());
    rsb.append(System.lineSeparator());

    System.out.println(rsb.toString());

  }
}

导入静态java.util.stream.Collectors.toSet;
导入java.io.IOException;
导入java.time.Duration;
导入java.time.Instant;
导入java.util.Collection;
导入java.util.Objects;
导入java.util.Random;
导入java.util.stream.IntStream;
导入java.util.stream.stream;
公共类处理器问题{
静态记录元素(int-id,字符串内容){
公共元素(int-id,字符串内容){
this.id=id;
this.content=content==null?“数据”+id:content;
}
}
静态记录行(int-id,字符串内容){
公共行(整数id,字符串内容){
this.id=id;
this.content=content==null?“行”+id:content;
}
}
静态记录RowVsElement(行、行、元素){
}
私有静态随机r=新随机();
受保护的静态流loadElementsData(){
返回IntStream.range(1,1\u 000\u 000)
.mapToObj(值->新元素(r.nextInt(235_000),null));
}
受保护的静态流loadRowsData(){
返回IntStream.范围(1235000)
.mapToObj(值->新行(r.nextInt(235_000),null));
}
公共静态void main(字符串[]args)引发IOException{
var init=Instant.now();
最终处理器问题处理器=新处理器问题(loadElementsData());
process();
System.err.println(“在”+Duration.between(init,Instant.now()).toMinutes()+min)中运行”;
}
私人最终收藏作品;
公共处理器问题(流条目){
this.entries=entries.collect(toSet());
}
无效过程(){
//System.out.println(“rows size=“+rows.size());
System.out.println(“elements size=“+entries.size());
loadRowsData().parallel()
//.filter(r0->entries.stream()
//.任何比赛(
//entry->entry.getId()==r0.getId())
.map(r1->entries.parallelStream()
.filter(条目->条目.id()==r1.id())
.findFirst()
.map(元素->新行元素(r1,元素))
.orElse(空))
.filter(对象::非空)
.forEachOrdered(pair->saveOnMedia(pair.row,pair.element));
}
void saveOnMedia(行、行、元素){
StringBuilder rsb=新的StringBuilder(Integer.toString(row.id());
append(Integer.toString(row.id());
rsb.追加(“;”);
append(Integer.toString(element.id());
rsb.追加(“;”);
append(row.content());
rsb.追加(“;”);
append(element.content());
append(System.lineSeparator());
System.out.println(rsb.toString());
}
}
我已经从VisualVM上执行的屏幕上打印了一些内容:


按照人们的建议,尝试使用地图:

Map<Integer, Element> elementMap = entries.stream().collect(Collectors.toMap(it -> it.id(), it -> it, (a, b) -> a));

loadRowsData()
        //                    .filter(r0 -> entries.stream()
        //                                                   .anyMatch(
        //                                                       entry -> entry.getId() == r0.getId()))
        .map(r1 -> elementMap.containsKey(r1.id()) ? new RowVsElement(r1, elementMap.get(r1.id())) : null)
        .filter(Objects::nonNull)
        .forEachOrdered(pair -> saveOnMedia(pair.row, pair.element));
Map elementMap=entries.stream().collect(Collectors.toMap(it->it.id(),it->it,(a,b)->a));
loadRowsData()
//.filter(r0->entries.stream()
//.任何比赛(
//entry->entry.getId()==r0.getId())
.map(r1->elementMap.containsKey(r1.id())?新的RowVsElement(r1,elementMap.get(r1.id()):null)
.filter(对象::非空)
.forEachOrdered(pair->saveOnMedia(pair.row,pair.element));
如果只是将结果保存到列表中,而不是打印所有结果,则应在一秒钟内完成。打印结果可能需要几秒钟


正如Knittl在评论中所说:“你的算法有O(m*n)复杂度——m=235000,n=1000000,即~235000000000”。这就是它花费如此长时间的原因。

首先,用
ThreadLocalRandom
替换
Random
。有重叠的子问题
new Element(…)
new Row(…)
,您可能希望使用数组缓存它们?您的算法具有O(m*n)复杂性–m=235000,n=1000000,这大约是235000000000次迭代。将您的条目存储在
HashMap
中,通过id进行O(1)访问可能是有意义的,这将您的总体复杂性降低到O(n)–1000000次迭代。这很奇怪。无论如何,我想指出的是,在这里使用数组而不是
HashMap
将是一个更好的选择,因为这样您就不需要将int框起来。我知道实际的代码是不同的,但代码中有很多重叠的子问题。我创建它是为了让您看看,它在我的计算机上运行不到1分钟。@Cristiano您始终可以将“主键”(即唯一标识您的对象的东西)放入它自己的类(可以由许多属性组成)中,然后提供equals和hashCode实现。然后将其用作查找结构中的键。只要实例化关键对象或计算其哈希代码/平等性测试成本不太高,这应该已经有所改善。