贝壳找房基于Flink+Paimon进行全量数据实时分组排序的实践

news2024/11/15 15:36:31

摘要:本文投稿自贝壳家装数仓团队,在结合家装业务场景下所探索出的一种基于 Flink+Paimon 的排序方案。这种方案可以在实时环境对全量数据进行准确的分组排序,同时减少对内存资源的消耗。在这一方案中,引入了“事件时间分段”的概念,以避免 Flink State 中冗余数据对排序结果的干扰,在保证排序结果准确性的同时,减少了对内存的消耗。并且基于数据湖组件 Paimon 的聚合模型和 Audit Log 数据在数据湖内构建了拉链表,为排序结果提供了灵活的历史数据基础。内容主要分为以下四个部分:

  1. 背景
  2. 现有的实时分组排序的一些做法及其特点
  3. Flink+Paimon进行全量数据实时分组排序
  4. 总结与展望

一、背景

家装家居业务,作为贝壳“一体三翼”战略的重要组成部分,在房屋回归居住属性的大背景下,正在迅猛发展。在过去的2023年中,家装家居业务合同额为133亿元,可比口径同比增长93%;净收入取得74%的可比口径同比增幅,达到109亿元。其中,北京和杭州的合同额突破20亿,上海全年合同额超10亿,合同额超过5亿的城市共有6个。此外,家装家居业务在更多城市跑出正循环,全年有11个城市实现运营利润为正。

在家装业务中,随着设计师对客户需求和期望的逐步了解和把握,一个装修项目往往会产生多份合同。在合同签订的过程中,业务上期望通过合同的顺序、内容、金额等信息实时匹配相应的风控和运营策略,以实现智能额度、动态尾款等等功能,为客户提供更加优质的服务体验。要实现这些功能,就需要对全量合同数据进行分组排序。然而,在实时场景中,这是一个不小的挑战。为了解决这个问题,我们进行了一系列的探索和尝试。

二、现有的实时分组排序的一些做法及其特点

首先,结合以往的经验,我们梳理了现有在实时链路中进行分组排序的方法。

第一种方法是基于Flink引擎自带的排序能力进行分组排序。该方法实现简单,逻辑直观,但是比较依赖内存资源。随着数据量的增长,排序任务所需要的内存资源会不断增加,这会给本就紧张的内存资源带来更大的压力。

第二种方法是基于离线处理结果和实时处理结果的融合计算分组排序。这种方法可以在一定程度上缓解内存压力,并且复用已有的离线计算结果。然而,同时维护并迭代离线和实时两套数据链路,会带来不小的运维压力。

第三种方法则是通过Redis、Hbase等NoSQL组件来存储和累计实时排序结果。这种占用内存少,不依赖批处理结果。然而,由于无法提供类似事务的ACID保证,存在数据脏读,进而伴随一定程度的统计误差。

通过上诉分析可以看到,在实时链路中,现有的分组排序方案在处理全量数据时,很难同时兼顾内存资源、数据链路和数据准确性三个方面。

三、Flink+Paimon进行全量数据实时分组排序

在实时数据的处理中,我们希望在需要保证数据时效性的前提下,避免依赖额外的批处理逻辑,同时减少对内存的消耗。

以Paimon为代表的数据湖组件的兴起为我们提供了全新的思路。它具备强大的数据存储和加工能力,并且能够顺滑地与Flink引擎配合,进一步扩大了Flink生态的实时处理领域的领先优势。

接下来,我们将详细介绍基于Flink+Paimon进行全量数据实时排序的新方式。整体思路可以概括为两个核心步骤:第一步,利用Flink引擎接收增量流入的数据,依托其State在内存中对数据进行排序,并将排序结果存储到数据湖中;第二步,从数据湖中读取历史时点的累计结果,结合第一步得到的内存排序结果一起计算得出最终的准确结果。

这两个步骤循环配合,互为起止,形成了一个完整的数据处理流程。为了方便表述说明,在介绍第一步的时候,我们假设第二步所产出的数据已经就绪。而在介绍第二步的时候,我们将展开讲解究竟如何产出了第一步所依赖的数据。

