Flink的窗口机制

窗口机制

  • tumble(滚动窗口)

  • hop(滑动窗口)

  • session(会话窗口)

  • cumulate(渐进式窗口)

  • Over(聚合窗口)

滚动窗口(tumble)

概念

滚动窗口 (tumble): 窗口大小 = 滑动距离。

它的窗口是紧密排布的,中间没有任何的数据重复和丢失。

案例 - SQL

--创建表
CREATE TABLE source_table ( 
 user_id STRING, 
 price BIGINT,
 `timestamp` bigint,
 row_time AS TO_TIMESTAMP(FROM_UNIXTIME(`timestamp`)),
 watermark for row_time as row_time - interval '0' second
) WITH (
  'connector' = 'socket',
  'hostname' = 'node1',        
  'port' = '9999',
  'format' = 'csv'
);

--语法
tumble(row_time,时间间隔),比如,如下的sql
tumble(row_time,interval '5' second),每隔5秒滚动一次。

--业务查询逻辑(传统方式)
select 
user_id,
count(*) as pv,
sum(price) as sum_price,
UNIX_TIMESTAMP(CAST(tumble_start(row_time, interval '5' second) AS STRING)) * 1000  as window_start,
UNIX_TIMESTAMP(CAST(tumble_end(row_time, interval '5' second) AS STRING)) * 1000  as window_end
from source_table
group by
    user_id,
    tumble(row_time, interval '5' second);

运行结果如下:

案例 - DataStream API

package day04;

import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.datastream.WindowedStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;

/**
 * @desc: 演示基于事件时间的滚动窗口。
 * 从socket数据源中接收数据(id,price,ts)
 */
public class Demo01_TumbleWindow {
    public static void main(String[] args) throws Exception {
        //1.创建流式执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        //2.数据源
        DataStreamSource<String> source = env.socketTextStream("node1", 9999);
        //3.数据处理
        //3.1 数据切分,转成Tuple3
        //3.2 分配窗口
        /**
         * WatermarkStrategy的策略有四种:
         * forMonotonousTimestamps,单调递增水印
         * forBoundedOutOfOrderness,允许乱序数据(数据迟到)的水印
         * forGenerator,自定义水印
         * noWatermarks,没有水印
         */
        SingleOutputStreamOperator<Tuple3<String, Integer, Long>> mapAndWatermarkStream = source.map(new MapFunction<String, Tuple3<String, Integer, Long>>() {
            @Override
            public Tuple3<String, Integer, Long> map(String value) throws Exception {
                String[] lines = value.split(",");
                /**
                 * lines分为3个字段:String id,Integer price,Long ts
                 */
                return Tuple3.of(lines[0], Integer.valueOf(lines[1]), Long.parseLong(lines[2]));
            }
        }).assignTimestampsAndWatermarks(WatermarkStrategy.<Tuple3<String, Integer, Long>>forMonotonousTimestamps()
                .withTimestampAssigner(new SerializableTimestampAssigner<Tuple3<String, Integer, Long>>() {
            @Override
            public long extractTimestamp(Tuple3<String, Integer, Long> element, long recordTimestamp) {
                //这个方法就是用来标识(标记)哪个列是用来表示时间戳的
                return element.f2 * 1000L;
            }
        }));

        mapAndWatermarkStream.print("源数据:");

        //3.3 根据id进行分组
        KeyedStream<Tuple3<String, Integer, Long>, String> keyedStream = mapAndWatermarkStream.keyBy(value -> value.f0);
        //3.4分组后,进行窗口划分
        //3.5 划分窗口后,对窗口内的数据进行sum
        //3.6为了显示的友好性,我们对Tuple3<String,Integer,Long>进行转换成Tuple2<String,Integer>
        SingleOutputStreamOperator<Tuple2<String, Integer>> result = keyedStream.window(TumblingEventTimeWindows.of(Time.seconds(5)))
                .sum(1)
                .map(value -> Tuple2.of(value.f0, value.f1)).returns(Types.TUPLE(Types.STRING, Types.INT));

        //4.数据输出
        result.printToErr("聚合后的数据:");
        //5.启动流式任务
        env.execute();
    }
}

运行结果如下:

SQL案例TVF写法

--语法,跟3个参数:
--参数1:表名
--参数2:表中事件时间列
--参数3:窗口大小
from table(tumble(table source,descriptor(row_time),interval '5' second))


--业务逻辑
SELECT 
    user_id,
    UNIX_TIMESTAMP(CAST(window_start AS STRING)) * 1000 as window_start,
    UNIX_TIMESTAMP(CAST(window_end AS STRING)) * 1000 as window_end,
    sum(price) as sum_price
FROM TABLE(TUMBLE(
        TABLE source_table
        , DESCRIPTOR(row_time)
        , INTERVAL '5' SECOND))
GROUP BY window_start, 
      window_end,
      user_id;
--window_start,window_end是新写法的关键字


      
--对照前面的方式:
select 
user_id,
count(*) as pv,
sum(price) as sum_price,
UNIX_TIMESTAMP(CAST(tumble_start(row_time, interval '5' second) AS STRING)) * 1000  as window_start,
UNIX_TIMESTAMP(CAST(tumble_end(row_time, interval '5' second) AS STRING)) * 1000  as window_end
from source_table
group by
    user_id,
    tumble(row_time, interval '5' second);

运行结果如下:

滑动窗口(hop)

概念

滑动窗口 :滑动距离 不等于 窗口大小。

(1)如果滑动距离小于窗口大小,则会产生数据重复

(2)如果滑动距离等于窗口大小,这就是滚动窗口

(3)如果滑动距离大于窗口大小,则会产生数据丢失(不考虑)

案例 - SQL

--创建表
CREATE TABLE source_table ( 
 user_id STRING, 
 price BIGINT,
 `timestamp` bigint,
 row_time AS TO_TIMESTAMP(FROM_UNIXTIME(`timestamp`)),
 watermark for row_time as row_time - interval '0' second
) WITH (
  'connector' = 'socket',
  'hostname' = 'node1',        
  'port' = '9999',
  'format' = 'csv'
);

--语法
hop(事件时间列,滑动间隔,窗口大小)
hop(row_time,interval '2' second, interval '5' second)

--业务SQL
SELECT user_id,
UNIX_TIMESTAMP(CAST(hop_start(row_time, interval '2' SECOND, interval '5' SECOND) AS STRING)) * 1000 as window_start,
UNIX_TIMESTAMP(CAST(hop_end(row_time, interval '2' SECOND, interval '5' SECOND) AS STRING)) * 1000 as window_end, 
    sum(price) as sum_price
FROM source_table
GROUP BY user_id
    , hop(row_time, interval '2' SECOND, interval '5' SECOND);--每隔两秒滑动一次

 运行结果如下:

SQL案例TVF写法

--语法
--table:表名
--descriptor:事件时间列
--滑动距离:interval 2 second
--窗口大小:interval 5 second
from table(hop(table 表名,descriptor(事件时间列),滑动间隔,窗口大小))
from table(hop(table source,descriptor(row_time),interval '2' second,interval '5' second))

--业务SQL
SELECT 
    user_id,
UNIX_TIMESTAMP(CAST(window_start AS STRING)) * 1000 as window_start,  
UNIX_TIMESTAMP(CAST(window_end AS STRING)) * 1000 as window_end, 
    sum(price) as sum_price
FROM TABLE(HOP(
        TABLE source_table
        , DESCRIPTOR(row_time)
        , interval '2' SECOND, interval '6' SECOND))
GROUP BY window_start, 
      window_end,
      user_id;

 运行结果如下:

案例 - DataStream API

package day04;

import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

/**
 * @desc: 演示基于事件时间的滑动窗口。
 * 从socket数据源中接收数据(id,price,ts)
 */
