Flink实时热榜TopN实战:窗口设计与两阶段聚合

做实时热榜这个话题,说多了都是泪。你在后台看需求,通常就一句话:“把最近5分钟最热的内容排出来”,可真做起来会发现,这句话背后牵扯出的是流式计算里几乎所有经典难题:事件时间怎么对齐、窗口边界如何处理、热门key带来的数据倾斜怎么缓解、全局排序和实时性怎么平衡。Flink在这类场景里被用得最多,因为它有完整的事件时间支持、分布式的窗口算子、以及可配置的状态后端,能在一个框架里把“窗口聚合 + 全局TopN + 容错恢复”全链路打通。这篇文章我从方案选型、窗口设计、核心实现到实战排查展开,全程结合模拟项目X(内容平台实时热门内容榜)来讲,适合正在做或准备做实时热榜的数据开发同学参考。

1. 实时TopN热榜的核心思路与方案选型

先聊方案。很多第一次做热榜的人,会下意识想:我能不能把数据全部累加到一个HashMap里,定时排个序就完了?能,但前提是你只需要计算“历史累计TopN”,而且数据量锁死在一个节点能扛住的范围。一旦要求变成“最近5分钟”“每10秒刷新一次”,这个思路就崩了,因为历史累计不随时间滚动退场,你根本没法表达“最近”这个概念。正确的做法是引入窗口:把无限的数据流切成有限的段,在每个段内完成聚合和排序。这也是Flink窗口算子存在的意义。

再往下一层,还有两条路线要选,先看热榜场景的难点,再对比路线优劣。

1.1 热榜场景的三个典型难点

第一个难点是“最近”的语义。业务方嘴上说最近5分钟,但数据真实到达时间是乱序的,日志可能延迟几秒甚至几十秒才进消息队列;如果你用处理时间算,高峰期一排队,榜单就会明显失真。处理时间只能反映“数据到达顺序”,不能反映“业务发生顺序”,所以热榜场景我基本都会切到事件时间(Event Time)。

第二个难点是热点聚集。短视频、大促商品的访问量天然集中,冲顶的内容可能在几秒内产生几十万次曝光,按内容ID做keyBy时,单个key的流量会明显拉高所在子任务的负载。这个点单独放在后面讲,但方案设计时就要心里有数,不是等到集群背压了再去救火。

第三个难点是排序本身。TopN看起来是个排序问题,但在分布式流上,全量数据分散在多个并行子任务里,要让每个并行度都拿出自己的TopN,再做全局合并,才不至于把所有明细都汇到一个节点。很多人写出来的代码能跑,但一上生产就挂,基本都是栽在“全局排序”这个环节上。

1.2 两条技术路线:增量聚合 vs 窗口全量排序

第一条路线叫“增量聚合 + 全局排序”:先用窗口聚合函数做分组计数,产出一个(item_id, cnt, window)的计数流,再以窗口标识为key汇聚到下游做排序。这种方法的好处是明细数据在被排序前已经被压缩成了计数,网络和内存压力小。它的问题是预聚合阶段做了一次keyBy,数据要经过一次网络shuffle,但这是值得的,因为后边的排序节点输入量已经小了很多。

第二条路线叫“明细进窗口再全量排序”:直接把明细数据开窗后交给AllWindowFunction做全局排序。代码最简单,但所有明细要进入同一个并行度,数据稍微大一点就扛不住,而且窗口状态会把明细全部攒着,内存压力非常大。实际开发里绝大多数情况应该走第一条路线,只有数据量很小(比如单机都能放下的量级)或对准确度要求极高、不允许预聚合丢信息时才考虑第二条。

这里要澄清一个常见误区:预聚合并不丢信息。聚合函数本身就是幂等的count/sum,窗口内增量聚合的结果等于全量聚合的结果。也就是说你用增量聚合先算出每个item的计数,后面在排序阶段拿到的数据就是完整计数,不是采样也不是近似,精确度没有损失。

2. 窗口设计与时间语义:先定好规则再写代码

写代码前,需要先把窗口和时间语义定下来。核心决策是:榜单是按滚动窗口算“最近5分钟”的热度,还是按滑动窗口算“每30秒刷新最近5分钟”?这两个词看着类似,实际处理逻辑完全不同,业务体感也差很多。

