Flink-处理函数以及TopN运用案例

news2024/11/30 0:26:32

7 处理函数

7.1 概述

在这里插入图片描述

更底层的操作,直接对流进行操作,直接调用处理函数

7.2 基本处理函数ProcessFunction

  1. 分析
  • ProcessFunction的来源
    在这里插入图片描述

处理函数继承了AbstractRichFunction富函数抽象类,因此就具有访问状态(state)和其他运行时环境

在这里插入图片描述

在这里插入图片描述

例如AbstractRichFunction类中有getRuntimeContext()这个方法返回的是RuntimeContext类

  • 内部分析

在这里插入图片描述
在这里插入图片描述

里面有个抽象方法processElements()处理元素,参数分别是:输入,上下文,用于输出的collector

以及onTimer()方法类似一个触发回调机制,主要用于定时器的回调,就是TimerService使用registerProcessingTimeTime()注册定时器[详见下面,有写],仅仅是这次,如果需要调用,那么调用就是onTimer()方法调用,但是仅仅限于keyby后的KeyedStream的定时器操作

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

上下文Context就有可以获取时间戳timestamp(),可以做测输出流output(),以及TimerService接口中有获取处理时间currentProcessingTime()的方法以及获取时间/水位线时间的currentWatermark()方法,以及注册定时器的registerProcessingTimeTime()的方法这边有问题

  • 关系图

在这里插入图片描述

  1. 使用
stream.process(new MyProcessFunction())
  1. 分类
  • 初步分析

在这里插入图片描述

stream.keyBy得到KeyedStream后调用.process函数,传进去的就是KeyedProcessFunction

在这里插入图片描述

ProcessFuntion只是一个,还有KeyedProcessFunction,两者没有继承关系,两者都继承了AbstractRichFunction富函数抽象类

在这里插入图片描述

stream.keyBy()
    .window()
    .process()

亦或者stream.keyBy得到KeyedStream后调用window方法,得到WindowedStream,再调用.process方法,此时传入的就是ProcessWindowFunction函数

  • 分类

Flink 提供了 8 个不同的处理函数:

(1)ProcessFunction 最基本的处理函数,基于 DataStream 直接调用.process()时作为参数传入。

(2)KeyedProcessFunction 对流按键分区后的处理函数,基于 KeyedStream 调用.process()时作为参数传入。要想使用 定时器,比如基于 KeyedStream。

(3)ProcessWindowFunction 开窗之后的处理函数,也是全窗口函数的代表。基于 WindowedStream 调用.process()时作 为参数传入。

(4)ProcessAllWindowFunction 同样是开窗之后的处理函数,基于 AllWindowedStream 调用.process()时作为参数传入。

(5)CoProcessFunction 188 合并(connect)两条流之后的处理函数,基于 ConnectedStreams 调用.process()时作为参 数传入。关于流的连接合并操作,我们会在后续章节详细介绍。

(6)ProcessJoinFunction 间隔连接(interval join)两条流之后的处理函数,基于 IntervalJoined 调用.process()时作为 参数传入。 (7)BroadcastProcessFunction 广播连接流处理函数,基于 BroadcastConnectedStream 调用.process()时作为参数传入。这 里的“广播连接流”BroadcastConnectedStream,是一个未 keyBy 的普通 DataStream 与一个广 播流(BroadcastStream)做连接(conncet)之后的产物。关于广播流的相关操作,我们会在后 续章节详细介绍。

(8)KeyedBroadcastProcessFunction 按键分区的广播连接流处理函数,同样是基于 BroadcastConnectedStream 调用.process()时 作为参数传入。与 BroadcastProcessFunction 不同的是,这时的广播连接流,是一个 KeyedStream 与广播流(BroadcastStream)做连接之后的产物。

  1. 代码
