当前位置: 首页 > news >正文

【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器

DataStream API编程模型

1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出
2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序


文章目录

  • DataStream API编程模型
  • 前言
  • 1.触发器
    • 1.1 代码示例
  • 2.驱逐器
    • 2.1 代码示例
  • 总结


前言

本小节我想把 窗口计算中 的触发器和驱逐器讲完
然后开始水位线,延迟数据处理,状态编程等。


1.触发器

触发器决定了窗口何时由窗口计算函数进行处理。
(触发器就类比枪的扳机,触发后 计算函数开始计算,计算函数在【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序)

每个窗口分配器都带有一个默认触发器。如果默认触发器不能满足业务需求,就需要自定义触发器。

实现自定义触发器的方法很简单,只需要继承Trigger接口并实现它的方法即可。
Trigger接口有五种方法,允许触发器对不同的事件作出反应,
具体如下:

  1. onElement()方法:每个元素被添加到窗口时调用;
  2. onEventTime()方法:当一个已注册的事件时间计时器启动时调用;
  3. onProcessingTime()方法:当一个已注册的处理时间计时器启动时调用;
  4. onMerge()方法:与状态性触发器相关,当使用会话窗口时,两个触发器对应的窗口合并时,合并两个触发器的状态;
  5. clear()方法:执行任何需要清除的相应窗口。
    在这里插入图片描述

触发器通过 TriggerContext 来管理和检查状态。
在触发器中,我们通常会使用 状态 来记录窗口中的一些信息,如已处理的事件数量或累计的值。这些状态决定了窗口是否应当触发计算。

触发器中的 TriggerResult 有几个重要的结果:

CONTINUE:表示窗口继续等待更多的事件,不触发计算。
FIRE:表示触发窗口计算并输出结果。
PURGE:表示删除某些数据,通常在某些特殊场景下使用。

1.1 代码示例

假设股票价格数据流连续不断到达系统,现在需要对到达的数据进行监控,每到达5条数据就触发计算。实现该功能的代码如下:

import java.util.Calendar
import org.apache.flink.api.common.functions.ReduceFunction
import org.apache.flink.api.common.state.ReducingStateDescriptor
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.source.RichSourceFunction
import org.apache.flink.streaming.api.functions.source.SourceFunction.SourceContext
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.triggers.{Trigger, TriggerResult}
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import scala.util.Randomcase class StockPrice(stockId:String,timeStamp:Long,price:Double)object TriggerTest {def main(args: Array[String]) {//创建执行环境val env = StreamExecutionEnvironment.getExecutionEnvironment//设置程序并行度env.setParallelism(1)//设置为处理时间env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)//创建数据源,股票价格数据流val source = env.socketTextStream("localhost", 9999)//指定针对数据流的转换操作逻辑val stockPriceStream = source.map(s => s.split(",")).map(s=>StockPrice(s(0).toString,s(1).toLong,s(2).toDouble))val sumStream = stockPriceStream.keyBy(s => s.stockId).timeWindow(Time.seconds(50)).trigger(new MyTrigger(5)).reduce((s1, s2) => StockPrice(s1.stockId,s1.timeStamp, s1.price + s2.price))//打印输出sumStream.print()//程序触发执行env.execute("Trigger Test")}class MyTrigger extends Trigger[StockPrice, TimeWindow] {//触发计算的最大数量private var maxCount: Long = _//记录当前数量的状态
private lazy val countStateDescriptor: ReducingStateDescriptor[Long] = new ReducingStateDescriptor[Long]("counter", new Sum, classOf[Long])def this(maxCount: Int) {this()this.maxCount = maxCount      
}override def onProcessingTime(time: Long, window: TimeWindow, ctx: Trigger.TriggerContext): TriggerResult = {TriggerResult.CONTINUE
}override def onEventTime(time: Long, window: TimeWindow, ctx: Trigger.TriggerContext): TriggerResult = {TriggerResult.CONTINUE
} override def onElement(element: StockPrice, timestamp: Long, window: TimeWindow, ctx: Trigger.TriggerContext): TriggerResult = {val countState = ctx.getPartitionedState(countStateDescriptor)//计数状态加1countState.add(1L)      if (countState.get() >= this.maxCount) {//达到指定指定数量       //清空计数状态countState.clear()//触发计算        TriggerResult.FIRE} else {TriggerResult.CONTINUE}}//窗口结束时清空状态override def clear(window: TimeWindow, ctx: Trigger.TriggerContext): Unit = {println("窗口结束时清空状态")ctx.getPartitionedState(countStateDescriptor).clear()}//更新状态为累加值class Sum extends ReduceFunction[Long] {override def reduce(value1: Long, value2: Long): Long = value1 + value2} }
}

注意 这一行代码:

val sumStream = stockPriceStream.keyBy(s => s.stockId).timeWindow(Time.seconds(50)).trigger(new MyTrigger(5)).reduce((s1, s2) => StockPrice(s1.stockId,s1.timeStamp, s1.price + s2.price))

在该代码中,MyTrigger 是一个自定义触发器,它控制在窗口中积累一定数量的事件后触发计算。

具体来说,窗口中的数据会根据 StockPrice 的数量来决定是否触发计算,而不是依赖于时间 。

接下来分析代码,

def this(maxCount: Int) {this()this.maxCount = maxCount      
}

这是它的主构造函数,它接受一个 maxCount 参数,表示在触发器中窗口内允许的最大元素数量。也就是说,窗口中的元素数达到 maxCount 时,触发器会触发计算(即调用 TriggerResult.FIRE)。
.trigger(new MyTrigger(5))表示创建一个 MyTrigger 的实例,并传入一个 maxCount 为 5 的参数,意思是窗口中最大允许 5 个元素,达到该数量后,窗口会触发计算。

private lazy val countStateDescriptor: ReducingStateDescriptor[Long] = new ReducingStateDescriptor[Long]("counter", new Sum, classOf[Long])

lazy:表示这是一个延迟初始化的变量。只有在第一次使用 countStateDescriptor 时,才会初始化它。这在性能优化上有作用,避免了不必要的初始化开销。

ReducingStateDescriptor 是 Flink 提供的一个状态描述符,它用于定义一个可减少的状态。这个状态会随着事件的到来不断累积,并且可以执行自定义的聚合操作。在 ReducingStateDescriptor 中,状态值的更新是通过 ReduceFunction 来实现的。

在这里,ReducingStateDescriptor[Long] 定义了一个状态,它的值是 Long 类型,并且该状态将执行 聚合操作(即对 Long 类型的值进行合并)。

ReducingStateDescriptor 的构造函数接受三个参数:

1.状态名称:“counter”
这是该状态的名称,用于在 Flink 的状态后端存储中标识该状态。

2.聚合操作:new Sum
这是一个 ReduceFunction 的实例,它定义了如何合并状态。在这个例子中,Sum 类是一个自定义的 ReduceFunction,用于对 Long 类型的值进行加法操作。

3.状态类型:classOf[Long]
这是状态的类型。classOf[Long] 表示状态值的类型是 Long,用于在 Flink 的状态管理中描述状态类型。

ClassOf(Long)这是 Scala 反射机制的语法,用于获取 Long 类型的 Class 对象。它在这里用于指定状态值的类型,以便 Flink 的状态管理能够正确地处理状态。

接下来的几个方法**TriggerResult.CONTINUE* 表示继续,不触发计算。
接下来是onElement方法

val countState = ctx.getPartitionedState(countStateDescriptor)

然后计数器+1,加到5就触发。
看是否到达maxcount。到达就触发,不到达就不触发,

自己的疑惑:才开始看代码的时候我一直纠结ctx( ctx.getPartitionedState(countStateDescriptor))这是从哪里来的,这个是

org.apache.flink.streaming.api.windowing.triggers.Trigger

下面的实例化对象,直接使用即可。

代码最后:
Sum类:它的作用是在状态更新时执行对状态的累加操作。

为什么用 Sum 作为累加器?

由于我们在 Trigger 中的 onElement 方法使用了 ctx.getPartitionedState(countStateDescriptor) 来获取一个 ReducingState(累加状态),这个状态将会不断地被更新,每次一个新元素进入时,都会触发 reduce 操作。

Sum 类就是定义了如何对这个 ReducingState 状态进行累加操作。
ReduceFunction 提供了累加器的逻辑,这样当多个元素进来时,value1 和 value2 就会被相加,最终在窗口中保持一个累积的状态。

2.驱逐器

学完上面的,学个单词:Evictor
在这里插入图片描述
驱逐器是Flink窗口机制的一个可选择组件。

驱逐 汉语意思就是 赶走,作用就是对进入窗口前后的数据进行驱逐(就是不接收,不要,你走 )

Flink内部实现了三种驱逐器,包括CountEvictor、DeltaEvictor和TimeEvictor。

三种驱逐器的功能如下:
CountEvictor:保持在窗口中具有固定数量的记录,将超过指定大小的数据在窗口计算之前删除;

DeltaEvictor:使用DeltaFunction和一个阈值,来计算窗口缓冲区中的最后一个元素与其余每个元素之间的差值,并删除差值大于或等于阈值的元素;

TimeEvictor:以毫秒为单位的时间间隔(interval)作为参数,对于给定的窗口,找到元素中的最大的时间戳max_ts,并删除时间戳小于max_ts - interval的所有元素。

在使用窗口函数之前被逐出的元素将不被处理。
默认情况下,所有内置的驱逐器在窗口函数之前使用。

和触发器一样,用户也可以通过实现Evictor接口完成自定义的驱逐器。
自定义驱逐器时,需要复写Evictor接口的两个方法:
evictBefore()和evictAfter()。
其中,evictBefore()方法定义数据在进入窗口函数计算之前执行驱逐操作的逻辑,
evictAfter()方法定义数据在进入窗口函数计算之后执行驱逐操作的逻辑。

2.1 代码示例

这个代码在做的事:统计窗口内股票价的平均值,并删除小于0的记录

import java.time.Duration
import java.util
import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy}
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.windowing.evictors.Evictor
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.streaming.runtime.operators.windowing.TimestampedValue
import org.apache.flink.util.Collectorcase class StockPrice(stockId:String,timeStamp:Long,price:Double)
object EvictorTest {def main(args: Array[String]) {//设置执行环境val env = StreamExecutionEnvironment.getExecutionEnvironment//设置程序并行度env.setParallelism(1)//设置为处理时间env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)//创建数据源,股票价格数据流val source = env.socketTextStream("localhost", 9999)//指定针对数据流的转换操作逻辑val stockPriceStream = source.map(s => s.split(",")).map(s=>StockPrice(s(0).toString,s(1).toLong,s(2).toDouble))val sumStream = stockPriceStream.assignTimestampsAndWatermarks(WatermarkStrategy//为了测试方便,这里把水位线设置为0.forBoundedOutOfOrderness[StockPrice](Duration.ofSeconds(0)).withTimestampAssigner(new SerializableTimestampAssigner[StockPrice] {override def extractTimestamp(element: StockPrice, recordTimestamp: Long): Long = element.timeStamp})).keyBy(s => s.stockId).timeWindow(Time.seconds(3)).evictor(new MyEvictor()) //自定义驱逐器.process(new MyProcessWindowFunction())  //自定义窗口计算函数//打印输出sumStream.print() //程序触发执行 env.execute("Evictor Test")}class MyEvictor() extends Evictor[StockPrice, TimeWindow] {override def evictBefore(iterable: java.lang.Iterable[TimestampedValue[StockPrice]], i: Int, w: TimeWindow, evictorContext: Evictor.EvictorContext): Unit = {val ite: util.Iterator[TimestampedValue[StockPrice]] = iterable.iterator()while (ite.hasNext) {val elment: TimestampedValue[StockPrice] = ite.next()println("驱逐器获取到的股票价格:" + elment.getValue().price)//模拟去掉非法参数数据if (elment.getValue().price <= 0) {println("股票价格小于0,删除该记录")ite.remove()}}} 
override def evictAfter(iterable: java.lang.Iterable[TimestampedValue[StockPrice]], i: Int, w: TimeWindow, evictorContext: Evictor.EvictorContext): Unit = {
//不做任何操作}}class MyProcessWindowFunction extends ProcessWindowFunction[StockPrice, (String, Double), String, TimeWindow] {// 一个窗口结束的时候调用一次(一个分组执行一次),不适合大量数据,全量数据保存在内存中,会造成内存溢出override def process(key: String, context: Context, elements: Iterable[StockPrice], out: Collector[(String, Double)]): Unit = {// 聚合,注意:整个窗口的数据保存到Iterable,里面有很多行数据var sumPrice = 0.0;elements.foreach(stock => {sumPrice = sumPrice + stock.price})out.collect(key, sumPrice/elements.size)}}
}

myEvictor 是我们自定义的驱逐器类,它实现了 Evictor[StockPrice, TimeWindow] 接口.
在Evictor类中定义了before和after两个方法。
这着重看before,after没做什么。

override def evictBefore(iterable: java.lang.Iterable[TimestampedValue[StockPrice]], i: Int, w: TimeWindow, evictorContext: Evictor.EvictorContext): Unit = {val ite: util.Iterator[TimestampedValue[StockPrice]] = iterable.iterator()while (ite.hasNext) {val elment: TimestampedValue[StockPrice] = ite.next()println("驱逐器获取到的股票价格:" + elment.getValue().price)if (elment.getValue().price <= 0) {println("股票价格小于0,删除该记录")ite.remove()}}

参数的迭代器里,每个元素都是TimestampedValue[StockPrice]。
i表示要处理的数据量。
evictorContext:这是 Evictor.EvictorContext 类型,它提供了访问驱逐器上下文的接口。在此方法中并未使用,通常它可以用于管理驱逐操作的状态或者提供更多的上下文信息。
while里面的代码就不解释啦。

这里的参数太长,且陌生,多解释一下。
在窗口中运行输入

stock_1,1602031567000,8
stock_1,1602031568000,-4
stock_1,1602031569000,3
stock_1,1602031570000,-8
stock_1,1602031571000,9
stock_1,1602031572000,10

输出后的结果是:

驱逐器获取到的股票价格:8.0
驱逐器获取到的股票价格:-4.0
股票价格小于0,删除该记录
(stock_1,8.0)
驱逐器获取到的股票价格:3.0
驱逐器获取到的股票价格:-8.0
股票价格小于0,删除该记录
驱逐器获取到的股票价格:9.0
(stock_1,6.0)
驱逐器获取到的股票价格:10.0
(stock_1,10.0)

驱逐器会在每个窗口开始时检查所有输入的事件,并对那些满足特定条件的事件(在本例中,股票价格 <= 0)进行处理并移除。

stock_1, 1602031567000, 8 — 股票价格大于0,保留。
stock_1, 1602031568000, -4 — 股票价格小于0,驱逐。
stock_1, 1602031569000, 3 — 股票价格大于0,保留。
stock_1, 1602031570000, -8 — 股票价格小于0,驱逐。
stock_1, 1602031571000, 9 — 股票价格大于0,保留。
stock_1, 1602031572000, 10 — 股票价格大于0,保留。
驱逐器输出的处理结果:
窗口 1(时间区间:1602031567000 - 1602031570000,窗口大小 3秒):

该窗口内剩下的有效记录:stock_1, 1602031567000, 8 和 stock_1, 1602031569000, 3(-4 和 -8 被驱逐)。
计算平均价格:(8 + 3) / 2 = 5.5
输出: (stock_1, 8.0)(按窗口内第一个事件的 stockId 输出)
窗口 2(时间区间:1602031569000 - 1602031572000,窗口大小 3秒):

该窗口内剩下的有效记录:stock_1, 1602031569000, 3 和 stock_1, 1602031571000, 9(-8 被驱逐)。
计算平均价格:(3 + 9) / 2 = 6.0
输出: (stock_1, 6.0)(按窗口内第一个事件的 stockId 输出)
窗口 3(时间区间:1602031571000 - 1602031574000,窗口大小 3秒):

该窗口内剩下的有效记录:stock_1, 1602031571000, 9 和 stock_1, 1602031572000, 10。
计算平均价格:(9 + 10) / 2 = 9.5
输出: (stock_1, 10.0)(按窗口内第一个事件的 stockId 输出)

输出后的结果是:

驱逐器获取到的股票价格:8.0
驱逐器获取到的股票价格:-4.0
股票价格小于0,删除该记录
(stock_1,8.0)
驱逐器获取到的股票价格:3.0
驱逐器获取到的股票价格:-8.0
股票价格小于0,删除该记录
驱逐器获取到的股票价格:9.0
(stock_1,6.0)
驱逐器获取到的股票价格:10.0
(stock_1,10.0)

总结

以上就是今天要讲的内容,触发器和驱逐器。下一小节应该讲水位线啦。

相关文章:

【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器

DataStream API编程模型 1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出 2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 文章目录 DataStream API编程模型前言1.触发器1.1 代码示例 2.驱逐器2.1 代码示例 总结 前言 本小节我想…...

毕昇入门学习

schemas.py 概述 这段代码主要定义了一系列基于 Pydantic 的数据模型&#xff08;BaseModel&#xff09;&#xff0c;用于数据验证和序列化&#xff0c;通常用于构建 API&#xff08;如使用 FastAPI&#xff09;。这些模型涵盖了用户认证、聊天消息、知识库管理、模型配置等多…...

实时数据开发|Flink实现数据输出--DataSinks操作

哇哦&#xff0c;又是快乐周五&#xff01;今天主管又又又请我们喝奶茶了&#xff0c;是乐乐茶的草莓新品。甜甜的草莓配上糯叽叽的麻薯&#xff0c;喝完好满足。这应该不是什么加班信号吧哈哈哈&#xff0c;不加不加周五要回家。 前几天被不同的bug缠身&#xff0c;今天终于正…...

详解网络代理模式:规则、全局与直连的应用与配置

“详解网络代理模式&#xff1a;规则、全局与直连的应用与配置” 当然&#xff0c;为了提供更深入的理解&#xff0c;让我们对每种代理模式进行更详尽的探讨&#xff0c;包括它们的内部工作机制、具体使用场景以及在实际应用中的优势和局限。 规则模式&#xff08;Rule-based…...

Nacos部署和使用(服务注册与发现、配置中心)

1. docker部署nacos 参考&#xff1a; docker安装nacos-CSDN博客 2.注册中心原理 在微服务远程调用的过程中&#xff0c;包括两个角色&#xff1a; 服务提供者&#xff1a;提供接口供其它微服务访问&#xff0c;比如 A-service服务消费者&#xff1a;调用其它微服务提供的…...

医学机器学习:数据预处理、超参数调优与模型比较的实用分析

摘要 本文介绍了医学中的机器学习&#xff0c;重点阐述了数据预处理、超参数调优和模型比较的技术。在数据预处理方面&#xff0c;包括数据收集与整理、处理缺失值、特征工程等内容&#xff0c;以确保数据质量和可用性。超参数调优对模型性能至关重要&#xff0c;介绍了多种调…...

【大数据学习 | Spark-SQL】关于RDD、DataFrame、Dataset对象

1. 概念&#xff1a; RDD&#xff1a; 弹性分布式数据集&#xff1b; DataFrame&#xff1a; DataFrame是一种以RDD为基础的分布式数据集&#xff0c;类似于传统数据库中的二维表格。带有schema元信息&#xff0c;即DataFrame所表示的二维表数据集的每一列都带有名称和类型…...

流媒体中ES流、PS流 、TS流怎么理解

在流媒体的领域中&#xff0c;ES流、PS流和TS流是视频和音频数据的不同封装格式。它们通常用于传输、存储和播放多媒体内容。让我们分别了解一下它们的定义和用途。 1. ES流&#xff08;Elementary Stream&#xff09; ES流&#xff08;基本流&#xff09;是最基本的视频或音…...

阿里云ECS服务器磁盘空间不足的几个文件

查看磁盘空间命令&#xff1a; df -h /mnt 清零 echo >nohup.out 磁盘空间不足的文件列表&#xff1a; 一、nohup.out&#xff1a;来自"nohup java -jar service.jar &"命令产生的文件&#xff0c;位置在服务jar所在目录 二、access.log&#xff1a;位于…...

pip 安装指定镜像源

pip 安装指定镜像源 使用 pip 安装时&#xff0c;可以通过指定镜像源来加速安装速度&#xff0c;尤其在网络状况不佳或需要访问国内镜像源的情况下。 常见的国内镜像源 清华大学: https://pypi.tuna.tsinghua.edu.cn/simple 阿里云: https://mirrors.aliyun.com/pypi/simple …...

java全栈day10--后端Web基础(基础知识)

引言&#xff1a;只要能通过浏览器访问的网站全是B/S架构&#xff0c;其中最常用的服务器就是Tomcat 在浏览器与服务器交互的时候采用的协议是HTTP协议 一、Tomcat服务器 1.1介绍 官网地址&#xff1a;Apache Tomcat - Welcome! 1.2基本使用(网上有安装教程&#xff0c;建议…...

GPT(Generative Pre-trained Transformer) 和 Transformer的比较

GPT&#xff08;Generative Pre-trained Transformer&#xff09; 和 Transformer 的比较 flyfish 1. Transformer 是一种模型架构 Transformer 是一种通用的神经网络架构&#xff0c;由 Vaswani 等人在论文 “Attention Is All You Need”&#xff08;2017&#xff09;中提…...

大数据营销

大数据营销是一个热门的大数据应用。对于多数企业而言&#xff0c;大数据营销的主要价值源于以下几个方面。 市场预测与决策分析支持 数据对市场预测及决策分析的支持&#xff0c;早就在数据分析与数据挖掘盛行的年代被提出过。沃尔玛著名的“啤酒与尿布”案例就是那个时候的杰…...

数据字典的实现与应用 —— 提高系统灵活性与维护效率的关键

目录 前言1. 数据字典的基本概念1.1 什么是数据字典1.2 数据字典的主要特点 2. 数据字典的优势2.1 提高代码复用性2.2 提升系统的灵活性2.3 方便非技术人员管理2.4 减少错误概率 3. 数据字典在若依中的实现3.1 若依框架简介3.2 数据字典的结构设计 4. 若依框架中数据字典的配置…...

Scrapy管道设置和数据保存

1.1 介绍部分&#xff1a; 文字提到常用的Web框架有Django和Flask&#xff0c;接下来将学习一个全球范围内流行的爬虫框架Scrapy。 1.2 内容部分&#xff1a; Scrapy的概念、作用和工作流程 Scrapy的入门使用 Scrapy构造并发送请求 Scrapy模拟登陆 Scrapy管道的使用 Scrapy中…...

Jenkins的使用

文章目录 一、Jenkins是什么\有什么用\与GitLab的对比二、Jenkins的安装与配置Jenkins的安装方式在Linux上安装Jenkins&#xff1a;在Windows上安装Jenkins&#xff1a;配置Jenkins&#xff1a; &#xff08;可选&#xff09;配置启动用户为root&#xff08;一定要是root吗??…...

计算机基础 原码反码补码问题

整数的二进制的表示形式&#xff1a;其实有三种 原码&#xff1a;直接根据数值写出的二进制序列就是原码 反码&#xff1a;原码的符号位不变&#xff0c;其他位按位取反就是反码 补码&#xff1a;反码1&#xff0c;就是补码 负数&#xff1a;-1 以补码形式存放在内存 写出 -1…...

ORB-SLAM2 ----- LocalMapping::SearchInNeighbors()

文章目录 一、函数意义二、函数讲解三、函数代码四、本函数使用的匹配方法ORBmatcher::Fuse()1. 函数讲解2. 函数代码 四、总结 一、函数意义 本函数是用于地图点融合的函数&#xff0c;前面的函数生成了新的地图点&#xff0c;但这些地图点可能在前面的关键帧中已经生成过了&a…...

游戏引擎学习第27天

仓库:https://gitee.com/mrxiao_com/2d_game 欢迎 项目的开始是从零开始构建一款完整的游戏&#xff0c;完全不依赖任何库或引擎。这样做有两个主要原因&#xff1a;首先&#xff0c;因为这非常有趣&#xff1b;其次&#xff0c;因为它非常具有教育意义。了解游戏开发的低层次…...

【超全总结】深度学习分割模型的损失函数类别及应用场景

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

基于HTML和CSS的校园网页设计与实现

摘要 随着计算机、互联网与通信技术的进步&#xff0c;Internet在人们的学习、工作和生活中的地位也变得越来越高&#xff0c;校园网站已经成为学校与学生&#xff0c;学生与学生之间交流沟通的重要平台&#xff0c;对同学了解学校内发生的各种事情起到了重要的作用。学校网站…...

深度学习基础02_损失函数BP算法(上)

目录 一、损失函数 1、线性回归损失函数 1.MAE损失 2.MSE损失 3.SmoothL1Loss 2、多分类损失函数--CrossEntropyLoss 3、二分类损失函数--BCELoss 4、总结 二、BP算法 1、前向传播 1.输入层(Input Layer)到隐藏层(Hidden Layer) 2.隐藏层(Hidden Layer)到输出层(Ou…...

Flutter:列表分页,上拉加载下拉刷新,在GetBuilder模板使用方式

GetBuilder模板使用方式参考上一节 本篇主要代码记录如何使用上拉加载下拉刷新&#xff0c; 接口请求和商品组件的代码不包括在内 pubspec.yaml装包 cupertino_icons: ^1.0.8# 分页 上拉加载&#xff0c;下拉刷新pull_to_refresh_flutter3: 2.0.2商品列表&#xff1a;controlle…...

使用eclipse构建SpringBoot项目

我这里用eclipse2018版本做演示&#xff0c;大家有需要的可以下载Eclipse Downloads | The Eclipse Foundation 1.打开eclipse&#xff0c;选择存放代码的位置 2.选择 file >> new >> project >> 选择springboot文件下的 spring starter project 2.这里选择N…...

Linux系统存储挂载与管理:从基础到高级

标题&#xff1a;Linux系统存储挂载与管理&#xff1a;从基础到高级 摘要 在Linux系统中&#xff0c;合理的存储管理和分配对于系统的性能、稳定性和资源利用至关重要。本文将详细介绍存储挂载的基本概念、如何进行存储分配和管理&#xff0c;并解释系统盘的作用。通过这些内…...

Flutter 权限申请

这篇文章是基于permission_handler 10.2.0版本写的 前言 在App开发过程中我们经常要用到各种权限&#xff0c;我是用的是permission_handler包来实现权限控制的。 pub地址&#xff1a;https://pub.dev/packages/permission_handler permission_handler 权限列表 变量 Androi…...

Linux之信号的产生,保存,捕捉

Linux之信号的产生&#xff0c;保存&#xff0c;捕捉处理 一.信号的概念1.1概念1.2分类 二.信号的产生2.1通过键盘产生的信号2.2系统调用接口产生的信号2.3硬件异常产生的信号2.4软件条件产生的信号 三.信号的保存四.信号的捕捉五.信号的其他杂碎知识5.1可重入函数5.2volatile关…...

基于AutoEncode自编码器的端到端无线通信系统matlab误码率仿真

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要 自编码器是…...

泛化调用 :在没有接口的情况下进行RPC调用

什么是泛化调用&#xff1f; 在RPC调用的过程中&#xff0c;调用端向服务端发起请求&#xff0c;首先要通过动态代理&#xff0c;动态代理可以屏蔽RPC处理流程&#xff0c;使得发起远程调用就像调用本地一样。 RPC调用本质&#xff1a;调用端向服务端发送一条请求消息&#x…...

2025年人工智能,自动化与机械工程国际学术会议(AIAME2025)

早鸟通道开启&#xff1a; 2025年人工智能&#xff0c;自动化与机械工程国际学术会议&#xff08;AIAME2025&#xff09; 2025 International Conference on Artificial Intelligence, Automation, and Mechanical Engineering 【重要日期】 早鸟征稿截止日期&#xff1a;…...

docker compose 快速搭建Nacos单节点测试环境(mysql 版)

〓 参考&#xff1a; https://nacos.io/docs/latest/quickstart/quick-start-docker/?sourcewuyi https://github.com/nacos-group/nacos-docker https://nacos.io/docs/latest/manual/admin/deployment/deployment-standalone/?sourcewuyi https://nacos.io/docs/latest/man…...

数字3D虚拟展厅成熟运用于旅游业

在数字空间展览会与VR3D虚拟企业展厅设计的兴起中&#xff0c;我们迎来了互联网、物联网与3D技术融合的大时代。这些企业虚拟展厅主要依托互联网作为传播媒介&#xff0c;利用图片、文字和Flash动画等形式&#xff0c;生动展现企业的核心产品。作为一种新型的网络信息技术展厅&…...

模数转换芯片AD9215

AD9215 是 Analog Devices 公司推出的一款高性能、低功耗、单通道 10 位模数转换器(ADC)。它具有采样速率高达 65 MSPS 或 105 MSPS(不同型号),并广泛应用于通信、成像和仪器仪表等领域。 AD9215 的关键特性 分辨率: 10 位,适合高精度应用。采样速率: 两种型号: AD921…...

MongoDB注入攻击测试与防御技术深度解析

MongoDB注入攻击测试与防御技术深度解析 随着NoSQL数据库的兴起&#xff0c;MongoDB作为其中的佼佼者&#xff0c;因其灵活的数据模型和强大的查询能力&#xff0c;受到了众多开发者的青睐。然而&#xff0c;与任何技术一样&#xff0c;MongoDB也面临着安全威胁&#xff0c;其…...

总结贴:Servlet过滤器、MVC拦截器

一:Servlet过滤器 1.1解析 Filter 即为过滤&#xff0c;用于请求到达Servlet之前(Request),以及再Servlet方法执行完之后返回客户端进行后处理(HttpServletResponse)。简单说就是对请求进行预处理&#xff0c;对响应进行后处理 在请求到达Servlet之前,可以经过多个Filt…...

鸿蒙开发-在ArkTS中制作音乐播放器

音频播放功能实现 导入音频播放相关模块 首先需要从ohos.multimedia.audio模块中导入必要的类和接口用于音频播放。例如&#xff1a; import audio from ohos.multimedia.audio;创建音频播放器实例并设置播放源 可以通过audio.createAudioPlayer()方法创建一个音频播放器实…...

mapstruct DTO转换使用

定义一个基础接口 package com.example.mapstruct;import org.mapstruct.Named;import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Date; import java.util.List;/*** Author zmn Dat…...

C++内存对齐

一、内存对齐的定义 内存对齐是一种计算机内存管理策略。在这种策略下&#xff0c;数据存储的内存地址必须是数据类型大小&#xff08;或者是某个特定对齐模数&#xff09;的整数倍。 例如&#xff0c;在一个 32 位系统中&#xff0c;如果一个int类型&#xff08;通常占用 4 …...

关于node全栈项目打包发布linux项目问题总集

1.用pm2部署nest 说明&#xff1a;如果一开始将nest直接打包放到linux服务器上用pm2执行则会报错&#xff0c;这是因为tsconfig.build.tsbuildinfo文件的路径以及相关依赖问题。 报错会为&#xff1a;什么东西找不到.... 所以建议以下为步骤一步一步配置 将整个nest添加压缩包直…...

40 基于单片机的温湿度检测判断系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;采用dht11温湿度传感器检测温湿度&#xff0c; 通过lcd1602显示屏各个参数&#xff0c;四个按键分别可以增加温湿度的阈值&#xff0c; 如果超过阈值&#xff0c;则…...

Vue 原理详解

Vue 原理详解 Vue.js 是一个渐进式框架&#xff0c;它通过数据驱动视图更新和响应式编程使得前端开发变得更加简单高效。在 Vue 的内部实现中&#xff0c;编译过程和响应式机制是两个至关重要的组成部分。本文将详细介绍 Vue.js 的编译器、响应式系统和运行时的工作原理&#…...

w064基于springboot的高校学科竞赛平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0…...

vue实现弹窗输入验证码

实现思路&#xff1a;前端输入完账号和密码&#xff0c;点击登录按钮的时候&#xff0c;弹出一个输入验证码的窗口&#xff0c;后端把验证码图片通过base64的字符传给前端&#xff0c;前端把字符当成图片展示出来。输入完验证码&#xff0c;点击确认进行登录&#xff0c;把验证…...

maven,java相关调试等

maven 增加调试信息的命令&#xff1a; mvn clean compile -Xmvn -X clean installmvn -e exec:execmodule jdk.compiler does not “opens com.sun.tools.java c.processing” 报错是因为用了JDK17&#xff0c;而老版本的1.18.4不支持。将lombok升级到1.18.32问题解决。 报错…...

ARP欺骗-断网攻击

ARP协议 arp协议(地址解析) &#xff0c;在局域网中传输的是帧&#xff0c;帧里面有目标主机的MAC地址&#xff0c;其中一台电脑和另一台电脑需要知道对面的ip地址所对应的MAC地址 ARP欺骗的原理 把自己的MAC地址伪造成网段来欺骗其他用户 实验环境 kali:192.168.21.128 win…...

鬼谷子的捭阖之道

捭&#xff08;bai&#xff09;是打开&#xff0c;开口说的意思&#xff0c;代表阴阳中的阳面 阖&#xff08;he&#xff09;是关闭&#xff0c;是闭嘴、观察&#xff0c;代表阴阳中的阴面 捭阖就是通过话术来试探对方的实情&#xff0c;用谋略让对方信服&#xff0c;从而推动…...

mysql之找回忘记的root密码

mysql之找回忘记的root密码 1.方法1&#xff0c;init-file重置密码2.方法2&#xff0c;–skip-grant-tables重置密码 1.方法1&#xff0c;init-file重置密码 使用init-file参数来对密码进行重新设置 1.停止mysql服务进程 首先将mysql的服务停用掉&#xff1b; 输入命令&#x…...

IDEA中Maven相关使用

一、Maven 的配置文件与本地仓库 Maven 是一种基于配置的工具&#xff0c;主要通过 配置文件 和 本地仓库 管理项目构建与依赖。 1. Maven 配置文件的层级 Maven 的配置文件分为两个层级&#xff1a;全局配置 和 用户配置。 &#xff08;1&#xff09;全局配置 位置&#…...

C语言基础数据类型

C语言------基础数据类型 思考、实践、总结、交流&#xff0c;八字真言是学习任何一门知识的内功&#xff0c;尤其是在很方便用鸡皮提的时代中&#xff0c;独立思考是很重要的。 一个 C 语言工程由多个.c(源码文件) .h&#xff08;头文件&#xff09;组成。.c 文件是实现逻辑的…...

excel中字符数字转换为数值类型:NUMBERVALUE()函数

excel中字符数字转换为数值类型&#xff1a;NUMBERVALUE()函数 例子&#xff1a; 假如这个文档被设置为文档类型&#xff1a;可以通过这个函数进行转换 有时候这个函数不起作用&#xff1a;可以试试对目标列的第一个字符数字进行设置单元单元格-设置为数值型 然后对第一个字…...