如何在Flink作业中操纵3 DataStream?

时间:2019-03-04 13:31:18

标签: apache-flink

我们有3个Java pojos,

class Foo{
 int id;
 String name;
 List<Bar1> list1;
 List<Bar2> list2;
}

class Bar1{
 int id;
 String field_x;
 String field_y;
}

class Bar2{
 int id;
 String field_a;
 String field_b;
}

我们的Flink作业中有3个DataStreams,

class Test{
 public static void main(...){
  DataStream<Foo> ds1 = ...;
  DataStream<Bar1> ds2 = ...;
  DataStream<Bar2> ds3 = ...;
 }
}

对于每个id,只有一个Foo对象,而Bar1和Bar2对象可以是多个。

我们想要做的是,对于ds1中的每个Foo,在ds2中找到具有相同ID的所有Bar1并将其放入list1,在ds3中找到具有相同ID的所有Bar2并将它们放入list2。

最好的方法是什么?

1 个答案:

答案 0 :(得分:1)

Flink的DataStream运算符最多支持两个输入流。 在三种流上实现操作有两种常用方法:

  1. 具有两个二进制操作。在您的情况下,这很简单,因为Bar1Bar2彼此不相关。大致如下所示:
DataStream<Foo> withList1 = ds1
  .connect(ds2).keyBy("id", "id")
  .process(
    // your processing logic
    new CoProcessFunction<Foo, Bar1, Foo>(){...});
DataStream<Foo> withList1AndList2 = withList1
  .connect(ds3).keyBy("id", "id")
  .process(
    // your processing logic
    new CoProcessFunction<Foo, Bar2, Foo>(){...});
  1. 通过将所有三个流合并为具有通用数据类型的单个流(例如,具有三个字段foobar1bar2的POJO,其中仅使用一个字段并使用带有单个输入的运算符来处理联合流。
// map Foo to CommonType
DataStream<CommonType> common1 = ds1.map(new MapFunction<Foo, CommonType>(){...}); 
// map Bar1 to CommonType
DataStream<CommonType> common2 = ds2.map(new MapFunction<Bar1, CommonType>(){...});
// map Bar2 to CommonType
DataStream<CommonType> common3 = ds3.map(new MapFunction<Bar2, CommonType>(){...});

DataStream<Foo> withList1AndList2 = ds1.union(ds2, ds3)
  .keyBy("id")
  .process(
    // your processing logic
    new KeyedProcessFunction<CommonType, Foo>(){...});

您也可以只合并ds2ds3并使用二进制运算符。

更大的问题可能是确定何时收到所有Bar1Bar2事件,以便您可以发出结果。再次,有一些选项(取决于您的用例)。

  1. 如果Foo知道需要等待多少Bar1Bar2,解决方案就很明显。
  2. 如果Foo不知道要等待多少事件,则可以尝试发送一条通知,该通知表明已发送了最后一个Bar1Bar2
  3. 如果您知道所有Bar1Bar2应该在x秒/分钟/等时间内到达,您还可以设置超时时间。