public class ProcessFunctionTest {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        SingleOutputStreamOperator<Event> stream = env.addSource(new ClickSource())
                .assignTimestampsAndWatermarks(WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ZERO)
                        .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
                            @Override
                            public long extractTimestamp(Event element, long recordTimestamp) {
                                return element.timestamp;
                            }
                        })

                );

        stream.process(new ProcessFunction<Event, String>() {
            @Override
            //onTimer()方法不一定实现了,参数输入,上下文,输出
            public void processElement(Event value, Context ctx, Collector<String> out) throws Exception {
                if(value.user.equals("Mary")){
                    out.collect(value.user+"clicks"+value.url);
                }else if(value.user.equals("Bob")){
                    //可以输出多条
                    out.collect(value.user);
                    out.collect(value.user);
                }
                out.collect(value.toString());

                //通过上下文获取当前的timestamp
                System.out.println("timestamp"+ctx.timestamp());
                System.out.println("watermark"+ctx.timerService().currentWatermark());

                //使用富函数
                System.out.println(getRuntimeContext().getIndexOfThisSubtask());
                //getRuntimeContext().getState()获取状态
            }
        }).print();
        env.execute();
    }
}

输出

Bob
Bob
Event{user='Bob', url='./prod?id=100', timestamp=2022-11-23 21:56:12.444}
timestamp1669211772444
watermark-9223372036854775808
0
Event{user='Alice', url='./home', timestamp=2022-11-23 21:56:13.46}
timestamp1669211773460
watermark1669211772443
0
Maryclicks./cart
Event{user='Mary', url='./cart', timestamp=2022-11-23 21:56:14.474}
timestamp1669211774474
watermark1669211773459
0
Event{user='Alice', url='./fav', timestamp=2022-11-23 21:56:15.487}
timestamp1669211775487
watermark1669211774473
0

7.3 按键分区处理函数(KeyedProcessFunction)

7.3.1 概述

主要有以下几个方法

在这里插入图片描述

7.3.2 使用

stream.keyBy(t->t.f0)
      .process(new MyKeyedProcessFunction())
  1. 处理时间定时器
  • 代码
public class ProcessingTimeTimerTest {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        DataStreamSource<Event> stream = env.addSource(new ClickSource());
        stream.keyBy(data -> data.user)
                        //参数是<K, I, O>
                        .process(new KeyedProcessFunction<String, Event, String>() {

                            @Override
                            public void processElement(Event value, Context ctx, Collector<String> out) {
                                Long currTs = ctx.timerService().currentProcessingTime();//获取系统时间
                                out.collect(ctx.getCurrentKey()+ "数据到达,到达时间:"+new Timestamp(currTs));

                                //注册一个10秒后的定时器,传入的是毫秒数
                                ctx.timerService().registerProcessingTimeTimer(currTs+10*1000L);
                            }

                            @Override
                            //参数:定时器时间,OnTimerContext继承Context,
                            public void onTimer(long timestamp,OnTimerContext ctx, Collector<String> out) throws Exception {
                                out.collect(ctx.getCurrentKey()+"定时器触发,触发时间:"+new Timestamp(timestamp));
                            }
                        }).print();
        env.execute();
    }
}
  • 结果
  1. 事件时间定时器
  • 代码
public class EventTimeTimerTest {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        SingleOutputStreamOperator<Event> stream = env.addSource(new ClickSource())
                .assignTimestampsAndWatermarks(WatermarkStrategy.<Event>forMonotonousTimestamps()
                        .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
                            @Override
                            public long extractTimestamp(Event element, long recordTimestamp) {
                                return element.timestamp;
                            }
                        }));

        stream.keyBy(data -> data.user)
                //参数是<K, I, O>
                .process(new KeyedProcessFunction<String, Event, String>() {

                    @Override
                    public void processElement(Event value, Context ctx, Collector<String> out) throws Exception {
                        Long currTs = ctx.timestamp();//获取事件时间,直接掉ctx的timestamp(),不掉service中的了
                        out.collect(ctx.getCurrentKey()+ "数据到达,时间戳:"+new Timestamp(currTs)+"watermark:"+ctx.timerService().currentWatermark());

                        //注册一个10秒后的定时器,传入的是毫秒数
                        ctx.timerService().registerEventTimeTimer(currTs+10*1000L);
                    }

                    @Override
                    //参数:定时器时间,OnTimerContext继承Context,
                    public void onTimer(long timestamp,OnTimerContext ctx, Collector<String> out) throws Exception {
                        out.collect(ctx.getCurrentKey()+"定时器触发,触发时间:"+new Timestamp(timestamp)+ctx.timerService().currentWatermark());
                    }
                }).print();
        env.execute();
    }
}
  • 结果

