Flink DataStream API 基础算子(一)

news2024/9/20 23:47:34

一、介绍

官网

DataStream API 得名于特殊的 DataStream 类,该类用于表示 Flink 程序中的数据集合。你可以认为 它们是可以包含重复项的不可变数据集合。这些数据可以是有界(有限)的,也可以是无界(无限)的,但用于处理它们的API是相同的。

二、基础算子

1、Map

Map算子:输入一个元素同时输出一个元素,这里的写法和Java类似,可以使用糖化语法或者实现Function接口

package com.xx.common.study.api.base;

import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

/**
 * @author xiaxing
 * @describe Map算子,输入一个元素同时输出一个元素,这里的写法和Java类似,可以使用糖化语法或者实现Function接口
 * @since 2024/5/17 14:27
 */
public class DataStreamMapApiDemo {

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Integer> sourceStream = env.fromElements(1, 2, 3);

        // 糖化语法
        SingleOutputStreamOperator<Integer> multiStream = sourceStream.map(e -> e * 2);
        multiStream.print("数据乘2");

        // 实现Function接口
        SingleOutputStreamOperator<Integer> addStream = sourceStream.map(new MapFunction<Integer, Integer>() {
            @Override
            public Integer map(Integer value) throws Exception {
                return value + 2;
            }
        });

        addStream.print("数据加2");
        env.execute();
    }
}

2、FlatMap

FlatMap算子:输入一个元素同时产生零个、一个或多个元素

package com.xx.common.study.api.base;

import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

import java.util.Arrays;
import java.util.List;

/**
 * @author xiaxing
 * @describe FlatMap算子,输入一个元素同时产生零个、一个或多个元素
 * @since 2024/5/17 14:27
 */
public class DataStreamFlatMapApiDemo {

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> sourceStream = env.fromElements("1,2,3");

        // 对source进行加工处理
        sourceStream.flatMap((FlatMapFunction<String, List<String>>) (value, out) -> {
            String[] split = value.split(",");
            out.collect(Arrays.asList(split));
        }).print();

        // 错误写法,和Java写法不用,无法使用这种糖化语法
//        sourceStream.flatMap((k, v) -> {
//            String[] split = k.split(",");
//            v.collect(split);
//        }).print();

        env.execute();
    }
}

3、Filter

Filter算子:为每个元素执行一个布尔 function,并保留那些 function 输出值为 true 的元素

package com.xx.common.study.api.base;

import org.apache.flink.api.common.functions.FilterFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

/**
 * @author xiaxing
 * @describe Filter算子,为每个元素执行一个布尔 function,并保留那些 function 输出值为 true 的元素
 * @since 2024/5/17 14:27
 */
public class DataStreamFilterApiDemo {

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Integer> sourceStream = env.fromElements(1, 2, 3);
        // 保留整数
        sourceStream.filter(e -> (e % 2) == 0).print("糖化语法保留整数");

        sourceStream.filter(new FilterFunction<Integer>() {
            @Override
            public boolean filter(Integer value) throws Exception {
                return value % 2 == 0;
            }
        }).print("实现Function保留整数");

        env.execute();
    }
}

4、KeyBy

KeyBy算子:在逻辑上将流划分为不相交的分区。具有相同 key 的记录都分配到同一个分区。在内部, keyBy() 是通过哈希分区实现的

package com.xx.common.study.api.base;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

/**
 * @author xiaxing
 * @describe KeyBy算子,在逻辑上将流划分为不相交的分区。具有相同 key 的记录都分配到同一个分区。在内部, keyBy() 是通过哈希分区实现的
 * @since 2024/5/17 14:27
 */
public class DataStreamKeyByApiDemo {

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class keyByDemo {
        private Integer id;
        private Integer count;
    }

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        DataStreamSource<keyByDemo> sourceStream = env.fromElements(
                new keyByDemo(1, 1),
                new keyByDemo(2, 2),
                new keyByDemo(3, 3),
                new keyByDemo(1, 4)
        );
        KeyedStream<keyByDemo, Integer> keyByStream = sourceStream.keyBy(keyByDemo::getId);
        keyByStream.print("按照key分组");

        // 使用key分组之后可以使用一些常用的聚合算子
        // positionToSum:可以用于Tuple类型数据传递索引位置,field:传递字段名称
        keyByStream.sum("count").print();
        env.execute();
    }
}