public class Demo02_SlideWindow {
    public static void main(String[] args) throws Exception {
        //1.创建流式执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        //2.数据源
        DataStreamSource<String> source = env.socketTextStream("node1", 9999);
        //3.数据处理
        //3.1数据map转换操作,转成Tuple3
        SingleOutputStreamOperator<Tuple3<String, Integer, Long>> mapStream = source.map(value -> {
            /**
             * 由一行数据中,用逗号进行切分【id,price,ts】
             * String id
             * Integer price
             * Long ts
             */
            String[] lines = value.split(",");
            return Tuple3.of(lines[0], Integer.valueOf(lines[1]), Long.parseLong(lines[2]));
        }).returns(Types.TUPLE(Types.STRING, Types.INT, Types.LONG));
        //3.2把Tuple3的数据添加Watermark(monotonousTimestamps)
        /**
         * WatermarkStrategy生成水印的策略有四种:
         * forMonotonousTimestamps,单调递增水印(用的次多)
         * forBoundedOutOfOrderness,运行数据迟到(乱序)(用的最多)
         * forGeneric,自定义水印(不用)
         * noWatermark,没有水印(不用)
         */
        SingleOutputStreamOperator<Tuple3<String, Integer, Long>> watermarks = mapStream.assignTimestampsAndWatermarks(WatermarkStrategy.<Tuple3<String, Integer, Long>>forMonotonousTimestamps()
                .withTimestampAssigner(new SerializableTimestampAssigner<Tuple3<String, Integer, Long>>() {
                    @Override
                    public long extractTimestamp(Tuple3<String, Integer, Long> element, long recordTimestamp) {
                        return element.f2 * 1000L;
                    }
                }));
        //3.3把数据根据id进行分组
        watermarks.print("源数据:");
        SingleOutputStreamOperator<Tuple3<String, Integer, Long>> sumStream = watermarks.keyBy(value -> value.f0)
                //3.4分组之后,设置滑动事件时间窗口,并且制定窗口大小为5秒钟,滑动间隔为2秒。
                /**
                 * SlidingEventTimeWindows,滑动事件时间窗口,带2个参数:
                 * 参数1:窗口大小
                 * 参数2:滑动间隔
                 */
                .window(SlidingEventTimeWindows.of(Time.seconds(5), Time.seconds(2)))
                //3.5对窗口内的数据进行sum操作
                .sum(1);
        //3.6把Tuple3转成了Tuple2(取id和sum的值)
        SingleOutputStreamOperator<Tuple2<String, Integer>> result = sumStream.map(value -> Tuple2.of(value.f0, value.f1))
                .returns(Types.TUPLE(Types.STRING,Types.INT));
        //4.数据输出
        result.printToErr("聚合后的数据:");
        //5.启动流式任务
        env.execute();
    }
}

运行结果如下:

会话窗口(session)

概念

会话窗口:在一个会话周期内,窗口的数据会累积,超过会话周期就会触发窗口的计算,同时开辟下一个新窗口。

注意:

数据本身的事件时间大于窗口间隔,才会触发当前窗口的计算。

案例 - SQL

--创建表
CREATE TABLE source_table ( 
 user_id STRING, 
 price BIGINT,
 `timestamp` bigint,
 row_time AS TO_TIMESTAMP(FROM_UNIXTIME(`timestamp`)),
 watermark for row_time as row_time - interval '0' second
) WITH (
  'connector' = 'socket',
  'hostname' = 'node1',        
  'port' = '9999',
  'format' = 'csv'
);

--语法
session(事件时间列,窗口间隔)
session(row_time,interval '5' second)

--业务SQL
SELECT 
    user_id,
UNIX_TIMESTAMP(CAST(session_start(row_time, interval '5' SECOND) AS STRING)) * 1000 as window_start,
UNIX_TIMESTAMP(CAST(session_end(row_time, interval '5' SECOND) AS STRING)) * 1000 as window_end, 
    sum(price) as sum_price
FROM source_table
GROUP BY user_id
      , session(row_time, interval '5' SECOND);

运行结果如下:

案例 - DataStream API

package day04;

import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.EventTimeSessionWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

/**
 * @desc: 演示基于事件时间的会话窗口。
 * 从socket数据源中接收数据(id,price,ts)
 */
public class Demo03_SessionWindow {
    public static void main(String[] args) throws Exception {
        //1.创建流式执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        //2.数据源
        DataStreamSource<String> source = env.socketTextStream("node1", 9999);
        //3.数据处理
        //3.1数据map转换操作,转成Tuple3
        SingleOutputStreamOperator<Tuple3<String, Integer, Long>> mapStream = source.map(new MapFunction<String, Tuple3<String, Integer, Long>>() {
            @Override
            public Tuple3<String, Integer, Long> map(String value) throws Exception {
                /**
                 * String id
                 * Integer price
                 * Long ts
                 */
                String[] lines = value.split(",");
                return Tuple3.of(lines[0], Integer.valueOf(lines[1]), Long.parseLong(lines[2]));
            }
        });
        //3.2把Tuple3的数据添加Watermark(monotonousTimestamps)
        SingleOutputStreamOperator<Tuple3<String, Integer, Long>> watermarks = mapStream
                .assignTimestampsAndWatermarks(WatermarkStrategy.<Tuple3<String, Integer, Long>>forMonotonousTimestamps()
                .withTimestampAssigner(new SerializableTimestampAssigner<Tuple3<String, Integer, Long>>() {
            @Override
            public long extractTimestamp(Tuple3<String, Integer, Long> element, long recordTimestamp) {
                return element.f2 * 1000L;
            }
        }));
        watermarks.print("源数据:");
        //3.3把数据根据id进行分组
        //3.4分组之后,设置会话事件时间窗口,并且指定窗口间隔为5秒钟。
        //3.5对窗口内的数据进行sum操作
        SingleOutputStreamOperator<Tuple3<String, Integer, Long>> sumStream = watermarks.keyBy(value -> value.f0)
                .window(EventTimeSessionWindows.withGap(Time.seconds(5)))
                .sum(1);
        //3.6把Tuple3转成了Tuple2(取id和sum的值)
        SingleOutputStreamOperator<Tuple2<String, Integer>> result = sumStream.map(value -> Tuple2.of(value.f0, value.f1)).returns(Types.TUPLE(Types.STRING, Types.INT));
        //4.数据输出
        result.printToErr("聚合后的结果:");
        //5.启动流式任务
        env.execute();
    }
}

运行结果如下:

 渐进式窗口(cumulate)

概念

渐进式窗口:在固定时间内,结果是单调递增的。比如周期性累计求某些指标。

如下图所示:

案例 -TVF方式

 

--语法
--1.source:表名
--2.事件时间列
--3.时间间隔,每隔多久把窗口内的数据统计一次
--4.窗口大小,窗口的时间长度
from table(cumulate(table source,descriptor(事件时间列),时间间隔,窗口大小))

--建表
CREATE TABLE source_table (
    -- 用户 id
    user_id BIGINT,
    -- 用户
    money BIGINT,
    -- 事件时间戳
    row_time AS cast(CURRENT_TIMESTAMP as timestamp(3)),
    -- watermark 设置
    WATERMARK FOR row_time AS row_time - INTERVAL '0' SECOND
) WITH (
  'connector' = 'datagen',
  'rows-per-second' = '10',
  'fields.user_id.min' = '1',
  'fields.user_id.max' = '100000',
  'fields.money.min' = '1',
  'fields.money.max' = '100000'
);


--业务SQL
SELECT 
FROM_UNIXTIME(UNIX_TIMESTAMP(CAST(window_start AS STRING)))  as window_start,
    FROM_UNIXTIME(UNIX_TIMESTAMP(CAST(window_end AS STRING))) as window_end, 
    sum(money) as sum_money,
    count(distinct user_id) as count_distinct_id
FROM TABLE(CUMULATE(
       TABLE source_table
       , DESCRIPTOR(row_time)
       , INTERVAL '5' SECOND
       , INTERVAL '30' SECOND))
GROUP BY
    window_start, 
    window_end;

--上面的cumulate窗口翻译如下:
--每隔5秒,统计最近30秒内的数据(总金额,用户量)

运行结果如下:

补充:

1.渐进式窗口没有普通SQL的写法。

2.渐进式窗口没有DataStream API。

Over 窗口

聚合窗口,用的不多。

Over 窗口分为两类:

  • 时间区间范围

  • 行数

时间区间范围

--语法
--range:范围,
--between ... and ... : 在...之间
--INTERVAL '1' HOUR PRECEDING:一小时前
--CURRENT ROW:当前行
RANGE BETWEEN 起始时间范围 AND CURRENT ROW
RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND CURRENT ROW


--建表SQL
CREATE TABLE source_table (
    order_id BIGINT,
    product BIGINT,
    amount BIGINT,
    order_time as cast(CURRENT_TIMESTAMP as TIMESTAMP(3)),
    WATERMARK FOR order_time AS order_time - INTERVAL '0' SECOND
) WITH (
  'connector' = 'datagen',
  'rows-per-second' = '1',
  'fields.order_id.min' = '1',
  'fields.order_id.max' = '2',
  'fields.amount.min' = '1',
  'fields.amount.max' = '10',
  'fields.product.min' = '1',
  'fields.product.max' = '2'
);

--业务SQL
SELECT product, order_time, amount,
  SUM(amount) OVER (
    PARTITION BY product
    ORDER BY order_time
    -- 标识统计范围是一个 product 的最近 30秒的数据
    RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND CURRENT ROW
  ) AS one_hour_prod_amount_sum
FROM source_table;

运行结果如下:

行数

--语法
--ROWS:行数
--行数 preceding:往前多少行
--:CURRENT ROW:当前行
ROWS BETWEEN 行数 PRECEDING AND CURRENT ROW
--统计最近100行到当前行的指标
ROWS BETWEEN 100 PRECEDING AND CURRENT ROW
对比前面的时间区间语法:
RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND CURRENT ROW


--创建表
CREATE TABLE source_table (
    order_id BIGINT,
    product BIGINT,
    amount BIGINT,
    order_time as cast(CURRENT_TIMESTAMP as TIMESTAMP(3)),
    WATERMARK FOR order_time AS order_time - INTERVAL '0' SECOND
) WITH (
  'connector' = 'datagen',
  'rows-per-second' = '1',
  'fields.order_id.min' = '1',
  'fields.order_id.max' = '2',
  'fields.amount.min' = '1',
  'fields.amount.max' = '2',
  'fields.product.min' = '1',
  'fields.product.max' = '2'
);


--业务SQL
SELECT product, order_time, amount,
  SUM(amount) OVER (
    PARTITION BY product
    ORDER BY order_time
    -- 标识统计范围是一个 product 的最近 5 行数据
    ROWS BETWEEN 100 PRECEDING AND CURRENT ROW
  ) AS one_hour_prod_amount_sum
FROM source_table;

运行结果如下:

 

补充:

1.Over窗口没有传统窗口的SQL写法。

2.Over窗口没有DataStream API的写法。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

系统复杂度之【高性能】

系统复杂度之【高性能】 今天我们来谈一谈系统复杂度的根源之【高性能】 对性能的不懈追求一直是人类科技持续发展的核心动力。例如计算机&#xff0c;从电子管计算机到晶体管计算机&#xff0c;再到集成电路计算机&#xff0c;运算性能从每秒几次提高到每秒几亿次。然而&#…

VUE_学习笔记

一、 xx 二、模板语法 1.模板语法之差值语法 &#xff1a;{{ }} 主要研究&#xff1a;{{ 这里可以写什么}} 在data中声明的变量、函数等都可以。常量只要是合法的javascript表达式&#xff0c;都可以。模板表达式都被放在沙盒中&#xff0c;只能访问全局变量的一个白名单&a…

【微服务笔记14】微服务组件之Config配置中心高可用环境搭建

这篇文章&#xff0c;主要介绍微服务组件之Config配置中心高可用环境搭建。 目录 一、高可用Config配置中心 1.1、高可用配置中心介绍 1.2、搭建Eureka注册中心 1.3、搭建ConfigServer服务端 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;添加配置文件 …

Jetson nano部署剪枝YOLOv8

目录前言一、YOLOv8模型剪枝训练1. Pretrain[option]1.1 项目的克隆1.2 数据集1.3 训练2. Constraint training3. Prune4. finetune二、YOLOv8模型剪枝部署1. 源码下载2. 环境配置2.1 trtexec环境变量设置3. ONNX导出3.1 Transpose节点的添加3.2 Resize节点解析的问题4. 运行4.…

FIFO的工作原理及其设计

1.简介 FIFO( First Input First Output)简单说就是指先进先出。FIFO存储器是一个先入先出的双口缓冲器&#xff0c;即第一个进入其内的数据第一个被移出&#xff0c;其中一个口是存储器的输入口&#xff0c;另一个口是存储器的输出口。 对于单片FIFO来说&#xff0c;主要有两种…

SHELL函数可课后作业

一、题目 1、编写函数&#xff0c;实现打印绿色OK和红色FAILED 判断是否有参数&#xff0c;存在为Ok&#xff0c;不存在为FAILED 2、编写函数&#xff0c;实现判断是否无位置参数&#xff0c;如无参数&#xff0c;提示错误 3、编写函数实现两个数字做为参数&#xff0c;返回最…

多线程 之 CAS与synchronized的优化过程

前言 本篇介绍什么是CAS与synchronized的优化过程&#xff0c;如有错误&#xff0c;请在评论区指正&#xff0c;让我们一起交流&#xff0c;共同进步&#xff01; 文章目录前言1. 什么是CAS&#xff1f;2. CAS实现的操作2.1 实现原子类2.2 实现自旋锁3. CAS的aba问题4. synchr…

【无人机】基于灰狼优化算法的无人机路径规划问题研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

链式二叉树及相关操作(前,中,后,层序遍历)

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; “春来无事&#xff0c;只为花忙。” 前言: 上一期给大家介绍了二叉树的一种顺序结构&#xff1a;堆&#xff0c;这一期承接上一期&#xff0c;给大家继续介绍二叉树的另一种结构&#xff1a;链式结构。 目录…

golang指针相关