在这里插入图片描述

在这里插入图片描述

结果分析

  • 时间戳带来watermark数据的改变,当定时器2021-08-20 16:50:23.427触发的时候定时器才到22秒512,因此定时器在16:50:23,524之后,触发在水位线之后

  • 代码

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

        SingleOutputStreamOperator<Event> stream = env.addSource(new CustomSource())
                .assignTimestampsAndWatermarks(WatermarkStrategy.<Event>forMonotonousTimestamps()
                        .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
                            @Override
                            public long extractTimestamp(Event element, long recordTimestamp) {
                                return element.timestamp;
                            }
                        }));

        stream.keyBy(data -> data.user)
                //参数是<K, I, O>
                .process(new KeyedProcessFunction<String, Event, String>() {

                    @Override
                    public void processElement(Event value, Context ctx, Collector<String> out) throws Exception {
                        Long currTs = ctx.timestamp();//获取事件时间,直接掉ctx的timestamp(),不掉service中的了
                        out.collect(ctx.getCurrentKey()+ "数据到达,时间戳:"+new Timestamp(currTs)+"watermark:"+ctx.timerService().currentWatermark());

                        //注册一个10秒后的定时器,传入的是毫秒数
                        ctx.timerService().registerEventTimeTimer(currTs+10*1000L);
                    }

                    @Override
                    //参数:定时器时间,OnTimerContext继承Context,
                    public void onTimer(long timestamp,OnTimerContext ctx, Collector<String> out) throws Exception {
                        out.collect(ctx.getCurrentKey()+"定时器触发,触发时间:"+new Timestamp(timestamp)+ctx.timerService().currentWatermark());
                    }
                }).print();
        env.execute();
    }

    //自定义测试数据源
    public static class CustomSource implements SourceFunction<Event>{
        @Override
        public void run(SourceContext<Event> ctx) throws Exception {
            //直接发出测试数据
            ctx.collect(new Event("Mary","./homne",1000L));

            Thread.sleep(5000L);

            ctx.collect(new Event( "Alice","./homne",11000L));
            Thread.sleep(5000L);
        }

        @Override
        public void cancel() {

        }
    }
}
  • 结果
Mary数据到达,时间戳:1970-01-01 08:00:01.0watermark:-9223372036854775808
Alice数据到达,时间戳:1970-01-01 08:00:11.0watermark:999
Mary定时器触发,触发时间:1970-01-01 08:00:11.09223372036854775807
Alice定时器触发,触发时间:1970-01-01 08:00:21.09223372036854775807

结果分析

如果输入数据已经结束,数据集处理完毕,那么事件时间语义会把watermark推到最大,因此定时器会被全部触发

7.4 窗口处理函数(ProcessWindowFunction )

  1. 分析

在这里插入图片描述

继承的富函数类

在这里插入图片描述

里面是process方法,参数分别是key,上下文,收集数据的集合,输出

在这里插入图片描述

Context中可以获取窗口,当前处理时间,当前的watermark,以及测输出流,发现跟之前相比没有TimeService,就不能注册定时器,但是可以通过定时器获取

7.5 应用案例-TopN

7.5.1 使用ProcessAllWindowFunction

  1. 场景

例如,需要统计最近10秒内最热门的两个url链接,并且每5秒

  1. 思路
  • 使用全窗口函数ProcessAllWindowFunction开窗处理,使用HashMap来保存每个url的访问次数(通过遍历)
  • 然后转成ArrayList,然后进行排序,取前两名输出即可
  1. 代码
  • 代码
