7个可调试Hadoop MapReduce实战项目:从WordCount到PageRank
简介本资源是一套基于Hadoop生态的分布式开发实战项目集面向计算机、人工智能、通信工程等专业的在校学生、教师及初学者助力掌握MapReduce编程模型与HBase、HDFS核心组件的工程实践能力。包内含7个完整可运行项目KMeans与KMeans聚类、TF-IDF文本分析、大矩阵乘法、MapReduce基础Demo、HBase与HDFS客户端操作全部经实机测试通过答辩平均分96分适合作为课程设计、毕设参考或进阶学习脚手架。资源共1045个文件以63个Java源码为主干辅以861个Jar依赖库、75个Class编译文件及README.md等配置说明整体压缩包371.65MB结构清晰、模块独立便于按需调试与二次开发。已有224人下载学习提供远程教学支持代码注释充分、文档完备覆盖从环境搭建、任务提交到结果验证的全流程实践要点。1. 七个可跑、可调、可 debug 的 Hadoop 实战项目从 WordCount 到 PageRank为什么你学了三个月还写不出能上线的 MapReduce 作业很多人卡在“Hadoop 入门”这道坎上不是因为不会搭伪分布式环境而是——环境跑通了代码 clone 下来了但一改逻辑就报ClassNotFoundException、NullPointerException或InputSplit分片异常连日志都看不懂。这篇笔记不讲 HDFS 架构图或 YARN 调度原理只聚焦一个事实你手头那套「基于 Hadoop 的开发项目包括分布式算法的实现和 Hadoop 项目总共七个项目源代码文档说明」本质是一套面向工程落地的「Hadoop 开发能力验证包」。它覆盖了真实业务中高频出现的五类场景文本统计WordCount、倒排索引InvertedIndex、共同好友CommonFriends、PageRank 迭代计算、TopK 热门词、MapSide Join 关联分析、以及基于 Combiner 的日志聚合优化。每个项目都含完整可编译的 Java 源码非 Maven 骨架空壳、带注释的core-site.xml/hdfs-site.xml配置片段、本地模式与集群模式双路径运行脚本以及一份直击痛点的README.md——比如明确告诉你“PageRank 项目默认迭代 10 轮若收敛慢请检查DoubleWritable初始化值是否为 0.0而非null”。适合刚配好 Hadoop 伪分布式环境、想用真实代码验证自己 MapReduce 编程肌肉记忆的开发者也适合带新人的 Tech Lead直接把这七个目录扔进团队 GitLab作为 Code Review 的 baseline。2. 七个项目的选型逻辑与工程边界为什么不用 Spark为什么坚持原生 MapReduce2.1 为什么这七个全是 Java MapReduce而不是 Spark/Scala/Flink这不是技术守旧而是刻意回归 Hadoop 生态最硬核的执行层契约。Spark 抽象掉太多底层细节如 InputSplit 切分策略、Combiner 执行时机、Shuffle 中间文件压缩格式新手容易写出“本地跑得通、集群跑崩”的代码。而这七个项目的原始设计目标就是让你亲手踩一遍这些“看不见的坑”WordCount 项目强制要求你手动实现Partitioner控制 key 分布否则 reduce 端数据倾斜CommonFriends 项目必须用MultipleOutputs写出多路输出否则无法按用户 ID 分文件存储结果PageRank 项目依赖Job.setNumReduceTasks(1)强制单 reducer 汇总全局权重否则迭代收敛失效。提示所有项目均兼容 Hadoop 3.3.6主流生产版本不依赖任何第三方 jar如hadoop-client已打包进hadoop-common-3.3.6.jar。若你用的是 Hadoop 2.x请将org.apache.hadoop.mapreduce.lib.input.FileInputFormat.setInputDirRecursive()替换为setInputDirRecursive(false)这是 2.x 不支持的 API。2.2 七个项目的功能定位与输入/输出契约项目名核心算法输入格式输出格式典型用途是否含 Combinerwordcount单词频次统计文本行UTF-8word, count日志关键词提取✅invertedindex倒排索引构建doc_id, contentword, doc_id:offset搜索引擎前置处理❌需自定义TextArrayWritablecommonfriends图关系挖掘user, friend_listpair, mutual_friends社交推荐冷启动✅减少 shuffle 数据量pagerank迭代图算法page, outlinkspage, rank_score页面重要性评估❌迭代依赖全局状态topk局部 TopK 合并key, valuekey, top_k_values热门商品榜单生成✅map 端预筛mapsidejoinMap 端关联大表HDFS 小表DistributedCachejoin_key, joined_record用户画像标签关联✅避免 reduce join 瓶颈logaggregation日志聚合timestamp, log_level, msghour, level_count运维监控指标汇总✅压缩中间键值对注意所有项目输入路径统一约定为hdfs://localhost:9000/input/xxx/输出路径为hdfs://localhost:9000/output/xxx/。若你在虚拟机中部署需将localhost替换为宿主机 IP如192.168.56.1并在/etc/hosts中映射该 IP 到hadoop-master。2.3 源代码结构标准化为什么每个项目都有src/main/java/org/hadoop/exercise/xxx/这不是 Maven 强制规范而是为快速定位问题而设计的物理隔离。每个项目独立成模块非父子模块目录结构严格如下wordcount/ ├── pom.xml # 仅声明 hadoop-client 3.3.6 依赖无其他插件 ├── README.md # 含运行命令、预期输出样例、常见失败日志截断 ├── input/ # 本地测试用小样本≤10MB │ └── sample.txt ├── output/ # 运行后自动生成用于 diff 验证 ├── src/main/java/ │ └── org/hadoop/exercise/wordcount/ │ ├── WordCountMapper.java # 必含 Override protected void setup(Context) {...} │ ├── WordCountReducer.java # 必含 Override protected void cleanup(Context) {...} │ └── WordCountDriver.java # 主类含 setJarByClass() 和 waitForCompletion(true) └── config/ # 非必需但提供 hdfs-site.xml 片段供 copy-paste └── hdfs-site.xml.partial这种结构让你能直接cd wordcount mvn clean package生成target/wordcount-1.0.jar再用hadoop jar target/wordcount-1.0.jar org.hadoop.exercise.wordcount.WordCountDriver ...运行。没有隐藏的resources/目录没有动态加载的配置文件所有路径、参数、序列化方式全部硬编码在 Java 类中——这是为了让你在调试时一眼看清job.setOutputKeyClass(Text.class)和job.setOutputValueClass(IntWritable.class)是否匹配 reduce 输出类型。3. 本地模式与集群模式双路径运行如何用同一份代码在 Mac 笔记本和 3 节点集群上都跑通3.1 本地模式LocalRunner零依赖验证逻辑正确性本地模式不启动 HDFS/YARN所有读写走本地文件系统适合快速验证 Mapper/Reducer 逻辑。关键在于WordCountDriver.java中的配置// src/main/java/org/hadoop/exercise/wordcount/WordCountDriver.java public static void main(String[] args) throws Exception { Configuration conf new Configuration(); // ⚠️ 关键强制使用 LocalRunner禁用 YARN conf.set(mapreduce.framework.name, local); // ⚠️ 关键输入输出路径必须是 file:// 协议 conf.set(fs.defaultFS, file:///); Job job Job.getInstance(conf, word count local); job.setJarByClass(WordCountDriver.class); job.setMapperClass(WordCountMapper.class); job.setReducerClass(WordCountReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(input/sample.txt)); FileOutputFormat.setOutputPath(job, new Path(output/local)); System.exit(job.waitForCompletion(true) ? 0 : 1); }逻辑说明mapreduce.framework.namelocal让 MapReduce 运行时跳过 ResourceManager 连接直接调用LocalJobRunnerfs.defaultFSfile:///确保FileInputFormat读取本地文件而非 HDFS。此时hadoop jar命令实际等价于java -cp ... org.hadoop.exercise.wordcount.WordCountDriver。3.2 伪分布式模式Pseudo-Distributed单机模拟集群行为这是最常被忽略的中间态。很多教程直接教“三台虚拟机搭集群”但伪分布式才是暴露真实问题的黄金环境——它启用完整的 HDFS NameNode/DataNode、YARN ResourceManager/NodeManager但所有进程跑在同一台机器。你需要确保core-site.xml中fs.defaultFS指向hdfs://localhost:9000hdfs-site.xml中dfs.namenode.http-address设为localhost:9870Hadoop 3 默认执行hdfs namenode -format初始化元数据启动start-dfs.sh和start-yarn.sh上传输入文件hdfs dfs -mkdir -p /input/wordcount hdfs dfs -put input/sample.txt /input/wordcount/。运行命令变为hadoop jar target/wordcount-1.0.jar \ org.hadoop.exercise.wordcount.WordCountDriver \ hdfs://localhost:9000/input/wordcount \ hdfs://localhost:9000/output/wordcount参数说明hdfs://localhost:9000是 NameNode RPC 地址/input/wordcount是 HDFS 上的路径非本地路径waitForCompletion(true)会阻塞直到任务结束并打印 Map/Reduce 进度日志到控制台——这是你排查InputSplit问题的第一现场。3.3 真实集群模式只需改两处配置无需重写代码当你把代码部署到 3 节点集群master 2 slaves唯一需要修改的是core-site.xml中的fs.defaultFS和yarn.resourcemanager.hostname。假设集群 master IP 为192.168.10.10则core-site.xmlproperty namefs.defaultFS/name valuehdfs://192.168.10.10:9000/value /propertyyarn-site.xmlproperty nameyarn.resourcemanager.hostname/name value192.168.10.10/value /property然后将target/wordcount-1.0.jar复制到 master 节点执行相同命令hadoop jar target/wordcount-1.0.jar \ org.hadoop.exercise.wordcount.WordCountDriver \ hdfs://192.168.10.10:9000/input/wordcount \ hdfs://192.168.10.10:9000/output/wordcount注意所有项目源码中绝不硬编码 IP 地址全部通过Configuration对象动态获取fs.defaultFS。这是你能在三种模式无缝切换的根本原因。4. 避坑指南七个项目的 5 个血泪经验每一条都来自线上翻车现场4.1 现象ClassNotFoundException: org.apache.hadoop.io.Text原因hadoop jar命令未自动包含 Hadoop 核心 jar 包而你的pom.xml只声明了hadoop-client依赖未设置scopeprovided/scope导致打包时把hadoop-common-3.3.6.jar也打进 fat jar引发类冲突。解决在pom.xml中为所有 Hadoop 依赖添加provided作用域dependency groupIdorg.apache.hadoop/groupId artifactIdhadoop-client/artifactId version3.3.6/version scopeprovided/scope !-- 关键 -- /dependency然后用mvn clean package -DskipTests生成不含 Hadoop jar 的 slim jar由hadoop jar命令自动注入运行时 classpath。4.2 现象java.lang.NullPointerException在setup()方法中原因Mapper.setup()或Reducer.setup()中尝试调用context.getConfiguration().get(my.param)但该参数未通过job.getConfiguration().set(my.param, value)设置返回null。解决所有自定义参数必须在 Driver 类中显式设置且不能依赖conf.set()全局配置// 正确在 Driver 中设置 job.getConfiguration().set(topk.k, 10); // ✅ // 错误在 setup() 中读取前未确保已设置 String k context.getConfiguration().get(topk.k); // ❌ 若未设knull int topK Integer.parseInt(k); // NPE应在setup()中加判空String kStr context.getConfiguration().get(topk.k); int topK kStr ! null ? Integer.parseInt(kStr) : 10;4.3 现象InputSplit数量远大于文件块数Map Task 过多原因输入文件是 gzip 压缩.gz而 GzipCodec 不支持 splitHadoop 将整个文件作为一个InputSplit但若你误设mapreduce.input.fileinputformat.split.minsize过小会触发错误切分逻辑。解决检查输入文件扩展名gzip 文件必须单独处理若必须用 gzip设置job.setInputFormatClass(GzipTextInputFormat.class)并确保GzipTextInputFormat继承自TextInputFormat更推荐用bzip2支持 split或解压后上传.txt或在 Driver 中强制设置 split sizeFileInputFormat.setMaxInputSplitSize(job, 128 * 1024 * 1024L); // 128MB4.4 现象PageRank迭代结果不收敛第 5 轮后 rank 值全为0.0原因PageRankReducer中当某个 page 没有出链时sum为 0rank sum / outlinks.size()触发除零异常JVM 捕获后静默吞掉后续context.write()传入new DoubleWritable(0.0)。解决在 reducer 中增加出链数校验if (outlinks.size() 0) { // 孤立节点分配平均权重 double avg totalRank / allPages.size(); context.write(key, new DoubleWritable(avg)); } else { double rank sum / outlinks.size(); context.write(key, new DoubleWritable(rank)); }4.5 现象mapsidejoin项目运行时报java.io.FileNotFoundException: File does not exist: hdfs://.../small_table.txt原因DistributedCache要求小表文件必须在 HDFS 上且addCacheFile()传入的是hdfs://路径但代码中误用了file://路径或本地绝对路径。解决确保小表已上传至 HDFS并在 Driver 中用URI.create()构造// 正确从 HDFS 加载 URI smallTableUri URI.create(hdfs://localhost:9000/input/small_table.txt); job.addCacheFile(smallTableUri); // 错误本地路径 // job.addCacheFile(new URI(/home/user/small_table.txt)); ❌5. 文档说明的实战价值如何用README.md定位 80% 的运行失败5.1 每个README.md的标准字段与真实作用不要把README.md当作文档摆设。这七个项目的README.md是经过 37 次线上故障复盘提炼出的最小信息集每个字段都对应一个决策点字段内容示例为什么必须写你该做什么 运行目标“统计 input/sample.txt 中单词频次输出到 output/wordcount期望 top3 为 (the, 12), (and, 8), (of, 7)”避免“跑完不知对错”运行后立即hdfs dfs -cat output/wordcount/part-r-00000 | head -3对比⚙️ 依赖版本“Hadoop 3.3.6, OpenJDK 11.0.22, Maven 3.9.6”JDK 版本错位会导致UnsupportedClassVersionErrorjava -version和mvn -v必须匹配 一键运行./run-local.sh和./run-cluster.sh脚本内容减少命令拼写错误直接chmod x run-local.sh ./run-local.sh 日志定位“若失败查看yarn logs -applicationId application_171...重点搜ERROR和Caused by:”新人不会看日志复制该命令粘贴执行别自己猜路径 关键参数“调整迭代轮数-D pagerank.iterations5”避免改代码重新编译hadoop jar ... -D pagerank.iterations5注意所有run-*.sh脚本都内置了set -e出错即停和set -x打印执行命令你看到的每一行 shell 输出都是真实执行的命令。5.2 如何用文档反推源码设计意图README.md不是代码说明书而是源码作者留下的调试线索。例如commonfriends/README.md中有一句“注意输入文件每行格式为A:B,C,D表示 A 的好友是 B、C、D。若某行含重复好友如A:B,B,C程序会自动去重。”这句话暗示了CommonFriendsMapper中必然有TreeSetString或HashSetString去重逻辑。你打开CommonFriendsMapper.java果然发现Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line value.toString(); String[] parts line.split(:); String user parts[0]; SetString friends new TreeSet(); // 文档提示的去重证据 if (parts.length 1) { Collections.addAll(friends, parts[1].split(,)); } // ... }这就是文档驱动开发Documentation-Driven Development的实践先写清楚用户要什么再写代码满足它最后用文档固化契约。5.3 文档中的⚠️ 警告条款那些没写进代码的隐性约束有些限制无法用代码强制只能靠文档警示。topk/README.md末尾有⚠️ 警告本项目TopKMapper使用TreeMap维护局部 TopK内存占用与k值线性相关。若k 10000请确保mapreduce.map.memory.mb≥ 2048否则 OOM。这条警告直接关联到 YARN 内存配置。如果你忽略它在集群上跑k50000会看到Container exited with a non-zero exit code 143OOM Kill。此时你应该查yarn logs -applicationId ...确认Exit code: 143回看README.md的警告修改mapred-site.xmlproperty namemapreduce.map.memory.mb/name value2048/value /property property namemapreduce.map.java.opts/name value-Xmx1638m/value !-- 0.8 * 2048 -- /property我带过的 12 个新人有 9 个第一次翻车都在这里——他们盯着代码找 bug却忘了README.md里那行小小的⚠️。现在我的习惯是任何项目先读README.md里的⚠️再跑run-local.sh最后才看源码。这省下至少 3 小时无效 debug 时间。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

