Java 为kafka流中的左联接在右流中仅获取空值

Java 为kafka流中的左联接在右流中仅获取空值,java,join,apache-kafka,apache-kafka-streams,Java,Join,Apache Kafka,Apache Kafka Streams,我正在尝试连接来自两个卡夫卡主题的两个数据流 每个主题都有一个键-值对,其中键是一个整数数据类型,值包含字符串格式的json。来自这两个来源的数据如下所示(键、值): 现在,我正试图基于ProductID左连接这两个流,因此所有这些记录的键都设置为ProductID。但不幸的是,我在正确的连接流值中不断得到空值。甚至没有一个记录被正确地加入。以下是我连接两条记录的代码: import org.apache.kafka.streams.StreamsConfig; import org.apach

我正在尝试连接来自两个卡夫卡主题的两个数据流

每个主题都有一个键-值对,其中键是一个整数数据类型,值包含字符串格式的json。来自这两个来源的数据如下所示(键、值):

现在,我正试图基于ProductID左连接这两个流,因此所有这些记录的键都设置为ProductID。但不幸的是,我在正确的连接流值中不断得到空值。甚至没有一个记录被正确地加入。以下是我连接两条记录的代码:

import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.streams.kstream.*;
import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.common.serialization.Serde;
import org.apache.kafka.common.serialization.Serdes;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.util.concurrent.TimeUnit;
import java.util.*;

public class Tester {
    public static void main(String[] args){
        final Properties streamsConfiguration = new Properties();

        final Serde<String> stringSerde = Serdes.String();
        final Serde<Integer> intSerde = Serdes.Integer();

        streamsConfiguration.put(StreamsConfig.APPLICATION_ID_CONFIG, "join-streams");
        streamsConfiguration.put(StreamsConfig.CLIENT_ID_CONFIG, "joining-Client");
        streamsConfiguration.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");

        streamsConfiguration.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, intSerde.getClass().getName());
        streamsConfiguration.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, stringSerde.getClass().getName());

        streamsConfiguration.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 100);
        streamsConfiguration.put(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG, 0);
        streamsConfiguration.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 9000);

        final KStreamBuilder builder = new KStreamBuilder();
        KStream<Integer,String> pData = builder.stream(intSerde,stringSerde,"Ptopic");
        KStream<Integer,String> streamData = builder.stream(intSerde,stringSerde,"Dtopic");
