DeepSeek总结的 Iceberg 表里面有什么
Iceberg 表里面有什么2026-10-13 12 分钟阅读DuckDB 团队TL;DR一个 Iceberg 表是一棵由 JSON、Avro 和 Parquet 文件组成的树。DuckDB 可以读取其中每一种文件所以你可以用 SQL 自己遍历这棵树从元数据文件经过清单列表和清单一直到数据文件和删除文件。Apache Iceberg 表在你查询它时看起来像一张普通表但在底层它是一棵由文件组成的小树顶部一个 JSON 文件中间几层 Avro 文件底部是 Parquet 文件。当某些东西慢或者看起来不对时了解这棵树里有什么会有帮助。DuckDB 可以读取所有三种格式所以你可以用普通 SQL 检查每一层。在本文中我们创建一个小 Iceberg 表修改它几次然后从上到下遍历这些文件。开始你需要带有 iceberg 扩展的 DuckDB以及一个要连接的 Iceberg REST catalog。catalogs 页面有关于 Apache Polaris、Lakekeeper 和 Amazon S3 Tables 等 catalog 的说明。需要 catalog 是因为文件本身无法告诉你哪个版本的表是当前的。Iceberg 表在每次变更时写入一个新的 metadata.json并且从不覆盖旧的。catalog 持有唯一一块可变状态指向当前元数据文件的指针。当你查询表时DuckDB 首先向 catalog 询问那个指针然后从那里沿着文件树向下走。在本文中我们在本地运行一个 catalog使用 Iceberg REST catalog fixture这是 Iceberg 项目作为 Docker 镜像发布的一个小型参考 catalog。它是最容易设置的 catalog它从单个镜像运行不需要 Cloud 账户不需要认证并把所有东西保存在本地磁盘上你可以自己打开这些文件。我们这样启动它dockerrun-p8181:8181\-v/data/lake:/data/lake\-eCATALOG_WAREHOUSE/data/lake\apache/iceberg-rest-fixture该命令的每一部分都对应 DuckDB 之后依赖的某个东西-p 8181:8181在 localhost:8181 上发布 catalog 的 REST API这是 DuckDB 连接的地址。-v /data/lake:/data/lake把主机目录挂载到容器中这样元数据、清单和 Parquet 文件在容器停止后仍然存在你可以直接读取它们。-e CATALOG_WAREHOUSE/data/lake告诉 catalog 把这些文件写到哪里这就是为什么下面输出中的每个路径都以 /data/lake 开头。注意在本地 DuckDB CLI 中运行下面的示例而不是在基于浏览器的 DuckDB Shell 中因为从 Web 提供的页面无法访问你自己 localhost 上的 catalog。fixture 运行后这样连接它ATTACHwarehouseASlake(TYPEiceberg,ENDPOINThttp://localhost:8181,AUTHORIZATION_TYPEnone);这会打开一个名为 lake 的 catalog 连接你可以像任何已连接的数据库一样查询它。TYPE iceberg告诉 DuckDB 使用 Iceberg REST 协议。ENDPOINT是上面-p标志发布的地址。AUTHORIZATION_TYPE none匹配 fixture它不需要凭据。第一个参数是仓库名称。fixture 提供单个仓库所以任何名称都行。使用对象存储时下面输出中的路径以s3://开头而不是/data/lake但其他一切相同。一个有历史的表我们创建一张按日期分区的列车服务表并修改它三次插入三天数据、插入第四天、一次删除。CREATESCHEMAlake.demo;CREATETABLElake.demo.services(service_idBIGINT,service_dateDATE,stationVARCHAR,delay_minINTEGER)PARTITIONEDBY(service_date);INSERTINTOlake.demo.servicesSELECTi,DATE2026-10-01(i%3)::INTEGER,[Utrecht Centraal,Delft,Leiden Centraal][1(i%3)::INTEGER],(i%9)::INTEGERFROMrange(1,9_001)t(i);INSERTINTOlake.demo.servicesSELECTi,DATE2026-10-04,Den Haag HS,(i%5)::INTEGERFROMrange(9_001,12_001)t(i);DELETEFROMlake.demo.servicesWHEREservice_dateDATE2026-10-02ANDdelay_min4;两次插入和删除各自独立提交。一次写入不会原地改变表DuckDB 读取当前快照在旧文件旁边写入新的数据和元数据文件然后要求 catalog 把表指针从那个快照移动到新快照。那个移动就是提交。提交会命名它期望替换的快照所以两个从同一快照开始的写入者不能都成功。第一个提交移动指针第二个被拒绝因为它想替换的快照不再是当前的。被拒绝的写入然后在新快照之上重试。从单个会话按顺序运行时这里的三个语句从不冲突因为每一个都从前一个提交的快照开始。表现在有 11,000 行第一次插入增加了 9,000第二次增加了 3,000删除移除了 10 月 2 日延迟为 4 分钟的 1,000 行。三个语句各自创建了一个新快照iceberg_snapshots 列出如下SELECTsequence_number,snapshot_id,operationFROMiceberg_snapshots(lake.demo.services)ORDERBYsequence_number;┌─────────────────┬─────────────────────┬───────────┐ │ sequence_number │ snapshot_id │ operation │ │ uint64 │ uint64 │ varchar │ ├─────────────────┼─────────────────────┼───────────┤ │ 1 │ 7523747767380427861 │ append │ │ 2 │ 3062515218093523051 │ append │ │ 3 │ 6456433563311493009 │ delete │ └─────────────────┴─────────────────────┴───────────┘这棵树在逐层讲解之前这里是整个结构。每一层指向它下面一层的文件metadata.json 每个表版本一个 └── manifest list (Avro) 每个快照一个 └── manifests (Avro) 在我们的情况下每次写入一个 ├── data files (Parquet) └── delete files (Parquet)所有这些文件都是不可变的。每次变更写入新文件和一个新的 metadata.json然后通过把 catalog 指针移动到它来提交。第 1 层元数据文件catalog 为每个表存储一个指针当前元数据文件的位置。iceberg_load_table_response 返回 DuckDB 加载表时 catalog 发回的内容包括那个位置SELECTmetadata_locationFROMiceberg_load_table_response(lake.demo.services);┌────────────────────────────────────────────────────────────────────────────────────────────┐ │ metadata_location │ │ varchar │ ├────────────────────────────────────────────────────────────────────────────────────────────┤ │ /data/lake/demo/services/metadata/00003-b79b5ffd-f118-44fd-9d8e-3551c147ef3b.metadata.json │ └────────────────────────────────────────────────────────────────────────────────────────────┘文件名以 00003 开头因为这是元数据的第四个版本从表创建时的 00000 算起。它是一个 JSON 文档所以 read_json 可以读取它。我们把位置存到一个变量中以保持查询简短SETVARIABLE metadata_file(SELECTmetadata_locationFROMiceberg_load_table_response(lake.demo.services));SELECTformat-version,current-snapshot-id,len(snapshots)ASsnapshots,len(metadata-log)ASprevious_metadata_filesFROMread_json(getvariable(metadata_file));┌────────────────┬─────────────────────┬───────────┬─────────────────────────┐ │ format-version │ current-snapshot-id │ snapshots │ previous_metadata_files │ │ int64 │ int64 │ int64 │ int64 │ ├────────────────┼─────────────────────┼───────────┼─────────────────────────┤ │ 2 │ 6456433563311493009 │ 3 │ 3 │ └────────────────┴─────────────────────┴───────────┴─────────────────────────┘除了 schema 和分区规范元数据文件还持有所有仍然存在的快照列表每个快照都有一个带计数器的摘要。这些计数器是一种廉价的方式可以看到每次变更做了什么而无需读取任何数据SELECTs.sequence-numberASseq,s.summary.operation,s.summary.added-records,s.summary.added-position-deletes,s.summary.total-records,s.summary.total-data-files,s.summary.total-delete-filesFROM(SELECTunnest(snapshots)ASsFROMread_json(getvariable(metadata_file)))ORDERBYseq;┌───────┬───────────┬───────────────┬────────────────────────┬───────────────┬──────────────────┬────────────────────┐ │ seq │ operation │ added-records │ added-position-deletes │ total-records │ total-data-files │ total-delete-files │ │ int64 │ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │ ├───────┼───────────┼───────────────┼────────────────────────┼───────────────┼──────────────────┼────────────────────┤ │ 1 │ append │ 9000 │ NULL │ 9000 │ 3 │ 0 │ │ 2 │ append │ 3000 │ NULL │ 12000 │ 4 │ 0 │ │ 3 │ delete │ NULL │ 1000 │ 12000 │ 4 │ 1 │ └───────┴───────────┴───────────────┴────────────────────────┴───────────────┴──────────────────┴────────────────────┘在最后一行删除之后total-records 仍然是 12,000仍然有四个数据文件。删除没有碰数据文件。它添加了一个有 1,000 个条目的删除文件。我们稍后会讲到那个文件。注意Iceberg 规范把这些摘要字段视为可选的所以引擎可以自由地省略其中任何一个。上面的计数器由 DuckDB 填充但由另一个引擎写入的表可能缺少其中一些在这种情况下该字段读作 NULL。把它们当作方便的提示而不是保证。提示元数据文件随着每次提交增长因为它保留快照列表和先前元数据文件的日志。在一个接收数千次小提交的表上它可能变得大到足以减慢表的加载。过期旧快照——大多数 catalog 和引擎都能做——会让它保持受控。第 2 层清单列表每个快照指向一个清单列表一个 Avro 文件列出构成该快照的清单。avro 扩展用 read_avro 读取它。我们取最新快照的清单列表SETVARIABLE manifest_list(SELECTmanifest_listFROMiceberg_snapshots(lake.demo.services)ORDERBYsequence_numberDESCLIMIT1);SELECTregexp_replace(manifest_path,.*/metadata/,)ASmanifest,content,sequence_number,added_files_count,added_rows_countFROMread_avro(getvariable(manifest_list));┌──────────────────────────────────────────────┬─────────┬─────────────────┬───────────────────┬──────────────────┐ │ manifest │ content │ sequence_number │ added_files_count │ added_rows_count │ │ varchar │ int32 │ int64 │ int32 │ int64 │ ├──────────────────────────────────────────────┼─────────┼─────────────────┼───────────────────┼──────────────────┤ │ ffbf7076-8d36-46f0-aaa2-76e7d95442f0-m0.avro │ 0 │ 1 │ 3 │ 9000 │ │ 74fa5b1f-0908-4e34-964a-504d946671de-m0.avro │ 0 │ 2 │ 1 │ 3000 │ │ 5282235d-42b4-4b5d-a190-147a867994b7-m0.avro │ 1 │ 3 │ 1 │ 1000 │ └──────────────────────────────────────────────┴─────────┴─────────────────┴───────────────────┴──────────────────┘每次写入有一个清单。content 对跟踪数据文件的清单是 0对跟踪删除文件的清单是 1。清单列表还存储每个清单中分区值的范围这里未显示所以当查询按分区列过滤时读取器可以跳过整个清单。最新快照仍然包括两个较早快照写入的清单。新快照重用任何未改变的东西。这就是提交廉价的原因也是为什么有许多小提交的表最终会有许多小清单。第 3 层清单清单列出实际文件每个文件一个条目带有分区值、行数和每列统计。它们也是 AvroSELECTstatus,data_file.content,regexp_replace(data_file.file_path,.*/data/,)ASfile,data_file.record_count,data_file.partitionFROMread_avro(/data/lake/demo/services/metadata/*-m*.avro)ORDERBYfile;┌────────┬─────────┬──────────────────────────────────────────────────────────────────────────────┬──────────────┬─────────────────────────────────────────┐ │ status │ content │ file │ record_count │ partition │ │ int32 │ int32 │ varchar │ int64 │ struct(identity_service_date_2 date) │ ├────────┼─────────┼──────────────────────────────────────────────────────────────────────────────┼──────────────┼─────────────────────────────────────────┤ │ 1 │ 0 │ service_date2026-10-01/01a12bb2-ad80-7cf4-8f63-beee9619f7c0.parquet │ 3000 │ {identity_service_date_2: 2026-10-01} │ │ 1 │ 0 │ service_date2026-10-02/01a12bb2-ad7f-7690-bda8-690b622b119a.parquet │ 3000 │ {identity_service_date_2: 2026-10-02} │ │ 1 │ 1 │ service_date2026-10-02/58a752c7-9925-4add-99ca-785505e17589-deletes.parquet │ 1000 │ {identity_service_date_2: 2026-10-02} │ │ 1 │ 0 │ service_date2026-10-03/01a12bb2-ad80-71f7-b4cd-58684f05b129.parquet │ 3000 │ {identity_service_date_2: 2026-10-03} │ │ 1 │ 0 │ service_date2026-10-04/01a12bb2-adbe-790f-bde9-50db3acba4b2.parquet │ 3000 │ {identity_service_date_2: 2026-10-04} │ └────────┴─────────┴──────────────────────────────────────────────────────────────────────────────┴──────────────┴─────────────────────────────────────────┘status 1 意味着该文件是在写入该清单的快照中添加的。content 对数据文件是 0对位置删除文件是 1。分区值是按文件存储的这就是让读取器无需打开文件就能跳过文件的原因。扩展有一个为你做这件事的函数。iceberg_metadata 沿着当前快照经过清单列表和清单每个文件返回一行SELECTmanifest_content,regexp_replace(file_path,.*/data/,)ASfile,record_countFROMiceberg_metadata(lake.demo.services)ORDERBYfile;┌──────────────────┬──────────────────────────────────────────────────────────────────────────────┬──────────────┐ │ manifest_content │ file │ record_count │ │ varchar │ varchar │ int64 │ ├──────────────────┼──────────────────────────────────────────────────────────────────────────────┼──────────────┤ │ DATA │ service_date2026-10-01/01a12bb2-ad80-7cf4-8f63-beee9619f7c0.parquet │ 3000 │ │ DATA │ service_date2026-10-02/01a12bb2-ad7f-7690-bda8-690b622b119a.parquet │ 3000 │ │ DELETE │ service_date2026-10-02/58a752c7-9925-4add-99ca-785505e17589-deletes.parquet │ 1000 │ │ DATA │ service_date2026-10-03/01a12bb2-ad80-71f7-b4cd-58684f05b129.parquet │ 3000 │ │ DATA │ service_date2026-10-04/01a12bb2-adbe-790f-bde9-50db3acba4b2.parquet │ 3000 │ └──────────────────┴──────────────────────────────────────────────────────────────────────────────┴──────────────┘直接读取 Avro 文件在你想看到函数不返回的字段时很有用或者在你看一个较旧快照或一个不在 catalog 中的表时。列统计清单还为每个数据文件存储每一列的下界和上界。iceberg_column_stats 以可读形式返回它们SELECTcolumn_name,regexp_replace(file_path,.*/data/,)ASfile,lower_bound,upper_boundFROMiceberg_column_stats(lake.demo.services)WHEREcolumn_nameservice_idORDERBYfile;┌─────────────┬──────────────────────────────────────────────────────────────────────────────┬─────────────┬─────────────┐ │ column_name │ file │ lower_bound │ upper_bound │ │ varchar │ varchar │ varchar │ varchar │ ├─────────────┼──────────────────────────────────────────────────────────────────────────────┼─────────────┼─────────────┤ │ service_id │ service_date2026-10-01/01a12bb2-ad80-7cf4-8f63-beee9619f7c0.parquet │ 3 │ 9000 │ │ service_id │ service_date2026-10-02/01a12bb2-ad7f-7690-bda8-690b622b119a.parquet │ 1 │ 8998 │ │ service_id │ service_date2026-10-02/58a752c7-9925-4add-99ca-785505e17589-deletes.parquet │ NULL │ NULL │ │ service_id │ service_date2026-10-03/01a12bb2-ad80-71f7-b4cd-58684f05b129.parquet │ 2 │ 8999 │ │ service_id │ service_date2026-10-04/01a12bb2-adbe-790f-bde9-50db3acba4b2.parquet │ 9001 │ 12000 │ └─────────────┴──────────────────────────────────────────────────────────────────────────────┴─────────────┴─────────────┘这些边界是 DuckDB 在你过滤一个不是分区列的列时用来跳过文件的东西。一个带 WHERE service_id 10000 的查询只需要打开 10 月 4 日的文件因为其他三个文件的边界排除了它们。前三天的范围几乎完全重叠因为行是轮转分散到各天的。按常被过滤的列的顺序写入的数据会得到更窄的边界和更多的跳过。分区统计上面的边界是每列、每个数据文件的。对于分区列有一个更粗的视图每个清单一行清单列表保留它以便读取器在打开任何文件之前跳过整个清单。iceberg_partition_stats 返回它SELECTpartition_field_name,partition_field_transform,lower_bound,upper_boundFROMiceberg_partition_stats(lake.demo.services)ORDERBYlower_bound;┌─────────────────────────┬───────────────────────────┬─────────────┬─────────────┐ │ partition_field_name │ partition_field_transform │ lower_bound │ upper_bound │ │ varchar │ varchar │ varchar │ varchar │ ├─────────────────────────┼───────────────────────────┼─────────────┼─────────────┤ │ identity_service_date_2 │ identity │ 2026-10-01 │ 2026-10-03 │ │ identity_service_date_2 │ identity │ 2026-10-02 │ 2026-10-02 │ │ identity_service_date_2 │ identity │ 2026-10-04 │ 2026-10-04 │ └─────────────────────────┴───────────────────────────┴─────────────┴─────────────┘每个清单一行所以边界追踪三次写入第一次插入把三天分散在一个清单中第二次插入添加了 10 月 4 日删除只碰了 10 月 2 日。partition_field_transform 是 identity因为我们直接按日期列分区。一个带 WHERE service_date DATE ‘2026-10-04’ 的查询可以仅凭这些边界排除第一个和第三个清单而不读取任何清单条目。第 4 层数据文件和删除文件树的底部是 Parquet 文件。数据文件是任何读取器都能打开的常规 Parquet。删除文件的工作方式不同。它是一个位置删除文件按文件和行位置列出要忽略的行SELECTregexp_replace(file_path,.*/data/,)ASdata_file,posFROMread_parquet(/data/lake/demo/services/data/*/*-deletes.parquet,hive_partitioningfalse)ORDERBYposLIMIT5;┌──────────────────────────────────────────────────────────────────────┬───────┐ │ data_file │ pos │ │ varchar │ int64 │ ├──────────────────────────────────────────────────────────────────────┼───────┤ │ service_date2026-10-02/01a12bb2-ad7f-7690-bda8-690b622b119a.parquet │ 1 │ │ service_date2026-10-02/01a12bb2-ad7f-7690-bda8-690b622b119a.parquet │ 4 │ │ service_date2026-10-02/01a12bb2-ad7f-7690-bda8-690b622b119a.parquet │ 7 │ │ service_date2026-10-02/01a12bb2-ad7f-7690-bda8-690b622b119a.parquet │ 10 │ │ service_date2026-10-02/01a12bb2-ad7f-7690-bda8-690b622b119a.parquet │ 13 │ └──────────────────────────────────────────────────────────────────────┴───────┘这就是扩展实现 DELETE 和 UPDATE 的方式它不碰数据文件而是记录被删除行的位置这种策略叫做 merge-on-read。然后每个读取器都必须合并两个文件才能得到正确的行。写入廉价读取付出一个小成本它随删除文件数量增长。我们设置 hive_partitioning false因为否则 service_date… 目录会被添加为一个额外的列。对于 format-version 3 的表同样的信息存储为 Puffin 文件中的紧凑二进制删除向量而不是 Parquet 文件。到底为什么要看这个大多数时候你不需要。FROM lake.demo.services 返回正确的 11,000 行扩展处理这棵树。当某些东西不像你预期的那样表现时它就有用了一个查询读取的文件比你预期的多。把清单中的分区值和列边界与你的过滤器比较。一个表随时间变慢。统计清单和删除文件。许多小提交和许多删除都会添加每个查询都必须处理的文件。行数看起来不对。快照摘要显示每次提交添加和删除了多少行。另一个引擎写了这个表。清单显示它写了什么包括 DuckDB 不使用的属性。由于每一层都是 DuckDB 已经能读取的格式的文件你可以用查询数据的同一个工具回答这些问题。进一步阅读DuckDB-Iceberg 中的写入浏览器中的 Icebergv1.5.3 中新的 DuckDB-Iceberg 功能

相关新闻

ShopXO商城中 hls.js 集成解析:基于 CKPlayer 播放 m3u8 流媒体的完整指南

ShopXO商城中 hls.js 集成解析:基于 CKPlayer 播放 m3u8 流媒体的完整指南

电商后端 【免费下载链接】ShopXO开源商城 🔥🔥🔥ShopXO企业级免费开源商城系统,可视化DIY拖拽装修、包含PC、H5、多端小程序(微信支付宝百度头条&抖音QQ快手)、APP、多仓库、多商户、多门店、IM客服、进销存,遵循…

2026/10/15 2:07:13 阅读更多 →
技术英语词汇精讲:evaluation —— 程序员语境下的“评价、计算“

技术英语词汇精讲:evaluation —— 程序员语境下的“评价、计算“

教程 【免费下载链接】most-frequent-technology-english-words 程序员工作中常见的英语词汇 项目地址: https://gitcode.com/gh_mirrors/mo/most-frequent-technology-english-words 点击查看 免费下载 在英语技术文档、代码评审和机器学习项目中,eval…

2026/10/15 2:07:13 阅读更多 →
Flink 自定义序列化器优化:用 POJO 替代 Kryo 降低序列化 CPU 损耗

Flink 自定义序列化器优化:用 POJO 替代 Kryo 降低序列化 CPU 损耗

在分布式流计算引擎 Flink 的高并发调优中,有一个极其隐蔽、却经常吞噬集群超过 40% CPU 算力 的“性能刺客”——序列化与反序列化(Serialization & Deserialization, 简称 SerDe)。 很多团队在双 11 或大促前夕进行全链路压测时&#x…

2026/10/15 2:07:13 阅读更多 →

最新新闻

IDEA 2025.3 新功能实战:多光标、调试数据流与临时文件提升编码效率

IDEA 2025.3 新功能实战:多光标、调试数据流与临时文件提升编码效率

IDEA 2025.3 的更新日志刚出来那会儿,我真没当回事,毕竟每个大版本都爱说“更快、更智能、更好用”。直到上周把开发环境从旧版本升上来,试了一圈新功能,才意识到这波“骚操作”是真的多,甚至有点跟不上了。这篇文章不…

2026/10/15 4:27:50 阅读更多 →
贝叶斯网络学习指南:从结构、参数到推断的完整实践

贝叶斯网络学习指南:从结构、参数到推断的完整实践

简介:《贝叶斯网络学习指南》是一份面向机器学习、概率建模与数据科学初学者的PDF电子书,系统覆盖从概率论基础到贝叶斯网络建模、推理与参数学习的完整知识链。全书从概率函数与空间、条件概率与独立性、贝叶斯定理、随机变量及联合概率分布讲起&#x…

2026/10/15 4:27:50 阅读更多 →
STM32F072C8T6裸机开发实战:从寄存器到USB/CAN外设

STM32F072C8T6裸机开发实战:从寄存器到USB/CAN外设

简介:这份资料面向嵌入式初学者与有一定经验的开发者,围绕意法半导体STM32F072C8T6(ARM Cortex-M0内核、48MHz主频、32KB闪存与2KB RAM)学习板展开,帮助读者快速掌握该芯片的初始化配置、中断处理、内存管理及驱动编写…

2026/10/15 4:27:50 阅读更多 →
C/C++不同位数数据互转的进制转换实现与避坑指南

C/C++不同位数数据互转的进制转换实现与避坑指南

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

2026/10/15 4:27:50 阅读更多 →
NC65销售订单批量导入全攻略:从模板准备到成功入库的避坑指南

NC65销售订单批量导入全攻略:从模板准备到成功入库的避坑指南

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

2026/10/15 4:27:50 阅读更多 →
Linux下C/C++动静态库制作与使用实战指南

Linux下C/C++动静态库制作与使用实战指南

长期以来在Linux下做C/C开发,动静态库始终是绕不开的一个核心技能。无论是自己封装模块、分发二进制产物,还是处理第三方依赖,理解库的制作与使用直接决定了你在编译链接这块能不能少掉头发。我见过不少开发者写业务逻辑很熟练,一…

2026/10/15 4:26:50 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →