flink的EventTime和Watermark

時間機制

Flink中的時間機制主要用在判斷是否觸發時間窗口window的計算。

在Flink中有三種時間概念:ProcessTime、IngestionTime、EventTime。

ProcessTime:是在數據抵達算子產生的時間(Flink默認使用ProcessTime)

IngestionTime:是在DataSource生成數據產生的時間

EventTime:是數據本身攜帶的時間,具有實際業務含義,不是Flink框架產生的時間

水位機制

由于網絡原因、故障等原因,數據的EventTIme并不是單調遞增的,是亂序的,有時與當前實際時間相差很大。

水位(watermark)用在EventTime語義的窗口計算,可以當作當前計算節點的時間。當水位超過窗口的endtime,表示事件時間t <= T的數據都**已經到達,**這個窗口就會觸發WindowFunction計算。當水位超過窗口的endtime+允許遲到的時間,窗口就會消亡。本質是DataStream中的一種特殊元素,每個水印都攜帶有一個時間戳。

  1. 隊列中是亂序的數據,流入長度3s的窗口。2s的數據進入[0,4)的窗口中
  2. 2s、3s、1s的數據進入[0,4)的窗口,7s的數據分配到[4,8)的窗口中
  3. 水印4s到達,代表4s以前的數據都已經到達。觸發[0,4)的窗口計算,[4,8)的窗口等待數據
  4. 水印9s到達,[4,8)的窗口觸發

多并行情況下,不同的watermark流到算子,取最小的wartermark當作當前算子的watermark。

如果所有流入水印中時間戳最小的那個都已經達到或超過了窗口的結束時間,那么所有流的數據肯定已經全部收齊,就可以安全地觸發窗口計算了。

生成水位

首先設置env為事件時間

