Hive树形结构展开实战:递归CTE、自关联与性能优化指南

Hive做树形结构展开,听起来不算难,但真上手做过的同学应该都有体会——这玩意儿坑远比想象中多。部门层级、商品分类、菜单权限、物料BOM,凡是带父子关系的表,落到Hive里做多级展开,要么写一串让人头皮发麻的重复join,要么被递归查询的性能和内存问题按在地上摩擦。我最早接触这个需求是在做某电商平台的商品分类树,四级类目嵌套,几十万商品挂在叶子节点上,当时想着“不就是递归嘛”,结果一路踩坑踩到怀疑人生。这篇就把这些年用Hive做树形展开的方案、踩过的坑、以及最终沉淀下来的标准化套路都摊开讲清楚,给同样被这类需求折磨的兄弟们一点参考。

1. 内容整体设计与思路拆解

1.1 树形结构展开的本质与常见场景

先把问题定义清楚。所谓树形结构展开,是指把存储在关系表中的父子节点数据,按照层级关系展开成“根到叶子”的多行结果。比如一张组织架构表,每行记录只有节点ID和父节点ID,我们要得到的是每个人从顶层部门到自己的完整路径,或者把所有层级的直接上下级关系全部拉平。

这跟普通的join完全不是一个量级的问题。普通join最多关联两三层,靠SQL硬写还能忍受;一旦层级变成动态的——今天三级,明天五级,后天某个分支冒出来十级——写死的SQL就彻底崩了。更麻烦的是,Hive这类离线数仓工具对递归的支持一直很别扭,不像MySQL 8.0或者PostgreSQL那样有原生递归CTE可以顺手就写。

我遇到的典型场景基本逃不出这几类:

  • 组织架构权限:员工挂在部门下,部门挂在事业部下,要查某个领导管辖的所有人。
  • 商品类目统计:类目是树形,商品挂在末级类目,要统计任意层级类目下的商品数和GMV。
  • 物料清单(BOM):成品拆半成品,半成品拆零件,要算一个成品的所有底层物料。
  • 菜单/功能权限树:菜单有父子关系,角色勾选权限时要拿到完整子树。

这些需求的共同点是:表结构简单,就是id和parent_id两列,但查询逻辑绕不开层级遍历,而且数据量动不动就是千万级起步。所以方案选型的第一原则不是“能不能跑通”,而是“在海量数据下还能不能稳定跑完”。

1.2 方案选型:为什么Hive做这件事这么难受

很多人不理解,为什么不用Spark或者直接上图数据库?原因很现实:数仓链路是现成的,Hive表是各个业务方都在用的公共资产,数据已经同步到HDFS上了,再来回搬运到其他引擎,成本和维护复杂度都不可接受。所以在Hive里解决问题,是大量团队的刚需。

Hive做递归难受的核心原因,是它的执行模型天生不擅长迭代计算。每轮递归本质上都是一次扫描+join,循环次数多了,MapReduce/Tez的调度开销和IO开销会叠加得非常难看。Hive 2.x之后虽然加入了递归CTE语法,但底层的实现仍然是把每一层递归拆成独立的Stage去跑,跟传统数据库的递归在工程实现上差距明显。

这就导致业内做树形展开,实际落地的方案就那么几条路:

  • 多次自关联:适用于层级深度固定且较浅的场景,代码直观但垃圾SQL满天飞。
  • 递归CTE:Hive 2.2+支持,语法简洁,但性能和稳定性需要谨慎验证。
  • 遍历式临时表:循环把每一层的结果追加到临时表,直到没有新节点产生。
  • UDF自定义函数:用自定义聚合或者Map端处理做树形展开,适合纯计算类场景。

没有哪个方案是全能的,后面我会逐个拆解它们的适用边界和实操细节。一句话总结:Hive里做树形展开没有银弹,只有根据层级深度、数据规模、查询频率去权衡的取舍。

2. 核心细节解析与实操要点

2.1 递归CTE的正确打开姿势

先聊现在最主流的做法——递归CTE。虽然Hive支持得比较晚,但只要版本到位,这玩意儿确实是最接近“标准答案”的写法,逻辑清晰、维护成本低、扩展性好。

Hive从2.2.0开始支持递归CTE,语法长这样:

WITH RECURSIVE temp_tree AS ( -- 第一层:根节点 SELECT id, parent_id, name, 1 AS depth FROM org_table WHERE parent_id IS NULL UNION ALL -- 递归层:子节点 SELECT c.id, c.parent_id, c.name, t.depth + 1 FROM org_table c JOIN temp_tree t ON c.parent_id = t.id ) SELECT * FROM temp_tree;

这个写法跟标准SQL里的递归CTE差不多,但有几个细节我得特别强调,都是实际跑的时候才暴露出来的问题。

首先是根节点的定义。WHERE parent_id IS NULL看起来很合理,但很多业务表的根节点parent_id不是NULL而是0,甚至有的表根节点会指向自己。我在一个项目里就遇到了根节点parent_id等于id的神奇设计,结果递归CTE直接死循环,跑了一个多小时还没结束,最后还是靠加深度限制才救回来。所以写之前必须先做数据探查,搞清楚根节点到底长什么样。

其次是递归层的join条件。这里必须要保证c.parent_id = t.id能够正确匹配,而且最好在parent_id上建立索引或者做Bucket。否则Hive每一层递归都要做一次全表扫描,数据量上来之后每一层都是一场灾难。

第三个坑是深度限制。Hive的递归CTE如果不加终止条件,遇到环形引用就会无限循环,直到把集群资源跑干。我习惯的做法是在递归层显式加上深度控制,类似WHERE t.depth < 20,这样就算数据有问题,任务最多跑到20层就会自己停下来,可控得多。

2.2 自关联join方案的适用边界

如果你们Hive版本太老,或者因为各种原因不敢用递归CTE(比如占用的公共节点资源太多),自关联可能是你唯一的选择。这个方案的核心思路是:既然递归CTE本质就是逐层join,那我自己手动join,把深度写死,效果是一样的。

举个四层分类的例子:

SELECT l1.id AS l1_id, l1.name AS l1_name, l2.id AS l2_id, l2.name AS l2_name, l3.id AS l3_id, l3.name AS l3_name, c.id AS leaf_id, c.name AS leaf_name FROM category c LEFT JOIN category l3 ON c.parent_id = l3.id LEFT JOIN category l2 ON l3.parent_id = l2.id LEFT JOIN category l1 ON l2.parent_id = l1.id;

这个方案最大的优点是简单粗暴,任何人一看就懂,跑起来性能也稳定,因为每一层就是一个固定的MapJoin,调度器可以提前优化。但缺点同样明显:深度一变,SQL就得改;join的层数一多,数据膨胀会非常恐怖。

我见过一个BOM展开的需求,物料层级最深到8层,用自关联写出来就是7个LEFT JOIN,跑一次要两个小时。每次需求方说“我们产品增加了一个新层级”,开发就得改一遍SQL,后来实在受不了才换了方案。所以自关联我只建议用在深度固定≤4层、数据量相对可控的场景,深度再深就该考虑其他方案了。

2.3 深度、循环、性能三座大山

不管用哪种方案,绕不开的就是这三座大山,我把它们拆开逐个说。

深度问题:树形数据的深度在建模阶段往往是“拍脑袋”决定的,业务方说“一般就3层”,结果数据一跑发现最深有12层,你写死的SQL直接失效。应对思路是宁可一开始就做好递归或遍历的准备,也不要赌深度不会变。

循环问题:业务数据是脏的,父子关系存在环是常态。A的父节点是B,B的父节点是C,C的父节点又指回A,这种在业务逻辑上不可能出现的环形,在数据里经常发生。结果就是递归查询永远跑不完。经验是必须预置双重保护:深度限制(max depth)和路径去重(path_id在递归层校验是否重复)。

性能问题:Hive每一轮递归都是一次全表扫描+shuffle。树深10层就是10轮迭代,HDFS上如果还有小文件问题,每轮光扫描元数据都能让人崩溃。后面我会专门讲性能调优的实操策略。

3. 实操过程与核心环节实现

3.1 场景一:层级可控的自关联展开

先给一个我已经在线上稳定跑了大半年的自关联例子。背景是某社区的用户邀请关系,深度上限是5层,数据量大概在每天2000万条左右变化。因为深度固定,自关联是最契合的方案。

具体做法是先建一张辅助表,把每一层的展开提前物化:

-- 每日全量构建邀请关系网络,限制深度为5 INSERT OVERWRITE TABLE dim_invite_tree SELECT n1.user_id AS root_user_id, n1.user_name AS root_user_name, n2.user_id AS level2_user_id, n3.user_id AS level3_user_id, n4.user_id AS level4_user_id, n5.user_id AS level5_user_id FROM invite_relation n1 LEFT JOIN invite_relation n2 ON n1.user_id = n2.inviter_id LEFT JOIN invite_relation n3 ON n2.user_id = n3.inviter_id LEFT JOIN invite_relation n4 ON n3.user_id = n4.inviter_id LEFT JOIN invite_relation n5 ON n4.user_id = n5.inviter_id WHERE n1.inviter_id IS NULL;

这里有个细节:WHERE n1.inviter_id IS NULL只保留最顶层根节点,这样每一行就是一棵完整的5层子树路径。但注意,如果树的深度不够5层,中间会有一部分join不上,从而产生NULL列,下游使用时要做好空值处理。

实际跑下来这个方案很稳,每天定时调度,30分钟左右完成全量计算。后续统计某个人拉了多少人,直接对root_user_id分组sum就行,不需要再递归。这种“空间换时间”的物化思路非常适合固定深度的冷数据。

3.2 场景二:利用递归CTE实现任意深度展开

再来看动态深度的场景。我用一个标准分类树的案例来演示,这是从一个权限系统里抽出来的简化版,表现方式就是常见的id/parent_id二列结构。

需求细节:分类没有固定层级,有的子类只有两层,有的分支能到十层。同时分类表本身有1700多万行,不能在递归过程里反复扫全表。

核心优化思路:先用一轮过滤把参与展开的节点收敛到临时表,再做递归。这里的关键是不要直接对全量业务表递归,而是先缩小数据范围。

WITH RECURSIVE cate_filtered AS ( SELECT id, parent_id, name FROM category WHERE status = 1 ), cate_tree AS ( SELECT id, parent_id, name, 1 AS depth, CAST(id AS STRING) AS path FROM cate_filtered WHERE parent_id IS NULL OR parent_id = '' UNION ALL SELECT c.id, c.parent_id, c.name, t.depth + 1, CONCAT_WS('/', t.path, CAST(c.id AS STRING)) FROM cate_filtered c JOIN cate_tree t ON c.parent_id = t.id WHERE t.depth < 20 ) SELECT * FROM cate_tree;

这版代码在Tez引擎下跑了12分钟,比之前同事用自关联join写出来的2小时快了整整10倍,而且深度扩展到20层都不需要改代码。

操作过程中有几个细节值得记录:

  • CAST(id AS STRING)把ID转成字符串再拼接,避免数值溢出。ID是bigint的时候,直接用||拼接偶尔会遇到隐式转换的坑。
  • depth字段不仅是展示用,更是递归终止条件的核心,一定不能省略。
  • 递归CTE里的cate_filtered在每一层都会被引用,所以要确保筛选条件足够紧凑,不然递归过程等于每层都在扫全表。

3.3 通用UDF点:数据预处理与结果回写

无论用自关联还是递归CTE,数据预处理都是决定成败的一环。不要拿到原始表就开始展开,先花10分钟清洗数据,后面能省两小时。

预处理两件事最关键:一是环检测,二是根节点识别。

环检测我习惯用一个小技巧,先算一遍每个节点到根的距离,如果一个节点在两张表里出现了不同的距离值,说明这个节点所在的分支可能有环。具体写法:

-- 检测环:同一节点存在多条到根路径 WITH RECURSIVE dist AS ( SELECT id, parent_id, 1 AS d FROM category WHERE parent_id IS NULL UNION ALL SELECT c.id, c.parent_id, d.d + 1 FROM category c JOIN dist d ON c.parent_id = d.id ) SELECT id, COUNT(DISTINCT d) AS cnt FROM dist GROUP BY id HAVING cnt > 1;