2.1 滚动窗口还是滑动窗口:实时性换不换准确性

滚动窗口把时间切成互不重叠的区间,比如1分钟一个窗口:09:00:00-09:01:00算一次,09:01:00-09:02:00再算一次。每1分钟输出一次完整榜单,窗口间没有交集。优点是逻辑简单,同一个内容不会在一个窗口内重复上榜;缺点是榜单刷新频率受限于窗口长度,实时感差,用户看到的榜单最长可能滞后一分钟。

滑动窗口则是每隔一个滑动步长就输出过去固定长度时间窗口的热度:比如窗口长度5分钟、滑动步长30秒,那每30秒会输出一个“最近5分钟”的TopN,且两次计算之间大部分数据重叠。滑动窗口更贴近“每30秒看一次最新热榜”这种产品需求,也是大多数内容平台实际采用的形式。但滑动窗口有一个天然问题:同一个内容在紧邻的两个窗口里都可能上榜,呈现出来的效果就是榜单变化频繁,运营有时候会抱怨“数字跳来跳去”。这时候可以加平滑策略,比如对相邻窗口的结果做加权平均,或者把步长调大一些来降低抖动。

工程上还要注意滑动窗口的触发逻辑。Flink的滑动窗口本质上会把每条元素放入它所属的多个窗口切片里,窗口数量等于窗口长度除以滑动步长(比如1分钟窗口、10秒步长,就是6个切片),每个切片都维护一份聚合状态,内存占用是滚动窗口的窗口长度/步长倍。所以滑动步长设置得太小,状态压力会成倍上涨,这块必须心里有数,别等集群OOM了再回头排查。

2.2 Watermark与乱序:迟到数据怎么处理

用事件时间就必须引入Watermark,它解决的核心问题是“等到什么时候窗口数据就算齐了”。热榜场景里,日志链路通常经过客户端上报、服务端汇总、消息队列转发,延迟几秒到几十秒都属于正常。如果你把Watermark延迟设成0,大量数据会被关在窗口外面,榜单数字偏低;设得太大,窗口触发很晚,榜单就失去了实时性。

我的建议是先按业务允许的延迟来定:一般内容产品能容忍10秒左右的榜单延迟,Watermark延迟可以先设5秒,再根据线上数据迟到率微调。判断标准是:用侧输出流把迟到数据接下来,看每分钟的迟到量占比,如果超过1%,就适当增大Watermark延迟或延长窗口结算容忍时间。

Flink里迟到数据的处理有三层:第一层是Watermark本身的延迟等待;第二层是窗口允许的late数据(允许窗口触发后再等一段时间接收迟到数据);第三层是侧输出流兜底,把彻底超时的数据单独接住,供线下修正或离线比对。热榜这种对结果实时展示要求高、但对绝对精确不那么敏感的场景,建议把侧输出流作为常态兜底,宁可做一次异步修正,也别牺牲展示实时性。

2.3 窗口参数怎么给:一张表讲清楚

参数典型配置选择的依据
窗口类型滑动窗口(长度5min、步长30s),或滚动窗口(长度1min)产品要求榜单多久刷新一次,数据量能否支撑滑动窗口的切片开销
Window长度5分钟较常见,大促时可缩短到1分钟时间越短,热度越敏感;时间越长,榜单越稳定
滑动步长30s,重实时场景可到10s步长越小越“实时”,但状态开销等比例上涨
Watermark延迟5~10s链路延迟与榜单实时性的平衡点
迟到数据处理窗口触发后再接收10s,超时进侧输出保证结果及时展示,又给正常乱序一定的修正空间
state TTL窗口长度 + 延迟buffer,如5min窗口设15~30min防止超大窗口或空闲key长期占用状态
Checkpoint间隔30s~1min恢复粒度与性能开销的平衡

这套参数不是死的。我见过很多团队把窗口参数写成配置项放到Flink参数里,方便业务调整,这个思路挺好,但一定要加监控,尤其是迟到率、窗口状态大小、Watermark延迟这三个指标,任何一个异常都直接影响榜单质量。

