Nathanael England
08/16/2024, 7:54 PMNathanael England
08/16/2024, 7:55 PMNathanael England
08/16/2024, 7:55 PMNathanael England
08/16/2024, 7:56 PMMichael LeGore
08/22/2024, 10:46 PMKen Krugler
08/22/2024, 11:06 PMDataStreamUtils.reinterpretAsKeyedStream() do what you need? You can insert this after a process function, and you get back to a KeyedStream. Of course you better not mess with the keys 🙂
2. When using a reduce or aggregate function, where you need the key in the result, you want to use the version of the reduce/aggregate API that also takes a ProcessWindowFunction parameter. This second function gives you access to the result’s key.Michael LeGore
08/22/2024, 11:12 PM/**
* The accumulator is used to keep a running sum and a count. The {@code getResult} method
* computes the average.
*/
private static class AverageAggregate
implements AggregateFunction<Tuple2<String, Long>, Tuple2<Long, Long>, Double> {
@Override
public Tuple2<Long, Long> createAccumulator() {
return new Tuple2<>(0L, 0L);
}
@Override
public Tuple2<Long, Long> add(Tuple2<String, Long> value, Tuple2<Long, Long> accumulator) {
return new Tuple2<>(accumulator.f0 + value.f1, accumulator.f1 + 1L);
}
@Override
public Double getResult(Tuple2<Long, Long> accumulator) {
return ((double) accumulator.f0) / accumulator.f1;
}
@Override
public Tuple2<Long, Long> merge(Tuple2<Long, Long> a, Tuple2<Long, Long> b) {
return new Tuple2<>(a.f0 + b.f0, a.f1 + b.f1);
}
}
DataStream<Tuple2<String, Long>> input = ...;
input
.keyBy(<key selector>)
.window(<window assigner>)
.aggregate(new AverageAggregate());
It’s much more natural to be able to output a single type and still have the key. If you were to use this example in real life, it would be pretty useless because what you’d get is a bunch of keyless doubles that don’t mean anything without their key.Michael LeGore
08/22/2024, 11:16 PMKen Krugler
08/23/2024, 5:14 PMreinterpretAsKeyedStream, yes, it doesn’t do a network shuffle (assumes the data is still partitioned the same).Ken Krugler
08/23/2024, 5:16 PMAverageAggregation example, you said:
> The solutions you gave all require you to manually pass the key information through your process or aggregate functions to their output
But that’s not true. If you do .aggregate(new AverageAggregate(), new MyProcessWindowFunction()), then in the ProcessWindowFunction you have access to the current key, so there’s no need to “manually pass the key information”.Nathanael England
08/23/2024, 5:17 PMMichael LeGore
08/23/2024, 5:18 PMKen Krugler
08/23/2024, 5:22 PMProcessWindowFunction.process() method. So you can then output the key in the result record, which is what I’m assuming you’re trying to do.Michael LeGore
08/23/2024, 5:26 PMMichael LeGore
08/23/2024, 5:29 PMKen Krugler
08/23/2024, 8:00 PMWindowedStream.aggregate() method that takes an additional KeySelector<K> function as a parameter, and returns a KeyedStream<T,K> by basically doing a call to reinterpretAsKeyedStream() for you. And I guess there could be a WindowedStream.aggregateWithKey() method that implicitly adds adds a ProcessWindowFunction to access the key, and returns a KeyedStream<Tuple2<K,T>, K> as the result.
Note that an important aspect of Flink’s KeyedStream is that it has to have a KeySelector function to extract the key from the record type, so unless that’s fixed (as per my second method above) and thus can be easily derived, it’s got to be explicitly provided to the method.