已更新:是否可以在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的两个窗口:
[0, 98, 145, 350]
[0, 40, 65, 120, 240, 352]
例如每次值达到0时,为该组启动一个新窗口。
答案 0 :(得分:0)
根据您的描述,可能不会。至少有两个问题:
PCollections
是无序的和分布的:
数据驱动的触发器不受支持(可能出于类似原因):
但是,您可以查看状态处理,看看是否可以手动处理。例如。您会累积该状态下的所有传入事件,然后不时分析累积的事件并发出结果。
或者,如果您可以在业务逻辑中提取/分配公用密钥,那么您可能想检查GroupByKey+ParDo
或Combine
是否有用。
请参阅:
答案 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。