Kafka流聚合了删除和/或关键更改

时间:2019-03-22 21:32:15

标签: apache-kafka apache-kafka-streams

我正在尝试定义一个kafka流,该流接受来自某个主题(例如EMPLOYEE)的记录,其中记录包含有关员工及其部门的属性,然后将其转换为另一个主题DEPARTMENT,其中包含部门属性,并且所有雇员的列表(对雇员进行了一些无状态转换)。

EMPLOYEE记录重复部门数据。 (我实际上是在处理一些DICOM标头数据,但我会坚持一个更为普遍理解的关系。我试图理解一个通用的解决方案)。另外,主题中的记录仅具有当前数据(即:如果部门更改,则没有先前的DepartmentId。)

这似乎是一项汇总工作。我有一些似乎适用于简单情况的东西:

        ...
        KStream<String, Employee> stream = kStreamBuilder.stream("EMPLOYEE"); // Stream from raw EMPLOYEE
        stream.map((k, v) -> new KeyValue<>(k, transformEmployee(v))) // <-- some stateless enrichment of the employee
                .groupBy((k, emp) -> emp.getDepartmentId(), jsonSerialisedWith(Employee.class))

                // dummy reduce to a get a ktable for agg:
                .reduce((aggValue, newEmp) -> newEmp) 
                .groupBy((k, emp2) -> new KeyValue<>(emp2.getDepartmentId(), emp2), jsonSerialisedWith(Employee.class))

                .aggregate(Department::new, this::addEmployee, this::removeEmployee,
                           jsonValueMaterializedAs("DEPARTMENT-AGG", Department.class))
                .toStream()
                .to("DEPARTMENT", jsonProducedWith(Department.class));
        ...

    private Department addEmployee(String deptId, Employee employee, Department department) {
        department.addEmployee(employee);
        if (department.getId() == null) {
            department.setId(employee.getDepartmentId());
            department.setName(employee.getDepartmentName());
        }
        return department;
    }

这适用于添加或更新。但是随着时间的流逝,员工可能会被删除或重新分配到另一个部门。我收集的删除应该是发送给EMPLOYEE主题的逻辑删除记录(k:empId,v:null)。但是,我不再拥有departmentId,我必须做一个空检查(并为DepartmentId返回null),所以删除雇员时再也不会发生removeEmployee。  更改DepartmentId的类似问题。

那么,解决这个问题的卡夫卡方式是什么?

1 个答案:

答案 0 :(得分:0)

我认为使用您的代码就足够了,但是稍微更改了删除员工的语义。

您应该添加某种Mock部门(将用户从部门中删除时将使用该部门)。

如果员工被撤职,而是将部门设置为null,则应将其分配给Mock部门。