C++与Java性能深度拆解:原理、实测与选型指南

C++与Java性能深度拆解:原理、实测与选型指南

C和Java的性能到底谁更厉害,这问题我几乎每隔一阵就会被人问一次。说实话,每次看到网上吵得不可开交的“C秒杀Java”“Java也不慢”之类的论战,我都觉得大家其实不在一个频道上。恰好最近热搜上又飘着“c为什么没有普遍”“java面试题”这类词…

2026/10/9 11:19:11 阅读更多 →
品味 + 工程思维:AI 时代最难被替代的两件事,TaoToken 视角下的 Agent 工程实践

品味 + 工程思维:AI 时代最难被替代的两件事,TaoToken 视角下的 Agent 工程实践

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

2026/10/9 11:19:11 阅读更多 →
树结构核心术语解析:根、父子兄弟、深度高度与路径的工程意义

树结构核心术语解析:根、父子兄弟、深度高度与路径的工程意义

1. 为什么“树”这个词在计算机里被反复提起,却没人真去种一棵?你打开任何一本算法入门书,翻到第三章,大概率会看到一个分叉的图示:一个圆圈在最上面,下面连着两个圆圈,再往下又分出更多——旁边…

2026/10/9 11:18:10 阅读更多 →

最新新闻

拆解MiniOB:几千行C++数据库内核的编译、执行与事务实践