这个查询如果跑出来有记录,那这些节点所在的子树就需要业务方先修正数据,否则后面展开一定会出问题。

结果回写方面,树展开的结果往往要反复被别的任务引用,所以展开之后建一张结果宽表很有必要,不要每次都现算。宽表的设计一般是:root_id、node_id、node_name、depth、path,然后按root_id做分区。这样下游要查任意一棵子树,都只需要按root_id过滤一次,效率高得多。

还有一点:如果树形结构更新不频繁(比如一天一次),直接用全量刷新就好;如果更新频繁(实时),那就得考虑增量展开。增量展开的难点在于:父节点的层级变化会影响所有后代节点的路径,所以增量更新时往往需要把变更节点所在子树全部重算,这个成本和全量差不了太多。我的建议是:不频繁就全量,频繁就分片全量,真正需要实时展开的场景,要么走另外一套实时链路,要么接受一定延迟。

4. 常见问题与排查技巧实录

4.1 性能突然暴跌的排查路径

好好的任务跑了一个月,突然某天从30分钟变成3小时还没跑完。这类问题我排查的顺序是先看Yarn资源、再看数据量变化、最后看表结构是否被动过。

有一次线上任务性能暴跌,排查了半天,最后发现是业务侧往分类表里灌了一批深度为25层的异常数据。之前最深处也就7层,递归CTE最多迭代到第8层就收敛了,突然来了一批25层的,相当于任务迭代次数翻了接近4倍,每一层还要全表扫描,自然就炸了。

解决办法不是改代码,而是在递归层把最大深度从20调整到一个合理值,同时在任务调度前置一个数据探查脚本,监控深度变化的趋势,一旦深度异常跳变,先告警再跑任务。

这里给个更加实用的保命配置:在Hive中开启自动的并行执行和向量化,对递归CTE有奇效:

SET hive.exec.parallel=true; SET hive.exec.parallel.thread.number=8; SET hive.vectorized.execution.enabled=true; SET hive.vectorized.execution.reduce.enabled=true;

实测下来,这两个参数在递归CTE场景下能把单层扫描耗时压缩30%左右。但注意,向量化在某些Hive版本上和递归CTE组合会触发奇怪的bug,如果开了之后结果schema变乱,关掉向量化再试。

4.2 数据倾斜与去重细节

树形展开天然容易数据倾斜。举个例子:一个超大类目下面挂了80%的商品,递归join的时候,这一层别的任务都跑完了,几十个Reduce全卡在这个大节点上。

我踩过的坑是拿商品分类树做统计时,某个顶级类目下有上亿商品,递归到这一层的时候直接拖垮整个任务。后面的处理思路主要是两种:

一是用MapJoin把小表广播,但这要求参与广播的表足够小。递归CTE场景下,如果你把“当前层”的结果集控制在几百MB以内,可以考虑加join hint强制MapJoin,能极大降低shuffle成本。

SELECT /*+ MAPJOIN(t) */ c.id, c.parent_id, c.name, t.depth + 1 FROM cate_filtered c JOIN cate_tree t ON c.parent_id = t.id;

注意,这个hint只在能广播的场景下有效,一旦当前层的中间结果超过节点内存,反而会因为内存溢出挂掉。所以用前先估算中间结果集大小。

二是把倾斜的大节点做子查询拆分。比如把顶级类目编码单独拎出来,走一条单独的分支,最后UNION回来。这种做法代码会复杂一些,但对于数据分布极度不均匀的场景,是唯一能治本的办法。

去重方面,递归CTE偶尔会出现重复记录的情况,原因通常是父子关系里有重复数据。展开前先对源表做去重:同一对父子关系只保留一条记录,千万不能带着重复数据跑递归,否则结果会指数级膨胀。

4.3 死循环与终止条件设置

这个坑反复出现,必须单独拿出来说。Hive的递归CTE不像标准SQL那样自动检测循环引用,一旦数据里有环,轻则任务跑不完,重则把整个队列的资源耗尽,影响同一集群上的其他任务。

我总结了一套“双重保险”的做法:

第一重保险是深度硬限制。所有递归CTE的递归层都写死最大深度,这个值根据业务经验设,比如组织架构设20、分类树设15,既不让正常数据被截断,又不会让异常数据跑飞。

WHERE t.depth < 20

第二重保险是路径查重。在递归CTE里维护一个path字段,每次生成新节点时检查目标节点的id是否已经在当前路径里出现过:

WHERE INSTR(t.path, CAST(c.id AS STRING)) = 0

INSTR返回0表示没出现过,说明不是环;如果返回值大于0,说明这条路径绕回了已访问节点,直接切断。

有人可能会问,深度限制不就够了吗?深度限制只防深环,不防短环。比如A→B→C→A,这个环深度才3,你不加路径查重的话它也一样会无限循环。所以这两个是配合使用的,只加一个都不够保险。

另外,跑递归CTE这类任务时,我强烈建议先拿一份小样本数据做验证,确认结果正确后再放全量。千万不要拿全量数据直接试跑,万一环检测没做干净,任务挂一晚上不说,还影响别人用集群。

4.4 版本兼容性与引擎选择细节

最后这部分纯经验分享。Hive的递归CTE在不同版本、不同引擎上表现差异非常大,这点很多朋友容易忽略。

  • Hive 2.x早期版本对递归CTE支持有bug,最典型的是递归层引用CTE名称时偶发解析失败,需要升级到2.2.0以上。
  • Tez引擎在递归CTE下表现优于MR引擎,因为Tez把多个依赖Stage合并成了DAG,减少了不必要的中间结果落盘。
  • Spark引擎跑递归CTE支持更好,但Hive on Spark的任务调度有额外的内存开销,混用时要测试稳定性。
  • Impala对递归CTE基本不支持,如果查询走了Impala接入层,会直接语法报错,需要路由到Hive执行。

实际项目里,我建议优先用Tez引擎跑递归CTE,把执行引擎显式指定:

SET hive.execution.engine=tez; SET hive.tez.container.size=4096; SET hive.tez.java.opts=-Xmx3072m;

容器内存的配置看数据量调整,树深、单层结果集大,就适当调大Container,不然每轮递归结束后GC会非常频繁。

另外还有一点,递归CTE的结果如果量很大,不建议一次性写入一张表,容易出现小文件爆炸。建议走分区写入,比如按root_id的哈希分几个分区,然后靠后续的MSCK REPAIR或者分区动态加载来维护。跑完尽量用INSERT OVERWRITE而不是INSERT INTO,避免重复跑的时候把老数据没清理掉,造成数据翻倍。

说实话,Hive做树形结构展开这类需求,方案不少,但没有一个是可以无脑套用的。我个人的习惯是:先确认数据规模、层级深度的稳定性、更新频率,再决定用固定深度自关联、递归CTE还是其他招。如果数据深度常年不变而且足够浅,自关联简单可靠,运维不操心;一旦深度开始变得不可控,趁早换递归CTE,早换早省事。最后再啰嗦一句,不管用哪种方案,环检测和深度限制这两道保险一定要加,这玩意儿就像安全带,平时没用,真出事的时候是救命的。

相关新闻

开源项目吐槽大会:那些年,我们共同踩过的“坑”与社区智慧

开源项目吐槽大会:那些年,我们共同踩过的“坑”与社区智慧

引言&#xff1a;为什么我们需要一场“吐槽大会”&#xff1f; 开源世界的另一面&#xff1a;光环下的真实协作体验。“吐槽”的价值&#xff1a;发现问题、促进理解、推动改进的社区文化。本文目标&#xff1a;以轻松、共情的方式&#xff0c;盘点常见痛点&#xff0c;并探讨建…

2026/10/20 10:59:56 阅读更多 →
企业AI Agent定制:单条数据出错为何拖垮整批任务?

企业AI Agent定制:单条数据出错为何拖垮整批任务?

以一个假设场景为例&#xff0c;财务在助手中提交一批付款指令。系统在执行前逐条校验&#xff0c;其中一条收款方账号格式异常&#xff0c;整批校验随即中断&#xff0c;剩余九十九条记录也未进入后续处理。复核时才发现&#xff0c;整批任务被一条格式错误的数据阻断。这类单…

2026/10/20 10:58:55 阅读更多 →
笔记 1:思小伴 搭载 EEG 脑电专注力监测的多功能儿童陪伴桌宠

笔记 1:思小伴 搭载 EEG 脑电专注力监测的多功能儿童陪伴桌宠

笔记 1&#xff5c;作品概述&#xff1a;脑电桌宠到底是什么#智能硬件 #脑机交互 #竞赛作品 &#xff5c; 2026 全国大学生数字媒体科技作品及创意竞赛 智能软硬件赛道思小伴是一台放在书桌上的智能陪伴机器人。它要解决的不是“再做一个会说话的玩具”&#xff0c;而是儿童学…

2026/10/20 10:58:55 阅读更多 →

最新新闻

Pygame性能优化:把静态障碍画进背景并用Mask碰撞检测

Pygame性能优化:把静态障碍画进背景并用Mask碰撞检测

我先说自己踩过的一个坑&#xff1a;做一个小游戏&#xff0c;十几种障碍物各自做成独立精灵对象&#xff0c;视觉上没问题&#xff0c;但数量一多&#xff0c;每帧要遍历、更新、碰撞检测&#xff0c;开销一下上去了。后来改成把所有障碍直接画到背景面上&#xff0c;再配合 m…

2026/10/20 11:58:56 阅读更多 →
VS2019下DuiLib从零配置WIN32空项目完整指南

VS2019下DuiLib从零配置WIN32空项目完整指南

DuiLib 这名字&#xff0c;做 Windows 客户端的老兵肯定不陌生。当年从 MFC 切到 DirectUI 的朋友&#xff0c;多少都摸过这套库&#xff0c;或者至少听过它的大名。到现在&#xff0c;VS2019 出来都这么多年了&#xff0c;网上翻来覆去找资料&#xff0c;很多还是老版本的方案…

2026/10/20 11:58:56 阅读更多 →
MPU6050 DMP直接输出pitch/roll/yaw原理与实战解析

MPU6050 DMP直接输出pitch/roll/yaw原理与实战解析

简介&#xff1a;本资源是一套基于MPU6050传感器DMP&#xff08;数字运动处理器&#xff09;功能实现姿态解算的完整嵌入式工程&#xff0c;面向嵌入式初学者、智能硬件开发者及飞控/机器人方向实践者&#xff0c;解决传统姿态解算中万向锁、算法复杂、滤波调试难等痛点。资源无…

2026/10/20 11:58:56 阅读更多 →
贝叶斯优化实战:从高斯过程到深度学习超参数调优

贝叶斯优化实战:从高斯过程到深度学习超参数调优

简介&#xff1a;面向机器学习与深度学习从业者&#xff0c;这份资源聚焦贝叶斯优化超参数调优&#xff0c;旨在解决手动调参效率低、模型性能难提升的痛点。压缩包共4个文件&#xff0c;核心是两个Python脚本&#xff0c;一个面向支持向量机、随机森林等传统机器学习模型&…

2026/10/20 11:58:56 阅读更多 →
CutMix数据增强在医学病灶检测中的实践:稳住训练与提升小病灶召回

CutMix数据增强在医学病灶检测中的实践:稳住训练与提升小病灶召回

1. 病灶检测的“过山车式”训练&#xff1a;问题到底出在哪做医疗图像的病灶检测有一段时间的人&#xff0c;大概率都见过这样一种场景&#xff1a;训练曲线前期掉得很快&#xff0c;一切看起来都正常&#xff0c;然后到某个阶段开始来回震荡&#xff0c;loss曲线像过山车一样上…

2026/10/20 11:58:56 阅读更多 →
如意报表 Ming-WebReport-V3 安装配置与避坑指南

如意报表 Ming-WebReport-V3 安装配置与避坑指南

简介&#xff1a;如意报表&#xff08;Ming-WebReport-V3&#xff09;安装程序面向需要在Web环境中搭建数据可视化与报表系统的开发者及企业信息化人员&#xff0c;帮助快速完成报表工具的部署与集成。资源包共408个文件&#xff0c;约26.45MB&#xff0c;涵盖o、mrf报表模板、…

2026/10/20 11:57:55 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →