Apache Flink KeyedStream после выяснения поведения оконного оператора
Я запрашиваю разъяснения о том, как именно Apache Flink (1.6.0) обрабатывает события из KeyedStreams после того, как события были отправлены через окно, и был применен какой-то оператор (например, Reduce() или Process()).
Предполагая, что в кластере с одним узлом после выполнения оператора в оконном потоке с ключом остается один с ровно 1 DataStreams или ровно k DataStreams (где k - количество уникальных значений для ключа)?
Для пояснения рассмотрим необходимость считывать события из какого-либо источника, нажимать их с помощью некоторого k, отправлять события с ключами в некоторый оконный поток, сокращать, а затем делать практически все остальное. Какой из двух приведенных ниже графиков действительно будет построен?
График А
|--------------|
| source |
| (DataStream) |
|--------------|
|
[all events]
|
v
|--------------|
| key by( k ) |
| (KeyedStream)|
|--------------|
/ | \
/ | \
[ k = 1 ] [ k = 2 ] [ k = 3 ]
/ | \
/ | \
v v v
|------------------||------------------||------------------|
| sliding window || sliding window || sliding window |
| (WindowedStream) || (WindowedStream) || (WindowedStream) |
|------------------||------------------||------------------|
| | |
[ k = 1 ] [ k = 2 ] [ k = 3 ]
| | |
v v v
|----------| |----------| |----------|
| reduce | | reduce | | reduce |
|----------| |----------| |----------|
| | |
[ k = 1 ] [ k = 2 ] [ k = 3 ]
| | |
v v v
|--------------| |--------------| |--------------|
| foo | | foo | | foo |
| (DataStream) | | (DataStream) | | (DataStream) |
|--------------| |--------------| |--------------|
График Б
|--------------|
| source |
| (DataStream) |
|--------------|
|
[all events]
|
v
|--------------|
| key by( k ) |
| (KeyedStream)|
|--------------|
/ | \
/ | \
[ k = 1 ] [ k = 2 ] [ k = 3 ]
/ | \
/ | \
v v v
|------------------||------------------||------------------|
| sliding window || sliding window || sliding window |
| (WindowedStream) || (WindowedStream) || (WindowedStream) |
|------------------||------------------||------------------|
| | |
[ k = 1 ] [ k = 2 ] [ k = 3 ]
| | |
v v v
|----------| |----------| |----------|
| reduce | | reduce | | reduce |
|----------| |----------| |----------|
\ | /
\ | /
\ | /
\ | /
\ | /
\ | /
\ | /
[all products]
|
v
|--------------|
| foo |
| (DataStream) |
|--------------|
Редактировать (2018-09-22)
Основываясь на ответе Дэвида, я думаю, что я неправильно истолковал, как именно KeyedStreams работают в сочетании с окном или другим потоком. Каким-то образом у меня сложилось впечатление, что KeyedStream разделил входящий поток, создав несколько потоков за сценой, а не просто сгруппировав объекты по некоторому значению, используя один и тот же поток.
Я думал, что Флинк делает эквивалент:
List<Foo> eventsForKey1 = ...;
List<Foo> eventsForKey2 = ...;
List<Foo> eventsForKey3 = ...;
...
List<Foo> eventsForKeyN = ...;
Теперь я вижу, что Флинк фактически делает эквивалент:
Map<Key, List<Foo>> events = ...;
2 ответа
Лучший способ изучить, как будет выглядеть график заданий для различных сценариев, - это написать несколько простых приложений и изучить их графики заданий на панели инструментов, которая поставляется вместе с Flink.
Я не уверен, как интерпретировать разветвление, которое вы показываете после keyBy, что затрудняет ответ на ваш вопрос. Если вы спрашиваете о параллелизме результирующего foo DataStream, он может быть тем, чем вы хотите.
Если параллелизм равен 1 как до, так и после keyBy, то поток не будет разделен, как вы показали. Вместо этого будет один оператор Window, который обрабатывает все ключи. (Параллелизм не зависит от количества клавиш, хотя оператор с клавишами, такой как скользящее окно и его функция уменьшения, не может использовать преимущество параллелизма, превышающее количество клавиш.)
Но даже в одном узле вы можете иметь несколько ядер и установить параллелизм оператора окна на 3. И результат функции сокращения может обрабатываться параллельно последующими операторами, если вы этого хотите. Но независимо от параллелизма, эта часть вашей работы будет иметь только один DataStream (foo).
Пожалуйста, обновите ваш вопрос, если я его неправильно истолковал, и я попробую еще раз.
Я думаю, что вы действительно спрашиваете, есть ли у вас KeyedStream
следуя reduce
операция. Если это так, то ответ нет, вы заводите с регулярным DataStream
,
Хотя это возможно через DataStreamUtils.reinterpretAsKeyedStream(DataStream, KeySelector)
бросить его обратно в KeyedStream
, если вы заботитесь о том, чтобы не изменить значения полей, используемые для создания ключа для окна.