Apache flink 尝试访问或读取Apache Flink中KeyedBroadCastProcessFunction中processElement方法中的只读ctx时出现NullPointer异常

Apache flink 尝试访问或读取Apache Flink中KeyedBroadCastProcessFunction中processElement方法中的只读ctx时出现NullPointer异常,apache-flink,flink-streaming,flink-cep,flink-sql,Apache Flink,Flink Streaming,Flink Cep,Flink Sql,我有一些有趣的场景,我正在flink中进行模式匹配,使用keyedbroadcastprocessfunction评估传入模式,当我在IDE中运行程序时,我在processElements函数中遇到空指针异常,当我尝试访问ReadOnlyContext时,但它在terminal中运行良好,下面是我的keyedbroadcastprocessfunction 下面是我的主课 import java.sql.Connection; import java.sql.DriverManager; imp

我有一些有趣的场景,我正在flink中进行模式匹配,使用keyedbroadcastprocessfunction评估传入模式,当我在IDE中运行程序时,我在processElements函数中遇到空指针异常,当我尝试访问ReadOnlyContext时,但它在terminal中运行良好,下面是我的keyedbroadcastprocessfunction

下面是我的主课

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.restartstrategy.RestartStrategies;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.time.Time;
import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.typeutils.MapTypeInfo;
import org.apache.flink.streaming.api.datastream.BroadcastStream;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;
import org.apache.flink.util.OutputTag;
import org.json.JSONObject;

public class SignalPatternMatchingApp {

    public static final MapStateDescriptor<String, Map<String, String>> patternRuleDescriptor =
            new MapStateDescriptor(SignalPatternMatchingConstants.PATTERN_RULE_DESCRIPTOR_NAME,
                    BasicTypeInfo.STRING_TYPE_INFO, new MapTypeInfo<>(String.class, String.class));

 
    public static final OutputTag<JSONObject> unMatchedSideOutput =
            new OutputTag<JSONObject>("sideoutput") {
            };

 
    public static void main(String[] args) throws Exception {

        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        
        
        DataStream<JSONObject> inputSignal = get input from kafka stream

        DataStream<Map<String, String>> rawPatternStream =
                env.fromElements(get data from database);

        DataStream<Tuple2<String, Map<String, String>>> patternStream =
                rawPatternStream.flatMap(new FlatMapFunction<Map<String, String>,
                        Tuple2<String, Map<String, String>>>() {
                    @Override
                    public void flatMap(Map<String, String> patternRules,
                                        Collector<Tuple2<String, Map<String, String>>> out) throws Exception {
                        for (Map.Entry<String, String> stringEntry : patternRules.entrySet()) {
                            JSONObject jsonObject = new JSONObject(stringEntry.getValue());
                            Map<String, String> map = new HashMap<>();
                            for (String key : jsonObject.keySet()) {
                                String value = jsonObject.get(key).toString();
                                map.put(key, value);
                            }
                            out.collect(new Tuple2<>(stringEntry.getKey(), map));
                        }
                    }
                });

        BroadcastStream<Tuple2<String, Map<String, String>>> patternBroadcast =
                patternStream.broadcast(patternRuleDescriptor);


        DataStream<Tuple2<String, JSONObject>> matchedSignal =
                inputSignal.map(new MapFunction<JSONObject, Tuple2<String, JSONObject>>() {
            @Override
            public Tuple2<String, JSONObject> map(JSONObject inputSignal) throws Exception {
                String sourceName = inputSignal.getJSONObject("signalHeader").get("sourceName").toString();
                return new Tuple2<>(sourceName, inputSignal);
            }
        }).keyBy(0).connect(patternBroadcast).process(new TestProcess());


        matchedSignal.print();
        
        DataStream<JSONObject> unmatchedSignal =
                ((SingleOutputStreamOperator<Tuple2<String, JSONObject>>) matchedSignal)
                .getSideOutput(unMatchedSideOutput);

        unmatchedSignal.print();

        env.execute();

    }
    

KeyedBroadcastProcessFunction as below




 public class TestProcess extends KeyedBroadcastProcessFunction<String, Tuple2<String, sampleSignal>,
            Tuple2<String, Map<String, String>>, Tuple2<String, sampleSignal>> {

   MapStateDescriptor<String, Map<String, String>> patternRuleDesc;

    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        patternRuleDesc = new MapStateDescriptor<>("RuleDescriptor",
                BasicTypeInfo.STRING_TYPE_INFO,new MapTypeInfo<>(String.class,String.class));
    }
    
        public static final MapStateDescriptor <String,Map<String,String>> ruleDescriptor =
                new MapStateDescriptor <>("RuleDiscriptor",
                        ,BasicTypeInfo.STRING_TYPE_INFO
                        ,new MapTypeInfo<>(String.class,String.class));
    
        @Override
        public void processElement(Tuple2<String, sampleSignal> value, ReadOnlyContext ctx, Collector<Tuple2<String,
                sampleSignal>> out) throws Exception {
  
            Map<String,String> patternConditions  = ctx.getBroadcastState(this.patternRuleDesc).get(Key);
    
            System.out.println("Before Rule Iterator");
            
            /*I tried below way to print the values in broadcaststream just to print the values
              in broadcast state it don't print anything*/
              
            for(Map.Entry<String, String> rules:
                    patternConditions.entrySet()){
                System.out.println("Key: " +rules.getKey());
                System.out.println("Value: "+rules.getValue());
            }
    
            out.collect(new Tuple2<>(value.f0,value.f1));
    
        }
    
        @Override
        public void processBroadcastElement(Tuple2<String, Map<String, String>> value, Context ctx,
                                            Collector<Tuple2<String, sampleSignal>> out) throws Exception {
    
            System.out.println("BroadCastState Key: " +value.f0);
            System.out.println("BroadCastState Value: " +value.f1);
            ctx.getBroadcastState(ruleDescriptor).put(value.f0,value.f1);
    
        }
    }

请帮助解决我使用的FLINK 1.10.0版本和INTELLiJ IDE以及Java 1.8版本的问题,假设代码的当前状态是这一部分,那么这是它实际失败的唯一地方:

 Map<String,String> patternConditions  = ctx.getBroadcastState(this.patternRuleDesc).get(Key);
    
            System.out.println("Before Rule Iterator");
            
            /*I tried below way to print the values in broadcaststream just to print the values
              in broadcast state it don't print anything*/
              
            for(Map.Entry<String, String> rules:
                    patternConditions.entrySet()){
                System.out.println("Key: " +rules.getKey());
                System.out.println("Value: "+rules.getValue());
            }
Map patternConditions=ctx.getBroadcastState(this.patternRuleDesc.get(Key);
System.out.println(“规则迭代器之前”);
/*我尝试了下面的方法来打印broadcaststream中的值,只是为了打印这些值
在广播状态下,它不打印任何内容*/
对于(Map.Entry规则:
patternConditions.entrySet()){
System.out.println(“Key:+rules.getKey());
System.out.println(“值:+rules.getValue());
}
问题不是真正获取广播状态,因为它不应该抛出
NullPointerException
,而是
IllegalArgumentException
。问题是您获取了一些
,然后尝试对此(
.entryset()
)执行一些操作。但是如果给定的
不存在,该状态将与正常的
映射
一样工作,这意味着它将返回
null
。如果您尝试在
null
上执行操作,您将得到
NullPointerException

您应该添加一些代码来验证给定的
是否处于状态,否则它总是会失败

编辑:

因此,如果问题是关于BroadcastStream和另一个流之间的竞争,那么这并不是您可以轻易阻止的事情。这是因为消费者消费信息的速度可能不同,通常不可能防止这种情况发生。 我认为有两种方法可以解决这个问题:

  • 创建
    ListState
    ,它将保留到达但没有相应
    键的元素,然后只要在给定
    键到达时发出它们即可。注意:您必须从
    processElement
    发出它们,因为
    BroadcastState
    未设置关键帧
  • 使用
    InputSelectable
    编写一个运算符,使其更喜欢一个源而不是另一个源,这样您就可以更喜欢广播流而不是元素流

  • 一般来说,如果您有连续的数据流,即您知道给定的
    将不止一次到达,那么我会说选项1更简单、更快。选项2提供了更大的灵活性,但也需要更多的知识,通常更难正确实施。

    StreamTwoInputProcessor.processInput上也有一个空点。我猜您正在尝试处理某个空事件。但是,
    incomingRule.size()
    上的另一个空指针真的很奇怪。@Felipe谢谢你的回复,我又错过了一个错误,我得到了以下错误,但我使用的是相同的mapstate描述符,我在广播流时也使用了它,原因是:java.lang.IllegalArgumentException:请求的状态不存在。检查状态描述符中是否有输入错误,或者如果忘记注册,请在datastream.broadcast(…)调用中指定状态描述符。我想问题可能是如何实例化
    MapStateDescriptor
    。您必须在open方法中实例化它,您必须从
    RichFunction
    重载该方法。这里有一个例子:是的,我真的不认为错误是在你认为的地方出现的。什么是
    incomingPattern
    Key
    ?@Felipe ya甚至也尝试过这种方法,声明open方法并启动Mapstate,但我仍然看到相同的空指针,但我同意密钥存在,因为它抛出NPE,我观察到的是广播流和数据流正在相互竞争other和此异常不一致有时它不会抛出NPE并正常运行,但有时它抛出NPE我在调试模式下运行程序时观察到的成功运行的NPE KeyedBroadCastProcessFn中的第一个广播方法首先执行失败的情况第一个processElement方法正在执行,因为映射状态为空白我在寻找提示我如何确保第一次广播状态被执行第一次,所以我想你也许应该在问题中说得更清楚,因为至少对我来说,这不是你要问的问题:)编辑答案你说编辑答案对不起,我不知道答案中更新了什么,你能指出吗?我同意你的观点,当我面对这个问题时,问题一开始并不清楚,我虽然我做错了什么,但在调试了很多之后,我我知道processElement方法在广播方法之前执行,因为映射状态为空,正在抛出NPE我会更新问题抱歉是的,很抱歉,我遇到了一些问题,答案没有正确添加:)感谢您的建议,但不幸的是,我不能在我的案例中使用列表状态。密钥只不过是数据来源,我将其作为信号的一部分获取,我使用flatmap函数提取密钥,因此我不会使用空密钥和InputSelectable不适合我的情况,我发现问题出在哪里,我接收到的输入信号是avro信号,我从JSON文件中读取模式,因为这个avro信号比jsonobject的流先得到处理,所以我改变了
     Map<String,String> patternConditions  = ctx.getBroadcastState(this.patternRuleDesc).get(Key);
        
                System.out.println("Before Rule Iterator");
                
                /*I tried below way to print the values in broadcaststream just to print the values
                  in broadcast state it don't print anything*/
                  
                for(Map.Entry<String, String> rules:
                        patternConditions.entrySet()){
                    System.out.println("Key: " +rules.getKey());
                    System.out.println("Value: "+rules.getValue());
                }