3. 核心实现:两阶段聚合与TopN计算

接下来看代码。这里给两套思路,一套是Flink SQL,适合快速上线、逻辑清晰、维护成本低的场景;另一套是DataStream API,适合要精细控制状态、窗口触发逻辑、或需要自定义去重规则的场景。两套最终都遵循同一个原则:先在窗口内把明细压成计数,再合并排序。

3.1 Flink SQL方案:窗口TVF + TopN语法

用模拟项目X(内容平台实时热门内容榜)演示。数据源是Kafka里的用户行为事件,字段包括用户ID、内容ID、行为类型、事件时间。需求是每10秒刷新一次最近5分钟的内容热度Top20。如果用SQL表达,自然是用窗口TVF加TopN语法,核心SQL如下。

先定义Kafka源表,注意要声明WATERMARK:

CREATE TABLE source_table ( user_id BIGINT, item_id STRING, behavior STRING, ts TIMESTAMP(3), WATERMARK FOR ts AS ts - INTERVAL '5' SECOND ) WITH ( 'connector' = 'kafka', 'topic' = 'user_behavior', 'properties.bootstrap.servers' = 'localhost:9092', 'properties.group.id' = 'topn-group', 'scan.startup.mode' = 'latest-offset', 'format' = 'json' );

然后写一个窗口聚合视图,把曝光行为按内容和5分钟窗口做计数:

CREATE VIEW window_cnt AS SELECT TUMBLE_START(ts, INTERVAL '5' MINUTE) AS win_start, item_id, COUNT(*) AS cnt FROM source_table WHERE behavior = 'view' GROUP BY TUMBLE(ts, INTERVAL '5' MINUTE), item_id;

最后用ROW_NUMBER窗口函数做全局TopN:

SELECT * FROM ( SELECT ROW_NUMBER() OVER (PARTITION BY win_start ORDER BY cnt DESC) AS rn, item_id, cnt, win_start FROM window_cnt ) WHERE rn <= 20;

这里有一个实现细节值得展开:Flink SQL的TopN语法本质上是先按分区字段排序再取前N条,它会在内部生成两个节点,第一个节点做局部TopN,第二个节点做全局TopN合并,也就是框架自动帮你完成了两阶段优化。所以只要把分区字段设成窗口标识win_start,就能让TopN在多个并行度上先各算各的,再归并,避免所有数据压到单节点。

另外,如果要用滑动窗口,SQL里把TUMBLE换成HOP就行:

SELECT * FROM ( SELECT HOP_START(ts, INTERVAL '30' SECOND, INTERVAL '5' MINUTE) AS win_start, item_id, COUNT(*) AS cnt FROM source_table WHERE behavior = 'view' GROUP BY HOP(ts, INTERVAL '30' SECOND, INTERVAL '5' MINUTE), item_id );

3.2 DataStream方案:局部TopN + 全局合并

再看DataStream API的写法。DataStream的思路是用一个增量聚合函数先在keyBy后的每个子任务里维护item_id对应的计数器,窗口触发时每个key输出一个局部计数;然后以窗口ID为key再做一次全局排序,输出TopN。核心算子链路如下:

DataStream<ItemEvent> stream = ...; // 第一阶段:按item_id做窗口内增量聚合 DataStream<ItemCount> preAgg = stream .keyBy(e -> e.getItemId()) .window(TumblingEventTimeWindows.of(Time.minutes(5))) .aggregate(new CountAgg(), new ItemCountWindowFunction()); // 第二阶段:按窗口标识做全局排序,输出TopN DataStream<TopNResult> topN = preAgg .keyBy(wc -> wc.getWinStart()) .process(new GlobalTopN(20));

这里需要解释一下GlobalTopN的实现思路。如果你直接写process全窗口函数,把所有局部计数拉到单并行度,效果等同于AllWindowFunction,性能没有优化。所以“局部TopN”的关键优化点在于:在第二阶段的全局排序前,先在下游每个并行度内各自取前N个,只把候选结果广播到单并行度做最终合并。这样全局排序节点的输入规模从“所有item数”降为“并行度 × N × 窗口个数”,量级大幅下降。