5、Reduce

Reduce算子:在相同 key 的数据流上“滚动”执行 reduce。将当前元素与最后一次 reduce 得到的值组合然后输出新值

package com.xx.common.study.api.base;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

/**
 * @author xiaxing
 * @describe Reduce算子,在相同 key 的数据流上“滚动”执行 reduce。将当前元素与最后一次 reduce 得到的值组合然后输出新值
 * @since 2024/5/17 14:27
 */
public class DataStreamReduceApiDemo {

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class reduceByDemo {
        private String id;
        private Integer count;
    }

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<reduceByDemo> sourceStream = env.fromElements(
                new reduceByDemo("1", 1),
                new reduceByDemo("2", 2),
                new reduceByDemo("3", 3),
                new reduceByDemo("1", 4)
        );

        sourceStream.keyBy(reduceByDemo::getId).reduce(new ReduceFunction<reduceByDemo>() {
            @Override
            public reduceByDemo reduce(reduceByDemo value1, reduceByDemo value2) throws Exception {
                value1.setCount(value1.getCount() + value2.getCount());
                return value1;
            }
        }).print();
        env.execute();
    }
}

三、窗口算子

官网地址

3.1、概念

窗口(Window)是处理无界流的关键所在。窗口可以将数据流装入大小有限的“桶”中,再对每个“桶”加以处理。

Flink 中的时间有三种类型:

  • Event Time:是事件创建的时间。它通常由事件中的时间戳描述,例如采集的日志数据中,每一条日志都会记录自己的生成时间,Flink 通过时间戳分配器访问事件时间戳。

  • Ingestion Time:是数据进入 Flink 的时间。

  • Processing Time:是每一个执行基于时间操作的算子的本地系统时间,与机器相关,默认的时间属性就是 Processing Time。

3.2、语法

Keyed Windows

stream
       .keyBy(...)               <-  仅 keyed 窗口需要
       .window(...)              <-  必填项:"assigner"
      [.trigger(...)]            <-  可选项:"trigger" (省略则使用默认 trigger)
      [.evictor(...)]            <-  可选项:"evictor" (省略则不使用 evictor)
      [.allowedLateness(...)]    <-  可选项:"lateness" (省略则为 0)
      [.sideOutputLateData(...)] <-  可选项:"output tag" (省略则不对迟到数据使用 side output)
       .reduce/aggregate/apply()      <-  必填项:"function"
      [.getSideOutput(...)]      <-  可选项:"output tag"

Non-Keyed Windows

stream
       .windowAll(...)           <-  必填项:"assigner"
      [.trigger(...)]            <-  可选项:"trigger" (else default trigger)
      [.evictor(...)]            <-  可选项:"evictor" (else no evictor)
      [.allowedLateness(...)]    <-  可选项:"lateness" (else zero)
      [.sideOutputLateData(...)] <-  可选项:"output tag" (else no side output for late data)
       .reduce/aggregate/apply()      <-  必填项:"function"
      [.getSideOutput(...)]      <-  可选项:"output tag"

3.3、Window Assigners

Window Assigners为抽象类,Flink默认已经实现了4种窗口

3.3.1、滚动窗口(Tumbling Windows)

滚动窗口的 assigner 分发元素到指定大小的窗口。滚动窗口的大小是固定的,且各自范围之间不重叠。 比如说,如果你指定了滚动窗口的大小为 5 分钟,那么每 5 分钟就会有一个窗口被计算,且一个新的窗口被创建(如下图所示)。

在这里插入图片描述

DataStream<T> input = ...;

// 滚动 event-time 窗口
input
    .keyBy(<key selector>)
    .window(TumblingEventTimeWindows.of(Time.seconds(5)))
    .<windowed transformation>(<window function>);

// 滚动 processing-time 窗口
input
    .keyBy(<key selector>)
    .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
    .<windowed transformation>(<window function>);

// 长度为一天的滚动 event-time 窗口, 偏移量为 -8 小时。
input
    .keyBy(<key selector>)
    .window(TumblingEventTimeWindows.of(Time.days(1), Time.hours(-8)))
    .<windowed transformation>(<window function>);

3.3.2、滑动窗口(Sliding Windows)

与滚动窗口类似,滑动窗口的 assigner 分发元素到指定大小的窗口,窗口大小通过 window size 参数设置。 滑动窗口需要一个额外的滑动距离(window slide)参数来控制生成新窗口的频率。 因此,如果 slide 小于窗口大小,滑动窗口可以允许窗口重叠。这种情况下,一个元素可能会被分发到多个窗口。

比如说,你设置了大小为 10 分钟,滑动距离 5 分钟的窗口,你会在每 5 分钟得到一个新的窗口, 里面包含之前 10 分钟到达的数据(如下图所示)。

在这里插入图片描述

DataStream<T> input = ...;

// 滑动 event-time 窗口
input
    .keyBy(<key selector>)
    .window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
    .<windowed transformation>(<window function>);

// 滑动 processing-time 窗口
input
    .keyBy(<key selector>)
    .window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
    .<windowed transformation>(<window function>);

// 滑动 processing-time 窗口,偏移量为 -8 小时
input
    .keyBy(<key selector>)
    .window(SlidingProcessingTimeWindows.of(Time.hours(12), Time.hours(1), Time.hours(-8)))
    .<windowed transformation>(<window function>);

3.3.3、会话窗口(Session Windows)

会话窗口的 assigner 会把数据按活跃的会话分组。 与滚动窗口和滑动窗口不同,会话窗口不会相互重叠,且没有固定的开始或结束时间。 会话窗口在一段时间没有收到数据之后会关闭,即在一段不活跃的间隔之后。 会话窗口的 assigner 可以设置固定的会话间隔(session gap)或 用 session gap extractor 函数来动态地定义多长时间算作不活跃。 当超出了不活跃的时间段,当前的会话就会关闭,并且将接下来的数据分发到新的会话窗口。

在这里插入图片描述

DataStream<T> input = ...;

// 设置了固定间隔的 event-time 会话窗口
input
    .keyBy(<key selector>)
    .window(EventTimeSessionWindows.withGap(Time.minutes(10)))
    .<windowed transformation>(<window function>);
    
// 设置了动态间隔的 event-time 会话窗口
input
    .keyBy(<key selector>)
    .window(EventTimeSessionWindows.withDynamicGap((element) -> {
        // 决定并返回会话间隔
    }))
    .<windowed transformation>(<window function>);

// 设置了固定间隔的 processing-time session 窗口
input
    .keyBy(<key selector>)
    .window(ProcessingTimeSessionWindows.withGap(Time.minutes(10)))
    .<windowed transformation>(<window function>);
    
// 设置了动态间隔的 processing-time 会话窗口
input
    .keyBy(<key selector>)
    .window(ProcessingTimeSessionWindows.withDynamicGap((element) -> {
        // 决定并返回会话间隔
    }))
    .<windowed transformation>(<window function>);

3.3.4、全局窗口(Global Windows)

全局窗口的 assigner 将拥有相同 key 的所有数据分发到一个全局窗口。 这样的窗口模式仅在你指定了自定义的 trigger 时有用。 否则,计算不会发生,因为全局窗口没有天然的终点去触发其中积累的数据。

在这里插入图片描述

DataStream<T> input = ...;

input
    .keyBy(<key selector>)
    .window(GlobalWindows.create())
    .<windowed transformation>(<window function>);

3.4、窗口函数

窗口函数有三种:ReduceFunction、AggregateFunction 或 ProcessWindowFunction

3.4.1、ReduceFunction

ReduceFunction 指定两条输入数据如何合并起来产生一条输出数据,输入和输出数据的类型必须相同

package com.xx.common.study.api.windows;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

/**
 * @author xiaxing
 * @describe 窗口函数-reduce
 * @since 2024/5/17 14:27
 */
public class DataStreamWindowsReduceApiDemo {

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class TumblingWindows {
        private Integer id;
        private Integer count;
    }

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> socketStream = env.socketTextStream("localhost", 7777);
        socketStream
                .map(new MapFunction<String, TumblingWindows>() {
                    @Override
                    public TumblingWindows map(String value) throws Exception {
                        String[] split = value.split(",");
                        return new TumblingWindows(Integer.valueOf(split[0]), Integer.valueOf(split[1]));
                    }
                })
                .keyBy(new KeySelector<TumblingWindows, Integer>() {
                    @Override
                    public Integer getKey(TumblingWindows value) throws Exception {
                        return value.getId();
                    }
                })
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5L)))
                .reduce(new ReduceFunction<TumblingWindows>() {
                    @Override
                    public TumblingWindows reduce(TumblingWindows value1, TumblingWindows value2) throws Exception {
                        return new TumblingWindows(value1.getId(), value1.getCount() + value2.getCount());
                    }
                })
                .print();

        env.execute();
    }
}


