对流的并集进行排序以识别Apache Flink中的用户会话

时间:2017-11-30 14:59:42

标签: scala apache-flink flink-streaming

我有两个事件流

  • L = (l1,l3,l8,...) - 更稀疏,表示用户登录到IP
  • E = (e2,e4,e5,e9,...) - 是特定IP的日志流

较低的索引表示时间戳...如果我们将两个流连接在一起并按时间对它们进行排序我们会得到:

  • l1 e2 l3 e4,e5 l8 e9 ,...

是否可以实现自定义Window / Trigger函数将事件分组到会话(不同用户登录之间的时间):

  • l1 - l3 e2
  • l3 - l8 e4,e5
  • l8 - l14 e9 e10 e11 e12 e13
  • ...

我看到的问题是两个流不一定是排序的。我想过按时间戳排序输入流。然后使用GlobalWindow和自定义Trigger实现窗口很容易 - 但似乎不可能。

我错过了什么,或者在当前的Flink(v1.3.2)中绝对不可能这样做?

由于

1 个答案:

答案 0 :(得分:3)

问题:E3不应该在L4之前出现吗?

使用ProcessFunction进行排序非常简单。像这样:

public static class SortFunction extends ProcessFunction<Event, Event> {
  private ValueState<PriorityQueue<Event>> queueState = null;

  @Override
  public void open(Configuration config) {
    ValueStateDescriptor<PriorityQueue<Event>> descriptor = new ValueStateDescriptor<>(
        // state name
        "sorted-events",
        // type information of state
        TypeInformation.of(new TypeHint<PriorityQueue<Event>>() {
        }));
    queueState = getRuntimeContext().getState(descriptor);
  }

  @Override
  public void processElement(Event event, Context context, Collector<Event> out) throws Exception {
    TimerService timerService = context.timerService();

    if (context.timestamp() > timerService.currentWatermark()) {
      PriorityQueue<Event> queue = queueState.value();
      if (queue == null) {
        queue = new PriorityQueue<>(10);
      }
      queue.add(event);
      queueState.update(queue);
      timerService.registerEventTimeTimer(event.timestamp);
    }
  }

  @Override
  public void onTimer(long timestamp, OnTimerContext context, Collector<Event> out) throws Exception {
    PriorityQueue<Event> queue = queueState.value();
    Long watermark = context.timerService().currentWatermark();
    Event head = queue.peek();
    while (head != null && head.timestamp <= watermark) {
      out.collect(head);
      queue.remove(head);
      head = queue.peek();
    }
  }
}