2016-05-15 12 views
5

Supponiamo di disporre di più flussi java 8 che ogni flusso potenzialmente può essere convertito in Set<AppStory>, ora voglio con le migliori prestazioni per aggregare tutti gli stream in un flusso DISTINCT da ID, in ordine di proprietà ("lastUpdate")Qual è il modo migliore per aggregare gli stream in un DISTINCT con Java 8

ci sono diversi modi per fare ciò, ma voglio il più veloce, per esempio:

Set<AppStory> appStr1 =StreamSupport.stream(splititerato1, true). 
map(storyId1 -> vertexToStory1(storyId1).collect(toSet()); 

Set<AppStory> appStr2 =StreamSupport.stream(splititerato2, true). 
map(storyId2 -> vertexToStory2(storyId1).collect(toSet()); 

Set<AppStory> appStr3 =StreamSupport.stream(splititerato3, true). 
map(storyId3 -> vertexToStory3(storyId3).collect(toSet()); 


Set<AppStory> set = new HashSet<>(); 
set.addAll(appStr1) 
set.addAll(appStr2) 
set.addAll(appStr3) , and than make sort by "lastUpdate".. 

//POJO Object: 
public class AppStory implements Comparable<AppStory> { 
private String storyId; 
private String ........... many other attributes...... 
public String getStoryId() { 
    return storyId; 
} 
@Override 
public int compareTo(AppStory o) { 
    return this.getStoryId().compareTo(o.getStoryId()); 
    } 
} 

... ma è il vecchio modo.

Come posso creare un unico distinto per ID ordinato flusso con la migliore prestazione

somethink come:

Set<AppStory> finalSet = distinctStream.sort((v1, v2) -> Integer.compare('not my issue').collect(toSet()) 

tutte le idee?

BR

Vitaly

+0

Come si presenta il metodo 'equals'? – Flown

+0

@Override public boolean equals (Object o) { if (this == o) return true; if (o == null || getClass()! = O.getClass()) restituisce false; AppStory appStory = (AppStory) o; return! (StoryId! = Null?! StoryId.equals (appStory.storyId): appStory.storyId! = Null); } – VitalyT

+0

Penso qualcosa del tipo: Set dsd = Stream.of (appStr1, appStr2) .flatMap (Stream :: distinto) .sorted ((s1, s2) -> Long.compare (s1.getLastUpdateTime(), s2 . .getLastUpdateTime())) raccogliere (Toset()); – VitalyT

risposta

1

penso che l'overhead parallelo è molto maggiore rispetto il lavoro effettivo come avete dichiarato nei commenti. Quindi lascia che il tuo Stream esegua il lavoro in modo sequenziale.

Nota: È preferibile utilizzare Stream::concat perché le operazioni di divisione come Stream::limit possono essere ignorate da Stream::flatMap.

Stream::sorted sta raccogliendo ogni elemento della Stream in un List, ordinare la List e poi spinta degli elementi nell'ordine desiderato lungo la conduttura. Quindi gli elementi vengono raccolti di nuovo. Quindi, questo può essere evitato raccogliendo gli elementi in un List e dopo l'ordinamento. L'utilizzo di List è una scelta di gran lunga migliore rispetto all'utilizzo di Set perché l'ordine è importante (so che c'è uno LinkedHashSet ma non è possibile ordinarlo).

Questa è la soluzione a mio parere la più pulita e forse la più veloce poiché non possiamo provarlo.

Stream<AppStory> appStr1 =StreamSupport.stream(splititerato1, false) 
             .map(this::vertexToStory1); 
Stream<AppStory> appStr2 =StreamSupport.stream(splititerato2, false) 
             .map(this::vertexToStory2); 
Stream<AppStory> appStr3 =StreamSupport.stream(splititerato3, false) 
             .map(this::vertexToStory3); 

List<AppStory> stories = Stream.concat(Stream.concat(appStr1, appStr2), appStr3) 
           .distinct().collect(Collectors.toList()); 
// assuming AppStory::getLastUpdateTime is of type `long` 
stories.sort(Comparator.comparingLong(AppStory::getLastUpdateTime)); 
+1

Parallel distinto è costoso per _ stream ordinati, ma per flussi non ordinati, è molto più efficiente. (Negli stream ordinati, 'distinct()' deve preservare il _primo_ di occorrenze uguali, simile al requisito di stabilità nell'ordinamento.) Tira un 'unordered()' nello stream e probabilmente troverai le prestazioni parallele molto più attraente. –

+0

È possibile ottenere prestazioni generali migliori utilizzando 'Stream.toArray()', seguito da entrambi, 'Arrays.sort' o' Arrays.parallelSort', seguito da 'Arrays.asList'. – Holger

1

Non posso garantire che questo sarebbe stato più veloce di quello che hai (immagino così, ma dovrete misurare per essere sicuri), ma si può semplicemente fare questo, a patto di avere 3 flussi:

List<AppStory> distinctSortedAppStories = 
    Stream.of(stream1, stream2, stream3) 
      .flatMap(Function.identity()) 
      .map(this::vertexToStory) 
      .distinct() 
      .sorted(Comparator.comparing(AppStory::getLastUpdate)) 
      .collect(Collectors.toList()); 
+0

perché usi "....mappa (this :: vertexToStory) "? tutti gli stream" stream1, stream2, stream3 "... hanno già trasformato tramite la funzione map perché non utilizzare Stream :: distinto? – VitalyT

+1

Perché ciò consente di farlo una volta invece di tre volte: basta passare i flussi originali invece di passare 3 flussi "mappati" e lasciare che il flusso combinato esegua la mappatura. Per quanto riguarda la seconda parte: la combinazione di 3 flussi distinti non porta a un flusso distinto. È necessario utilizzare distinct() sulla combinazione stream, per assicurarti che tutti gli elementi siano univoci –

+3

Forse potresti usare Stream.concat invece di stream.of + flatmqp –

Problemi correlati