public class TopNExample_ProcessAllWindowFunction {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        //读取数据
        SingleOutputStreamOperator<Event> stream = env.addSource(new ClickSource())
                //乱序种延迟0,相当于-1毫秒而已
                .assignTimestampsAndWatermarks(WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ZERO)
                        .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
                            @Override
                            public long extractTimestamp(Event element, long recordTimestamp) {
                                return element.timestamp;
                            }
                        })
                );
        //直接开窗,收集数据排序
        stream.map(data->data.url)//得到String类型的Stream
                .windowAll(SlidingEventTimeWindows.of(Time.seconds(10),Time.seconds(5)))//直接开窗
                .aggregate(new UrlHashMapCountAgg(),new UrlAllWindowResult())
                .print();

        env.execute();
    }
    //实现自定义的增量聚合函数
    public static class UrlHashMapCountAgg implements AggregateFunction<String, HashMap<String,Long>, ArrayList<Tuple2<String,Long>>> {
        @Override
        public HashMap<String, Long> createAccumulator() {
            return new HashMap<>();
        }

        @Override
        public HashMap<String, Long> add(String value, HashMap<String, Long> accumulator) {
            if(accumulator.containsKey(value)){
                Long count = accumulator.get(value);
                accumulator.put(value,count+1);
            }else {
                accumulator.put(value,1L);
            }
            return accumulator;
        }

        //就HashMap转成ArrayList<Tuple2<String, Long>>的操作
        @Override
        public ArrayList<Tuple2<String, Long>> getResult(HashMap<String, Long> accumulator) {
            ArrayList<Tuple2<String, Long>> result = new ArrayList<>();
            for(String key:accumulator.keySet()){
                result.add(Tuple2.of(key,accumulator.get(key)));
            }
            //排序
            result.sort(new Comparator<Tuple2<String, Long>>() {
                @Override
                //降序,后减前
                public int compare(Tuple2<String, Long> o1, Tuple2<String, Long> o2) {
                    return o2.f1.intValue()-o1.f1.intValue();
                }
            });
            return result;
        }

        @Override
        public HashMap<String, Long> merge(HashMap<String, Long> a, HashMap<String, Long> b) {
            return null;
        }
    }
    //实现自定义全窗口函数,包装信息输出结果
    public static class UrlAllWindowResult extends ProcessAllWindowFunction<ArrayList<Tuple2<String, Long>>, String, TimeWindow> {
        @Override
        public void process(Context context, Iterable<ArrayList<Tuple2<String, Long>>> elements, Collector<String> out) throws Exception {

            //先拿出来
            ArrayList<Tuple2<String, Long>> list = elements.iterator().next();

            StringBuilder result = new StringBuilder();
            result.append("---------------\n");

            //获取窗口信息
            result.append("窗口结束时间:"+new Timestamp(context.window().getEnd())+"\n");

            //取List排过序后的前两个,包装信息输出
            for(int i = 0;i<2;i++){
                Tuple2<String, Long> currTuple = list.get(i);
                String info = "No."+(i+1)+" "
                            +"url:"+currTuple.f0+" "
                            +"访问量"+currTuple.f1+"\n ";
                result.append(info);
            }
            result.append("--------------------\n");

            out.collect(result.toString());

        }
    }
}
  • 结果
窗口结束时间:2022-11-25 21:58:35.0
No.1 url:./fav 访问量1
 No.2 url:./home 访问量1
 --------------------

---------------
窗口结束时间:2022-11-25 21:58:40.0
No.1 url:./home 访问量3
 No.2 url:./prod?id=100 访问量3
 --------------------

---------------
窗口结束时间:2022-11-25 21:58:45.0
No.1 url:./prod?id=100 访问量4
 No.2 url:./cart 访问量2
 --------------------

---------------
窗口结束时间:2022-11-25 21:58:50.0
No.1 url:./prod?id=100 访问量4
 No.2 url:./fav 访问量3
 --------------------
  1. 评价

用这个方法思路易懂,但是使用了windowAll的全窗口函数,stream直接开窗,所有数据收集到窗口中,导致无分区也就是并行度会变成1大数据场景下内存估计会炸掉,OOM警告

7.5.2 使用 KeyedProcessFunction

  1. 场景

例如,需要统计最近10秒内最热门的两个url链接,并且每5秒

  1. 思路
  • 触发

    • 参照窗口的流式处理原理,将数据汇聚一段时间后输出,就可以使用定时器

    • 窗口结束时间+1豪秒使得watermark触发,即数据到齐

  • 收集

    • 定义一个列表把所有数据保存下来
    • 使用状态,根据之前keyby按键分组的状态
  • 输出

    • 排序
    • 输出
  1. 代码

跟上面差不多,多了状态设置,可以理解urlViewCountListState这个就是用来存有状态的数据的

  • 代码