具体实现上,GlobalTopN可以维护一个TreeMap或优先队列,key是计数,value是itemId列表。每来一条ItemCount,先插入本地缓存,如果缓存大小超过N就把最小的一条淘汰。窗口结束时,把所有并行度传来的局部候选归并排序,输出前N条。注意TreeMap要按计数倒序排列,同时要把窗口标识作为状态的key,防止不同窗口的数据互相干扰。

两阶段聚合的顺序问题也要强调:SQL写法中ROW_NUMBER的OVER (PARTITION BY win_start)是把窗口作为分区,这样局部TopN是发生在每个窗口分区的并行子任务上的。DataStream写法里,第一阶段按item_id聚合,第二阶段按win_start聚合。两次KeyBy的key不同,这个细节必须清楚,很多人写错成一直按item_id,导致第二阶段无法汇总。

还有一种写法是用windowAll配合定时器,在单并行度上维护一个全窗口的排序状态。这个写法最简单,但单节点压力大,只建议用于每秒几百条的低流量场景。流量稍大,老老实实走两阶段。

3.3 状态与内存:TTL和Checkpoint配置

TopN本身计算不复杂,复杂的是状态。窗口聚合的中间状态、TopN缓存的候选数据、以及消费位点,全部依赖状态后端。生产环境我建议用RocksDB,原因是它把大状态存到本地磁盘,可以突破JVM堆内存限制;不过RocksDB的读写有序列化开销,每次keyBy读写状态会变慢。如果状态量不大,比如候选item数在万级以内,直接用它默认的内存状态后端更省事。

状态TTL要特别设置。窗口聚合之后,状态里会积累大量历史窗口的key,如果不设置过期时间,一段时间后状态只会越滚越大。Flink的StateTtlConfig可以按窗口长度设置,比如窗口5分钟、Watermark延迟10秒,TTL可以设15分钟到30分钟,既保证窗口数据不提前过期,又不让旧key长期占用空间。代码大概是这样:

StateTtlConfig ttlConfig = StateTtlConfig .newBuilder(Time.minutes(30)) .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite) .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired) .build();

另外开启增量Checkpoint和本地恢复会缩短故障恢复时间,对线上热榜这种持续输出的任务很重要。核心还是在状态后端和TTL上,这两个点做好了,内存和恢复问题能解决一大半。

4. 实战中常见的坑与排查技巧

最后聊几个我在真实debug中见到的典型问题,都不算冷门,但踩的人真不少。

4.1 热点Key导致倾斜:怎么压住单节点压力

真实场景里,某个爆款内容的浏览量会突然冲到其他内容的上百倍。如果第一阶段按item_id keyBy,那这单个key所在子任务就会变成瓶颈,表现为整个任务的背压集中在某一个子任务,其他节点都很空闲。

解决办法通常有三个。一是对key加随机后缀拆分,比如把item_id拆成item_id_0到item_id_99,在窗口聚合时先按拆分key聚合,再合并回原始item_id;这套方案能显著缓解热点key的写放大,但代价是多一轮聚合,SQL里要写子查询或者用双聚合改造。二是调整并行度和分区策略,把热点key的数据打散到不同的子任务,但要保证同一窗口内同一item的计数最终能合并,所以拆key的逻辑要设计在业务层,而不是简单换分区器。三是给热点item单独设置采样或限流,比如对超大key做抽样式计数再乘以系数做近似值,适合对精确性要求不高的场景。

实际项目中我建议优先方法一。它最通用,而且Flink的窗口状态天然能处理拆分后的key,只需要在窗口函数里再把随机后缀去掉做一次merge。比如聚合的中间结果key里带上随机后缀,窗口输出前用item_id本身做一次GroupBy,这样热点数据会被摊到多个子任务,最终结果不受影响。

4.2 滑动窗口重复计算与去重

滑动窗口下,同一个item在多个窗口里重复出现并输出,这个不是bug,是语义。但如果业务方要求“同一个内容在榜单里只能出现一次”,或者去重口径不是以窗口而是以活跃周期来算,就需要额外处理。