拆解MiniOB:几千行C++数据库内核的编译、执行与事务实践

简介:基于C实现的MiniOB数据库系统,是由OceanBase与华中科技大学联合推出的数据库入门实践项目,主要面向零基础学生,帮助其快速理解数据库内核各模块及其关联,并能设计出高效SQL。资源包内共三百六十三个文件&#xff…

2026/10/9 11:50:55 阅读更多 →
送水系统数据库课设实战:建模、SQL与存储过程完整指南

送水系统数据库课设实战:建模、SQL与存储过程完整指南

简介:面向数据库课程设计的某送水公司送水系统完整参考资源,适合高校数据库课程设计实践。压缩包内共含三个文件,分别是一个doc设计文档、一个sql脚本和一个bak数据库备份,整体大小约三百八十八KB。文档系统梳理了从需求分析、流程…

2026/10/9 11:50:55 阅读更多 →
easydict:让Python字典支持点号访问的轻量级工具

easydict:让Python字典支持点号访问的轻量级工具

1. 从字典的痛点说起:为什么需要easydict写过Python的人都有过这样的经历:从接口拿回来一坨嵌套字典,想取里面某个字段,得一层一层用中括号剥开,像剥洋葱一样。比如config[database][connection][host],写起…

2026/10/9 11:50:55 阅读更多 →
PostGIS 3.5.0二进制包Windows/Linux部署避坑指南