3.4.2、ReduceFunction糖化语法

使用Lambda糖化语法对代码进行了简化

package com.xx.common.study.api.windows;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

/**
 * @author xiaxing
 * @describe 窗口函数-reduce-糖化语法
 * @since 2024/5/17 14:27
 */
public class DataStreamWindowsReduceLambdaApiDemo {

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class TumblingWindows {
        private Integer id;
        private Integer count;
    }

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> socketStream = env.socketTextStream("localhost", 7777);

        socketStream
                .map(value -> {
                    String[] split = value.split(",");
                    return new TumblingWindows(Integer.valueOf(split[0]), Integer.valueOf(split[1]));
                })
                .keyBy(TumblingWindows::getId)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5L)))
                .reduce((value1, value2) -> new TumblingWindows(value1.getId(), value1.getCount() + value2.getCount()))
                .print();

        env.execute();
    }
}


3.4.3、AggregateFunction

ReduceFunction 是 AggregateFunction 的特殊情况。 AggregateFunction 接收三个类型:输入数据的类型(IN)、累加器的类型(ACC)和输出数据的类型(OUT)。 输入数据的类型是输入流的元素类型,AggregateFunction 接口有如下几个方法: 把每一条元素加进累加器、创建初始累加器、合并两个累加器、从累加器中提取输出(OUT 类型)

package com.xx.common.study.api.windows;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.flink.api.common.functions.AggregateFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

import java.util.Optional;

/**
 * @author xiaxing
 * @describe 窗口函数-Aggregate
 * @since 2024/5/17 14:27
 */
public class DataStreamWindowsAggregateApiDemo {

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class TumblingWindows {
        private Integer id;
        private Integer count;
    }

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> socketStream = env.socketTextStream("localhost", 7777);

        // 求和
        AggregateFunction<TumblingWindows, TumblingWindows, TumblingWindows> aggregateFunction = new AggregateFunction<TumblingWindows, TumblingWindows, TumblingWindows>() {
            @Override
            public TumblingWindows createAccumulator() {
                // 创建累加器,并将其初始化为默认值
                return new TumblingWindows();
            }

            @Override
            public TumblingWindows add(TumblingWindows value, TumblingWindows accumulator) {
                // 将输入的元素添加到累加器,返回更新后的累加器
                Integer count1 = Optional.of(value.getCount()).orElse(0);
                Integer count2 = Optional.ofNullable(accumulator.getCount()).orElse(0);
                return new TumblingWindows(value.getId(), count1 + count2);
            }

            @Override
            public TumblingWindows getResult(TumblingWindows accumulator) {
                // 从累加器中提取操作的结果
                return accumulator;
            }

            @Override
            public TumblingWindows merge(TumblingWindows a, TumblingWindows b) {
                // 将两个累加器合并为一个新的累加器
                return new TumblingWindows(a.getId(), a.getCount() + b.getCount());
            }
        };

        socketStream
                .map(value -> {
                    String[] split = value.split(",");
                    return new TumblingWindows(Integer.valueOf(split[0]), Integer.valueOf(split[1]));
                })
                .keyBy(TumblingWindows::getId)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5L)))
                .aggregate(aggregateFunction)
                .print();

        env.execute();
    }
}

3.4.4、ProcessWindowFunction