最常见的是按点击用户去重:同一用户1分钟内反复点击同一个item,热度只计一次。Flink SQL可以在窗口聚合前用COUNT(DISTINCT user_id)处理,但要注意COUNT DISTINCT在流式场景下要维护用户的去重状态,内存开销很大。高频大促场景建议用近似去重代替,比如用APPROX_COUNT_DISTINCT函数,它内部是基于HyperLogLog实现的,时效和内存都比精确计数好很多,误差通常在1%以内,热榜这种展示型场景完全够用。

榜单展示层的去重则比较简单,下游Sink写成upsert模式,按item_id覆盖写最新计数,就可以避免同一个item出现在多条记录里。

4.3 热榜不更新或数据不准的排查路径

现象一:榜单一直不输出。优先查水位线是不是没涨。很多情况是源表里没有声明WATERMARK,或者上游某个慢分区长时间不发送事件,导致整个算子的Watermark停住。可以打开Web UI看Watermark进度,如果停在某个时间点不动,基本就是这个原因,处理办法是给源表增加空闲检测,或者定期发送一条Punctuated Watermark来推动水位线。

现象二:数字比离线少很多。大概率是Watermark延迟太短,部分迟到数据进了侧输出没参与计算,可以看一下侧输出流的条数占比来确认。我见过一个case,日志链路有一层代理会重试上报,导致30%的数据延迟超过10秒,跟业务确认后Watermark延迟从5秒调到了30秒,偏低的数字才恢复正常。

现象三:某个子任务内存暴涨。通常是滑动窗口切片太多或状态TTL没设,按前面说的调小步长、配置StateTtl来解决。排查时最好先在Sink端把原始窗口的明细日志打出来,比对几条数据就能定位是窗口问题还是聚合问题,不要一上来就猜状态后端。

现象可能原因排查/修改建议
榜单不输出Watermark未推进查看Web UI Watermark进度,开启空闲源检测或周期Watermark
榜单纯度偏低迟到数据被丢弃查看侧输出流数量,调整Watermark延迟或等待时间
单节点背压明显热点key造成倾斜加随机后缀拆分key,降低单key压力
内存持续上涨滑动窗口切片过多或TTL未配置减少滑动步长,配置StateTtl,必要时切换RocksDB
结果飘忽不定窗口重叠且无平滑增加平滑策略或调整窗口参数
恢复后数据错乱Checkpoint周期过长或状态后端配置不当缩短Checkpoint间隔,开启本地恢复

最后分享一点经验:实时热榜这类需求,最容易翻车的地方往往不是Flink语法,而是窗口语义和业务口径没有对齐。需求方说“实时”,你一定要追问一句“多实时、准不准、可不可以容忍几秒延迟”,把这几个问题确认清楚,窗口参数自然就定下来了。我个人在落地时习惯先用SQL把链路跑通,把窗口、水位线、结果输出都验证一轮,再根据性能瓶颈决定要不要改造成DataStream模型。这样即使后续要换窗口步长、加去重规则,底层思路也不用推倒重来。希望能给你的实时热榜开发省下一些试错时间。

相关新闻

Cornell抓取数据集txt转pcd全流程:从2D标注到3D可执行姿态

Cornell抓取数据集txt转pcd全流程:从2D标注到3D可执行姿态

1. 项目概述&#xff1a;为什么康奈尔抓取检测数据集至今仍是点云理解的“教科书级”起点 如果你正在做机器人抓取规划、6D位姿估计&#xff0c;或者刚入门三维视觉方向&#xff0c;大概率绕不开Cornell Grasp Detection Dataset——这个2013年发布的经典数据集&#xff0c;至今…

2026/10/20 17:16:45 阅读更多 →
基于SSM+Vue的连锁驾校管理系统设计与实现

基于SSM+Vue的连锁驾校管理系统设计与实现

2. 项目概述作为一个经历过毕业设计全流程的过来人&#xff0c;我深知选题阶段有多纠结。市面上千篇一律的图书管理系统、商城系统已经让导师审美疲劳&#xff0c;而真正能体现技术含量、又能结合实际业务场景的题目就那么几个。今天分享的这个题目——“驾考新时代&#xff1a…

