From a7c384b9456c6bfe89d8e9e0a23a2bb57ba2a0a2 Mon Sep 17 00:00:00 2001 From: Richard Imaoka Date: Tue, 28 Nov 2017 17:03:13 +0900 Subject: [PATCH] Add stream-substream.md #23461 --- .../stream-substream-flatMapConcat1.png | Bin 0 -> 4906 bytes .../stream-substream-flatMapConcat2.png | Bin 0 -> 5143 bytes .../images/stream-substream-flatMapMerge.png | Bin 0 -> 6813 bytes .../images/stream-substream-groupBy1.png | Bin 0 -> 5029 bytes .../images/stream-substream-groupBy2.png | Bin 0 -> 6445 bytes .../images/stream-substream-groupBy3.png | Bin 0 -> 8282 bytes .../images/stream-substream-groupBy4.png | Bin 0 -> 7091 bytes .../stream-substream-splitWhen-splitAfter.png | Bin 0 -> 7379 bytes akka-docs/src/main/paradox/stream/index.md | 3 +- .../main/paradox/stream/stages-overview.md | 3 + .../main/paradox/stream/stream-substream.md | 145 ++++++++++++++++++ .../java/jdocs/stream/SubstreamDocTest.java | 115 ++++++++++++++ .../scala/docs/stream/SubstreamDocSpec.scala | 79 ++++++++++ 13 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 akka-docs/src/main/paradox/images/stream-substream-flatMapConcat1.png create mode 100644 akka-docs/src/main/paradox/images/stream-substream-flatMapConcat2.png create mode 100644 akka-docs/src/main/paradox/images/stream-substream-flatMapMerge.png create mode 100644 akka-docs/src/main/paradox/images/stream-substream-groupBy1.png create mode 100644 akka-docs/src/main/paradox/images/stream-substream-groupBy2.png create mode 100644 akka-docs/src/main/paradox/images/stream-substream-groupBy3.png create mode 100644 akka-docs/src/main/paradox/images/stream-substream-groupBy4.png create mode 100644 akka-docs/src/main/paradox/images/stream-substream-splitWhen-splitAfter.png create mode 100644 akka-docs/src/main/paradox/stream/stream-substream.md create mode 100644 akka-docs/src/test/java/jdocs/stream/SubstreamDocTest.java create mode 100644 akka-docs/src/test/scala/docs/stream/SubstreamDocSpec.scala diff --git a/akka-docs/src/main/paradox/images/stream-substream-flatMapConcat1.png b/akka-docs/src/main/paradox/images/stream-substream-flatMapConcat1.png new file mode 100644 index 0000000000000000000000000000000000000000..138136c5d35869c9e98cc9fbb6a1683e804de12d GIT binary patch literal 4906 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 YhCxj`D|7Y@1_lNOPgg&ebxsLQ0K@3a0RR91 literal 0 HcmV?d00001 diff --git a/akka-docs/src/main/paradox/images/stream-substream-groupBy1.png b/akka-docs/src/main/paradox/images/stream-substream-groupBy1.png new file mode 100644 index 0000000000000000000000000000000000000000..de8765b283c79532aaaf7e878a004a216574c4b4 GIT binary patch literal 5029 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 literal 0 HcmV?d00001 diff --git a/akka-docs/src/main/paradox/images/stream-substream-groupBy3.png b/akka-docs/src/main/paradox/images/stream-substream-groupBy3.png new file mode 100644 index 0000000000000000000000000000000000000000..0a2d8be5a6c48d2f0b5bc7d4d1d78d4c5ee883e7 GIT binary patch literal 8282 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 literal 0 HcmV?d00001 diff --git a/akka-docs/src/main/paradox/images/stream-substream-groupBy4.png b/akka-docs/src/main/paradox/images/stream-substream-groupBy4.png new file mode 100644 index 0000000000000000000000000000000000000000..89d752bbe7affb9e62edcf075ea51d5c7d3bd729 GIT binary patch literal 7091 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 U?e{NZU|?YIboFyt=akR{0DMzv*Z=?k literal 0 HcmV?d00001 diff --git a/akka-docs/src/main/paradox/images/stream-substream-splitWhen-splitAfter.png b/akka-docs/src/main/paradox/images/stream-substream-splitWhen-splitAfter.png new file mode 100644 index 0000000000000000000000000000000000000000..815fec43684369502f77859a6d7e95f2efda0c66 GIT binary patch literal 7379 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 R85kHCJYD@<);T3K0RS{z2T1?` literal 0 HcmV?d00001 diff --git a/akka-docs/src/main/paradox/stream/index.md b/akka-docs/src/main/paradox/stream/index.md index f1fa4daddd..93be480114 100644 --- a/akka-docs/src/main/paradox/stream/index.md +++ b/akka-docs/src/main/paradox/stream/index.md @@ -19,7 +19,8 @@ * [stream-parallelism](stream-parallelism.md) * [stream-testkit](stream-testkit.md) * [stages-overview](stages-overview.md) +* [stream-substream](stream-substream.md) * [stream-cookbook](stream-cookbook.md) * [../general/stream/stream-configuration](../general/stream/stream-configuration.md) -@@@ \ No newline at end of file +@@@ diff --git a/akka-docs/src/main/paradox/stream/stages-overview.md b/akka-docs/src/main/paradox/stream/stages-overview.md index b320f9a838..c4917a8fb3 100644 --- a/akka-docs/src/main/paradox/stream/stages-overview.md +++ b/akka-docs/src/main/paradox/stream/stages-overview.md @@ -1375,9 +1375,12 @@ the flow with a `BufferOverflowException`. ## Nesting and flattening stages + These stages either take a stream and turn it into a stream of streams (nesting) or they take a stream that contains nested streams and turn them into a stream of elements instead (flattening). +See the [Substreams](stream-substream.md) page for more detail and code samples. + --------------------------------------------------------------- ### prefixAndTail diff --git a/akka-docs/src/main/paradox/stream/stream-substream.md b/akka-docs/src/main/paradox/stream/stream-substream.md new file mode 100644 index 0000000000..fd84bb467c --- /dev/null +++ b/akka-docs/src/main/paradox/stream/stream-substream.md @@ -0,0 +1,145 @@ +# Substreams + +Substreams are represented as `SubSource` or `SubFlow` instances, on which you can multiplex a single `Source` or `Flow` +into a stream of streams. + +SubFlows cannot contribute to the super-flow’s materialized value since they are materialized later, +during the runtime of the flow graph processing. + +Stages that create substreams are listed on @ref:[Nesting and flattening stages](stages-overview.md#nesting-and-flattening-stages) + +## Nesting stages + +### groupBy + +A typical operation that generates substreams is `groupBy`. + +Scala +: @@snip [SubstreamDocSpec.scala]($code$/scala/docs/stream/SubstreamDocSpec.scala) { #groupBy1 } + +Java +: @@snip [SubstreamDocTest.java]($code$/java/jdocs/stream/SubstreamDocTest.java) { #groupBy1 } + +![stream-substream-groupBy1.png](../../images/stream-substream-groupBy1.png) + +This operation splits the incoming stream into separate output +streams, one for each element key. The key is computed for each element +using the given function, which is `f` in the above diagram. When a new key is encountered for the first time +a new substream is opened and subsequently fed with all elements belonging to that key. + +If you add a `Sink` or `Flow` right after the `groupBy` stage, +all transformations are applied to all encountered substreams in the same fashion. +So, if you add the following `Sink`, that is added to each of the substreams as in the below diagram. + +Scala +: @@snip [SubstreamDocSpec.scala]($code$/scala/docs/stream/SubstreamDocSpec.scala) { #groupBy2 } + +Java +: @@snip [SubstreamDocTest.java]($code$/java/jdocs/stream/SubstreamDocTest.java) { #groupBy2 } + +![stream-substream-groupBy2.png](../../images/stream-substream-groupBy2.png) + +Also substreams, more precisely, `SubFlow` and `SubSource` have methods that allow you to +merge or concat substreams into the master stream again. + +The `mergeSubstreams` method merges an unbounded number of substreams back to the master stream. + +Scala +: @@snip [SubstreamDocSpec.scala]($code$/scala/docs/stream/SubstreamDocSpec.scala) { #groupBy3 } + +Java +: @@snip [SubstreamDocTest.java]($code$/java/jdocs/stream/SubstreamDocTest.java) { #groupBy3 } + +![stream-substream-groupBy3.png](../../images/stream-substream-groupBy3.png) + +You can limit the number of active substreams running and being merged at a time, +with either the `mergeSubstreamsWithParallelism` or `concatSubstreams` method. + +Scala +: @@snip [SubstreamDocSpec.scala]($code$/scala/docs/stream/SubstreamDocSpec.scala) { #groupBy4 } + +Java +: @@snip [SubstreamDocTest.java]($code$/java/jdocs/stream/SubstreamDocTest.java) { #groupBy4 } + +However, since the number of running (i.e. not yet completed) substreams is capped, +be careful so that these methods do not cause deadlocks with back pressure like in the below diagram. + +Element one and two leads to two created substreams, but since the number of substreams are capped to 2 +when element 3 comes in it cannot lead to creation of a new substream until one of the previous two are completed +and this leads to the stream being deadlocked. + +![stream-substream-groupBy4.png](../../images/stream-substream-groupBy4.png) + +### splitWhen and splitAfter + +`splitWhen` and `splitAfter` are two other operations which generate substreams. + +The difference from `groupBy` is that, if the predicate for `splitWhen` and `splitAfter` returns true, +a new substream is generated, and the succeeding elements after split will flow into the new substream. + +`splitWhen` flows the element on which the predicate returned true to a new substream, + whereas `splitAfter` flows the next element to the new substream after the element on which predicate returned true. + +Scala +: @@snip [SubstreamDocSpec.scala]($code$/scala/docs/stream/SubstreamDocSpec.scala) { #splitWhenAfter } + +Java +: @@snip [SubstreamDocTest.java]($code$/java/jdocs/stream/SubstreamDocTest.java) { #splitWhenAfter } + +These are useful when you scanned over something and you don't need to care about anything behind it. +A typical example is counting the number of characters for each line like below. + +Scala +: @@snip [SubstreamDocSpec.scala]($code$/scala/docs/stream/SubstreamDocSpec.scala) { #wordCount } + +Java +: @@snip [SubstreamDocTest.java]($code$/java/jdocs/stream/SubstreamDocTest.java) { #wordCount } + +This prints out the following output. + +``` +23 +16 +26 +``` + +![stream-substream-splitWhen-splitAfter.png](../../images/stream-substream-splitWhen-splitAfter.png) + +## Flattening stages + +### flatMapConcat + +`flatMapConcat` and `flatMapMerge` are substream operations different from `groupBy` and `splitWhen/After`. + +`flatMapConcat` takes a function, which is `f` in the following diagram. +The function `f` of `flatMapConcat` transforms each input element into a `Source` that is then flattened +into the output stream by concatenation. + +Scala +: @@snip [SubstreamDocSpec.scala]($code$/scala/docs/stream/SubstreamDocSpec.scala) { #flatMapConcat } + +Java +: @@snip [SubstreamDocTest.java]($code$/java/jdocs/stream/SubstreamDocTest.java) { #flatMapConcat } + +![stream-substream-flatMapConcat1.png](../../images/stream-substream-flatMapConcat1.png) + +Like the `concat` operation on `Flow`, it fully consumes one `Source` after the other. +So, there is only one substream actively running at a given time. + +Then once the active substream is fully consumed, the next substream can start running. +Elements from all the substreams are concatnated to the sink. + +![stream-substream-flatMapConcat2.png](../../images/stream-substream-flatMapConcat2.png) + +### flatMapMerge + +`flatMapMerge` is similar to `flatMapConcat`, but it doesn't wait for one `Source` to be fully consumed. + Instead, up to `breadth` number of streams emit elements at any given time. + +Scala +: @@snip [SubstreamDocSpec.scala]($code$/scala/docs/stream/SubstreamDocSpec.scala) { #flatMapMerge } + +Java +: @@snip [SubstreamDocTest.java]($code$/java/jdocs/stream/SubstreamDocTest.java) { #flatMapMerge } + +![stream-substream-flatMapMerge.png](../../images/stream-substream-flatMapMerge.png) diff --git a/akka-docs/src/test/java/jdocs/stream/SubstreamDocTest.java b/akka-docs/src/test/java/jdocs/stream/SubstreamDocTest.java new file mode 100644 index 0000000000..7e20e7ea16 --- /dev/null +++ b/akka-docs/src/test/java/jdocs/stream/SubstreamDocTest.java @@ -0,0 +1,115 @@ +/** + * Copyright (C) 2015-2017 Lightbend Inc. + */ +package jdocs.stream; + +import akka.actor.ActorSystem; +import akka.stream.ActorMaterializer; +import akka.stream.Materializer; +import akka.stream.javadsl.Sink; +import akka.stream.javadsl.Source; +import akka.testkit.javadsl.TestKit; +import jdocs.AbstractJavaTest; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class SubstreamDocTest extends AbstractJavaTest { + + static ActorSystem system; + static Materializer mat; + + @BeforeClass + public static void setup() { + system = ActorSystem.create("FlowDocTest"); + mat = ActorMaterializer.create(system); + } + + @AfterClass + public static void tearDown() { + TestKit.shutdownActorSystem(system); + system = null; + mat = null; + } + + @Test + public void demonstrateGroupBy() throws Exception { + //#groupBy1 + Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + .groupBy(3, elem -> elem % 3); + //#groupBy1 + + //#groupBy2 + Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + .groupBy(3, elem -> elem % 3) + .to(Sink.ignore()) + .run(mat); + //#groupBy2 + + //#groupBy3 + Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + .groupBy(3, elem -> elem % 3) + .mergeSubstreams() + .runWith(Sink.ignore(), mat); + //#groupBy3 + + //#groupBy4 + Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + .groupBy(3, elem -> elem % 3) + .mergeSubstreamsWithParallelism(2) + .runWith(Sink.ignore(), mat); + //concatSubstreams is equivalent to mergeSubstreamsWithParallelism(1) + Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + .groupBy(3, elem -> elem % 3) + .concatSubstreams() + .runWith(Sink.ignore(), mat); + //#groupBy4 + } + + @Test + public void demonstrateSplitWhenAfter() throws Exception { + //#splitWhenAfter + Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + .splitWhen(elem -> elem == 3); + + Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + .splitAfter(elem -> elem == 3); + //#splitWhenAfter + + //#wordCount + String text = + "This is the first line.\n" + + "The second line.\n" + + "There is also the 3rd line\n"; + + Source.from(Arrays.asList(text.split(""))) + .map(x -> x.charAt(0)) + .splitAfter(x -> x == '\n') + .filter(x -> x != '\n') + .map(x -> 1) + .reduce((x,y) -> x + y) + .to(Sink.foreach(x -> System.out.println(x))) + .run(mat); + //#wordCount + Thread.sleep(1000); + } + + @Test + public void demonstrateflatMapConcatMerge() throws Exception { + //#flatMapConcat + Source.from(Arrays.asList(1, 2)) + .flatMapConcat(i -> Source.from(Arrays.asList(i, i, i))) + .runWith(Sink.ignore(), mat); + //#flatMapConcat + + //#flatMapMerge + Source.from(Arrays.asList(1, 2)) + .flatMapMerge(2, i -> Source.from(Arrays.asList(i, i, i))) + .runWith(Sink.ignore(), mat); + //#flatMapMerge + } +} diff --git a/akka-docs/src/test/scala/docs/stream/SubstreamDocSpec.scala b/akka-docs/src/test/scala/docs/stream/SubstreamDocSpec.scala new file mode 100644 index 0000000000..ec458e640f --- /dev/null +++ b/akka-docs/src/test/scala/docs/stream/SubstreamDocSpec.scala @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2015-2017 Lightbend Inc. + */ +package docs.stream + +import akka.stream.scaladsl.{ Sink, Source } +import akka.stream.{ ActorMaterializer, SubstreamCancelStrategy } +import akka.testkit.AkkaSpec + +class SubstreamDocSpec extends AkkaSpec { + implicit val materializer = ActorMaterializer() + + "generate substreams by groupBy" in { + //#groupBy1 + val source = Source(1 to 10).groupBy(3, _ % 3) + //#groupBy1 + + //#groupBy2 + Source(1 to 10).groupBy(3, _ % 3).to(Sink.ignore).run() + //#groupBy2 + + //#groupBy3 + Source(1 to 10) + .groupBy(3, _ % 3) + .mergeSubstreams + .runWith(Sink.ignore) + //#groupBy3 + + //#groupBy4 + Source(1 to 10) + .groupBy(3, _ % 3) + .mergeSubstreamsWithParallelism(2) + .runWith(Sink.ignore) + + //concatSubstreams is equivalent to mergeSubstreamsWithParallelism(1) + Source(1 to 10) + .groupBy(3, _ % 3) + .concatSubstreams + .runWith(Sink.ignore) + //#groupBy4 + } + + "generate substreams by splitWhen and splitAfter" in { + //#splitWhenAfter + Source(1 to 10).splitWhen(SubstreamCancelStrategy.drain)(_ == 3) + + Source(1 to 10).splitAfter(SubstreamCancelStrategy.drain)(_ == 3) + //#splitWhenAfter + + //#wordCount + val text = + "This is the first line.\n" + + "The second line.\n" + + "There is also the 3rd line\n" + + val charCount = Source(text.toList) + .splitAfter { _ == '\n' } + .filter(_ != '\n') + .map(_ ⇒ 1) + .reduce(_ + _) + .to(Sink.foreach(println)) + .run() + //#wordCount + } + + "generate substreams by flatMapConcat and flatMapMerge" in { + //#flatMapConcat + Source(1 to 2) + .flatMapConcat(i ⇒ Source(List.fill(3)(i))) + .runWith(Sink.ignore) + //#flatMapConcat + + //#flatMapMerge + Source(1 to 2) + .flatMapMerge(2, i ⇒ Source(List.fill(3)(i))) + .runWith(Sink.ignore) + //#flatMapMerge + } +}