Apache Beam Windowing在信号阶段

时间:2019-06-05 17:10:46

标签: apache-beam

已更新:是否可以在signals phase上打开数据流窗口。

例如,存在时间戳,键,值流:

[<t0, k1, 0>, <t1, k1, 98>, <t2, k1, 145>, <t4, k1, 0>, <t3, k1, 350>, <t5, k1, 40>, <t6, k1, 65>, <t7, k1, 120>, <t8, k1, 240>, <t9, k1, 352>]

输出将是密钥k1的两个窗口:

  • t0-t3:[0, 98, 145, 350]
  • t4-t9:[0, 40, 65, 120, 240, 352]

例如每次值达到0时,为该组启动一个新窗口。

2 个答案:

答案 0 :(得分:0)

根据您的描述,可能不会。至少有两个问题:

但是,您可以查看状态处理,看看是否可以手动处理。例如。您会累积该状态下的所有传入事件,然后不时分析累积的事件并发出结果。

或者,如果您可以在业务逻辑中提取/分配公用密钥,那么您可能想检查GroupByKey+ParDoCombine是否有用。

请参阅:

答案 1 :(得分:0)

在对问题进行编辑并明确用例之后,我建议您研究自定义窗口以扩展标准sessions。首先,我构建了以下示例(可以对其进行改进)。

通过WindowFn.AssignContext,我们可以访问element(),该窗口正在进入原型会话。如果它等于给定的stopValue,则窗口长度将被限制为最小值,而不是为此目的而使用gapDuration

@Override
public Collection<IntervalWindow> assignWindows(AssignContext c) {
  Duration newGap = c.element().getValue().equals(this.stopValue) ? new Duration(1) : gapDuration;
  return Arrays.asList(new IntervalWindow(c.timestamp(), newGap));
}

然后,在合并排序后的窗口时,我们将检查它们是否确实重叠,但是窗口持续时间不等于1 ms。

Collections.sort(sortedWindows);
List<MergeCandidate> merges = new ArrayList<>();
MergeCandidate current = new MergeCandidate();
for (IntervalWindow window : sortedWindows) {
  // get window duration and check if it's a stop session request
  Long windowDuration = new Duration(window.start(), window.end()).getMillis();

  if (current.intersects(window) && !windowDuration.equals(1L)) {
    current.add(window);
  } else {
    merges.add(current);
    current = new MergeCandidate(window);
  }
}
merges.add(current);
for (MergeCandidate merge : merges) {
  merge.apply(c);
}

当然,我们还可以添加一些代码,以便提供不同的停止值:stopValue字段,withStopValue方法,构造函数,如果使用Dataflow Runner则显示数据等。< / p>

/** Value that closes the session. */
private final Integer stopValue;

/** Creates a {@code StopSessions} {@link WindowFn} with the specified gap duration. */
public static StopSessions withGapDuration(Duration gapDuration) {
  return new StopSessions(gapDuration, 0);
}

/** Creates a {@code StopSessions} {@link WindowFn} with the specified stop value. */
public StopSessions withStopValue(Integer stopValue) {
  return new StopSessions(gapDuration, stopValue);
}

/** Creates a {@code StopSessions} {@link WindowFn} with the specified gap duration and stop value. */
private StopSessions(Duration gapDuration, Integer stopValue) {
  this.gapDuration = gapDuration;
  this.stopValue = stopValue;

现在,在我们的管道中,我们可以通过以下方式导入和使用新的StopSessions类:

import org.apache.beam.sdk.transforms.windowing.StopSessions; // custom one
...

.apply("Window into StopSessions", Window.<KV<String, Integer>>into(StopSessions
  .withGapDuration(Duration.standardSeconds(10))
  .withStopValue(0)))

为模仿您的示例,我们使用以下方法创建一些数据:

.apply("Create data", Create.timestamped(
    TimestampedValue.of(KV.of("k1", 0), new Instant()), // <t0, k1, 0>
    TimestampedValue.of(KV.of("k1",98), new Instant().plus(1000)), // <t1, k1, 98>
    TimestampedValue.of(KV.of("k1",145), new Instant().plus(2000)), // <t2, k1, 145>
    TimestampedValue.of(KV.of("k1",0), new Instant().plus(4000)), // <t4, k1, 0>
    ...

对于标准会话,输出为:

user=k1, scores=[0,145,350,120,0,40,65,98,240,352], window=[2019-06-08T19:13:46.785Z..2019-06-08T19:14:05.797Z)

使用自定义选项,我得到以下信息:

user=k1, scores=[350,145,98], window=[2019-06-08T21:18:51.395Z..2019-06-08T21:19:03.407Z)
user=k1, scores=[0], window=[2019-06-08T21:18:54.407Z..2019-06-08T21:18:54.408Z)
user=k1, scores=[65,240,352,120,40], window=[2019-06-08T21:18:55.407Z..2019-06-08T21:19:09.407Z)
user=k1, scores=[0], window=[2019-06-08T21:18:50.395Z..2019-06-08T21:18:50.396Z)

stopValue更改为.withStopValue(<int>)可以正常工作。 98, 145 and 350事件与其余事件处于不同的会话中。请注意,这与描述中的不完全一样,因为stopValue被分配给一个单独的窗口而不是新窗口,但是可以在下游进行过滤,它为您提供了如何进行操作的想法。我想重温这一点,也希望找到Python实现。

所有文件here