3.1基于历史数据的实时分组排序

在不引入额外的批处理逻辑,并且不把全量数据保留在内存中的前提下,想要实现分组排序,需要解决两个问题。其一,需要引入其他组件暂存结果,并且需要保证Flink引擎对于暂存结果的写入和读取不能同时针对同一条记录,否则会造成脏读;其二,未及时过期的Flink State数据与暂存结果之间不能出现重叠,否则会造成双算,导致结果偏高。

我们借鉴了Flink引擎中的滚动窗口思路,引入一个“事件时间分段”的概念,将实时数据根据事件时间分段,以得到准确的分组排序结果。

接下来,我们举个例子来具体说明数据的处理过程。现在假设一个项目A,它在历史上已经签约过两份合同,分别为C1和C2,它们的签约时间对应为T1和T2。实时数据中新流入一条合同签约记录C3,对应的时间为T3。将事件时间进行取整处理后,我们得到它们分别归属于起点为TG1和TG2的两个时间分段内。

SQL代码可以参考如下样例:

select project_id  -- 项目id
    ,contract_id -- 合同id
    ,sign_time  -- 签约时间
    ,FROM_UNIXTIME(UNIX_TIMESTAMP(sign_time,'yyyy-MM-dd HH:mm:ss')/(24*60*60)*(24*60*60)
           ,'yyyy-MM-dd HH:mm:ss'
           ) as event_time_group_start_point -- 事件时间分段起点
 from default_catalog.default_database.mysql_project_contract_table -- 项目合同信息

接下来,在Flink SQL的排序代码中,将项目id和事件时间段的起点一同作为分组主键,对数据按照事件时间的进行排序。SQL代码可以参考如下样例:

insert into paimon_catalog.paimon_db.dwd_project_contract_memory_result_table -- 实时数据排序结果
​
select project_id  -- 项目id      
    ,contract_id -- 合同id  
    ,sign_time  -- 签约时间         
    ,event_time       
    ,event_time_group_start_point -- 事件时间分段起点`
    ,DENSE_RANK() over (PARTITION BY project_id ,event_time_group_start_point ORDER BY event_time asc) as mem_rn -- 实时数据排序结果
 from paimon_catalog.paimon_db.dwd_project_contract_table -- 项目合同信息`

然后,我们需要根据每个事件时间分段的起点,找到对应的累计结果快照。累计结果快照代表了截至某个时点,各个装修项目已签约的合同数。(累计结果快照具体的实现方式将在3.2详细展开。)

读取到的累计结果快照代表截止各分段起点的历史结果,而实时排序结果则代表了自各分段起点起之后的增量结果。将这两个结果相加,我们就得到了准确的排序结果。

这个方法中,读入的累计结果是之前时刻的快照,它已经是既定事实,不会再被更改,进而避免了脏读;各个累计结果与增量结果之间以事件时间分段起点为边界,进而避免了双算问题。

此外,在实际应用中,我们还需要考虑如何处理历史State的逐步失效问题。由于State的生命周期是有限的,随着时间的推移,一些早期的State可能会被清除或失效。为了应对这种情况,我们可以将State的生命周期设置成略长于事件时间分段的间隔。这样,即使一些早期的State失效了,我们仍然能够确保最新的事件时间分段内的数据能够在内存中进行完整的排序,进而持续得到准确结果。

当然,对于那些已经失效的历史事件时间分段,其排序结果可能会因为数据清除而逐渐变小。为了解决这个问题,我们需要在排序操作的输出端取得每行数据排序结果的最大值。因此,在实际应用中,我们使用Paimon聚合模型来承接排序结果。

到目前为止,我们已经基于历史数据和有限的内存消耗在实时环境中实现了全量数据的分组排序。但是,这一操作的基础,是我们一直都是在假设的这样一份“随叫随到”的累计结果快照。那么,这种历史数据究竟是以如何生成、存储、和使用的呢?接下来我们将详细讨论这一部分。

3.2如何通过Paimon存储和呈现历史累计数据

接下来,让我们讨论如何生成并且呈现出各个事件时间分段起点的历史累计结果。

基于分组排序结果,我们可以在Paimon中采用聚合模型,以业务分组字段作为主键,获取各个分组中最大的事件时间和最大的排序结果。在我们的例子中,就是以项目id作为主键,得到项目A最新一份合同的签约时间,以及当前项目A所对应的合同中,最大的分组排序结果是多少。

SQL代码可以参考如下样例:

-- 分组内聚合的累计结果
CREATE TABLE if not exists paimon_catalog.paimon_db.dwd_project_contract_final_result_max_table (
   project_id   bigint COMMENT '项目id'
  ,max_rn     bigint COMMENT '该项目下当前最大的rn值'
  ,max_event_time string  COMMENT '该项目下当前最大的event_time'  
  ,PRIMARY KEY (project_id) NOT ENFORCED
) 
WITH (
   'merge-engine' = 'aggregation'
  ,'changelog-producer' = 'lookup'
  ,'fields.max_rn.aggregate-function' = 'max'
  ,'fields.max_rn.ignore-retract'='true'
  ,'fields.max_event_time.aggregate-function' = 'max'
  ,'fields.max_event_time.ignore-retract'='true'
);
​
insert into paimon_catalog.paimon_db.dwd_project_contract_final_result_max_table  
​
select project_id -- 项目id       
    ,asc_rn   -- 分组排序结果
    ,sign_time  -- 合同签约时间(事件时间)
 from paimon_catalog.paimon_db.dwd_project_contract_final_result_table -- 分组排序结果

随着数据的不断流入,累计结果表中的记录会被不断地更新,呈现出一个又一个版本。为了把累计结果的各个版本反映到历史时间轴上,我们想到了离线数据开发中的拉链表概念。

构建拉链表的关键步骤,是将相邻版本的数据记录拼接到同一行,以得到一个版本的起止时间。Paimon提供了一系列系统表,其中的Audit Log表记录了数据变更的完整日志,为构建累计结果的版本变更信息提供了可能。

基于累计结果表的Audit Log记录,我们创建了一张Paimon表来存储累计结果每个版本的起止时间信息。这张表包含两组字段:第一组字段用于表示累计结果每个版本的起始时刻,我们通过不断解析累计结果的-U日志来更新这些字段;第二组字段则用于表示累计结果每个版本的终止时间,我们利用累计结果的+U日志来实时更新这些字段。通过这种方式,我们得以追踪并体现出了累计结果的版本变更信息。

SQL代码可以参考如下样例:

CREATE TABLE if not exists paimon_catalog.paimon_db.dwd_project_contract_final_result_table_max_history_table (
   project_id      bigint COMMENT '项目id'
  ,pre_max_rn      bigint COMMENT '该项目下当前最大的rn值'
  ,pre_max_event_time  string COMMENT '该项目下当前最大的event_time'  
  ,next_max_event_time string COMMENT '被更新后该项目下当前最大的event_time'  
  ,PRIMARY KEY (project_id) NOT ENFORCED
)
WITH (
   'merge-engine' = 'aggregation'
  ,'changelog-producer' = 'lookup'
  ,'fields.pre_max_rn.aggregate-function' = 'max'
  ,'fields.pre_max_rn.ignore-retract'='true'
  ,'fields.pre_max_event_time.aggregate-function' = 'max'
  ,'fields.pre_max_event_time.ignore-retract'='true'
  ,'fields.next_max_event_time.aggregate-function' = 'max'
  ,'fields.next_max_event_time.ignore-retract'='true'
);INSERT INTO paimon_catalog.paimon_db.dwd_project_contract_final_result_table_max_history_table
select project_id   
    ,max_rn     
    ,max_event_time   
    ,'0000-00-00 00:00:00'
 from paimon_catalog.paimon_db.dwd_project_contract_final_result_max_table$audit_log
 where rowkind = '-U'
​
 union all
​
select project_id   
    ,0
    ,'0000-00-00 00:00:00'    
    ,max_event_time  
 from paimon_catalog.paimon_db.dwd_project_contract_final_result_max_table$audit_log
 where rowkind = '+U'

现在,我们已经成功记录了累计结果的版本变更信息。接下来的目标,就是展现历史上所有的版本变更记录。为此,我们再次将目光投向了Audit Log表。累计结果的版本变更信息表对应的Audit Log表中记录了其中各个版本出现的痕迹。因此,我们决定读取其中的+I和+U数据。

在读取这些数据时,我们还需要进行一定的过滤操作。因为在数据更新的过程中,会出现起止时间相等的版本。这种情况通常是由于Audit Log表中下一次的-U和上一次+U所包含的信息相同所导致的。为了避免冗余信息的干扰,我们需要在读取数据时进行甄别,过滤掉这些起止时间相等的版本。

经过这样的处理,就能够将所有的历史版本平铺呈现出来。

除了这些历史版本之外,拉链表中仍然需要包含当前位置的最新版本。所以,在展示历史版本的同时,还需要将当前最新结果合并到拉链表中,以确保数据的完整性和准确性。

SQL代码可以参考如下样例:

CREATE TABLE if not exists paimon_catalog.paimon_db.dwd_project_contract_base_version_table (
   project_id      bigint COMMENT '项目id'
  ,base_ver_start_time  string  COMMENT '该版本开始时间'
  ,base_ver_end_time   string  COMMENT '该版本结束时间'
  ,base_ver_max_rn    bigint COMMENT '该版本最大的rn'
  ,PRIMARY KEY (project_id,base_ver_start_time) NOT ENFORCED
)
WITH (
   'merge-engine' = 'deduplicate'
  ,'changelog-producer' = 'lookup'
);INSERT INTO paimon_catalog.paimon_db.dwd_project_contract_base_version_table -- 累计结果拉链表
select project_id      
    ,pre_max_event_time  as base_ver_start_time
    ,next_max_event_time as base_ver_end_time
    ,pre_max_rn      as base_ver_max_rn  
 from paimon_catalog.paimon_db.dwd_project_contract_final_result_max_history_table$audit_log -- 累计结果的版本变更信息的 audit log
 where rowkind in ('+I','+U')
  and pre_max_event_time <> next_max_event_time
​
 union all 
​
select project_id   
    ,max_event_time     as base_ver_start_time
    ,'9999-99-99 99:99:99' as base_ver_end_time   
    ,max_rn         as base_ver_max_rn
 from paimon_catalog.paimon_db.dwd_project_contract_final_result_max_table -- 累计结果

3.3 Flink+Paimon全量数据实时分组排序链路全景

在深入剖析了整体方案的两大核心操作思路及其具体实现后,让我们从整体角度审视整个方案的架构和各个组件之间的交互关系。

整个方案由若干Flink任务和Paimon模型组成,整体链路如下图。在这个方案中,实时流入的数据是整个流程的起点。这些数据在经过一系列的排序和处理后,会不断更新数据湖中的累计结果拉链表。这个拉链表不仅记录了累计结果的历史变化,还为后续的实时任务提供了历史时点的累计结果快照。通过这种方式,数据在整个方案中实现了循环流转和持续更新。

在这个流程中,通过实时数据与Paimon表进行look up join的方式,实现内存排序结果与累计结果快照的关联。在关联过程中,需要在匹配分组业务主键的同时,将事件时间分段起点与拉链表中各个版本的起止时间进行比较。

SQL代码可以参考如下样例:

CREATE TABLE if not exists paimon_catalog.paimon_db.dwd_project_contract_final_result_table (
   project_id           bigint    COMMENT '项目id'
  ,contract_id          bigint    COMMENT '合同id'
  ,sign_time           string    COMMENT '合同签约时间'
  ,event_time           TIMESTAMP(3) COMMENT 'sign_time作为event_time'
  ,event_time_group_start_point  STRING    COMMENT '业务时间分段起点'
  ,mem_rn             bigint    COMMENT '这条数据在内存排序中排出来的rn'
  ,base_ver_start_time      string    COMMENT '该版本开始时间'
  ,base_ver_end_time       string    COMMENT '该版本结束时间'
  ,base_ver_max_rn        bigint    COMMENT '该版本最大的rn'
  ,asc_rn             bigint    COMMENT '最终排序结果'
  ,PRIMARY KEY (project_id,contract_id,sign_time,event_time,event_time_group_start_point) NOT ENFORCED
)
WITH (
   'merge-engine' = 'aggregation'
  ,'changelog-producer' = 'lookup'
  ,'fields.mem_rn.aggregate-function' = 'max'
  ,'fields.mem_rn.ignore-retract'='true'
  ,'fields.base_ver_start_time.ignore-retract'='true'
  ,'fields.base_ver_end_time.ignore-retract'='true'  
  ,'fields.base_ver_max_rn.aggregate-function' = 'max'  
  ,'fields.base_ver_max_rn.ignore-retract' = 'true'    
  ,'fields.asc_rn.aggregate-function' = 'max'  
  ,'fields.asc_rn.ignore-retract'='true'         
);
​
insert into paimon_catalog.paimon_db.dwd_project_contract_final_result_table
​
-- 实时数据 lookup join 累计结果的历史快照
select s.project_id  
    ,s.contract_id
    ,s.sign_time  
    ,s.event_time
    ,s.event_step_start_point
    ,s.mem_rn
    ,coalesce(base.base_ver_start_time ,'0000-00-00 00:00:00') as base_ver_start_time
    ,coalesce(base.base_ver_end_time  ,'0000-00-00 00:00:00') as base_ver_end_time  
    ,coalesce(base.base_ver_max_rn   ,0) as base_ver_max_rn   
    ,s.mem_rn + coalesce(base.base_ver_max_rn,0) as asc_rn
 from paimon_catalog.paimon_db.dwd_project_contract_memory_result_table s -- 实时数据的内存排序结果
 left join paimon_catalog.paimon_db.dwd_project_contract_base_version_table FOR SYSTEM_TIME AS OF s.proctime AS base -- 累计结果拉链表
  on s.project_id = base.project_id
  and s.event_step_start_point >= base.base_ver_start_time 
  and s.event_step_start_point < base.base_ver_end_time

3.4 特定情况下的脏读及自修正方式

实际运行过程中,考虑到集群的计算负载以及HDFS的底层操作,数据湖中各表的更新需要一个短暂的时间。当所处理数据的业务时间刚好在业务时间段起点附近时,仍然可能出现脏读。

如图所示,C1和C2两条数据在业务时间分段起点TG2前后出现。当C1流入之后,累计结果拉链无法立刻将TG2时刻的快照版本从TG2-1更新到TG2-2。进而导致C2关联到的累计结果为未包含C1结果的TG2-1。

对于家装业务而言,由于作业人员通常在白天作业,因此我们可以将事件时间分段的交界点调节为每日零点,从而规避这一问题。

此处我们跳出家装业务,考虑这种特定情况的通用解法。在关联任务中,除了使用内存排序结果关联拉链表以外,还可以同时使用拉链表的变更记录来反向关联内存排序数据。这样能够将拉链表最新的版本变动同步到实时数据当中,进而修正C2的最终排序结果。

四、总结与展望

随着Flink引擎能力的不断增强以及Flink生态中像Paimon这样优秀项目的崛起,数仓开发人员在实时数据处理方面拥有了更多优秀的工具。这些新的功能和特性使得我们能够更加灵活地应对各种数据需求。

“新居住”的时代正在到来。贝壳家装数仓将不断吸收新理念、新技术,继续深入挖掘数据价值,持续打磨贴合家装场景的数据大脑,引领家装行业的数据实践,进一步助力贝壳家装业务为消费者提供更优质、更便捷的服务体验,让“家的美好,一站实现”的美好愿景成为更多家庭的现实。

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

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

相关文章

k8s设置pod资源请求和限制

设置资源请求和限制 实验目标&#xff1a; 学习如何为 Pod 设置资源请求和限制&#xff0c;以优化集群资源分配。 实验步骤&#xff1a; 创建一个 Deployment&#xff0c;并设置 CPU 和内存的资源请求和限制。使用 kubectl describe 命令查看资源分配情况。观察资源限制对 P…

2024年虚拟现实、图像和信号处理国际学术会议(ICVISP 2024,8月2日-4)

2024年虚拟现实、图像和信号处理国际学术会议&#xff08;ICVISP 2024&#xff09;将于2024年8月2-4日在中国厦门召开。ICVISP 2024将围绕“虚拟现实、图像和信号处理”的最新研究领域&#xff0c; 为来自国内外高等院校、科学研究所、企事业单位的专家、教授、学者、工程师等提…

Linux常用基本命令

linux目录 1.查看linux本机ip ip addr 2.新建文件夹 mkdir 文件夹名 3.新建文件 touch 文件名.后缀 4.删除文件 rm 文件名.后缀 5.删除文件 rm -r 文件名 6.不询问直接删除 rm -rf 文件名/文件名/ 7.显示目录下文件&#xff0c;文件夹 作用&#xff1a;显示指定目…

鸿蒙应用开发 - 软件安装 - DevEco

第一步 前往下载点下载安装包下载中心 | 华为开发者联盟-HarmonyOS开发者官网&#xff0c;共建鸿蒙生态https://developer.huawei.com/consumer/cn/download/ 根据自身需求下载对应安装包 第二步 点击打开安装包,配置安装路径 我个人选择放E盘,避免占用c盘空间 第三步 …

00_Python核心编程

Python入门 一 Python初识 1 Python的历史 Python的历史python是蟒蛇的含义python是一种解释型的,面向对象的,带有动态语义的高级程序设计语言. python是一种使你在编程时能够保持自己的风格的程序设计语言,你不用费什么劲就可以实现你想要的功能,并且编写的程序清晰易懂. …

宠物空气净化器哪家强?希喂、小米、安德迈谁最具性价比?

猫咪掉毛是一种正常的生理现象&#xff0c;每只猫咪都会周期性地更换毛发。但是&#xff0c;当您发现家里的沙发、地毯、衣物、甚至空气中都漂浮着难以清理的猫浮毛时。还是会很烦恼&#xff0c;最重要的是空气中的浮毛如果不及时清理的话长时间停留在空气中会对身体造成一定威…

苏州大学气膜综合馆成为师生活动新中心—轻空间

苏州大学应用技术学院的气膜综合馆自建成以来&#xff0c;已成为校园内的热门活动场所。由轻空间&#xff08;江苏&#xff09;膜科技有限公司&#xff08;以下简称“轻空间”&#xff09;全力打造&#xff0c;这座现代化、环保的多功能运动场馆&#xff0c;不仅为师生提供了一…

小米汽车SU7全色系H5自适应展示源码

为了满足广大车迷和潜在消费者对小米汽车SU7全色系的视觉体验需求&#xff0c;我们特别推出了一款基于HTML的自适应H5源码&#xff0c;用于在线展示小米汽车SU7的全色系。这款源码不仅兼容各种设备和屏幕尺寸&#xff0c;而且能够完美地呈现出小米汽车SU7的优雅外观和精致细节。…

vue3-openlayers 轨迹回放(历史轨迹)(ol-animation-path实现)

本篇介绍一下使用vue3-openlayers轨迹回放&#xff08;历史轨迹&#xff09;&#xff08;ol-animation-path实现&#xff09; 1 需求 轨迹回放&#xff08;历史轨迹&#xff09;实时轨迹 2 分析 轨迹回放&#xff08;历史轨迹&#xff09;&#xff0c;一般是一次性拿到所有…

高效记录收支明细:揭秘如何通过曲线图精准分析每月开销

在理财的道路上&#xff0c;你是否曾感到迷茫和无力&#xff1f;每个月的开销如同流水般悄无声息地滑过指尖&#xff0c;但你却始终难以掌握自己的财务脉络。今天&#xff0c;我们为你揭秘一个全新的理财方法——通过曲线图精准分析每月开销&#xff0c;让你的财务生活焕发智慧…

java设计模式(二)工厂方法模式(pattern of factory method)

1、模式介绍&#xff1a; 工厂方法模式&#xff08;pattern of factory method&#xff09;是一种创建型设计模式&#xff0c;它定义了一个用于创建对象的接口&#xff0c;但将实际创建对象的工作延迟到子类中&#xff0c;这样可以在不改变整体结构的情况下&#xff0c;通过子…

java编写的界面可以调用python吗

如何使用Java调用Python程序 本文为大家介绍如何java调用python方法&#xff0c;供大家参考。 实际工程项目中可能会用到Java和python两种语言结合进行&#xff0c;这样就会涉及到一个问题&#xff0c;就是怎么用Java程序来调用已经写好的python脚本呢&#xff0c;一共有三种…

Verilog HDL语法入门系列(四):Verilog的语言操作符规则(下)

目录 7.移位操作符8.关系操作符9.相等操作符9.1逻辑等与case等9.2逻辑等与逻辑不等9.3 case等与case不等 10.条件操作符11.级联操作符12.复制 微信公众号获取更多FPGA相关源码&#xff1a; 7.移位操作符 符号含义>>逻辑右移<<逻辑左移 移位操作符对其左边的操作…

JVM虚拟机的组成

一、为什么要学习 JVM &#xff1f; 1. “ ⾯试造⽕箭&#xff0c;⼯作拧螺丝” &#xff0c; JVM 属于⾯试官特别喜欢提问的知识点&#xff1b; 2. 未来在⼯作场景中&#xff0c;也许你会遇到以下场景&#xff1a; 线上系统突然宕机&#xff0c;系统⽆法访问&#xff0c;甚⾄直…

IDS Gaia-X Catena-X Manufacturing-X的关系

来源&#xff1a;小盟科普丨Catena-X数据空间在汽车领域落地https://mp.weixin.qq.com/s/Ftp0UGAohsh4ltLn3DylAw

苹果电脑清理垃圾怎么清理 macbook怎么清理电脑垃圾文件 macos优化软件 cleanmymac怎么使用

在选择电脑时&#xff0c;不少人都会选择拥有高性能和轻薄机身的mac。一开始&#xff0c;它确实如我们所期待的那样健步如飞&#xff0c;然而&#xff0c;随着时间的流逝&#xff0c;有没有觉得您的Mac有时候像是需要一个好的春季大扫除一样&#xff1f;随着我们不断使用电脑&a…

IMU应用于颈部健康监测

随着电脑成为日常工作的必备工具&#xff0c;长时间使用电脑导致的颈部疼痛问题日益受到关注。近日&#xff0c;一项创新研究利用IMU开发了一种新型监测系统&#xff0c;用来监测电脑使用者的颈部姿势和疼痛情况。 在为期两天的实验中&#xff0c;8名办公室工作者分别在静态和…

2024年世界移动大会(MWC Shanghai)——飞睿智能诚邀您,超宽带技术定位测距传输全家桶

超宽带UWB芯片SIP系列&#xff1a; FS100 FS200 超宽带UWB标签系列&#xff1a; FU3620-2 FUP410-1 超宽带UWB应用系列&#xff1a; FMFB200A&#xff08;门锁方案&#xff09; FU2625-2&#xff08;TAG方案&#xff09; FPDB200A&#xff08;音频&#xff09; FSTB200…

中学政史地杂志中学政史地杂志社中学政史地编辑部2024年第4期目录

每月时政 时政要闻&#xff08;2024年3月&#xff09; 李伟; 3-4 热点聚焦 全面加强基础设施建设,积极扩大有效投资 刘华; 5-7《中学生政史地》投稿&#xff1a;cn7kantougao163.com 蒙古国努力应对冰雪灾害 张仁杰; 8-10 复习指导 高中政治经济全球化内容复习…

【SQL Server数据库】数据的增删改操作

目录 一、用SQL语句完成下列功能。 1、新开设一门课程&#xff0c;名叫网络安全与防火墙&#xff0c;学时40&#xff0c;编号为“0118”&#xff0c;主要介绍网络的安全与主要的防火墙软件。 2、先建立monitor表&#xff0c;其结构与student表大致一样&#xff0e;…