浅谈 ByteHouse Projection 优化实践

news2025/7/4 7:37:28

预聚合是 OLAP 系统中常用的一种优化手段,在通过在加载数据时就进行部分聚合计算,生成聚合后的中间表或视图,从而在查询时直接使用这些预先计算好的聚合结果,提高查询性能,实现这种预聚合方法大多都使用物化视图来实现。

Clickhouse 社区实现的 Projection 功能类似于物化视图,原始的概念来源于 Vertica,在原始表数据加载时,根据聚合 SQL 定义的表达式,计算写入数据的聚合数据与原始数据同步写入存储。在数据查询的过程中,如果查询 SQL 通过匹配分析可以通过聚合数据计算得到,直接查询聚合数据减少计算开销,大幅提升查询性能。

Clickhouse Projection 是针对物化视图现有问题,在查询匹配,数据一致性上扩展了使用场景:

  • 支持 normal projection,按照不同列进行数据重排,对于不同条件快速过滤数据
  • 支持 aggregate projection, 使用聚合查询在源表上直接定义出预聚合模型
  • 查询分析能根据查询代价,自动选择最优 Projection 进行查询优化,无需改写查询
  • projeciton 数据存储于原始 part 目录下,在任一时刻针对任一数据变换操作均提供一致性保证
  • 维护简单,不需另外定义新表,在原始表添加 projection 属性

ByteHouse 是火山引擎基于 ClickHouse 研发的一款分析型数据库产品,是同时支持实时和离线导入的自助数据分析平台,能够对 PB 级海量数据进行高效分析。具备真实时分析、存储-计算分离、多级资源隔离、云上全托管服务四大特点,为了更好的兼容社区的 projection 功能,扩展 projection 使用场景,ByteHouse 对 Projection 进行了匹配场景和架构上进行了优化。在 ByteHouse 商业客户性能测试 projection 的性能测试,在 1.2 亿条的实际生产数据集中进行测试,查询并发能力提升 10~20 倍,下面从 projeciton 在优化器查询改写和基于 ByteHouse 框架改进两个方面谈一谈目前的优化工作。

Projection 使用

为了提高 ByteHouse 对社区有很好的兼容性,ByteHouse 保留了原有语法的支持,projection 操作分为创建,删除,物化,删除数据几个操作。为了便于理解后面的优化使用行为分析系统例子作为分析的对象。

语法

-- 新增projection定义
ALTER TABLE [db].table ADD PROJECTION name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY] )

-- 删除projection定义并且删除projection数据 
ALTER TABLE [db].table DROP PROJECTION name 

-- 物化原表的某个partition数据
ALTER TABLE [db.]table MATERIALIZE PROJECTION name IN PARTITION partition_name

-- 删除projection数据但不删除projection定义
ALTER TABLE [db.]table CLEAR PROJECTION name IN PARTITION partition_name 

实例

CREATE DATABASE IF NOT EXISTS tea_data;

创建原始数据表
CREATE TABLE tea_data.events(
  app_id UInt32,
  user_id UInt64,
  event_type UInt64,
  cost UInt64,
  action_duration UInt64,
  display_time UInt64,
  event_date Date
) ENGINE = CnchMergeTree PARTITION BY toDate(event_date)
ORDER BY
  (app_id, user_id, event_type);

创建projection前写入2023-05-28分区测试数据
INSERT INTO tea_data.events
SELECT
    number / 100,
    number % 10,
    number % 3357,
    number % 166,
    number % 5,
    number % 40,
    '2023-05-28 05:11:55'
FROM system.numbers LIMIT 100000;

创建聚合projection
ALTER TABLE tea_data.events ADD PROJECTION agg_sum_proj_1
(
SELECT
    app_id,
    user_id,
    event_date,
    sum(action_duration)
    GROUP BY app_id,
    user_id, event_date
);

