Apache Kafka分组两次

时间:2018-06-26 17:02:26

标签: apache-kafka apache-kafka-streams

我正在编写一个应用程序,试图计算每小时访问页面的用户数。我试图过滤特定的事件,按userId和事件小时时间分组,然后仅按小时分组以获取用户数。但是将KTable分组会导致过度的cpu刻录并在尝试关闭流时锁定。有更好的方法吗?

    events
   .groupBy(...)
   .aggregate(...)
   .groupBy(...);
   .count();

1 个答案:

答案 0 :(得分:1)

鉴于您在“我只想在一个小时的时间窗口内知道执行特定操作的用户数量”上方的问题的答案,我建议以下几点。

假设您有类似这样的记录:

class ActionRecord {
  String actionType;
  String user;
}

您可以定义一个聚合类,如下所示:

class ActionRecordAggregate {
  private Set<String> users = new HashSet<>();

  public void add(ActionRecord rec) {
    users.add(rec.getUser());
  }

  public int count() {
    return users.size();
  }

}

然后您的流媒体应用程序可以:

  • 接受事件
  • 根据事件类型(.map())对其进行重新命名
  • 按事件类型(.groupByKey())对它们进行分组
  • 按时间显示它们(选择1分钟,但选择YMMV)
  • 将它们聚合到ActionRecordAggregate
  • 将它们具体化为StateStore

所以看起来像这样:

stream()
.map((key, val) -> KeyValue.pair(val.actionType, val)) 
.groupByKey() 
.windowedBy(TimeWindows.of(60*1000)) 
.aggregate(
  ActionRecordAggregate::new, 
  (key, value, agg) -> agg.add(value),
  Materialized
      .<String, ActionRecordAggregate, WindowStore<Bytes, byte[]>>as("actionTypeLookup")
      .withValueSerde(getSerdeForActionRecordAggregate())
);

然后,要返回事件,您可以查询状态存储:

ReadOnlyWindowStore<String, ActionRecordAggregate> store = 
  streams.store("actionTypeLookup", QueryableStoreTypes.windowStore());

WindowStoreIterator<ActionRecordAggregate> wIt = 
  store.fetch("actionTypeToGet", startTimestamp, endTimestamp);

int totalCount = 0;
while(wIt.hasNext()) {
  totalCount += wIt.next().count();
}

// totalCount is the number of distinct users in your 
// time interval that raised action type "actionTypeToGet"

希望这会有所帮助!

相关问题