PostGIS 3.5.0二进制包Windows/Linux部署避坑指南

简介:本资源是PostGIS 3.5.0官方二进制安装包,专为64位PostgreSQL 15环境定制,面向GIS开发人员、空间数据库管理员及地理信息专业学习者,解决在PostgreSQL中快速启用标准空间数据存储、查询与分析能力的核心需求。压缩包共1335个文…

2026/10/9 11:50:55 阅读更多 →
外景 建筑场景 圆形观众席 3d模型

外景 建筑场景 圆形观众席 3d模型

本项目为前几天收费帮学妹做的一个项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 建筑场景 圆形观众席 3d模型 地址:本地PC端运行(或WebGL端部…

2026/10/9 11:50:55 阅读更多 →
视觉骨干网络演进:VIT、Swin、MAE、CLIP四篇论文精读与实战

视觉骨干网络演进:VIT、Swin、MAE、CLIP四篇论文精读与实战

1. 从四篇论文说起:视觉骨干网络的演进逻辑搞视觉模型的人大概都有这样的体会:2020年之后,Transformer这个在NLP领域大杀四方的东西,终于按捺不住杀进了计算机视觉的地盘。而这一杀,直接改写了整个视觉骨干网络的设计范…

2026/10/9 11:49:54 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 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/8 21:13:17 阅读更多 →
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/8 15:26: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/9 6:17:20 阅读更多 →