创建projection后写入2023-05-29分区测试数据
INSERT INTO tea_data.events
SELECT
    number / 100,
    number % 10,
    number % 3357,
    number % 166,
    number % 5,
    number % 40,
    '2023-05-29 05:11:55'
FROM system.numbers LIMIT 100000;

Note:CnchMergeTree是Bytehouse特有的引擎

Query Optimizer 扩展 Projection 改写

Bytehouse 优化器

ByteHouse 优化器为业界目前唯一的 ClickHouse 优化器方案。ByteHouse 优化器的能力简单总结如下:
图片

  • RBO:支持:列裁剪、分区裁剪、表达式简化、子查询解关联、谓词下推、冗余算子消除、Outer-JOIN 转 INNER-JOIN、算子下推存储、分布式算子拆分等常见的启发式优化能力。
  • CBO:基于 Cascade 搜索框架,实现了高效的 Join 枚举算法,以及基于 Histogram 的代价估算,对 10 表全连接级别规模的 Join Reorder 问题,能够全量枚举并寻求最优解,同时针对大于 10 表规模的 Join Reorder 支持启发式枚举并寻求最优解。CBO 支持基于规则扩展搜索空间,除了常见的 Join Reorder 问题以外,还支持 Outer-Join/Join Reorder,Magic Set Placement 等相关优化能力。
  • 分布式计划优化:面向分布式 MPP 数据库,生成分布式查询计划,并且和 CBO 结合在一起。相对业界主流实现:分为两个阶段,首先寻求最优的单机版计划,然后将其分布式化。我们的方案则是将这两个阶段融合在一起,在整个 CBO 寻求最优解的过程中,会结合分布式计划的诉求,从代价的角度选择最优的分布式计划。对于 Join/Aggregate 的还支持 Partition 属性展开。
  • 高阶优化能力:实现了 Dynamic Filter pushdown、单表物化视图改写、基于代价的 CTE (公共表达式共享)。

借助 bytehouse 优化器强大的能力,针对 projection 原有实现的几点局限性做了优化,下面我们先来看一下社区在 projection 改写的具体实现。

社区 Projection

改写实现在非优化器执行模式下,对原始表的聚合查询可通过 aggregate projection 加速,即读取 projection 中的预聚合数据而不是原始数据。计算支持了 normal partition 和 projection partition 的混合查询,如果一个 partition 的 projection 还没物化,可以使用原始数据进行计算。
具体改写执行逻辑:

  • 计划阶段
  1. 将原查询计划和已有 projection 进行匹配筛选能满足查询要求的 projection candidates;
  2. 基于最小的 mark 读取数选择最优的 projection candidate;
  3. 对原查询计划中的 ActionDAG 进行改写和折叠,之后用于 projection part 数据的后续计算;
  4. 将当前数据处理阶段提升到 WithMergeableState;
  • 执行阶段
  1. MergeTreeDataSelectExecutor 会将 aggregate 之前的计算进行拆分:对于 normal part,使用原查询计划进行计算;对于 projection part,使用改写后 ActionDAG 构造 QueryPipeline;
  2. 将两份数据合并,用于 aggregate 之后的计算。
    图片

Bytehouse 优化器改写实现

优化器会将查询切分为不同的 plan segment 分发到 worker 节点并行执行,segment 之间通过 exchange 交换数据,在 plan segment 内部根据 query plan 构建 pipeline 执行,以下面简单聚合查询为例,说明优化器如何匹配 projection。

Q1: 
SELECT   
app_id,    
user_id,    
sum(action_duration)
FROM tea_data.eventsWHERE event_date = '2023-05-29'
GROUP BY    
app_id,    
user_id

在执行计划阶段优化器尽量的将 TableScan 上层的 Partial Aggregation Step,Projection 和 Filter 下推到 TableScan 中,在将 plan segment 发送到 worker 节点后,在根据查询代价选择合适 projection 进行匹配改写,从下面的执行计划上看,命中 projection 会在 table scan 中直接读取 AggregateFunction(sum, UInt64)的 state 数据,相比于没有命中 projection 的执行计划减少了 AggregaingNode 的聚合运算。

  • Q1 查询计划(optimizer_projection_support=0)
    图片