ProcessWindowFunction 可以与 ReduceFunction 或 AggregateFunction 搭配使用, 使其能够在数据到达窗口的时候进行增量聚合。当窗口关闭时,ProcessWindowFunction 将会得到聚合的结果。 这样它就可以增量聚合窗口的元素并且从 ProcessWindowFunction` 中获得窗口的元数据。

package com.xx.common.study.api.windows;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;

/**
 * @author xiaxing
 * @describe 窗口函数-reduce-process
 * @since 2024/5/17 14:27
 */
public class DataStreamWindowsReduceProcessApiDemo {

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class TumblingWindows {
        private Integer id;
        private Integer count;
    }

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> socketStream = env.socketTextStream("localhost", 7777);

        socketStream
                .map(value -> {
                    String[] split = value.split(",");
                    return new TumblingWindows(Integer.valueOf(split[0]), Integer.valueOf(split[1]));
                })
                .keyBy(TumblingWindows::getId)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5L)))
                .reduce(new MyReduceFunction(), new MyProcessWindowsFunction())
                .print();

        env.execute();
    }

    private static class MyReduceFunction implements ReduceFunction<TumblingWindows> {
        @Override
        public TumblingWindows reduce(TumblingWindows value1, TumblingWindows value2) throws Exception {
            return new TumblingWindows(value1.getId(), value1.getCount() + value2.getCount());
        }
    }

    private static class MyProcessWindowsFunction extends ProcessWindowFunction<TumblingWindows, TumblingWindows, Integer, TimeWindow> {
        @Override
        public void process(Integer integer, ProcessWindowFunction<TumblingWindows, TumblingWindows, Integer, TimeWindow>.Context context, Iterable<TumblingWindows> elements, Collector<TumblingWindows> out) throws Exception {
            elements.forEach(e -> {
                Integer count = e.getCount();
                // 当count > 10时才数据元素
                if (count > 10) {
                    out.collect(e);
                }
            });
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1685903.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s node NotReady后会发生什么?

K8s 是一种强大的容器编排和管理平台&#xff0c;能够高效地调度、管理和监控容器化应用程序&#xff1b;其本身使用声明式语义管理着集群内所有资源模型、应用程序、存储、网络等多种资源&#xff0c;Node 本身又属于 K8s 计算资源&#xff0c;上面承载运行着各种类型的应用程…

selenium环境安装和web自动化基础

webUI自动化背景 因为web页面经常会变化&#xff0c;所以UI自动化测试的维护成本很高。不如接口的适用面广&#xff0c;所以大部分公司会做接口自动化测试&#xff0c;但是未必会做UI自动化测试&#xff1b; UI自动化测试要做也是覆盖冒烟测试&#xff0c;不会到很高的覆盖率&a…

gpt-4o考场安排

说明 &#xff1a;经过多次交互&#xff0c;前后花了几个小时&#xff0c;总算完成了基本功能。如果做到按不同层次分配考场&#xff0c;一键出打印结果就完美了。如果不想看中间“艰苦”的过程&#xff0c;请直接跳到“最后结果”及“食用方法”。中间过程还省略了一部分交互&…

集中抄表系统是什么?

1.集中抄表系统简述 集中抄表&#xff0c;又称为智能抄表&#xff0c;是一种现代化能源管理体系技术性&#xff0c;主要运用于电力工程、水、气等公共事业的计量。它通过自动化的形式收集解决大量用户的计量数据信息&#xff0c;大大提升了数据收集的效率和精确性&#xff0c;…

基于SSM实现的新生报到系统源码+数据库+论文

项目简介 基于SSM实现的新生报到系统&#xff0c;主要分为五种用户角色&#xff0c;分别是&#xff1a; 学院管理员管理所有内容&#xff0c;涵盖了班级&#xff0c;专业&#xff0c;学院&#xff0c;学生&#xff0c;缴费以及宿舍等方面的信息&#xff0c;学院管理员可以统计…

java-查询字符串当中是否包含中文

文章目录 前言java-查询字符串当中是否包含中文 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&#xff0c;实在白嫖的话&#xff0c;那欢迎常来啊…

2024电工杯数学建模A题思路模型代码

最新版完整内容见文末名片 A 题&#xff1a;园区微电网风光储协调优化配置 园区微电网由风光发电和主电网联合为负荷供电&#xff0c;为了尽量提高风光电量的 负荷占比&#xff0c;需配置较高比例的风光发电装机容量&#xff0c;但由于园区负荷与风光发电功 率时序不匹配&am…

噪声条件分数网络——NCSN原理解析

1、前言 本篇文章&#xff0c;我们讲NCSN&#xff0c;也就是噪声条件分数网络。这是宋飏老师在2019年提出的模型&#xff0c;思路与传统的生成模型大不相同&#xff0c;令人拍案叫绝&#xff01;&#xff01;&#xff01; 参考论文&#xff1a; ①Generative Modeling by Es…

IDEA设置运行内存

1.开启内存指示条​​​​​​​ 查看idea右下角​​​​​​​ 2.环境变量查看ideaVM地址&#xff0c;没有的话那就是默认的配置文件&#xff1a; idea 安装 bin 目录下 idea64.exe.vmoptions 3.去对应路径修改内存参数大小 4.重启IDEA&#xff0c;end

leetcode-主持人调度(二)-110

题目要求 思路 1.先将开始时间和结束时间拆分放到两个数组中进行排序 2.如果开始的时间小于结束时间&#xff0c;说明目前没有空闲的人&#xff0c;需要增加人&#xff0c;如果大于等于&#xff0c;说明有人刚结束了主持&#xff0c;可以进行新的主持了&#xff0c;变更到下一…

JavaEE技术之分布式事务(理论、解决方案、Seata解决分布式事务问题、Seata之原理简介、断点查看数据库表数据变化)

文章目录 JavaEE技术之分布式事务准备:1. 本地事务回顾1.1 什么是事务1.2 事务的作用1.3 事务ACID四大特性1.4 事务的并发问题1.5 MySQL事务隔离级别1.6 事务相关命令(了解)1.7 事务传播行为&#xff08;propagation behavior&#xff09;1.8 伪代码练习1.9 回滚策略1.10 超时事…

重构2:重构的原则之笔记

最近在看重构2&#xff1a;改善既有代码的设计这本书&#xff0c;对于代码重构指导非常有帮助&#xff0c;然后也是做个笔记记录下&#xff0c;以下是我阅读本书的前两章的时候整理的思维导图&#xff1a;

The Sandbox 和 Bitkub 联手增强东南亚元宇宙中心

作为去中心化游戏虚拟世界和区块链平台的先驱&#xff0c;The Sandbox 正与泰国领先的区块链网络 Bitkub Blockchain Technology Co., Ltd. 展开创新合作。双方合作的目的是将Bitkub元宇宙的影响力扩展到The Sandbox&#xff0c;建立一个元宇宙中心&#xff0c;向用户承诺从 Bi…

react使用antd警告:Warning: findDOMNode is deprecated in StrictMode.

警告信息&#xff1a; Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of DOMWrap which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: htt…

SerDes系列之CTLE均衡技术

CTLE&#xff08;连续时间线性均衡&#xff09;是一种施加在接收器上的线性模拟高通滤波器&#xff0c;通过衰减低频信号分量&#xff0c;以补偿奈奎斯特频率附近的衰减比例&#xff0c;从而实现信道补偿。当低频信号分量向下衰减并推入底噪范围时&#xff0c;CTLE就会失去调节…

解决Wordpress中Cravatar头像无法访问问题

一、什么是Cravatar Gravatar是WordPress母公司Automattic推出的一个公共头像服务&#xff0c;也是WordPress默认的头像服务。但因为长城防火墙的存在&#xff0c;Gravatar在中国时不时就会被墙一下&#xff0c;比如本次从2021年2月一直到8月都是不可访问状态。 在以往的时候&…

JS 实现鼠标框选(页面选择)时返回对应的 HTML 或文案内容

JS 实现鼠标框选&#xff08;页面选择&#xff09;时返回对应的 HTML 或文案内容 一、需求背景 1、项目需求 当用户进行鼠标框选选择了页面上的内容时&#xff0c;把选择的内容进行上报。 2、需求解析 虽然这需求就一句话的事&#xff0c;但是很显然&#xff0c;没那么简单…

MySQL -- 相关知识点

1.数据库相关介绍 数据库的选择通常取决于具体的应用需求&#xff0c;如性能、扩展性、数据一致性和易用性等因素。 1. 关系型数据库&#xff08;RDBMS&#xff09; MySQL&#xff1a; 广泛使用的开源数据库&#xff0c;支持大多数操作系统。强调易用性、灵活性和广泛的社区支…

代码随想录算法训练营第36期DAY37

DAY37 先二刷昨天的3道题目&#xff0c;每种方法都写&#xff1a;是否已完成&#xff1a;是。 报告&#xff1a;134加油站的朴素法没写对。原因是&#xff1a;在if中缺少了store>0的判断&#xff0c;只给出了indexi的判断。前进法没写出来。因为忘记了总油量的判断。Sum。…

基于Vue的自定义服务说明弹窗组件的设计与实现

基于Vue的自定义服务说明弹窗组件的设计与实现 摘要 随着技术的不断发展&#xff0c;前端开发面临着越来越高的复杂性和不断变化的需求。传统开发方式往往将整个系统构建为整块应用&#xff0c;这导致对系统的任何微小改动都可能触发整体的逻辑变更&#xff0c;从而增加了开发…