Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Kafka Streams:ktable作为查找和合并流的目标_Java_Apache Kafka_Apache Kafka Streams - Fatal编程技术网

Java Kafka Streams:ktable作为查找和合并流的目标

Java Kafka Streams:ktable作为查找和合并流的目标,java,apache-kafka,apache-kafka-streams,Java,Apache Kafka,Apache Kafka Streams,嗨,我有3个事件流,我想用卡夫卡流合并 我找不到解决并发问题的简单解决方案: // merged values Ktable KTable<String, ProdForecastPowerPlantAgg> mergedTable = builder.table( getMergedValuesTopic(), [...]); // records A // stream KStream&

嗨,我有3个事件流,我想用卡夫卡流合并

我找不到解决并发问题的简单解决方案:

    // merged values Ktable
    KTable<String, ProdForecastPowerPlantAgg> mergedTable = builder.table(
            getMergedValuesTopic(),
            [...]);


    // records A

    // stream
    KStream<String, RecordA> recordsAStream = builder.stream(
            getRecordATopic(),
            [...]);

    // rekeyed stream
    KStream<String, ProductionRecordValue> recordsABySomeId = recordsAStream
            .selectKey((k, v) -> getKey(v);


    // records B

    // stream
    KStream<String, RecordB> recordsBStream = builder.stream(
            getRecordBTopic(),
            [...]);

    // rekeyed stream
    KStream<String, RecordB> recordsBBySomeId = recordsBStream
            .selectKey((k, v) -> getKey(v);


    // records C

    // stream
    KStream<String, RecordA> recordsCStream = builder.stream(
            getRecordCTopic(),
            [...]);

    // rekeyed stream
    KStream<String, ProductionRecordValue> recordsCBySomeId = recordsCStream
            .selectKey((k, v) -> getKey(v);


    // when a recordA arrives
    KStream<String, RecordA> aggFromA = recordsABySomeId
            .filter((k, v) -> v != null)
            // join recordA and current join result together
            .leftJoin(mergedTable, (recA, oldMerge) -> {
                        if (oldMerge != null) {
                            return new Merge(recA, oldMerge.B, oldMerge.C);
                        }
                        return new Merge(recA, null, null)
                    },
                    [...]
            );

    // when a recordB arrives
    KStream<String, RecordB> aggFromB = recordsBBySomeId
            .filter((k, v) -> v != null)
            // join recordB and current join result together
            .leftJoin(mergedTable, (recB, oldMerge) -> {
                        if (oldMerge != null) {
                            return new Merge(oldMerge.A, recB, oldMerge.C);
                        }
                        return new Merge(null, recB, null)
                    },
                    [...]
            );


    // when a recordC arrives
    KStream<String, RecordB> aggFromC = recordsCBySomeId
            .filter((k, v) -> v != null)
            // join recordB and current join result together
            .leftJoin(mergedTable, (recC, oldMerge) -> {
                        if (oldMerge != null) {
                            return new Merge(oldMerge.A, oldMerge.B, recC);
                        }
                        return new Merge(null, null, recC)
                    },
                    [...]
            );


    // save aggreagtion
aggFromA.merge(aggFromB).merge(aggFromC)
            .to(getMergedValuesTopic(), Produced.with(Serdes.String(), aggSerdes));



    return builder.build();
//合并值Ktable
KTable mergedTable=builder.table(
getMergedValuesTopic(),
[...]);
//记录A
//溪流
KStream recordsAStream=builder.stream(
getRecordATopic(),
[...]);
//重新键入的流
KStream recordsABySomeId=recordsAStream
.选择键((k,v)->获取键(v);
//记录B
//溪流
KStream recordsBStream=builder.stream(
getRecordBTopic(),
[...]);
//重新键入的流
KStream recordsBBySomeId=recordsBStream
.选择键((k,v)->获取键(v);
//记录C
//溪流
KStream recordsCStream=builder.stream(
getRecordCTopic(),
[...]);
//重新键入的流
KStream recordsCBySomeId=recordsCStream
.选择键((k,v)->获取键(v);
//当记录到达时
KStream aggFromA=recordsABySomeId
.filter((k,v)->v!=null)
//将记录A和当前联接结果联接在一起
.leftJoin(合并表,(recA,oldMerge)->{
if(oldMerge!=null){
返回新合并(recA、oldMerge.B、oldMerge.C);
}
返回新合并(recA、null、null)
},
[...]
);
//当记录B到达时
KStream aggFromB=recordsBBySomeId
.filter((k,v)->v!=null)
//将记录B和当前联接结果联接在一起
.leftJoin(合并表,(recB,oldMerge)->{
if(oldMerge!=null){
返回新合并(oldMerge.A、recB、oldMerge.C);
}
返回新合并(null、recB、null)
},
[...]
);
//当recordC到达时
KStream aggFromC=recordsCBySomeId
.filter((k,v)->v!=null)
//将记录B和当前联接结果联接在一起
.leftJoin(合并表,(recC,oldMerge)->{
if(oldMerge!=null){
返回新合并(oldMerge.A、oldMerge.B、recC);
}
返回新合并(null、null、recC)
},
[...]
);
//拯救仇恨
aggFromA.merge(aggFromB.merge(aggFromC)
.to(getMergedValuesTopic(),producted.with(Serdes.String(),aggSerdes));
返回builder.build();
事实上,此代码段是无效的:当查找完成时,基于getMergedValuesTopic的KTable不能反映合并的最新状态: 当两个不同的记录同时到达时,一个更新可以取消另一个更新(因为查找已过时)


有人能用Kafka streams简单地解决这个问题吗?

我认为简单的聚合应该可以解决这个问题。聚合执行您描述的操作:“KTable as lookup and destination”

在每个到达的记录上,检查聚合表是否匹配。如果未找到匹配项,则使用聚合中定义的初始值设定项生成新的初始记录:文档可用

示例代码:

public class KTableMerge {

protected Topology buildTopology() {
    final StreamsBuilder builder = new StreamsBuilder();

    //Streams
    KStream<String, RecordA> recordAKStream = builder.stream("test-record-a");
    KStream<String, RecordB> recordBKStream = builder.stream("test-record-b");
    KStream<String, RecordC> recordCKStream = builder.stream("test-record-c");

    //Re-key and Merge Streams in parent 'Record' container
    KStream<String, Record> mergedStream =
        recordAKStream
            .selectKey((key, value) -> value.getForeignKey())
            .mapValues(value -> (Record) value)
            .merge(recordBKStream
                .selectKey((key, value) -> value.getForeignKey())
                .mapValues(value -> (Record) value))
            .merge(recordCKStream
                .selectKey((key, value) -> value.getForeignKey())
                .mapValues(value -> (Record) value));

    //Aggregate
    mergedStream
        .groupByKey()
        .aggregate(
            Merge::new,
            (key, value, aggregate) -> {
                if (value instanceof RecordA) {
                    aggregate.recordA = (RecordA) value;
                } else if (value instanceof RecordB) {
                    aggregate.recordB = (RecordB) value;
                } else if (value instanceof RecordC) {
                    aggregate.recordC = (RecordC) value;
                }
                return aggregate;
            })
        .toStream()
        .to("merge-topic");

    return builder.build();
}

private static class Merge {
    RecordA recordA;
    RecordB recordB;
    RecordC recordC;
}

private interface Record {
    String getForeignKey();
}

private static class RecordA implements Record {
    String id;
    String foreignKey;

    public String getForeignKey() {
        return foreignKey;
    }
}

private static class RecordB implements Record {
    String id;
    String foreignKey;

    public String getForeignKey() {
        return foreignKey;
    }
}

private static class RecordC implements Record {
    String id;
    String foreignKey;

    public String getForeignKey() {
        return foreignKey;
    }
}
公共类KTableMerge{
受保护的拓扑buildTopology(){
最终StreamsBuilder生成器=新StreamsBuilder();
//溪流
KStream recordAKStream=builder.stream(“test-record-a”);
KStream recordBKStream=builder.stream(“test-record-b”);
KStream recordCKStream=builder.stream(“test-record-c”);
//在父“记录”容器中为流重新设置密钥并合并流
KStream合并流=
recordAKStream
.selectKey((键,值)->value.getForeignKey()
.mapValues(值->(记录)值)
.merge(记录流)
.selectKey((键,值)->value.getForeignKey()
.mapValues(值->(记录)值)
.merge(记录流)
.selectKey((键,值)->value.getForeignKey()
.mapValues(值->(记录)值);
//聚合
合并流
.groupByKey()
.合计(
合并::新建,
(键、值、聚合)->{
if(记录A的值实例){
aggregate.recordA=(recordA)值;
}else if(记录B的值实例){
aggregate.recordB=(recordB)值;
}else if(记录C的值实例){
aggregate.recordC=(recordC)值;
}
总回报;
})
.toStream()
。合并主题;
返回builder.build();
}
私有静态类合并{
记录a记录a;
记录b记录b;
RecordC RecordC;
}
专用接口记录{
字符串getForeignKey();
}
私有静态类Record实现Record{
字符串id;
串外键;
公共字符串getForeignKey(){
返回外键;
}
}
私有静态类RecordB实现Record{
字符串id;
串外键;
公共字符串getForeignKey(){
返回外键;
}
}
私有静态类RecordC实现Record{
字符串id;
串外键;
公共字符串getForeignKey(){
返回外键;
}
}
}


希望这有帮助

哦,谢谢你,奥利弗,简单而优雅,我现在就测试一下。