图片

  • Q1 查询计划(optimizer_projection_support=1)
    图片

图片

混合读取 Projection

Projection 在创建之后不支持更新 schema,只能创建新的 projection,但是在一些对于 projection schema 变更需求频繁业务场景下,需要同一个查询既能够读取旧 projection 也能读取新 projection,所以在匹配时需要从 partition 维度进行匹配而不是从 projection 定义的维度进行匹配,混合读取不同 projection 的数据,这样会使查询更加灵活,更好的适应业务场景,下面举个具体的实例:

创建新的projection
ALTER TABLE tea_data.events ADD PROJECTION agg_sum_proj_2
(
SELECT
    app_id,
    sum(action_duration),
    sum(cost)
    GROUP BY app_id
);

写入2023-05-30的数据
INSERT INTO tea_data.events
SELECT
    number / 10,
    number % 100,
    number % 23,
    number % 3434,
    number % 23,
    number % 55,
    '2023-05-30 04:12:43'
FROM system.numbers LIMIT 100000;

执行查询
Q2:
SELECT
    app_id,
    sum(action_duration)
FROM tea_data.events
WHERE event_date >= '2023-05-28'
GROUP BY app_id
  • Q2 执行计划
    图片
  • 按照 partition 来匹配 projection
    查询过滤条件 WHERE event_date >= ‘2023-05-28’ 会读取是三个分区的数据, 并且 agg_sum_proj_1, agg_sum_proj_2 都满足 Q2 的查询条件,所以 table scan 会读取 2023-05-28 的原始数据,2023-05-29 会读取 agg_sum_proj_1 的数据,2023-05-30 由于 agg_sum_proj_2 相对于 agg_sum_proj_1 的数据聚合度更高,读取代价较小,选择读取 agg_sum_proj_2 的数据,混合读取不同 projection 的数据。
    图片
原始表 Schema 更新

当对原始表添加新字段(维度或指标 ),对应 projection 不包含这些字段,这时候为了利用 projection 一般情况下需要删除 projection 重新做物化,比较浪费资源,如果优化器匹配算法能正确处理不存在缺省字段,并使用缺省值参与计算就可以解决这个问题。


ALTER TABLE tea_data.events ADD COLUMN device_id String after event_type;
ALTER TABLE tea_data.events ADD COLUMN stay_time UInt64 after device_id;

执行查询
Q3:
SELECT
    app_id,
    device_id,
    sum(action_duration),
    max(stay_time)
FROM tea_data.events
WHERE event_date >= '2023-05-28'
GROUP BY app_id,device_id
  • Q3 执行计划
    图片
  • 默认值参与计算
    从查询计划可以看出,即使 agg_sum_proj_1 和 agg_sum_proj_2 并不包含新增的维度字段 device_id,指标字段 stay_time, 仍然可以命中原始的 partiton 的 projection,并且使用默认值来参与计算,这样可以利用旧的 projection 进行查询加速。

Bytehouse Projection 实现

Projection 是按照 Bytehouse 的存算分离架构进行设计的,Projecton 数据由分布式存储统一进行管理,而针对 projection 的查询和计算则在无状态的计算节点上进行。相比于社区版,Bytehouse Projection 实现了以下优势:

  • 对于 Projection 数据的存储节点和计算节点可以独立扩展,即可以根据不同业务对于 Projection 的使用需求,增加存储或者计算节点。
  • 当进行 Projection 查询时,可以根据不同 Projection 的数据查询量来分配计算节点的资源,从而实现资源的隔离和优化,提高查询效率。
  • Projection 的元数据存储十分轻量,在业务数据急剧变化的时候,计算节点可以做到业务无感知扩缩容,无需额外的 Projection 数据迁移。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OXCQGex3-1686027117180)(/img/bVc8ev0)]

Projection 数据存储

在 Bytehouse 中,多个 projections 数据与 data 数据存储在一个共享存储文件中。文件的外部数据对 projections 内部的内容没有感知,相当于一个黑盒。当需要读取某个 projection 时,通过 checksums 里面存储的 projection 指针,定位到特定 projection 位置,完成 projection 数据解析与加载。
图片

Write 操作

Projection 写入分为两部分,先在本地做数据写入,产生 part 文件存储在 worker 节点本地,然后通过 dumpAndCommitCnchParts 将数据 dump 到远程共享存储。

  • 写入本地  
    通过 writeTempPart()将 block 写入本地,当写完原始 part 后,循环通过方法 addProjectionPart()将每一个 projection 写入 part 文件夹,并添加到 new_part 中进行管理。
  • dump 到远程存储  
    dumpCnchParts()的时候,按照上述的存储格式,写入完原始 part 中的 bin 和 mark 数据后,循环将每一个 projection 文件夹中的数据写入到共享存储文件中,并记录位置和大小到 checksums,如下:
    写入 header
    写入 data
    写入 projections
    写入 Primary index
    写入 Checksums
    写入 Metainfo
    写入 Unique Key Index
    写入 data footger

Merge 操作

随着时间的推移,针对同一个 partition 会存在越来越多的 parts,而 parts 越多查询过滤时的代价就会越大。因此,Bytehouse 在后台进程中会 merge 同一个 partition 的 parts 组成更大的 part,从而减少 part 的数量提高查询的效率。

  • 对于每一个要 merge 的 part
    对于 part 中的每一列,缓存对应的 segments 到本地
    创建 MergeTreeReaderStreamWithSegmentCache,通过远程文件 buffer 或者本地 segments 的 buffer 初始化
  • 通过 MergingSortedTransform 或 AggregatingSortedTransform 等将 sources 融合成 PipelineExecutingBlockInputStream
  • 创建 MergedBlockOutputStream
  • 对于 projection,进行如下操作
  • 建立每一个 projection 的读取流,本地缓存 buffer 或者远程文件 buffer
  • 原始表 merge 过程,对 parts 中的 projections 进行 merge
  • 通过 dumper 将新的完整 part 存储到远端
    图片

图片

Mutate 操作

Bytehouse 采用 MVCC 的方式,针对 mutate 涉及的列,新增一个 delta part 版本存储此次 mutate 涉及到的列。相应地,我们在 mutate 的时候,构造 projection 的 mutate 操作的 inputstream,将 mutate 后的 projection 和原始表数据一起写到同一个 delta part 中。

  • 在 MutationsInterpreter 里面,通过 InterpreterSelectQuery(mutation_ast)获取 BlockInputStream
  • projection 通过 block 和 InterpreterSelectQuery(projection.ast)重新构建
    图片

Materialize 物化操作

如下图所示,根据 Bytehouse 的 part 管理方式,针对 mutate 操作或新增物化操作,我们为 part 生成新的 delta part,在下图 part 中,它所管理的三个 projections 由 base part 中的 proj2,delta part#1 中的 proj1’,以及 delta part#2 中的 proj3 共同构成。当 parts 加载完成后,delta part#2 会存储 base part 中的 proj2 的指针和 delta part#1 中的 proj1’指针,以及自身的 proj3 指针,对上层提供统一的访问服务。
图片

Worker 端磁盘缓存

目前,CNCH 中针对不同数据设计了不同的缓存类型

  • DiskCacheSegment:管理 bin 和 mark 数据
  • ChecksumsDiskCacheSegment:管理 checksums 数据
  • PrimaryIndexDiskCacheSegment:管理主键索引数据BitMapIndexDiskCacheSegment:管理 bitmap 索引数据
    针对 Projection 中的数据,分别通过上述的 DiskCache,ChecksumsDiskCache 和 PrimaryIndexDiskCache 对 bin,mark,checksums 以及索引进行缓存。

另外,为了加快 Projection 数据的加载过程,我们新增了 MetaInfoDiskCacheSegment 用于缓存 Projection 相关的元数据信息。

实际案例分析

某真实用户场景的数据集,我们利用它对 Projection 性能进行了测试。
该数据集约 1.2 亿条,包含 projection 约 240G 大小,测试机器 80CPU(s) / 376G Mem,配置如下:

  • SET allow_experimental_projection_optimization = 1
  • use_uncompressed_cache = true
  • max_threads = 1
  • log_level = error
  • 开启 Projection 查询并发度 80,关闭 Projection 查询并发度为 30

测试结果

开启 Projection 后,针对 1.2 亿条的数据集,查询性能提升 10~20 倍。
图片

表结构

                                                 
CREATE TABLE user.trades(                                     
 `type` UInt8,
 `status` UInt64,
 `block_hash` String, 
 `sequence_number` UInt64, 
 `block_timestamp` DateTime`transaction_hash` String, 
 `transaction_index` UInt32, 
 `from_address` String, 
 `to_address` String,
 `value` String,
 `input` String,
 `nonce` UInt64, 
 `contract_address` String,
 `gas` UInt64,
 `gas_price` UInt64,
 `gas_used` UInt64, 
 `effective_gas_price` UInt64, 
 `cumulative_gas_used` UInt64, 
 `max_fee_per_gas` UInt64, 
 `max_priority_fee_per_gas` UInt64, 
 `r` String,
 `s` String,
 `v` UInt64,
 `logs_count` UInt32,
 PROJECTION tx_from_address_hit
  (                                         
    SELECT *                                                
    ORDER BY from_address
  ),                                            
 PROJECTION tx_to_address_hit (                                           
    SELECT *                                                 
    ORDER BY to_address 
 ),                                                  
 PROJECTION tx_sequence_number_hit (                                      
    SELECT *                                              
    ORDER BY sequence_number 
 ),                            
 PROJECTION tx_transaction_hash_hit (                                         
    SELECT *                                                  
    ORDER BY transaction_hash 
 )                         
)
ENGINE=CnchMergeTree()
PRIMARY KEY (transaction_hash, from_address, to_address) 
ORDER BY (transaction_hash, from_address, to_address) 
PARTITION BY toDate(toStartOfMonth(`block_timestamp`));                            

开启Projection

Q1

WITH tx AS ( SELECT * FROM user.trades WHERE from_address = '0x9686cd65a0e998699faf938879fb' ORDER BY sequence_number DESC,transaction_index DESC UNION ALL SELECT * FROM user.trades WHERE to_address = '0x9686cd65a0e998699faf938879fb' ORDER BY sequence_number DESC, transaction_index DESC ) SELECT * FROM tx LIMIT 100;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZ0YQjwV-1686027117184)(/img/bVc8ewb)]
Q2

with tx as (select sequence_number, transaction_index, transaction_hash, input from user.trades where from_address = '0xdb03b11f5666d0e51934b43bd' order by sequence_number desc,transaction_index desc UNION ALL select sequence_number, transaction_index, transaction_hash, input from user.trades where to_address = '0xdb03b11f5666d0e51934b43bd' order by sequence_number desc, transaction_index desc) select sequence_number, transaction_hash, substring(input,18) as func_sign from tx order by sequence_number desc, transaction_index desc limit 100 settings max_threads = 1, allow_experimental_projection_optimization = 1, use_uncompressed_cache = true;

图片

关闭 Projection

Q1
图片
Q2
图片

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

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

相关文章

基于javaweb jsp+SSM 简易版教务管理系统的设计与实现

目录 一.项目介绍 二.环境需要 三.技术栈 四.使用说明 五. 运行截图 六. 视频演示 一.项目介绍 本系统分为管理员、老师、学生三类 管理员&#xff1a;维护课程信息、维护老师信息、维护学生信息、密码重置&#xff08;其他账户&#xff09;、修改密码、退出系统 老…

macOS Sonoma 14.0 Beta 1 (23A5257q) ISO、IPSW、PKG 下载

macOS Sonoma 14.0 Beta 1 (23A5257q) ISO、IPSW、PKG 下载 本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。另外也支持在 Windows 和 Li…

JVM暂时私有

Jvm: 一、类加载器分类 引导类加载器&#xff1a;BootStrapClassLoader&#xff08;出于安全考虑&#xff0c;Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类&#xff09;自定义类加载器&#xff1a;Extension ClassLoader AppClassLoader &#xff08;Tomcat也…

DBeaver 23.0.5发布

导读SQL 编辑器是一款功能强大的数据库管理工具&#xff0c;为用户提供了便捷的 SQL 编写和编辑功能。最近&#xff0c;该编辑器进行了多项更新&#xff0c;提升了使用体验。 首先&#xff0c;WHERE 和 SELECT 等自动完成功能现在显示与别名表的别名。用户可以使用键盘快捷键或…

https通信加密原理

为什么要用https HTTP 由于是超文本传输协议&#xff0c;是一个简单的请求-响应协议&#xff0c;它通常运行在TCP之上&#xff0c;它是明文传输&#xff0c;不能保证数据的完整性&#xff0c;不能保证是否被窃听&#xff0c;不能保证数据是否被篡改 https采用了一些加解密&am…

安装银河麒麟操作系统

文章目录 一、安装银河麒麟操作系统1.1、简介1.2、银河麒麟高级服务器操作系统V101.3、下载银河麒麟镜像1.4、安装银河麒麟操作系统兼容版 一、安装银河麒麟操作系统 1.1、简介 银河麒麟&#xff08;KylinOS&#xff09;原是在863计划和国家核高基科技重大专项支持下&#xf…

HFish蜜罐部署教程(windows版)—HW蓝队主动防御利器

文章目录 前言基础环境蜜罐部署管理端部署添加节点&开启服务 攻击展示端口扫描测试目录扫描测试POC测试 && ssh测试失陷测试 酷炫大屏后记Tips 前言 一年一度的HW马上又要来了&#xff0c;【不过听说今年推迟了一些】 &#xff0c;各位师傅应该都按耐不住了&#…

Tcl-12. 数组

TCL支持通过数组的形式存储多个元素。 Tcl中的数组和其他高级语言的数组有些不同&#xff1a;Tcl 数组元素的索引&#xff0c;或称键值&#xff0c;可以是任意的字符串&#xff0c;而且其本身没有所谓多维数组的概念。数组的存取速度要比列表有优势&#xff0c;数组在内部使用散…

从理论上理解SQL注入、XSS、中间件解析漏洞、挖矿马

目录 1、SQL注入 &#xff08;1&#xff09;原理 &#xff08;2&#xff09;分类 &#xff08;3&#xff09;防御 2、XSS &#xff08;1&#xff09;原理 &#xff08;2&#xff09;分类 3、中间件&#xff08;解析漏洞&#xff09; &#xff08;1&#xff09;IIS6.X …

JDK安装教程

jdk 链接&#xff1a;https://pan.baidu.com/s/1xAFaR7AQdy_hPVFHc1CVnA 提取码&#xff1a;cypz 环境配置 1、我的电脑–》右键属性–》高级系统设置–》环境变量 2、系统变量–》新建系统变量–》完成后点击确定 变量名&#xff1a;JAVA_HOME 变量值&#xff1a;&#xff0…

chatgpt赋能python:Python中的分词技术及其应用

Python中的分词技术及其应用 什么是分词&#xff1f; 分词是自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;中的一个重要环节&#xff0c;指将一段文本切分成若干个单词或词组。在中文分词中&#xff0c;由于中文没有明显的词汇边界&#…

进入IT领域,多久能月入过万?

当下打拼的很多人都有这样的困惑&#xff1a;刚毕业或者工作时间不长&#xff0c;也有一些基本技能&#xff0c;对未来有美好憧憬&#xff0c;一身干劲&#xff0c;却拿着微薄的薪水过着捉襟见肘的生活。 有些同龄人进入IT领域后快速升职加薪&#xff0c;观望者经常会问&#…

C++设计模式之生成器模式(Builder)

文章目录 定义前言1. 问题2. 解决方案 结构适用场景实现方法优点缺点与其他模式的关系实例 定义 生成器是一种创建型设计模式&#xff0c;使你能够分步骤创建复杂对象。该模式允许你使用相同的创建 代码生成不同类型和形式的对象。 前言 1. 问题 假设有这样一个复杂对象&a…

100种思维模型之事物关系思维模型-72

具体的事物是形象的、容易观察和理解的&#xff0c;而事物间的关系则容易让人忽视&#xff0c;乃至无法意识到它正在发生作用。 生活中&#xff0c;我们习惯于低估事物关系的影响。 事物关系思维模型一个提醒我们关注事物关系、从宏观层面找到更好的工作方向、实现可持续发展的…

显示反馈与隐式反馈

文章目录 1. 数据分类2. 显性反馈数据模型评价方法&#xff1a;3. 显式反馈转换为隐式反馈4. 隐式反馈的作用5. 参考资料 本文来介绍一下显示反馈与隐式反馈&#xff0c;作为我学习推荐系统的笔记以便日后忘记了可以回过头来温习。 1. 数据分类 显式反馈是指&#xff1a;用户明…

光量子计算机+GPU!NVIDIA、Rolls-Royce和Classiq宣布取得技术突破

​ &#xff08;图片来源&#xff1a;网络&#xff09; 5月21日&#xff0c;英伟达&#xff08;NVIDIA&#xff09;、罗尔斯罗伊斯&#xff08;Rolls-Royce&#xff09;和以色列量子软件公司Classiq宣布了一项量子计算技术突破成果&#xff0c;旨在不断提高喷气发动机的效率。 …

AB32VG:(2)app.cbp工程源码阅读笔记(ADC按键和红外)

文章目录 1.SDK文件目录2.ADCKEY和红外遥控器相关源码2.1 初始化2.2 在定时器中断服务程序中查询按键 3. 更改参数以适应自己的ADC按键板3.1 我的ADC按键板硬件3.2 ADC值转换为键值 4.红外遥控器5. 相关配置 参考文章&#xff1a; 作者&#xff1a;nunu1010&#xff0c;中科蓝…

VSCode+Git+TortoiseGit+Tools

目录 一、Tools 1、VSCode(visual studio code)下载安装 VSCode使用技巧和经验 2、Git下载安装 3、TortoiseGit 简介 3.1、下载安装Git及Tortoisegit 3.2、Tortoisegit拉取gitee仓库到本地 3.3、Git拉取gitee仓库到本地 3.4、Git提交到gitee仓库 4、国内获取GitHub链…

华为OD机试真题B卷 Java 实现【蛇形矩阵】,附详细解题思路

一、题目描述 蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。 例如&#xff0c;当输入5时&#xff0c;应该输出的三角形为&#xff1a; 1 3 6 10 15 2 5 9 14 4 8 13 7 12 11 二、输入描述 输入正整数N&#xff08;N不大于100&#xff09;。 三、输出描述…

Vector DDFS

矢量数字频率生成器 版本&#xff1a;vivado2021.1 帮助文档&#xff1a;C:/Xilinx/Vivado/2021.1/doc/sysgen/html_help/vectorddfs.html 接口 I 频率控制字&#xff0c;I 输出频率 * 采样时间 * 2^&#xff08;频率分辨率&#xff09;&#xff1b;VI、VO 用于同步&#x…