// Test the data type and value of the key
        pbData.selectKey((k,v)->{System.out.println("Table : P, Type : "+k.getClass()+" Value : "+k);return k;});
        streamData.selectKey((k,v)->{System.out.println("Table : StreamRecord, Type : "+k.getClass()+" Value : "+k);return k;});

        KStream<Integer,String> joined = streamData.leftJoin(pbData,(table1Value,table2Value)->returnJoin(table1Value,table2Value),JoinWindows.of(TimeUnit.SECONDS.toMillis(30)));

        final KafkaStreams streams = new KafkaStreams(builder, streamsConfiguration);
        streams.cleanUp();
        streams.start();

        // Add shutdown hook to respond to SIGTERM and gracefully close Kafka Streams
        Runtime.getRuntime().addShutdownHook(new Thread(streams::close));
    }
    private static HashMap convertToHashMap(String jsonString, String tablename){
        try{
            HashMap<String,String> map = new Gson().fromJson(jsonString, new TypeToken<HashMap<String, String>>(){}.getType());
            return map;
        }
        catch(Exception x){
            //couldn't properly parse json
            HashMap<String,String> record = new HashMap<>();
            if (tablename.equals("PB")){
                List<String> keys = new ArrayList<>(Arrays.asList("ProductName", ", "CategoryID", "ProductID", "BrandID", "BrandName", "ProductCategoryID"));
                for(String key : keys){
                    record.put(key,null);
                }
            }
            else{
                List<String> keys = new ArrayList<>(Arrays.asList("UniqueID", "ConsumerID", "CategoryID", "BrandID", "ProductID", "Date","Flag","ProductDetails"));
                for(String key : keys){
                    record.put(key,null);
                }
            }
            return record;
        }
    }
    private static String returnJoin(String map1, String map2){
        HashMap h1 = convertToHashMap(map1,"consumer_product");
        HashMap h2 = convertToHashMap(map2,"PB");
        HashMap map3 = new HashMap<>();

        System.out.println("First : " + map1);
        System.out.println("Second : " + map2);
        //else{System.out.println("Null only");}
        for (Object key : h1.keySet()) {
            key = key.toString();
            if (map3.containsKey(key)) {
                continue;
            }
            map3.put(key, h1.get(key));
        }
        try {
            for (Object key : h2.keySet()) {
                key = key.toString();
                if (map3.containsKey(key)) {
                    continue;
                }
                map3.put(key, h2.get(key));
            }
            System.out.println("Worked Okay PB!!!\n--------------------------------------------------------------------------------------");
        }
        catch (NullPointerException ex){
            /*System.out.println("Exception\n----------------------------------------------------------------------------");
            HashMap fakeC = getHashMap("{","consumer");
            for (Object key : fakeC.keySet()) {
                key = key.toString();
                if (map3.containsKey(key)) {
                    continue;
                }
                map3.put(key, fakeC.get(key));
            }*/
            return "INVALID";
        }
        //return map3;
        return serializeObjectJSON(map3);
    }
    private static String serializeObjectJSON(Map row){
        StringBuilder jsonString = new StringBuilder();
        jsonString.append("{");
        for ( Object key : row.keySet()){
            jsonString.append("\""+key.toString()+"\":");
            try {
                jsonString.append("\"" + row.get(key).toString() + "\",");
            }
            catch (NullPointerException Nexp){
                jsonString.append("\"" + "null" + "\",");
            }

        }
        jsonString.deleteCharAt(jsonString.length()-1);
        jsonString.append("}");
        String jsString = jsonString.toString();
        ////System.out.println("JString :"+jsString);
        return jsString;
    }
}
以下两条语句的控制台日志示例如下所示(注意:总体日志太大,无法添加,但主要是流键都是整数,键重叠):

控制台日志:

Table : streamRecord, Type:class java.lang.Integer Value:1342
Table : streamRecord, Type:class java.lang.Integer Value:595
Table : streamRecord, Type:class java.lang.Integer Value:1934
Table : streamRecord, Type:class java.lang.Integer Value:2384
Table : streamRecord, Type:class java.lang.Integer Value:1666
Table : streamRecord, Type:class java.lang.Integer Value:665
Table : streamRecord, Type:class java.lang.Integer Value:2671
Table : streamRecord, Type:class java.lang.Integer Value:949
Table : streamRecord, Type:class java.lang.Integer Value:2455
Table : streamRecord, Type:class java.lang.Integer Value:928
Table : streamRecord, Type:class java.lang.Integer Value:1602
Table : streamRecord, Type:class java.lang.Integer Value:74
Table : P, Type:class java.lang.Integer Value:2
Table : streamRecord, Type:class java.lang.Integer Value:1795
Table : P, Type:class java.lang.Integer Value:21
Table : streamRecord, Type:class java.lang.Integer Value:1265
Table : P, Type:class java.lang.Integer Value:22
Table : streamRecord, Type:class java.lang.Integer Value:2420
Table : P, Type:class java.lang.Integer Value:23
Table : streamRecord, Type:class java.lang.Integer Value:1419
Table : P, Type:class java.lang.Integer Value:24
Table : streamRecord, Type:class java.lang.Integer Value:1395
Table : P, Type:class java.lang.Integer Value:26
Table : streamRecord, Type:class java.lang.Integer Value:1783
Table : P, Type:class java.lang.Integer Value:29
Table : streamRecord, Type:class java.lang.Integer Value:1177
Table : P, Type:class java.lang.Integer Value:34
Table : streamRecord, Type:class java.lang.Integer Value:1395
Table : P, Type:class java.lang.Integer Value:35
Table : streamRecord, Type:class java.lang.Integer Value:2551
Table : P, Type:class java.lang.Integer Value:36
Table : P, Type:class java.lang.Integer Value:2551
Table : streamRecord, Type:class java.lang.Integer Value:2530
Table : P, Type:class java.lang.Integer Value:37
Table : streamRecord, Type:class java.lang.Integer Value:541
Table : P, Type:class java.lang.Integer Value:39
Table : streamRecord, Type:class java.lang.Integer Value:787
Table : P, Type:class java.lang.Integer Value:40
Table : streamRecord, Type:class java.lang.Integer Value:2498
Table : P, Type:class java.lang.Integer Value:41
Table : streamRecord, Type:class java.lang.Integer Value:1439
Table : P, Type:class java.lang.Integer Value:44
Table : streamRecord, Type:class java.lang.Integer Value:784
Table : P, Type:class java.lang.Integer Value:284
Table : P, Type:class java.lang.Integer Value:285
Table : P, Type:class java.lang.Integer Value:929
Table : P, Type:class java.lang.Integer Value:286
Table : P, Type:class java.lang.Integer Value:287
Table : P, Type:class java.lang.Integer Value:2225
Table : P, Type:class java.lang.Integer Value:288
Table : P, Type:class java.lang.Integer Value:289
Table : P, Type:class java.lang.Integer Value:290
Table : P, Type:class java.lang.Integer Value:295
Table : P, Type:class java.lang.Integer Value:297
Table : P, Type:class java.lang.Integer Value:300
Table : P, Type:class java.lang.Integer Value:302
Table : P, Type:class java.lang.Integer Value:305
Table : P, Type:class java.lang.Integer Value:306
Table : P, Type:class java.lang.Integer Value:307
Table : P, Type:class java.lang.Integer Value:308
Table : P, Type:class java.lang.Integer Value:309
Table : P, Type:class java.lang.Integer Value:310
Table : streamRecord, Type:class java.lang.Integer Value:929
Table : streamRecord, Type:class java.lang.Integer Value:1509
Table : streamRecord, Type:class java.lang.Integer Value:136
Table : streamRecord, Type:class java.lang.Integer Value:2225
Table : streamRecord, Type:class java.lang.Integer Value:906
Table : streamRecord, Type:class java.lang.Integer Value:1013
Table : streamRecord, Type:class java.lang.Integer Value:1759
Table : streamRecord, Type:class java.lang.Integer Value:1759
Table : streamRecord, Type:class java.lang.Integer Value:885
Table : streamRecord, Type:class java.lang.Integer Value:1165
Table : streamRecord, Type:class java.lang.Integer Value:453

Update-2:有趣的是,对于同一组键值对,KTables,leftJoin工作正常。但不是因为某个原因。但是我需要使用KStreams,因为我有许多与密钥相关的记录。一般来说,在大多数情况下,这种加入流就像一个符咒,但在这种特殊情况下,它的表现很奇怪。我猜这可能与RocksDB或内部缓存有关。

似乎没有将ProductID设置为键:

pbData.selectKey((k,v)->{System.out.println(“表:P,键入:+k.getClass()+”值:+k);返回k;});
streamData.selectKey((k,v)->{System.out.println(“表:StreamRecord,类型:“+k.getClass()+”值:”+k);返回k;});
在这两条语句中,都返回原始键->
返回k
;而是从JSON解析productId并返回它

更新

我仍然不确定我是否能正确地把所有的部分放在一起,就像在你的更新中,你使用的那样

KStream rekeyedProductID=inserts.selectKey((k,v)->setTheKey(v.getdata(),“ProductID”);
KStream消费者\产品\流=
mapValues((v)->serializeObjectJSON(v.getdata())


现在还不清楚
inserts
rekeyedProductID
是什么(类型是什么?)。无论如何,我认为这部分是正确的。正如您提到的,如果右侧是一个KTable(使用相同的数据),那么它可以工作,我只是假设您的join窗口不够大,以至于具有相同键的两个记录彼此之间的距离(时间)比您指定的30秒远。你能仔细检查两个输入流的记录时间戳吗?(cf)

没有matthias这只是我用来测试同一类型并将键值打印到控制台的几个测试语句。当我将数据写入主题时,键被设置为整数。我已经用设置键值的代码更新了上面的问题。这里有趣的是,leftJoin对于同一组键值对的KTables工作良好。但不是因为某些原因。但是我需要使用KStreams,因为我有许多与密钥相关的记录。奇怪的是,我用这种方法在一个分布式集群中加入了非常大的早期记录,这种方法非常有效,但不适用于这种特殊情况。这可能与RocksDB或缓存有关吗?更新了我的答案。如果不是时间戳,我的想法就没有了…更新:*插入**只是在另一个以前的流上使用过滤器创建的另一个KStream,Windows大小相当大,因为我的一个流只有2K条产品记录,而另一个流有12k条记录,这个Windows大小通常可以正常工作,因为,它也应该加入至少一个或两个记录,但问题是,它甚至不会发生在一个案件。此外,我还尝试将窗口大小增加到120秒,但即使这样,连接也不起作用。奇怪的是,当我连接两个不同的流,每个流有1M条记录时,这个连接逻辑工作正常,但在这种情况下不行
public class recordHashmap {
    private String database;
    private String table;
    private String type;
    private Integer ts;
    private Integer xid;
    private Map<String,String> data;

    public Map getdata(){
        return data;
    }
    public String getdatabase(){return database;}
    public String gettable(){return table;}
    public String gettype(){return type;}
    public Integer getts(){return ts;}
    public Integer getxid(){return xid;}

    public void setdata(Map<String, String> dta){
        data=dta;
    }
    public void setdatabase(String db){ database=db; }
    public void settable(String tble){ table=tble; }
    public void settype(String optype){type=optype;}
    public void setts(Integer unixTime){ts = unixTime;}
    public void setxid(Integer Xid){xid = Xid;}

    public String toString() {
        return "Database=" + this.database + ", Table=" + this.table+", OperationType="+this.type+", UnixOpTime"+this.ts + ", Data="
                + this.data;
    }

}
KStream<Integer,recordHashmap> rekeyedProductID = inserts.selectKey((k,v)->setTheKey(v.getdata(),"ProductID"));
KStream<Integer,String> consumer_product_Stream = rekeyedProductID.mapValues((v)->serializeObjectJSON(v.getdata()));
private static Integer setTheKey(Map map, String Key){
        try {
            //System.out.println("New Key : " + map.get(Key));
            return Integer.parseInt(map.get(Key).toString());
        }
        catch (NumberFormatException nmb){
            //fake return a custom value
            return -1;
        }
    }
pbData.selectKey((k,v)->{System.out.println("Table : P, Type : "+k.getClass()+" Value : "+k);return k;});
streamData.selectKey((k,v)->{System.out.println("Table : StreamRecord, Type : "+k.getClass()+" Value : "+k);return k;});
Table : streamRecord, Type:class java.lang.Integer Value:1342
Table : streamRecord, Type:class java.lang.Integer Value:595
Table : streamRecord, Type:class java.lang.Integer Value:1934
Table : streamRecord, Type:class java.lang.Integer Value:2384
Table : streamRecord, Type:class java.lang.Integer Value:1666
Table : streamRecord, Type:class java.lang.Integer Value:665
Table : streamRecord, Type:class java.lang.Integer Value:2671
Table : streamRecord, Type:class java.lang.Integer Value:949
Table : streamRecord, Type:class java.lang.Integer Value:2455
Table : streamRecord, Type:class java.lang.Integer Value:928
Table : streamRecord, Type:class java.lang.Integer Value:1602
Table : streamRecord, Type:class java.lang.Integer Value:74
Table : P, Type:class java.lang.Integer Value:2
Table : streamRecord, Type:class java.lang.Integer Value:1795
Table : P, Type:class java.lang.Integer Value:21
Table : streamRecord, Type:class java.lang.Integer Value:1265
Table : P, Type:class java.lang.Integer Value:22
Table : streamRecord, Type:class java.lang.Integer Value:2420
Table : P, Type:class java.lang.Integer Value:23
Table : streamRecord, Type:class java.lang.Integer Value:1419
Table : P, Type:class java.lang.Integer Value:24
Table : streamRecord, Type:class java.lang.Integer Value:1395
Table : P, Type:class java.lang.Integer Value:26
Table : streamRecord, Type:class java.lang.Integer Value:1783
Table : P, Type:class java.lang.Integer Value:29
Table : streamRecord, Type:class java.lang.Integer Value:1177
Table : P, Type:class java.lang.Integer Value:34
Table : streamRecord, Type:class java.lang.Integer Value:1395
Table : P, Type:class java.lang.Integer Value:35
Table : streamRecord, Type:class java.lang.Integer Value:2551
Table : P, Type:class java.lang.Integer Value:36
Table : P, Type:class java.lang.Integer Value:2551
Table : streamRecord, Type:class java.lang.Integer Value:2530
Table : P, Type:class java.lang.Integer Value:37
Table : streamRecord, Type:class java.lang.Integer Value:541
Table : P, Type:class java.lang.Integer Value:39
Table : streamRecord, Type:class java.lang.Integer Value:787
Table : P, Type:class java.lang.Integer Value:40
Table : streamRecord, Type:class java.lang.Integer Value:2498
Table : P, Type:class java.lang.Integer Value:41
Table : streamRecord, Type:class java.lang.Integer Value:1439
Table : P, Type:class java.lang.Integer Value:44
Table : streamRecord, Type:class java.lang.Integer Value:784
Table : P, Type:class java.lang.Integer Value:284
Table : P, Type:class java.lang.Integer Value:285
Table : P, Type:class java.lang.Integer Value:929
Table : P, Type:class java.lang.Integer Value:286
Table : P, Type:class java.lang.Integer Value:287
Table : P, Type:class java.lang.Integer Value:2225
Table : P, Type:class java.lang.Integer Value:288
Table : P, Type:class java.lang.Integer Value:289
Table : P, Type:class java.lang.Integer Value:290
Table : P, Type:class java.lang.Integer Value:295
Table : P, Type:class java.lang.Integer Value:297
Table : P, Type:class java.lang.Integer Value:300
Table : P, Type:class java.lang.Integer Value:302
Table : P, Type:class java.lang.Integer Value:305
Table : P, Type:class java.lang.Integer Value:306
Table : P, Type:class java.lang.Integer Value:307
Table : P, Type:class java.lang.Integer Value:308
Table : P, Type:class java.lang.Integer Value:309
Table : P, Type:class java.lang.Integer Value:310
Table : streamRecord, Type:class java.lang.Integer Value:929
Table : streamRecord, Type:class java.lang.Integer Value:1509
Table : streamRecord, Type:class java.lang.Integer Value:136
Table : streamRecord, Type:class java.lang.Integer Value:2225
Table : streamRecord, Type:class java.lang.Integer Value:906
Table : streamRecord, Type:class java.lang.Integer Value:1013
Table : streamRecord, Type:class java.lang.Integer Value:1759
Table : streamRecord, Type:class java.lang.Integer Value:1759
Table : streamRecord, Type:class java.lang.Integer Value:885
Table : streamRecord, Type:class java.lang.Integer Value:1165
Table : streamRecord, Type:class java.lang.Integer Value:453