减少键控流中的功能行为

时间:2019-04-03 08:42:31

标签: apache-flink flink-streaming

对于我们的一种用例,我们需要根据文件中的更改来重做一些计算,然后广播该文件的结果,以便我们可以在其他流中使用它。

程序的生命周期大致如下:

数据流1:受监视的文件->检测到一些更改->重新处理文件中的所有元素->计算一个结果->广播

数据流2:某些转换->在使用所有当前广播的元素的同时对DS2中的每个元素执行某些操作(某些数据丢失在广播的元素中可以忍受一段时间)

我将提供一些代码示例,以更好地解释问题所在:

这是DS1: 映射每个元素,将它们发送到reducer,然后计算总数

env.readFile(format, clientPath, FileProcessingMode.PROCESS_CONTINUOUSLY, interval)
    .map(new Adder())
    .keyBy(Map::size)
    .reduce(new Reducer());

这是映射阶段,它只是从一行创建一个哈希表

public static class Adder extends RichMapFunction<String, Map<String, String>> {
  private static final long serialVersionUID = 1L;

  @Override
  public Map<String, String> map(String string) throws Exception {
    String[] strings = string.split("=");
    HashMap<String, String> hashMap = new HashMap<>();
    hashMap.put(strings[0], strings[1]);
    return hashMap;
  }
}

这是最后一步,减速器。从映射器获取所有归约元素,然后返回总数,即单个哈希图

public static class Reducer extends RichReduceFunction<Map<String, String>> {
  private static final long serialVersionUID = 1L;

  @Override
  public Map<String, String> reduce(Map<String, String> stringStringMap, Map<String, String> t1) throws Exception {
    stringStringMap.putAll(t1);
    return stringStringMap;
  }
}

然后像下面的代码段一样广播DS1。

MapStateDescriptor<String, String> descriptor = new MapStateDescriptor<>("Brodcasted map state", Types.STRING, Types.STRING);
BroadcastStream<Map<String, String>> broadcastedProperties =  clientProperties.broadcast(descriptor); 
ds2.connect(broadcastedProperties).process(new EventListener(properties));

在给定时间内使用以下元素

Time    Document
T1      K1=V1, K2=V2
T2      K2=V2
T3      K3=V3, K1=V4

运行程序时,我期望的是:

Time    Broadcasted Elements
T1      K1=V1, K2=V2
T2      K2=V2
T3      K3=V3, K1=V4

我看到的是这样的:

Time    Broadcasted Elements
T1      K1=V1, K2=V2
T2      K1=V1, K2=V2
T3      K1=V4, K2=V2, K3=V3

我为克服此问题所做的只是在数据流上打开一个窗口,并使用带有累加器而不是reducer的聚合函数,但我更喜欢采用非窗口方法。

我做了一些调试,我意识到,即使在map阶段,它只在那个时候映射可用的元素,而在reduce阶段,它是根据先前的状态进行缩减的(通过我时间的平均结果– 1)+此时的所有元素。我发现在还原阶段具有不可见状态非常奇怪。从我的角度来看,它应该仅基于直接来自映射器的元素。也许我对Flink中的reduce的理解是错误的,但我希望对此进行一些澄清。

2 个答案:

答案 0 :(得分:0)

是的,当Flink的任何内置聚合器(例如sum,max,reduce等)应用于流时,它会以增量,有状态的方式聚合整个流。或更准确地说,这是在KeyedStreams上完成的,聚合是在每个键的基础上完成的,但以一种持续的,不受限制的方式进行。例如,如果您在整数1、2、3、4、5 ...的流上使用sum(),那么sum()将产生流1、3、6、10、15 ...。在您的情况下,reduce()将产生不断更新的流,其中将包含越来越多的键/值对。

如果您要按时间对流进行键控,则应该获得所需的结果,但是键控状态将永远保持不变,这可能会出现问题。我建议您要么使用窗口API,要么使用RichFlatMap或ProcessFunction之类的东西,您可以在其中直接管理状态。

答案 1 :(得分:0)

不带窗口的缩小功能将滚动减少。如果要在滚动减少之间保持一致的状态,请使用状态对象保存状态,以后再检索和更新它。我认为@David Anderson也在RichReduceFunction中提出了建议。

Sub SplitterA()

Dim x As Variant
    x = Split(Range("A1").Value2, vbLf)
    Range("A1").Resize(, UBound(x) + 1).Value2 = x

End Sub