Java 在KStream&;KTables

Java 在KStream&;KTables,java,apache-kafka,stream,apache-kafka-streams,Java,Apache Kafka,Stream,Apache Kafka Streams,我试图在Kafka Streams中实现一个用例,在这个用例中,我基于对这个流应用一些过滤器来填充一个Ktable,让我们将这个表称为跟踪表,其中键是从事件派生的,值是事件。 现在,对于后续事件,我检查此表以验证它们是否被跟踪,如果被跟踪,则更新事件或将其发布到其他主题。我不知道如何同时做到这一点。这是我到目前为止所拥有的 // Branch based on conditions KStream<String, Event>[] segregatedRecords = branch

我试图在Kafka Streams中实现一个用例,在这个用例中,我基于对这个流应用一些过滤器来填充一个Ktable,让我们将这个表称为跟踪表,其中键是从事件派生的,值是事件。 现在,对于后续事件,我检查此表以验证它们是否被跟踪,如果被跟踪,则更新事件或将其发布到其他主题。我不知道如何同时做到这一点。这是我到目前为止所拥有的

// Branch based on conditions
KStream<String, Event>[] segregatedRecords = branches[0]
                       .branch((key, event) -> event.getStatus().getStatus().equals("A"),
                        (key, event) -> event.getStatus().getStatus().equals("B"),
                        (key, event) -> event.getStatus().getStatus().equals("C"),


// Store events with status A to a topic
segregatedRecords[0]
                .selectKey((key, event) -> createKey(event))
                .mapValues(transform)
                .to(intermediateTopic);

// Load topic from previous step as GlobalKtable
GlobalKTable<String, Event> trackedEvents = streamsBuilder.globalTable(intermediateTopic);

// The following step is where I'm stuck, because I can not perform conditional actions
// If the event exists in the tracking table (update) but if not then how to publish it to a different topic?
segregatedRecords[1]
                 // derive key for lookup
                .selectKey((key, event) -> createKey(event))
                // update the event status in the table 
                .join(trackedEvents, (key, value) -> key,(event, tracked) -> modifiedEvent
                ).to(intermediateTopic);

// Other events will need to refer the latest information in the tracked table for further processing 


//基于条件的分支
KStream[]隔离记录=分支[0]
.branch((键,事件)->event.getStatus().getStatus().equals(“A”),
(键,事件)->event.getStatus().getStatus().equals(“B”),
(键,事件)->event.getStatus().getStatus().equals(“C”),
//将状态为A的事件存储到主题
隔离记录[0]
.selectKey((键,事件)->createKey(事件))
.mapValues(转换)
.至(中间技术顾问);
//将上一步中的主题加载为GlobalKtable
GlobalKTable TrackeEvents=streamsBuilder.globalTable(intermediateTopic);
//以下步骤是我遇到的问题,因为我无法执行条件操作
//如果该事件存在于跟踪表(更新)中,但如果不存在,则如何将其发布到其他主题?
隔离记录[1]
//派生用于查找的键
.selectKey((键,事件)->createKey(事件))
//更新表中的事件状态
.join(trackedEvents,(key,value)->key,(event,tracked)->modifiedEvent
).至(中间技术顾问);
//其他事件将需要参考跟踪表中的最新信息以进行进一步处理

您可以通过将
隔离记录[1]
分为两个子拓扑来实现这一点,一个分支将表锁定作为您的代码,另一个分支使用低级处理器API(在本例中使用transformValues)要检查底层的
GlobalKTable
状态存储是否包含新派生键的记录,如果该记录存在,则将事件转换为
null
事件,然后筛选出具有null
事件的事件(因为我们已经在您的第一个子拓扑中加入了这些事件)。
我稍微更新了您的代码:

//give your GlobalKTable a name to query later
GlobalKTable<String, Event> trackedEvents = streamsBuilder.globalTable(intermediateTopic, Materialized.as("tracked_event_global_store"));

KStream<String, Event> derivedKStream = segregatedRecords[1]
    // derive key for lookup
    .selectKey((key, event) -> createKey(event));
// this sub-topology perform table lockup as normal: update the event status in the table
derivedKStream.join(trackedEvents, (key, value) -> key,(event, tracked) -> modifiedEvent)
    .to(intermediateTopic);
// this sub-topology check whether the event existed in trackedEvents, if yes then event has been already joined 
// so we transform to null value and filter in next step 
derivedKStream.transformValues(() -> new ValueTransformerWithKey<String, Event, Event>() {
    //get the underlying store of Tracked GlobalKTable
    KeyValueStore<String, Event> trackedKvStore;
    @Override
    public void init(ProcessorContext context) {
        //using the previous name
        trackedKvStore = (KeyValueStore<String, Event>) context.getStateStore("tracked_event_global_store");
    }

    @Override
    public Event transform(String derivedKey, Event event) {
        //if event existed in trackedEvents then return a null event so we can filter out in next pipe
        if (trackedKvStore.get(derivedKey) != null) {
            return null;
        }
        //event not exist in trackedEvents, keep the event and send to different topic
        return event;
    }

    @Override
    public void close() {
    }
})
.filter((derivedKey, event) -> event != null)
.to("your different toic name");

谢谢Tuyen,这正是我要找的。我会测试它并让你知道。它可以用于更新,但我无法从GlobalKtable中进行流式处理。最后一部分是仅查询全局Ktable并过滤现有记录并将其发布到第三个主题。但当我尝试流式处理时,它会抛出以下错误:-``无效拓扑:Topic“intermediate”已由另一个源注册。更新的表包含我需要的所有信息,但我无法在不传递流、分支流或流的情况下查询它。对此有一个开放的票证。请查看。有什么建议吗?您的“Branchs[0]”KStream或此KStream之上的KStream是否也是主题中的stream()“中间”?似乎可以从主题流式传输并创建KStream和KTable,但目前没有GlobalKTable的解决方案,因为GlobalKTable使用输入主题进行容错。我只能想到一种解决方法,即发送到GlobalKTable的单独输入主题,但这是不同的问题(通过添加子拓扑并将重复数据发送到此主题)。Mabye a
leftJoin
还可以帮助执行连续的
分支()
,检查“右侧"结果的值是否为
null
。我确实尝试过,但如果我理解正确,仍然存在根据拓扑下的条件更新右侧值的问题。左侧连接将更新流,但不会更新表状态。哦,是的。我错过了您也要更新状态的问题。例如,我不知道他的案例a
leftJoin()
不起作用。很抱歉造成混淆。我的错。
KStream<Object, Object> intermediateKStream = streamsBuilder.stream(intermediate);
intermediateKStream.to(trackedInputTopic);
//instead of building GlobalKTable from intermediate, use this dedicated topic trackedInputTopic
GlobalKTable<String, Event> trackedEvents = streamsBuilder.globalTable(trackedInputTopic, Materialized.as("tracked_event_global_store"));

//Perform things you want to do with the intermediate topic
intermediateKStream
        ...