使用 DataStream API 實現 Flink 任務時,Watermark Assigner 能靠近 Source 節點就靠近 Source 節點,能前置盡量前置

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);//測試數據,間隔1s發送
DataStreamSource<Tuple2<String, Long>> source = env.addSource(new SourceFunction<Tuple2<String, Long>>() {@Overridepublic void run(SourceContext<Tuple2<String, Long>> ctx) throws Exception {ctx.collect(Tuple2.of("aa", 1681909200000L));//2023-04-19 21:00:00Thread.sleep(1000);ctx.collect(Tuple2.of("aa", 1681909500000L));//2023-04-19 21:05:00Thread.sleep(1000);ctx.collect(Tuple2.of("aa", 1681909800000L));//2023-04-19 21:10:00Thread.sleep(1000);ctx.collect(Tuple2.of("aa", 1681910100000L));//2023-04-19 21:15:00Thread.sleep(1000);ctx.collect(Tuple2.of("aa", 1681910400000L));//2023-04-19 21:20:00Thread.sleep(1000);ctx.collect(Tuple2.of("aa", 1681910700000L));//2023-04-19 21:25:00Thread.sleep(Long.MAX_VALUE);}@Overridepublic void cancel() {}});

抽取EventTime、生成Watermark

周期性水位–AssignerWithPeriodicWatermarks�(常用)

周期性生成水位。周期默認的時間是 200ms.

源碼如下:

@PublicEvolving
public void setStreamTimeCharacteristic(TimeCharacteristic characteristic) {this.timeCharacteristic = Preconditions.checkNotNull(characteristic);if (characteristic == TimeCharacteristic.ProcessingTime) {getConfig().setAutoWatermarkInterval(0);} else {getConfig().setAutoWatermarkInterval(200);}

自定義實現AssignerWithPeriodicWatermarks,代碼如下:

source.assignTimestampsAndWatermarks(new AssignerWithPeriodicWatermarks<Tuple2<String, Long>>() {private long currentTimestamp;@Nullable@Override// 生成watermarkpublic Watermark getCurrentWatermark() {return new Watermark(currentTimestamp);}@Override//獲取事件時間public long extractTimestamp(Tuple2<String, Long> element, long previousElementTimestamp) {if (element.f1>=currentTimestamp){currentTimestamp = element.f1;}return element.f1;}}).keyBy(value -> value.f0).timeWindow(Time.minutes(10)).process(new ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>() {@Overridepublic void process(String key, ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>.Context context, Iterable<Tuple2<String, Long>> elements, Collector<Object> out) throws Exception {System.out.println("----------------");System.out.println("系統當前時間:"+ DateUtil.date());System.out.println("當前水位時間:"+DateUtil.date(context.currentWatermark()));System.out.println("窗口開始時間:"+DateUtil.date(context.window().getStart()));System.out.println("窗口結束時間:"+DateUtil.date(context.window().getEnd()));elements.forEach(element -> System.out.println("數據攜帶時間:"+DateUtil.date(element.f1)));}}).print();

運行結果如下:

水位時間到達2023-04-19 21:10:00觸發窗口2023-04-19 21:00:00到2023-04-19 21:10:00,窗口中的數據為2023-04-19 21:00:00和2023-04-19 21:05:00

水位時間到達2023-04-19 21:20:00觸發窗口2023-04-19 21:10:00到2023-04-19 21:20:00,窗口中的數據為2023-04-19 21:10:00和2023-04-19 21:15:00

長時間等待后,2023-04-19 21:20:00到2023-04-19 21:30:00是存在一個2023-04-19 21:25:00的數據,一直沒有觸發。這是因為沒有新的數據進入,周期性生成的watermark一直是2023-04-19 21:20:00。所以后面窗口即使有數據也沒有觸發計算。

BoundedOutOfOrdernessTimestampExtractor�

BoundedOutOfOrdernessTimestampExtractor實現了AssignerWithPeriodicWatermarks接口,是flink內置的實現類。

主要源碼如下:

public BoundedOutOfOrdernessTimestampExtractor(Time maxOutOfOrderness) {if (maxOutOfOrderness.toMilliseconds() < 0) {throw new RuntimeException("Tried to set the maximum allowed " +"lateness to " + maxOutOfOrderness + ". This parameter cannot be negative.");}this.maxOutOfOrderness = maxOutOfOrderness.toMilliseconds();this.currentMaxTimestamp = Long.MIN_VALUE + this.maxOutOfOrderness;}public abstract long extractTimestamp(T element);@Overridepublic final Watermark getCurrentWatermark() {long potentialWM = currentMaxTimestamp - maxOutOfOrderness;if (potentialWM >= lastEmittedWatermark) {lastEmittedWatermark = potentialWM;}return new Watermark(lastEmittedWatermark);}@Overridepublic final long extractTimestamp(T element, long previousElementTimestamp) {long timestamp = extractTimestamp(element);if (timestamp > currentMaxTimestamp) {currentMaxTimestamp = timestamp;}return timestamp;}

BoundedOutOfOrdernessTimestampExtractor產生的時間戳和水印是允許“有界亂序”的,構造它時傳入的參數maxOutOfOrderness就是亂序區間的長度,而實際發射的水印為通過覆寫extractTimestamp()方法提取出來的時間戳減去亂序區間,相當于讓水印把步調“放慢一點”。這是Flink為遲到數據提供的第一重保障。

當然,亂序區間的長度要根據實際環境謹慎設定,設定得太短會丟較多的數據,設定得太長會導致窗口觸發延遲,實時性減弱。

設置maxOutOfOrderness為5min,代碼如下:

source.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<Tuple2<String, Long>>(Time.minutes(5)) {@Overridepublic long extractTimestamp(Tuple2<String, Long> element) {return element.f1;}}).keyBy(value -> value.f0).timeWindow(Time.minutes(10)).process(new ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>() {@Overridepublic void process(String key, ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>.Context context, Iterable<Tuple2<String, Long>> elements, Collector<Object> out) throws Exception {System.out.println("----------------");System.out.println("系統當前時間:"+ DateUtil.date());System.out.println("當前水位時間:"+DateUtil.date(context.currentWatermark()));System.out.println("窗口開始時間:"+DateUtil.date(context.window().getStart()));System.out.println("窗口結束時間:"+DateUtil.date(context.window().getEnd()));elements.forEach(element -> System.out.println("數據攜帶時間:"+DateUtil.date(element.f1)));}}).print();

運行結果如下:

看起來和我們自定義實現結果一樣。但是10min的水位時間是來自數據15min減去延遲時間5min得來的。

同理20min的水位時間是來自數據25min減去延遲時間5min得來的。

我們可以設置延遲時間為10min,看一下結果。最后一條數據是25min,那么最后的水位線就是25min-10min=15min。只會觸發00-10的窗口。

同樣的,由于沒有后續數據導致后面的窗口沒有觸發。

AscendingTimestampExtractor

AscendingTimestampExtractor要求生成的時間戳和水印都是單調遞增的。用戶實現從數據中獲取自增的時間戳extractAscendingTimestamp與上一次時間戳比較。如果出現減少,則打印warn日志。

源碼如下:

    public abstract long extractAscendingTimestamp(T element);@Overridepublic final long extractTimestamp(T element, long elementPrevTimestamp) {final long newTimestamp = extractAscendingTimestamp(element);if (newTimestamp >= this.currentTimestamp) {this.currentTimestamp = newTimestamp;return newTimestamp;} else {violationHandler.handleViolation(newTimestamp, this.currentTimestamp);return newTimestamp;}}@Overridepublic final Watermark getCurrentWatermark() {return new Watermark(currentTimestamp == Long.MIN_VALUE ? Long.MIN_VALUE : currentTimestamp - 1);}

間斷性水位線

適用于根據接收到的消息判斷是否需要產生水位線的情況,用這種水印生成的方式并不多見。

舉例如下,數據為15min的時候生成水位。

source.assignTimestampsAndWatermarks(new AssignerWithPunctuatedWatermarks<Tuple2<String, Long>>() {@Nullable@Overridepublic Watermark checkAndGetNextWatermark(Tuple2<String, Long> lastElement, long extractedTimestamp) {DateTime date = DateUtil.date(lastElement.f1);return date.minute()==15?new Watermark(lastElement.f1):null;}@Overridepublic long extractTimestamp(Tuple2<String, Long> element, long previousElementTimestamp) {return element.f1;}}).keyBy(value -> value.f0).timeWindow(Time.minutes(10)).process(new ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>() {@Overridepublic void process(String key, ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>.Context context, Iterable<Tuple2<String, Long>> elements, Collector<Object> out) throws Exception {System.out.println("----------------");System.out.println("系統當前時間:"+ DateUtil.date());System.out.println("當前水位時間:"+DateUtil.date(context.currentWatermark()));System.out.println("窗口開始時間:"+DateUtil.date(context.window().getStart()));System.out.println("窗口結束時間:"+DateUtil.date(context.window().getEnd()));elements.forEach(element -> System.out.println("數據攜帶時間:"+DateUtil.date(element.f1)));}}).print();

結果如下:

15min的數據生成了15min的水位,只觸發了00-10的窗口。

窗口處理遲到的數據

allowedLateness�

Flink提供了WindowedStream.allowedLateness()方法來設定窗口的允許延遲。也就是說,正常情況下窗口觸發計算完成之后就會被銷毀,但是設定了允許延遲之后,窗口會等待allowedLateness的時長后再銷毀。在該區間內的遲到數據仍然可以進入窗口中,并觸發新的計算。當然,窗口也是吃資源大戶,所以allowedLateness的值要適當。給個完整的代碼示例如下。

source.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<Tuple2<String, Long>>(Time.minutes(5)) {@Overridepublic long extractTimestamp(Tuple2<String, Long> element) {return element.f1;}}).keyBy(value -> value.f0).timeWindow(Time.minutes(10)).allowedLateness(Time.minutes(5)).process(new ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>() {@Overridepublic void process(String key, ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>.Context context, Iterable<Tuple2<String, Long>> elements, Collector<Object> out) throws Exception {System.out.println("----------------");System.out.println("系統當前時間:"+ DateUtil.date());System.out.println("當前水位時間:"+DateUtil.date(context.currentWatermark()));System.out.println("窗口開始時間:"+DateUtil.date(context.window().getStart()));System.out.println("窗口結束時間:"+DateUtil.date(context.window().getEnd()));elements.forEach(element -> System.out.println("數據攜帶時間:"+DateUtil.date(element.f1)));}}).print();

side output

側輸出(side output)是Flink的分流機制。遲到數據本身可以當做特殊的流,我們通過調用WindowedStream.sideOutputLateData()方法將遲到數據發送到指定OutputTag的側輸出流里去,再進行下一步處理(比如存到外部存儲或消息隊列)。代碼如下。

// 側輸出的OutputTagOutputTag<Tuple2<String, Long>> lateOutputTag = new OutputTag<>("late_data_output_tag");SingleOutputStreamOperator<Object> process = source.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<Tuple2<String, Long>>(Time.minutes(5)) {@Overridepublic long extractTimestamp(Tuple2<String, Long> element) {return element.f1;}}).keyBy(value -> value.f0).timeWindow(Time.minutes(10)).allowedLateness(Time.minutes(5)).sideOutputLateData(lateOutputTag).process(new ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>() {@Overridepublic void process(String key, ProcessWindowFunction<Tuple2<String, Long>, Object, String, TimeWindow>.Context context, Iterable<Tuple2<String, Long>> elements, Collector<Object> out) throws Exception {System.out.println("----------------");System.out.println("系統當前時間:" + DateUtil.date());System.out.println("當前水位時間:" + DateUtil.date(context.currentWatermark()));System.out.println("窗口開始時間:" + DateUtil.date(context.window().getStart()));System.out.println("窗口結束時間:" + DateUtil.date(context.window().getEnd()));elements.forEach(element -> System.out.println("數據攜帶時間:" + DateUtil.date(element.f1)));}});//處理側輸出數據
//        process.getSideOutput(lateOutputTag).addSink()

最后的window不觸發解決方法

自定義自增水位

周期性獲取watermark時,自定義增加水位

source.assignTimestampsAndWatermarks(new AssignerWithPeriodicWatermarks<Tuple2<String, Long>>() {private long currentTimestamp;@Nullable@Override// 生成watermarkpublic Watermark getCurrentWatermark() {currentTimestamp+=60000;return new Watermark(currentTimestamp);}@Override//獲取事件時間public long extractTimestamp(Tuple2<String, Long> element, long previousElementTimestamp) {if (element.f1>=currentTimestamp){currentTimestamp = element.f1;}return element.f1;}})

結果如下:

自定義trigger

當watermark不能滿足關窗條件時,我們給注冊一個晚于事件時間的處理時間定時器使它一定能達到關窗條件。

import org.apache.flink.streaming.api.windowing.triggers.Trigger;
import org.apache.flink.streaming.api.windowing.triggers.TriggerResult;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;public class MyTrigger extends Trigger<Object, TimeWindow> {@Overridepublic TriggerResult onElement(Object element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception {if (window.maxTimestamp() <= ctx.getCurrentWatermark()) {// if the watermark is already past the window fire immediatelyreturn TriggerResult.FIRE;} else {ctx.registerEventTimeTimer(window.maxTimestamp());ctx.registerProcessingTimeTimer(window.maxTimestamp() + 30000L);return TriggerResult.CONTINUE;}}@Overridepublic TriggerResult onProcessingTime(long time, TimeWindow window, TriggerContext ctx) throws Exception {ctx.deleteEventTimeTimer(window.maxTimestamp());return TriggerResult.FIRE;}@Overridepublic TriggerResult onEventTime(long time, TimeWindow window, TriggerContext ctx) throws Exception {if (time == window.maxTimestamp()) {ctx.deleteProcessingTimeTimer(window.maxTimestamp() + 30000L);return TriggerResult.FIRE;} else {return TriggerResult.CONTINUE;}}@Overridepublic void clear(TimeWindow window, TriggerContext ctx) throws Exception {ctx.deleteEventTimeTimer(window.maxTimestamp());ctx.deleteProcessingTimeTimer(window.maxTimestamp() + 30000L);}
}

Test.java

參考鏈接:

https://www.jianshu.com/p/c612e95a5028

https://blog.csdn.net/lixinkuan328/article/details/104129671

https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/dev/datastream/event-time/generating_watermarks/

https://cloud.tencent.com/developer/article/1573079

https://blog.csdn.net/m0_73707775/article/details/129560540?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-129560540-blog-118368717.235%5Ev29%5Epc_relevant_default_base3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-129560540-blog-118368717.235%5Ev29%5Epc_relevant_default_base3&utm_relevant_index=10

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/65510.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/65510.shtml
英文地址,請注明出處:http://en.pswp.cn/web/65510.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

web服務器架構,websocket

1. 非前后端分離架構 1. 前端html后端servlet 被tomcat服務器打包&#xff0c;統一指定根目錄入口。通過原生表單發送到后端&#xff0c;后端根據請求數據進行重定向或請求轉發&#xff0c;這樣就不能進行動態渲染&#xff0c;也就必須存在很多靜態html對應每一個請求。 這里…

Ubuntu 下測試 NVME SSD 的讀寫速度

在 Ubuntu 系統下&#xff0c;測試 NVME SSD 的讀寫速度&#xff0c;有好多種方法&#xff0c;常用的有如下幾種&#xff1a; 1. Gnome-disks Gnome-disks&#xff08;也稱為“Disks”&#xff09;是 GNOME 桌面環境中的磁盤管理工具&#xff0c;有圖形界面&#xff0c;是測試…

SpringBoot之核心配置

學習目標&#xff1a; 1.熟悉Spring Boot全局配置文件的使用 2.掌握Spring Boot配置文件屬性值注入 3.熟悉Spring Boot自定義配置 4.掌握Profile多環境配置 5.了解隨機值設置以及參數間引用 1.全局配置文件 Spring Boot使用 application.properties 或者application.yaml 的文…

后端服務集成ElasticSearch搜索功能技術方案

文章目錄 一、為什么選用ElasticSearch二、ElasticSearch基本概念1、文檔和字段2、索引和映射3、倒排索引、文檔和詞條4、分詞器 三、ElasticSearch工作原理1、Term Dictionary、Term index2、Stored Fields3、Docs Values4、Segment5、Lucene6、高性能、高擴展性、高可用①高性…

舉例說明AI模型怎么聚類,最后神經網絡怎么保存

舉例說明怎么聚類,最后神經網絡怎么保存 目錄 舉例說明怎么聚類,最后神經網絡怎么保存K - Means聚類算法實現神經元特征聚類劃分成不同專家的原理和過程 特征提取: 首先,需要從神經元中提取有代表性的特征。例如,對于一個多層感知機(MLP)中的神經元,其權重向量可以作為特…

ocrmypdf使用時的cannot import name ‘PdfMatrix‘ from ‘pikepdf‘問題

最近在做pdf的ocr,之前使用過ocrmypdf&#xff0c;打算再次使用&#xff0c;發現它更新了&#xff0c;所以就打算使用最新版 環境&#xff1a;win11anaconda 創建虛擬環境后安裝語句&#xff1a; pip install ocrmypdf -i https://pypi.tuna.tsinghua.edu.cn/simple pip in…

【JavaEE進階】獲取Cookie/Session

&#x1f340;Cookie簡介 HTTP協議自身是屬于 "?狀態"協議. "?狀態"的含義指的是: 默認情況下 HTTP 協議的客?端和服務器之間的這次通信,和下次通信之間沒有直接的聯系.但是實際開發中,我們很多時候是需要知道請求之間的關聯關系的. 例如登陸?站成…

Oracle:ORA-00904: “10“: 標識符無效報錯詳解

1.報錯Oracle語句如下 SELECT YK_CKGY.ID,YK_CKGY.DJH,YK_CKGY.BLRQ,YK_CKGY.ZBRQ,YK_CKGY.SHRQ,YK_CKGY.YT,YK_CKGY.ZDR,YK_CKGY.SHR,YK_CKGY.BZ,YK_CKGY.JZRQ,YK_CKGY.ZT,YK_CKGY.CKLX,(case YK_CKGY.CKLXwhen 09 then藥房調借when 02 then科室退藥when 03 then損耗出庫when…

Linux 磁盤管理命令:使用xfs 管理命令

文章目錄 Linux磁盤管理命令使用xfs 管理命令1.命令說明2&#xff0e;建立 XFS 文件系統4&#xff0e;調整 XFS 文件系統各項參數5&#xff0e;在線調整 XFS 文件系統的大小6&#xff0e;暫停和恢復 XFS 文件系統7&#xff0e;嘗試修復受損的 XFS 文件系統8&#xff0e;備份和恢…

《Spring Framework實戰》3:概覽

歡迎觀看《Spring Framework實戰》視頻教程 Spring Framework 為基于現代 Java 的企業應用程序提供了全面的編程和配置模型 - 在任何類型的部署平臺上。 Spring 的一個關鍵要素是應用程序級別的基礎設施支持&#xff1a;Spring 專注于企業應用程序的 “管道”&#xff0c;以便…

借助免費GIS工具箱輕松實現las點云格式到3dtiles格式的轉換

在當今數字化浪潮下&#xff0c;地理信息系統&#xff08;GIS&#xff09;技術日新月異&#xff0c;廣泛滲透到城市規劃、地質勘探、文化遺產保護等諸多領域。而 GISBox 作為一款功能強大且易用的 GIS 工具箱&#xff0c;以輕量級、免費使用、操作便捷等諸多優勢&#xff0c;為…

均值濾波從圖像復原角度的解釋

廖老師說若將圖像生成看作一個隨機過程&#xff0c;均值濾波&#xff08;Mean Filtering&#xff09;可以視為在高斯噪聲模型下的線性最小均方估計&#xff08;Linear Minimum Mean Squared Error, LMMSE&#xff09;或者極大似然估計&#xff08;Maximum Likelihood Estimatio…

高等數學學習筆記 ? 一元函數微分的基礎知識

1. 微分的定義 &#xff08;1&#xff09;定義&#xff1a;設函數在點的某領域內有定義&#xff0c;取附近的點&#xff0c;對應的函數值分別為和&#xff0c; 令&#xff0c;若可以表示成&#xff0c;則稱函數在點是可微的。 【 若函數在點是可微的&#xff0c;則可以表達為】…

linux之自動掛載

如果想要實現自動掛載&#xff0c;應該掛在客戶端&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 客戶端&#xff1a; [rootlocalhost ~]# yum install nfs-utils -y &#xff08;下載軟件&#xff09; [rootlocalhost ~]# systemctl start nfs-utils.servic…

用戶界面軟件01

Jens Coldewey 著&#xff0c;Tom.X 譯 本文中的模式語言逐步深入地探討用戶界面架構的設計&#xff0c;它基于人機工程學&#xff0c;足以形成一套完整的體系。如果你對這方面有興趣&#xff0c;請參考[Tog92]&#xff0c;[Coo95]和[Col95]。 本文不討論用戶界面的布局&…

Spring整合SpringMVC

目錄 【pom.xml】文件&#xff1b; 新建【applicationContext.xml】文件 新建【springmvc.xml】文件&#xff1b; 配置【src/main/webapp/WEB-INF/web.xml】文件&#xff1b; 新建【com.gupaoedu.service.IUserService】&#xff1b; 新建【com.gupaoedu.service.impl.Use…

【數據結構-堆】2233. K 次增加后的最大乘積

給你一個非負整數數組 nums 和一個整數 k 。每次操作&#xff0c;你可以選擇 nums 中 任一 元素并將它 增加 1 。 請你返回 至多 k 次操作后&#xff0c;能得到的 nums的 最大乘積 。由于答案可能很大&#xff0c;請你將答案對 109 7 取余后返回。 示例 1&#xff1a; 輸入&…

2025.1.8(c++對c語言的擴充——堆區空間,引用,函數)

筆記 上一筆記接續&#xff08;練習2的答案&#xff09; 練習&#xff1a;要求在堆區連續申請5個int的大小空間用于存儲5名學生的成績&#xff0c;分別完成空間的申請、成績的錄入、升序排序、成績輸出函數以及空間釋放函數&#xff0c;并在主程序中完成測試 要求使用new和d…

(長期更新)《零基礎入門 ArcGIS(ArcScene) 》實驗七----城市三維建模與分析(超超超詳細!!!)

城市三維建模與分析 三維城市模型已經成為一種非常普遍的地理空間數據資源,成為城市的必需品,對城市能化管理至關重要。語義信息豐富的三維城市模型可以有效實現不同領域數據與IS相信息的高層次集成及互操作,從而在城市規劃、環境模擬、應急響應和輔助決策等眾多領域公揮作用、…

在離線環境中安裝 `.rpm` 包的步驟

在一些環境中&#xff0c;可能無法直接通過網絡安裝軟件包。特別是在沒有互聯網連接的情況下&#xff0c;我們仍然可以手動下載 .rpm 安裝包并進行離線安裝。本文將介紹如何在離線環境中安裝多個 .rpm 包&#xff0c;確保軟件的順利安裝和依賴關系的處理。 1. 將 .rpm 文件復制…