public class TopNExample {
    public static void main(String[] args) throws Exception{
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        //读取数据
        SingleOutputStreamOperator<Event> stream = env.addSource(new ClickSource())
                //乱序种延迟0,相当于-1毫秒而已
                .assignTimestampsAndWatermarks(WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ZERO)
                        .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
                            @Override
                            public long extractTimestamp(Event element, long recordTimestamp) {
                                return element.timestamp;
                            }
                        })
                );
        //1.按照url分组,统计窗口内每个url的访问量
        SingleOutputStreamOperator<UrlViewCount> urlCountStream = stream
                .keyBy(data -> data.url)
                .window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
                .aggregate(new UrlCountViewExample.UrlViewCountAgg(), new UrlCountViewExample.UrlViewCountResult());

        urlCountStream.print("url count");

        //2.对一同一窗口统计出的访问量,进行手机和排序(以聚合过的结果按照窗口间隔不间断流式输出)
        urlCountStream.keyBy(data->data.windowEnd)
                        .process(new TopNProcessResult(2))
                        .print();
        env.execute();


    }
    //实现自定义的KeyProcessFunction
    public static class TopNProcessResult extends KeyedProcessFunction<Long,UrlViewCount,String> {
        //定义一个属性n
        private Integer n;

        //1.定义列表状态
        private ListState<UrlViewCount> urlViewCountListState;

        public TopNProcessResult(Integer n) {
            this.n = n;
        }

        //2.管理状态,在环境中获取状态,使用生命周期方法获取
        @Override
        public void open(Configuration parameters) throws Exception {
            urlViewCountListState= getRuntimeContext().getListState(//传入描述器
                    //两个参数:一个名字,一个类型
                    new ListStateDescriptor<UrlViewCount>("url-count-list", Types.POJO(UrlViewCount.class)));
        }

        @Override
        public void processElement(UrlViewCount value,Context ctx, Collector<String> out) throws Exception {
            //3.将数据保存到状态中
            urlViewCountListState.add(value);
            //4.注册windowEnd+1ms的定时器
            ctx.timerService().registerEventTimeTimer(ctx.getCurrentKey()+1);
        }
        //5.用来触发定时器
        //将状态拿出来,保存成ArrayList
        //输出包装
        @Override
        public void onTimer(long timestamp, OnTimerContext ctx, Collector<String> out) throws Exception {

            ArrayList<UrlViewCount> urlViewCountArrayList = new ArrayList<>();
            for(UrlViewCount urlViewCount:urlViewCountListState.get())//得到OUT是一个iterable类型
                urlViewCountArrayList.add(urlViewCount);

            //排序
            urlViewCountArrayList.sort(new Comparator<UrlViewCount>() {
                @Override
                public int compare(UrlViewCount o1, UrlViewCount o2) {
                   return o2.count.intValue()-o1.count.intValue();
                }
            });


            //6.包装信息打印输出

            StringBuilder result = new StringBuilder();
            result.append("---------------\n");

            //获取窗口信息
            result.append("窗口结束时间:"+new Timestamp(ctx.getCurrentKey())+"\n");

            //包装信息输出
            for(int i = 0;i<2;i++){
                UrlViewCount currTuple = urlViewCountArrayList.get(i);
                String info = "No."+(i+1)+" "
                        +"url:"+currTuple.url+" "
                        +"访问量"+currTuple.count+"\n ";
                result.append(info);
            }
            result.append("--------------------\n");

            out.collect(result.toString());
            
        }
    }
}
  • 结果
url count> UrlViewCount{url='./home', count=1, windowStart=2022-11-25 22:42:30.0, windowEnd=2022-11-25 22:42:40.0}
url count> UrlViewCount{url='./cart', count=2, windowStart=2022-11-25 22:42:30.0, windowEnd=2022-11-25 22:42:40.0}
---------------
窗口结束时间:2022-11-25 22:42:40.0
No.1 url:./cart 访问量2
 No.2 url:./home 访问量1
 --------------------

url count> UrlViewCount{url='./home', count=2, windowStart=2022-11-25 22:42:35.0, windowEnd=2022-11-25 22:42:45.0}
url count> UrlViewCount{url='./prod?id=100', count=2, windowStart=2022-11-25 22:42:35.0, windowEnd=2022-11-25 22:42:45.0}
url count> UrlViewCount{url='./cart', count=4, windowStart=2022-11-25 22:42:35.0, windowEnd=2022-11-25 22:42:45.0}
---------------
窗口结束时间:2022-11-25 22:42:45.0
No.1 url:./cart 访问量4
 No.2 url:./home 访问量2
 --------------------
  • 评价

可以做并行计算

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

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

相关文章

Day39——Dp专题

文章目录01背包二维数组一维数组6.整数拆分7.不同的二叉搜索01背包 01背包&#xff1a;每一个物品只能选一次&#xff0c;选或者不选 状态标识&#xff1a;f[i][j]&#xff1a;所有只考虑前i个物品&#xff0c;且总体积不超j的所有选法的集合 属性&#xff1a;Max 状态计算&a…

链表之反转链表

文章目录链表之反转链表题目描述解题思路代码实现链表之反转链表 力扣链接 题目描述 定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头节点。 示例&#xff1a; ​ 输入: 1->2->3->4->5->NULL ​ 输出: 5->4-&…

如何设计高性能架构

高性能复杂度模型 高性能复杂度分析和设计 单机 集群 任务分配 将任务分配给多个服务器执行 复杂度分析 增加“任务分配器”节点&#xff0c;可以是独立的服务器&#xff0c;也可以是SDK任务分配器需要管理所有的服务器&#xff0c;可以通过配置文件&#xff0c;也可以通过…

RK3588移植-opencv交叉编译aarch64

文章参考&#xff1a;https://blog.csdn.net/KayChanGEEK/article/details/80365320 文章目录概括准备资源交叉编译OPENCV修改CMakelist文件将lib库复制到/lib目录注意&#xff1a;本文中的所有配置相关路径都与当前安装的路径有关&#xff0c;需要根据自己的环境进行自行修改&…

『Java课设』JavaSwing+MySQL实现学生成绩管理系统

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位喜欢写作&#xff0c;计科专业大三菜鸟 &#x1f3e1;个人主页&#xff1a;starry陆离 如果文章有帮到你的话记得点赞&#x1f44d;收藏&#x1f497;支持一下哦 『Java课设』JavaSwingMySQL实现学生成绩管理系统前言1.开…

SparkMlib 之随机森林及其案例

文章目录什么是随机森林&#xff1f;随机森林的优缺点随机森林示例——鸢尾花分类什么是随机森林&#xff1f; 随机森林算法是机器学习、计算机视觉等领域内应用极为广泛的一个算法&#xff0c;它不仅可以用来做分类&#xff0c;也可用来做回归即预测&#xff0c;随机森林机由…

RabbitMQ之可靠性分析

在使用任何消息中间件的过程中&#xff0c;难免会出现消息丢失等异常情况&#xff0c;这个时候就需要有一个良好的机制来跟踪记录消息的过程&#xff08;轨迹溯源&#xff09;&#xff0c;帮助我们排查问题。在RabbitMQ 中可以使用Firehose 功能来实现消息追踪&#xff0c;Fire…

艾美捷MTT细胞增殖检测试剂盒结果示例引用文献

艾美捷MTT细胞增殖检测试剂盒测定原理&#xff1a; 该试剂盒提供了比色形式测量和监测细胞增殖&#xff0c;含有足够的试剂用于评估在96孔板中进行960次测定或在24孔板中进行192次测定。细胞可以被镀&#xff0c;然后用影响增殖的化合物或药剂。然后用增殖试剂检测细胞&#x…

3.矩阵计算及导数基础

1. 梯度 将导数拓展到向量。 1. 标量对向量求导 x是列向量&#xff0c;y是标量&#xff0c;求导之后变成了行向量 ps&#xff1a; x1^2 2x2^2 这个函数可以画成等高线,对于&#xff08;x1&#xff0c;x2&#xff09;这个点&#xff0c;可以做等高线的切线&#xff0c;再做出…

Spark Streaming(二)

声明&#xff1a; 文章中代码及相关语句为自己根据相应理解编写&#xff0c;文章中出现的相关图片为自己实践中的截图和相关技术对应的图片&#xff0c;若有相关异议&#xff0c;请联系删除。感谢。转载请注明出处&#xff0c;感谢。 By luoyepiaoxue2014 B站&#xff…

动态规划算法(2)最长回文子串详解

文章目录最长回文字串动态规划代码示例前篇&#xff1a; &#xff08;1&#xff09;初识动态规划 最长回文字串 传送门&#xff1a; https://leetcode.cn/problems/longest-palindromic-substring/description/ 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 s &qu…

大数据学习:使用Java API操作HDFS

文章目录一、创建Maven项目二、添加依赖三、创建日志属性文件四、在HDFS上创建文件五、写入HDFS文件1、将数据直接写入HDFS文件2、将本地文件写入HDFS文件六、读取HDFS文件1、读取HDFS文件直接在控制台显示2、读取HDFS文件&#xff0c;保存为本地文件一、创建Maven项目 二、添加…

Spring Security 中重要对象汇总

前言 已经写了好几篇关于 Spring Security 的文章了&#xff0c;相信很多读者还是对 Spring Security 的云里雾里的。这是因为对 Spring Security 中的对象还不了解。本文就来介绍介绍一下常用对象。 认证流程 SecurityContextHolder 用户认证通过后&#xff0c;为了避免用…

【JavaWeb】Servlet系列 --- HttpServlet【底层源码分析】

HttpServlet一、什么是协议&#xff1f;什么是HTTP协议&#xff1f;二、HTTP的请求协议&#xff08;B -- > S&#xff09;1. HTTP的请求协议包括4部分&#xff08;记住&#xff09;2. HTTP请求协议的具体报文&#xff1a;GET请求3. HTTP请求协议的具体报文&#xff1a;POST请…

生成式模型和判别式模型

决策函数Yf(x)Y f(x)Yf(x)或者条件概率分布 P(Y∣X)P(Y|X)P(Y∣X) 监督学习的任务都是从数据中学习一个模型&#xff08;也叫做分类器&#xff09;&#xff0c;应用这一模型&#xff0c;对给定的输入xxx预测相应的输出YYY,这个模型的一般形式为:决策函数Yf(x)Y f(x)Yf(x)&…

java 每日一练(6)

java 每日一练(6) 文章目录单选不定项选择题编程题单选 1.关于抽象类与最终类&#xff0c;下列说法错误的是&#xff1f;   A 抽象类能被继承&#xff0c;最终类只能被实例化。   B 抽象类和最终类都可以被声明使用   C 抽象类中可以没有抽象方法&#xff0c;最终类中可以没…

Bean 管理(工厂bean)

IOC操作Bean 管理&#xff08;FactoryBean&#xff09; 下面是在Bean 管理&#xff08;工厂bean&#xff09;之前的学习&#xff0c;基于xml方式注入集合并实现 基于xml方式注入集合并实现 &#xff1a;http://t.csdn.cn/H0ipR Spring 有两种类型bean&#xff0c;一种普通bean…

第五章. 可视化数据分析分析图表—图表的常用设置2

第五章. 可视化数据分析分析图 5.2 图表的常用设置2 本节主要介绍图表的常用设置&#xff0c;设置标题和图例&#xff0c;添加注释文本&#xff0c;调整图表与画布边缘间距以及其他设置。 7.设置标题&#xff08;title&#xff09; 1).语法&#xff1a; matplotlib.pyplot.ti…

iOS15适配 UINavigationBar和UITabBar设置无效,变成黑色

今天更新了xcode13&#xff0c;运行项目发现iOS15以上的手机导航栏和状态栏之前设置的颜色等属性都不起作用了&#xff0c;都变成了黑色&#xff0c;滚动的时候才能变成正常的颜色&#xff0c;经确认得用UINavigationBarAppearance和UITabBarAppearance这两个属性对导航栏和状态…

开发SpringBoot+Jwt+Vue的前后端分离后台管理系统VueAdmin - 前端笔记

一个spring security jwt vue的前后端分离项目&#xff01;综合运用&#xff01; 关注公众号 MarkerHub&#xff0c;回复【 VueAdmin 】可以加群讨论学习、另外还会不定时安排B站视频直播答疑&#xff01; 首发公众号&#xff1a;MarkerHub 作者&#xff1a;吕一明 视频讲解&…