2026/10/20 17:16:45 阅读更多 →
边缘计算网关EG20实战:从Modbus采集到MQTT上云

边缘计算网关EG20实战:从Modbus采集到MQTT上云

1. 项目概述与核心价值 1.1 边缘计算网关到底在解决什么问题 去年我在做一个产线数据采集项目时&#xff0c;甲方提了一个看似简单的要求&#xff1a;把车间里几十台不同品牌的PLC数据统一采集上来&#xff0c;同时还要做本地报警、数据清洗和断网续传。当时我第一反应是上一台…

2026/10/20 17:16:45 阅读更多 →

最新新闻

基于51单片机的PM2.5检测仪DIY:从传感器选型到标定实战

基于51单片机的PM2.5检测仪DIY:从传感器选型到标定实战

大概半年前&#xff0c;我在朋友家里看到新买的空气净化器&#xff0c;屏幕上那个不断跳动的PM2.5数值让我有点出神&#xff1a;一个小方盒子就能感知空气中看不见的颗粒物&#xff0c;这套系统如果拆出来&#xff0c;能不能用最简单的单片机和传感器自己搭一套&#xff1f;于是…

2026/10/20 18:04:15 阅读更多 →
OpenCV边缘检测对比:Laplacian算子与Canny实战指南

OpenCV边缘检测对比:Laplacian算子与Canny实战指南

最近在整理一批图像处理的入门案例&#xff0c;正好做到边缘检测这一块。很多人接触OpenCV的边缘检测时&#xff0c;第一反应都是直接用cv2.Canny()。这没什么问题&#xff0c;Canny确实是最常用的&#xff0c;但如果你只会Canny&#xff0c;遇到一些问题就容易抓瞎——比如想快…

2026/10/20 18:04:15 阅读更多 →
C# RFID读卡器方案:串口通信与M1卡读写实战

C# RFID读卡器方案:串口通信与M1卡读写实战

简介&#xff1a;这份基于C#的RFID卡识别与读写示例工程&#xff0c;面向需要开发RFID应用的.NET开发者&#xff0c;覆盖设备连接、事件驱动编程、数据解析、读写操作与错误处理等完整流程&#xff0c;可应用于门禁系统、物流跟踪、商品防伪等场景。工程共29个文件&#xff0c;…

2026/10/20 18:04:15 阅读更多 →
Browser-use 与 Playwright-MCP 深度对比:浏览器自动化 Agent 框架与工具协议层的选型指南

Browser-use 与 Playwright-MCP 深度对比:浏览器自动化 Agent 框架与工具协议层的选型指南

1. 从两个真实场景说起&#xff1a;为什么"浏览器自动化"突然分成了两条路去年下半年到现在&#xff0c;我陆续在三个不同类型的项目里用到了浏览器自动化&#xff1a;一个是帮运营团队做竞品价格监控&#xff0c;一个是给内部知识库做网页内容采集&#xff0c;还有一…

2026/10/20 18:04:15 阅读更多 →
Windows流媒体服务端实战:RTSP拉流转HLS与低延迟调优

Windows流媒体服务端实战:RTSP拉流转HLS与低延迟调优

简介&#xff1a;EasyDarwin是一款基于标准HTTP/RTSP协议的开源流媒体服务器&#xff0c;这份Windows x86_64平台的v7.3.17.0325压缩包面向需要快速搭建视频直播、监控或转码服务的开发者和运维人员&#xff0c;也适合通过实际部署学习流媒体协议的学生与初级工程师。资源共135…

2026/10/20 18:04:15 阅读更多 →
Jetpack Compose实现裸眼3D:传感器驱动+视差多层位移全攻略

Jetpack Compose实现裸眼3D:传感器驱动+视差多层位移全攻略

最近在某房产App上看到头部banner的裸眼3D效果&#xff0c;第一反应是这里用了“视差滚动传感器驱动”的组合玩法。这个效果在原生Android端有过不少实现&#xff0c;但在Jetpack Compose里怎么落地&#xff0c;网上完整资料并不多。我花了一个周末把仿自如裸眼3D效果的Compose…

2026/10/20 18:03:13 阅读更多 →

日新闻

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 阅读更多 →