本文介绍了如何在Fink中实例化MapStateDescriptor以计算多个平均流查询?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试计算3个不同房间的平均温度,其中每个房间都有3个温度传感器.我正在使用Flink(在Java中).首先,我用一个键(房间,A,B或C)分割传感器,然后创建一个RichFlatMapFunction,其中保存一个MapState以保存温度,而直到3次测量时我都没有.经过三次测量,我计算出平均值.为了使用MapState,我需要一个不知道如何正确实例化的MapStateDescriptor.有人可以帮我弄这个吗?谢谢.

I am trying to compute the temperature average of 3 different rooms where each room has 3 temperature sensors. I am using Flink (in Java). First I split the sensors by a key that is the room (A, B, or C) and them I create a RichFlatMapFunction which holds a MapState to save the temperature while I don't have until 3 measurements. After three measurements I compute the average. In order to use the MapState I need a MapStateDescriptor which I don't know how to instantiate properly. Can someone help me with this? Thanks.

public class SensorsMultipleReadingMqttEdgentQEP2 {

    private boolean checkpointEnable = false;
    private long checkpointInterval = 10000;
    private CheckpointingMode checkpointMode = CheckpointingMode.EXACTLY_ONCE;

    public SensorsMultipleReadingMqttEdgentQEP2() throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);

        if (checkpointEnable) {
            env.enableCheckpointing(checkpointInterval, checkpointMode);
        }

        DataStream<MqttTemperature> temperatureStream01 = env.addSource(new TemperatureMqttConsumer("topic-edgent-01"));
        DataStream<MqttTemperature> temperatureStream02 = env.addSource(new TemperatureMqttConsumer("topic-edgent-02"));
        DataStream<MqttTemperature> temperatureStream03 = env.addSource(new TemperatureMqttConsumer("topic-edgent-03"));

        DataStream<Tuple2<String, Double>> averageStream01 = temperatureStream01.map(new SensorMatcher()).keyBy(0)
                .flatMap(new AverageTempMapper());
        DataStream<Tuple2<String, Double>> averageStream02 = temperatureStream02.map(new SensorMatcher()).keyBy(0)
                .flatMap(new AverageTempMapper());
        DataStream<Tuple2<String, Double>> averageStream03 = temperatureStream03.map(new SensorMatcher()).keyBy(0)
                .flatMap(new AverageTempMapper());

        DataStream<Tuple2<String, Double>> averageStreams = averageStream01.union(averageStream02)
                .union(averageStream03);

        averageStreams.print();
        env.execute("SensorsMultipleReadingMqttEdgentQEP");
    }

    public static class SensorMatcher implements MapFunction<MqttTemperature, Tuple2<String, MqttTemperature>> {

        private static final long serialVersionUID = 7035756567190539683L;

        @Override
        public Tuple2<String, MqttTemperature> map(MqttTemperature value) throws Exception {
            String key = "no-room";
            if (value.getId().equals(1) || value.getId().equals(2) || value.getId().equals(3)) {
                key = "room-A";
            } else if (value.getId().equals(4) || value.getId().equals(5) || value.getId().equals(6)) {
                key = "room-B";
            } else if (value.getId().equals(7) || value.getId().equals(8) || value.getId().equals(9)) {
                key = "room-C";
            } else {
                System.err.println("Sensor not defined in any room.");
            }
            return new Tuple2<>(key, value);
        }
    }

    public static class AverageTempMapper
            extends RichFlatMapFunction<Tuple2<String, MqttTemperature>, Tuple2<String, Double>> {

        private static final long serialVersionUID = -4780146677198295204L;
        private MapState<String, Tuple2<Integer, Double>> modelState;

        @Override
        public void open(Configuration parameters) throws Exception {
            TypeInformation<Tuple2<String, Tuple2<Integer, Double>>> typeInformation = TypeInformation
                    .of(new TypeHint<Tuple2<String, Tuple2<Integer, Double>>>() {
                    });

            // HOW TO INSTANTIATE THIS descriptor?
            MapStateDescriptor<String, Tuple2<Integer, Double>> descriptor = new MapStateDescriptor<>("modelState",
                    String.class, Tuple2.class);
            modelState = getRuntimeContext().getMapState(descriptor);
        }

        @Override
        public void flatMap(Tuple2<String, MqttTemperature> value, Collector<Tuple2<String, Double>> out)
                throws Exception {
            Double temp = null;
            Integer count = 0;
            if (modelState.contains(value.f0)) {
                count = modelState.get(value.f0).f0 + 1;
                temp = (modelState.get(value.f0).f1 + value.f1.getTemp());
            } else {
                count = 1;
                temp = value.f1.getTemp();
            }
            modelState.put(value.f0, Tuple2.of(count, temp));

            if (count >= 3) {
                out.collect(Tuple2.of("room", null));
            }
        }
    }
}

推荐答案

要定义MapStateDescriptor,您可以执行以下操作:

In order to define the MapStateDescriptor you could do the following:

MapStateDescriptor<String, Tuple2<Integer, Double>> modelState = new MapStateDescriptor<>(
    "modelState", 
    BasicTypeInfo.STRING_TYPE_INFO, 
    TupleTypeInfo.getBasicTupleTypeInfo(Integer.class, Double.class));
this.modelState = getRuntimeContext().getMapState(modelState);

但是,实际上您无需使用MapState.由于流已经被加密,因此使用ValueState就足够了.代码如下所示:

However, there is actually no need to use a MapState in your case. Since the stream is already keyed it is enough to use a ValueState. The code would look the following way:

public static class AverageTempMapper extends RichFlatMapFunction<Tuple2<String, MqttTemperature>, Tuple2<String, Double>> {

    private static final long serialVersionUID = -4780146677198295204L;
    private ValueState<Tuple2<Integer, Double>> modelState;

    @Override
    public void open(Configuration parameters) {
        this.modelState = getRuntimeContext().getState(new ValueStateDescriptor<>("modelState", TupleTypeInfo.getBasicTupleTypeInfo(Integer.class, Double.class)));
    }

    @Override
    public void flatMap(Tuple2<String, MqttTemperature> value, Collector<Tuple2<String, Double>> out) throws Exception {
        Double temp;
        Integer count;
        if (modelState.value() != null) {
            Tuple2<Integer, Double> state = modelState.value();
            count = state.f0 + 1;
            temp = state.f1 + value.f1.getTemp();
        } else {
            count = 1;
            temp = value.f1.getTemp();
        }
        modelState.update(Tuple2.of(count, temp));

        if (count >= 3) {
            out.collect(Tuple2.of(value.f0, temp/count));
        }
    }
}

这篇关于如何在Fink中实例化MapStateDescriptor以计算多个平均流查询?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-31 13:40