指针相关的部分实在是没有搞太明白&#xff0c;抽时间来总结下。 1.指针相关基础知识 比如现在有一句话&#xff1a;『谜底666』&#xff0c;这句话在程序中一启动&#xff0c;就要加载到内存中&#xff0c;假如内存地址0x123456&#xff0c;然后我们可以将这句话复制给变量A&…

多线程(八):常见锁策略

目录 前言 1. 乐观锁 VS 悲观锁 乐观锁 悲观锁 2. 轻量级锁 VS 重量级锁 轻量级锁 3. 自旋锁 VS 挂起等待锁 自旋锁 挂起等待锁 4. 读写锁 VS 互斥锁 5. 可重入锁 vs 不可重入锁 死锁 发生死锁的情况 死锁产生的四个必要条件如下&#xff1a; 6. 公平锁和非公平锁…

【Java EE】-多线程编程(九) 锁策略CAS锁优化

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【JavaEE】 分享&#xff1a; 主要内容&#xff1a;乐观锁VS悲观锁、轻量级锁VS重量级锁、自旋锁VS挂起等待锁、互斥锁VS读写锁、公平锁VS非公平锁、可重入锁VS不可重入锁。CAS实…

Python数据结构与算法-树

一、树的概念详情见 https://blog.csdn.net/little_limin/article/details/129845592 Python数据结构与算法-堆排序&#xff08;NB组&#xff09;—— 一、树的基础知识二、树的实例&#xff1a;模拟文件系统1、树的存储树结构也是链式存储的&#xff0c;与链表的结构相似&…

类ChatGPT代码级解读:如何从零起步实现Transformer、llama/ChatGLM

前言 最近一直在做类ChatGPT项目的部署 微调&#xff0c;关注比较多的是两个&#xff1a;一个LLaMA&#xff0c;一个ChatGLM&#xff0c;会发现有不少模型是基于这两个模型去做微调的&#xff0c;说到微调&#xff0c;那具体怎么微调呢&#xff0c;因此又详细了解了一下微调代…

Vulnhub_Pylington

目录 一、信息收集 &#xff08;一&#xff09;端口服务探测 &#xff08;二&#xff09;目录扫描 二、漏洞挖掘 &#xff08;一&#xff09;robots敏感信息泄露 &#xff08;二&#xff09;python IDE沙箱绕过RCE 1. python敏感函数沙盒绕过 2. exec(__import_…

【ES】搜索结果处理RestClient查询文档

【ES】搜索结果处理&RestClient查询文档2.搜索结果处理2.1.排序2.1.1.普通字段排序2.1.2.地理坐标排序2.2.分页2.2.1.基本的分页2.2.2.深度分页问题2.2.3.小结2.3.高亮2.3.1.高亮原理2.3.2.实现高亮2.4.总结3.RestClient查询文档3.1.快速入门3.1.1.发起查询请求3.1.2.解析响…

Python做个猫狗识别系统,给人美心善的邻居

嗨害大家好鸭&#xff01;我是爱摸鱼的芝士❤ 宠物真的看着好治愈 谁不想有一只属于自己的乖乖宠物捏~ 这篇文章中我放弃了以往的model.fit()训练方法&#xff0c; 改用model.train_on_batch方法。 两种方法的比较&#xff1a; model.fit()&#xff1a;用起来十分简单&#…

Kubernetes 部署 StarRocks 集群

文章目录StarRocks简介系统架构图安装部署StarRocks手动部署通过 Docker部署使用 StarGo 部署管理通过 StarRocks Manager部署管理通过 Kubernetes部署工作原理逻辑图部署 StarRocks Operator部署 StarRocks 集群访问 StarRocks 集群集群内访问 StarRocks 集群集群外访问 StarR…

【案例实践】R语言多元数据统计分析在生态环境中的实践应用

查看原文>>>R语言生物群落分析绘图、多元统计分析、CMIP6、遥感碳储量、GEE林业、InVEST等 生态环境领域研究中常常面对众多的不同类型的数据或变量&#xff0c;当要同时分析多个因变量&#xff08;y&#xff09;时需要用到多元统计分析&#xff08;multivariate sta…

Spark----DataFrame和DataSet

Spark之DataFrame和DataSet 文章目录Spark之DataFrame和DataSetDataFrameDSL 语法创建DataFrame查看DataFrame的Schema信息只查看列数据的6种方式按照“age”分区&#xff0c;查看数据条数增加列withColumn修改列名withColumnRenamedRDD 转换为 DataFrameDataFrame 转换为 RDD转…