---
title: Stream API Overview
layout: documentation
documentation: true
---

* [Concepts](#concepts)
    * [Stream Builder](#streambuilder)
    * [Value mapper](#valuemapper)
* [Stream APIs](#streamapis)
    * [Basic transformations](#basictransformations)
        * [filter](#filter)
        * [map](#map)
        * [flatmap](#flatmap)
    * [Windowing](#windowing)
    * [Transformation to key-value pairs](#keyvaluepairs)
        * [mapToPair](#mapflatmaptopair)
        * [flatMapToPair](#mapflatmaptopair)
    * [Aggregations](#aggregations)
        * [aggregate](#aggregatereduce)
        * [reduce](#aggregatereduce)
        * [aggregateByKey](#aggregatereducebykey)
        * [reduceByKey](#aggregatereducebykey)
        * [groupByKey](#groupbykey)
        * [countByKey](#countbykey)
    * [Repartition](#repartition)
    * [Output operations](#outputoperations)
        * [print](#print)
        * [peek](#peek)
        * [forEach](#foreach)
        * [to](#to)
    * [Branch](#branching)
    * [Joins](#joins)
    * [CoGroupByKey](#cogroupbykey)
    * [State](#state)
        * [updateStateByKey](#updatestatebykey)
        * [stateQuery](#statequery)
* [Guarantees](#guarantees)        
* [Example](#example)

Historically Storm provided Spout and Bolt apis for expressing streaming computations. Though these apis are fairly simple to use, 
there are no reusable constructs for expressing common streaming operations like filtering, transformations, windowing, joins, 
aggregations and so on.

Stream APIs build on top of the Storm's spouts and bolts to provide a typed API for expressing streaming computations and supports functional style operations such as map-reduce. 

# <a name="concepts"></a> Concepts 

Conceptually a `Stream` can be thought of as a stream of messages flowing through a pipeline. A `Stream` may be generated by reading messages out of a source like spout, or by transforming other streams. For example,

```java
// imports
import org.apache.storm.streams.Stream;
import org.apache.storm.streams.StreamBuilder;
...

StreamBuilder builder = new StreamBuilder();

// a stream of sentences obtained from a source spout
Stream<String> sentences = builder.newStream(new RandomSentenceSpout()).map(tuple -> tuple.getString(0));

// a stream of words obtained by transforming (splitting) the stream of sentences
Stream<String> words = sentences.flatMap(s -> Arrays.asList(s.split(" ")));

// output operation that prints the words to console
words.forEach(w -> System.out.println(w));
```


Most stream operations accept parameters that describe user-specified behavior typically via lambda expressions like `s -> Arrays.asList(s.split(" "))` as in the above example.

A `Stream` supports two kinds of operations, 

1. **Transformations** that produce another stream from the current stream  (like the `flatMap` operation in the example above) 
1. **Output operations** that produce a result. (like the `forEach` operation in the example above).

## <a name="streambuilder"></a> Stream Builder

`StreamBuilder` provides the builder apis to create a new stream. Typically a spout forms the source of a stream.

```java
StreamBuilder builder = new StreamBuilder();
Stream<Tuple> sentences = builder.newStream(new TestSentenceSpout());
```

The `StreamBuilder` tracks the overall pipeline of operations expressed via the Stream. One can then create the Storm topology
via `build()` and submit it like a normal storm topology via `StormSubmitter`.

```java
StormSubmitter.submitTopologyWithProgressBar("test", new Config(), streamBuilder.build());
```

## <a name="valuemapper"></a> Value mapper

Value mappers can be used to extract specific fields from the tuples emitted from a spout to produce a typed stream of values. Value mappers are passed as arguments to the `StreamBuilder.newStream`.

```java
StreamBuilder builder = new StreamBuilder();

// extract the first field from the tuple to get a Stream<String> of sentences
Stream<String> sentences = builder.newStream(new TestWordSpout(), new ValueMapper<String>(0));
```

Storm provides strongly typed tuples via the `Pair` and Tuple classes (Tuple3 upto Tuple10). One can use a `TupleValueMapper` to produce a stream of typed tuples as shown below.

```java
// extract first three fields of the tuple emitted by the spout to produce a stream of typed tuples.
Stream<Tuple3<String, Integer, Long>> stream = builder.newStream(new TestSpout(), TupleValueMappers.of(0, 1, 2));
```

# <a name="streamapis"></a> Stream APIs 

Storm's streaming apis (defined in [Stream](../storm-client/src/jvm/org/apache/storm/streams/Stream.java) and [PairStream](../storm-client/src/jvm/org/apache/storm/streams/PairStream.java)) currently support a wide range of operations such as transformations, filters, windowing, aggregations, branching, joins, stateful, output and debugging operations.

## <a name="basictransformations"></a> Basic transformations 

### <a name="filter"></a> filter

`filter` returns a stream consisting of the elements of the stream that matches the given `Predicate` (for which the predicate returns true). 

```java
Stream<String> logs = ...
Stream<String> errors = logs.filter(line -> line.contains("ERROR"));
```

In the above example log lines with 'ERROR' are filtered into an error stream which can be then be further processed.

### <a name="map"></a> map 

`map` returns a stream consisting of the result of applying the given mapping function to the values of the stream.

```java
Stream<String> words = ...
Stream<Integer> wordLengths = words.map(String::length);
```

The example generates a stream of word lengths from a stream of words by applying the String.length function on each value. Note that the type of the resultant stream of a map operation can be different from that of the original stream.  

### <a name="flatmap"></a> flatMap

`flatMap` returns a stream consisting of the results of replacing each value of the stream with the contents produced by applying the provided mapping function to each value. This is similar to map but each value can be mapped to 0 or more values.

```java
Stream<String> sentences = ...
Stream<String> words = sentences.flatMap(s -> Arrays.asList(s.split(" ")));
```


In the above example, the lambda function splits each value in the stream to a list of words and the flatMap function generates a flattened stream of words out of it.

## <a name="windowing"></a> Windowing

A `window` operation produces a windowed stream consisting of the elements that fall within the window as specified by the window parameter. All the windowing options supported in the underlying windowed bolts are supported via the Stream apis.

`Stream<T> windowedStream = stream.window(Window<?, ?> windowConfig);`

The windowConfig parameter specifies the windowing config like sliding or tumbling windows based on time duration or event count.
 
```java 
// time based sliding window
stream.window(SlidingWindows.of(Duration.minutes(10), Duration.minutes(1)));

// count based sliding window
stream.window(SlidingWindows.of(Count.(10), Count.of(2)));

// tumbling window
stream.window(TumblingWindows.of(Duration.seconds(10));

// specifying timestamp field for event time based processing and a late tuple stream.
stream.window(TumblingWindows.of(Duration.seconds(10)
                     .withTimestampField("ts")
                     .withLateTupleStream("late_events"));
```
                     
A windowing operation splits the continuous stream of values into subsets and is necessary for performing operations like Joins and Aggregations.
                     
## <a name="keyvaluepairs"></a> Transformation to key-value pairs
                 
### <a name="mapflatmaptopair"></a> mapToPair and flatMapToPair
                 
These operations transform a Stream of values into a stream of key-value pairs.

```java                  
Stream<Integer> integers = … // 1, 2, 3, 4, ... 
PairStream<Integer, Integer> squares = integers.mapToPair(x -> Pair.of(x, x*x)); // (1, 1), (2, 4), (3, 9), (4, 16), ...
```

A key-value pair stream is required for operations like groupByKey, aggregateByKey, joins etc.

## <a name="aggregations"></a> Aggregations

Aggregate operations aggregate the values (or key-values) in a stream. Typically the aggregation operations are performed on a windowed stream where the aggregate results are emitted on each window activation.

### <a name="aggregatereduce"></a> aggregate and reduce
                  
`aggregate` and `reduce` computes global aggregation i.e. the values across all partitions are forwarded to a single task for computing the aggregate. 

```java
Stream<Long> numbers = …
// aggregate the numbers and produce a stream of last 10 sec sums.
Stream<Long> sums = numbers.window(TumblingWindows.of(Duration.seconds(10)).aggregate(new Sum());

// the last 10 sec sums computed using reduce
Stream<Long> sums = numbers.window(...).reduce((x, y) -> x + y);
```

`aggregate` and `reduce` differs in the way in which the aggregate results are computed. 

A `reduce` operation repeatedly applies the given reducer and reduces two values to a single value until there is only one value left. This may not be feasible or easy for all kinds of aggreagations (e.g. avg).
 
An `aggregate` operation does a mutable reduction. A mutable reduction accumulates results into an accumulator as it processes the values.
    
The aggregation operations (aggregate and reduce) automatically does a local aggregation whenever possible before doing the network shuffle to minimize the amount of messages transmitted over the network. For example to compute sum, a per-partition partial sum is computed and only the partial sums are transferred over the network to the target bolt where the partial sums are merged to produce the final sum. A `CombinerAggregator` interface is used as the argument of `aggregate` to enable this.

For example the `Sum` (passed as the argument of aggregate in the example above) can be implemented as a `CombinerAggregator` as follows.

```java
public class Sum implements CombinerAggregator<Long, Long, Long> {

    // The initial value of the sum
    @Override
    public Long init() {
        return 0L;
    }

    // Updates the sum by adding the value (this could be a partial sum)
    @Override
    public Long apply(Long aggregate, Long value) {
        return aggregate + value;
    }

    // merges the partial sums
    @Override
    public Long merge(Long accum1, Long accum2) {
        return accum1 + accum2;
    }

    // extract result from the accumulator (here the accumulator and result is the same)
    @Override
    public Long result(Long accum) {
        return accum;
    }
}
```

### <a name="aggregatereducebykey"></a> aggregateByKey and reduceByKey

These are similar to the aggregate and reduce operations but does the aggregation per key.

`aggregateByKey` aggregates the values for each key of the stream using the given Aggregator.

```java
Stream<String> words = ...                                              // a windowed stream of words
Stream<String, Long> wordCounts = words.mapToPair(w -> Pair.of(w,1)     // convert to a stream of (word, 1) pairs
                                       .aggregateByKey(new Count<>());  // compute counts per word
```
                                       
`reduceByKey` performs a reduction on the values for each key of this stream by repeatedly applying the reducer.

```java
Stream<String> words = ...                                              // a windowed stream of words
Stream<String, Long> wordCounts = words.mapToPair(w -> Pair.of(w,1)     // convert to a stream of (word, 1) pairs
                                       .reduceByKey((x, y) -> x + y);   // compute counts per word
```


Like the global aggregate/reduce, per-partition local aggregate (per key) is computed and the partial results are send to the target bolts where the partial results are merged to produce the final aggregate.

### <a name="groupbykey"></a> groupByKey

`groupByKey` on a stream of key-value pairs returns a new stream where the values are grouped by the keys.
 
```java
// a stream of (user, score) pairs e.g. ("alice", 10), ("bob", 15), ("bob", 20), ("alice", 11), ("alice", 13)
PairStream<String, Double> scores = ... 

// list of scores per user in the last window, e.g. ("alice", [10, 11, 13]), ("bob", [15, 20])
PairStream<String, Iterable<Integer>> userScores =  scores.window(...).groupByKey(); 
```

###  <a name="countbykey"></a> countByKey
`countByKey` counts the values for each key of this stream.

```java
Stream<String> words = ...                                              // a windowed stream of words
Stream<String, Long> wordCounts = words.mapToPair(w -> Pair.of(w,1)     // convert to a stream of (word, 1) pairs
                                       .countByKey();                   // compute counts per word
```

Internally `countByKey` uses `aggregateByKey` to compute the count.

## <a name="repartition"></a> Repartition 

A `repartition` operation re-partitions the current stream and returns a new stream with the specified number of partitions. Further operations on resultant stream would execute at that level of parallelism. Re-partiton can be used to increase or reduce the parallelism of the operations in the stream.

The initial number of partitions can be also specified while creating the stream (via the StreamBuilder.newStream)

```java
// Stream 's1' will have 2 partitions and operations on s1 will execute at this level of parallelism
Stream<String> s1 = builder.newStream(new TestWordSpout(), new ValueMapper<String>(0), 2);

// Stream 's2' and further operations will have three partitions
Stream<String, Integer> s2 = s1.map(function1).repartition(3);

// perform a map operation on s2 and print the result
s2.map(function2).print();
```          
                  
Note: a `repartition` operation implies network transfer. In the above example the first map operation (function1) would be executed at a parallelism of 2 (on two partitions of s1), whereas the second map operation (function2) would be executed at a parallelism of 3 (on three partitions of s2). This also means that the first and second map operations has to be executed on two separate bolts and involves network transfer.

## <a name="outputoperations"></a> Output operations

Output operations push out the transformed values in the stream to the console, external sinks like databases, files or even Storm bolts.
 
### <a name="print"></a> print

`print` prints the values in the stream to console. For example,

```java
// transforms words to uppercase and prints to the console
words.map(String::toUpperCase).print();
```

### <a name="peek"></a> peek

`peek` returns a stream consisting of the elements of the stream, additionally performing the provided action on each element as they are consumed from the resulting stream. This can be used to ‘inspect’ the values flowing at any stage in a stream.

```java
builder.newStream(...).flatMap(s -> Arrays.asList(s.split(" ")))
       // print the results of the flatMap operation as the values flow across the stream.
      .peek(s -> System.out.println(s))
      .mapToPair(w -> new Pair<>(w, 1))
```

### <a name="foreach"></a> forEach

This is the most generic output operation and can be used to execute an arbitrary code for each value in the stream, like storing the results into an external database, file and so on.

```java
stream.forEach(value -> {
    // log it
    LOG.debug(value)
    // store the value into a db and so on...
    statement.executeUpdate(..);
  }
);
```

### <a name="to"></a>  to 

This allows one to plug in existing bolts as sinks. 

```java
// The redisBolt is a standard storm bolt
IRichBolt redisBolt = new RedisStoreBolt(poolConfig, storeMapper);
...
// generate the word counts and store it in redis using redis bolt
builder.newStream(new TestWordSpout(), new ValueMapper<String>(0))
       .mapToPair(w -> Pair.of(w, 1))
       .countByKey()
       // the (word, count) pairs are forwarded to the redisBolt which stores it in redis
       .to(redisBolt);
```

Note that this will provide guarantees only based on what the bolt provides.

## <a name="branching"></a> Branch

A `branch` operation can be used to express If-then-else logic on streams.

```java
Stream<T>[] streams  = stream.branch(Predicate<T>... predicates)
```

The predicates are applied in the given order to the values of the stream and the result is forwarded to the corresponding (index based) result stream based on the first predicate that matches. If none of the predicates match a value, that value is dropped.

For example,

```java
Stream<Integer>[] streams = builder.newStream(new RandomIntegerSpout(), new ValueMapper<Integer>(0))
                                   .branch(x -> (x % 2) == 0, 
                                          x -> (x % 2) == 1);
Stream<Integer> evenNumbers = streams[0];
Stream<Integer> oddNumbers = streams[1];
```

## <a name="joins"></a> Joins

A `join` operation joins the values of one stream with the values having the same key from another stream. 

```java
PairStream<Long, Long> squares = … // (1, 1), (2, 4), (3, 9) ...
PairStream<Long, Long> cubes = … // (1, 1), (2, 8), (3, 27) ...

// join the sqaures and cubes stream to produce (1, [1, 1]), (2, [4, 8]), (3, [9, 27]) ...
PairStream<Long, Pair<Long, Long>> joined = squares.window(TumblingWindows.of(Duration.seconds(5))).join(cubes);
```

Joins are typically invoked on a windowed stream, joining the key-values that arrived on each stream in the current window. The parallelism of the stream on which the join is invoked is carried forward to the joined stream. An optional `ValueJoiner` can be passed as an argument to join to specify how to join the two values for each matching key (the default behavior is to return a `Pair` of the value from both streams).

Left, right and full outer joins are supported. 

## <a name="cogroupbykey"></a> CoGroupByKey

`coGroupByKey` Groups the values of this stream with the values having the same key from the other stream.

```java
// a stream of (key, value) pairs e.g. (k1, v1), (k2, v2), (k2, v3)
PairStream<String, String> stream1 = ...

// another stream of (key, value) pairs e.g. (k1, x1), (k1, x2), (k3, x3)
PairStream<String, String> stream2 = ...

// the co-grouped values per key in the last window, e.g. (k1, ([v1], [x1, x2]), (k2, ([v2, v3], [])), (k3, ([], [x3]))
PairStream<String, Iterable<String>> coGroupedStream =  stream1.window(...).coGroupByKey(stream2);
```

## <a name="state"></a> State

Storm provides APIs for applications to save and update the state of its computation and also to query the state.

### <a name="updatestatebykey"></a> updateStateByKey

`updateStateByKey` updates the state by applying a given state update function to the previous state and the new value for the key. `updateStateByKey` can be invoked with either an initial value for the state and a state update function or by directly providing a `StateUpdater` implementation.

```java
PairStream<String, Long> wordCounts = ...
// Update the word counts in the state; here the first argument 0L is the initial value for the state and 
// the second argument is a function that adds the count to the current value in the state.
StreamState<String, Long> streamState = wordCounts.updateStateByKey(0L, (state, count) -> state + count)
streamState.toPairStream().print();
```

The state value can be of any type. In the above example its of type `Long` and stores the word count. 

Internally storm uses stateful bolts for storing the state. The Storm config `topology.state.provider` can be used to choose the state provider implementation. For example set this to `org.apache.storm.redis.state.RedisKeyValueStateProvider` for redis based state store.

### <a name="statequery"></a> stateQuery

`stateQuery` can be used to query the state (updated by `updateStateByKey`). The `StreamState` returned by the updateStateByKey operation has to be used for querying stream state. The values in the stream are used as the keys to query the state.

```java

// The stream of words emitted by the QuerySpout is used as the keys to query the state.
builder.newStream(new QuerySpout(), new ValueMapper<String>(0))
// Queries the state and emits the matching (key, value) as results. 
// The stream state returned by updateStateByKey is passed as the argument to stateQuery.
.stateQuery(streamState).print();
```

# <a name="guarantees"></a> Guarantees

Right now the topologies built using Stream API provides **at-least once** guarantee. 

Note that only the `updateStateByKey` operation currently executes on an underlying StatefulBolt. The other stateful operations (join, windowing, aggregation etc) executes on an IRichBolt and stores its state in memory. It relies on storms acking and replay mechanisms to rebuild the state.
 
In future the underlying framework of the Stream API would be enhanced to provide **exactly once** guarantees.

# <a name="example"></a> Example

Here's a word count topology expressed using the Stream API,

```java
StreamBuilder builder = new StreamBuilder();

builder
   // A stream of random sentences with two partitions
   .newStream(new RandomSentenceSpout(), new ValueMapper<String>(0), 2)
   // a two seconds tumbling window
   .window(TumblingWindows.of(Duration.seconds(2)))
   // split the sentences to words
   .flatMap(s -> Arrays.asList(s.split(" ")))
   // create a stream of (word, 1) pairs
   .mapToPair(w -> Pair.of(w, 1))
   // compute the word counts in the last two second window
   .countByKey()
   // print the results to stdout
   .print();
```

The `RandomSentenceSpout` is a regular Storm spout that continuously emits random sentences. The stream of sentences are split into two second windows and the word count within each window is computed and printed.

The stream can then be submitted just like a regular topology as shown below.

```java
  Config config = new Config();
  config.setNumWorkers(1);
  StormSubmitter.submitTopologyWithProgressBar("topology-name", config, builder.build());
```

More examples are available under [storm-starter](../examples/storm-starter/src/jvm/org/apache/storm/starter/streams) which will help you get started.
