项目复盘 · 2019
数据生产线:从受限来源采集到统一公司对象
把终端采集、垂直爬虫、投融资合并、公司主表、跨库查询和存储迁移放回同一条可追溯生产线,分析其实现、断点与技术债。
历史资料把数据工作拆成多个项目:有的负责在终端上采集受限来源,有的维护垂直爬虫,有的清洗投融资事件,有的合并公司,有的只承接临时数据需求。单独看,每个项目都像一组零散脚本;沿时间和数据流拼接后,则能看到一条“需求进入—原始采集—字段规一—实体合并—统一查询—业务消费”的生产线。
本文区分四种结论:文档事实来自工单、交接与字段文档;代码事实来自现存仓库;合理推断由多条证据共同支持但缺少完整验收;缺失证据表示不能确认。
现存境外投融资导入器用完成与失败日志实现断点续跑。以下等价伪代码保留其有限队列、重试和落库逻辑,同时把“先记完成再写数据库”的风险显式改为正确顺序。
等价伪代码
queue = bounded_queue(capacity=40)
for worker in workers(5):
worker.consume(queue)
for source_id in source_catalog:
if state[source_id] in ["done", "permanent_failure"]:
continue
queue.put(source_id)
worker.consume(id):
for attempt in range(1, 4):
response = fetch_detail(id, timeout=10)
if response.not_found: return save_failure(id, "not_found")
if response.retryable: backoff(attempt); continue
record = normalize(response.data)
database.upsert(id, record)
return save_state(id, "done")
save_failure(id, "retry_exhausted")项目时间线:先合并来源,再建设入口,最后补迁移
文档事实|2017 年 10 月。 投融资合并项目从字段统一开始:先梳理三个国内来源的所有可能字段,再将原始数据迁入三个规范表;各来源内部按公司全名去重,把同名记录标识集合写入中间字段;随后合成全局中间表,再执行跨来源公司合并。首轮六项主链路在 10 月下旬至 12 月中旬完成。
文档事实|2017 年 11 月至 12 月。 公司大表项目以两条工单交付前端展示与后端接口。同期,基础爬虫补美国专利增量、开放论文数据和上市公司投资事件。受限来源采集项目在 12 月 23 日至次年 2 月集中完成云端前后端、开放接口、客户端引擎、心跳、上传联调、任务切换、查询优化和离线预警;计划继续扩展的一批设备仍停留在待办。
文档事实|2018 年 1 月至 5 月。 投融资项目把重点转到持续维护:爬虫升级完成,但每日同步、人工订正前后端和面向检索的统一描述字段没有完成。基础爬虫继续承担月度招聘更新、人才与论文数据。需求池在这段时间快速膨胀,却只有少量事项落地。
代码事实|2018 年 8 月至 2019 年 3 月。 内部数据工具前端的 36 次提交补齐公司、融资、人员和并购查询,处理多选轮次、金额格式、分页、下载文件名和主搜索。其时间晚于公司大表 Jira,说明它更像消费统一对象的后续工具,而不是最初两条工单的原始前端。
代码事实|2019 年 5 月至 8 月。 数据迁移仓出现 46 次提交,将旧键值存储中的 PDF 页面和 HTML 迁往 MongoDB GridFS,随后加入分块、远程消息、图片更新、HTML 压缩和失败捕获。这条历史解释了金融主服务同期“替换旧存储”的提交,但不能证明所有历史对象都完成核对。
XSpider:设备在线不等于采集成功
文档事实。 受限来源采集被拆为云端和终端两部分。云端保存订阅、下发任务、接收上传并提供文章查询;终端在设备上按队列切换不同应用任务,周期性上传设备标识与心跳。部署记录证明至少进行过多设备联调、账号替换和新增设备,不只是界面原型。
2017 年 12 月 29 日的优化明确针对文章检索速度和上传名称去重,次年 1 月又关闭静默升级,并在 2 月加入设备离线邮件预警。这组改动揭示了真实运行问题:同名内容会重复,应用间任务切换会卡住,自动更新本身也可能造成不稳定。
合理推断。 心跳只能证明进程或设备仍可联系,不能证明账号有效、目标应用可用或数据持续更新。更可靠的监控应至少区分:
- 设备最近心跳与客户端版本;
- 最近一次任务领取、开始、成功和上传时间;
- 来源账号状态与连续失败次数;
- 按来源计算的最新数据时间和预期更新延迟。
缺失证据。 当前 GitLab 快照没有找到云端与终端的完整对应源码,无法核对任务租约、重复投递、端侧加密和账号隔离方式,也不能确认待扩展设备最终部署。
垂直爬虫:真正成本来自来源变化
文档事实。 基础爬虫工单从 2017 年 10 月延续到 2019 年 5 月,覆盖专利全量更新、论文开放数据、上市公司投资事件、人才库调研和按月招聘更新。项目明确要求比较实际采集条数与来源宣称规模,并梳理专利缺口和抓取瓶颈;另一项来源专项任务正是因对方策略变化而重构。
代码事实。 金融采集仓把来源拆为 Spider、Item 与 Pipeline,使用重复检查、文件下载、PDF 解析、关系库存储和全文索引。国际投融资仓则从 CSV 中读取组织标识,用线程池加有限队列请求详情:组织任务采用 5 个工作线程、队列容量 40,融资轮次任务采用 10 个线程、队列容量 400;完成和失败标识分别写日志,以便重启时跳过。
状态码处理体现了当时的工程取舍:找不到的标识写失败集;鉴权或请求错误最多重复若干次;JSON 解析失败随机等待;文档无法写入则单独记录;已存在主键直接跳过。它具备基础断点续跑,却把日志文件当作任务状态数据库。
边界。 日志先写“完成”再插入数据库时,进程崩溃可能造成永久漏数;失败集也没有失败原因和下次重试时间。队列中用一个特殊字符串表示结束,多个消费者再把结束标识放回,虽能使所有线程退出,却不具备任务租约、超时回收与独立死信。
Merge:五层表逐步收敛到公司与融资事件
文档事实。 投融资合并可以还原出五层结构:
- 三个来源原始表;
- 字段规一后的来源表;
- 各来源内部按公司名称合并的最终表;
- 合并三个来源的全局中间表;
- 使用全局规则再次合并的公司与融资事件结果。
合并时不只合公司。各来源的融资轮次会补来源信息,再聚合到公司记录。后续又加入城市属性,并根据既有使用情况重做结果表。2018 年 1 月的需求提出为国内、境外投融资增加统一检索描述字段,因为原先需要分别查询描述和标签,表达式笨重且性能差;该事项未完成。
文档事实。 项目 20 条工单中 12 条完成、8 条待办。未完成项集中在境外数据规一、每日同步、人工订正平台和检索字段。这说明批量合并主链路已经运行过,但持续更新与人工治理没有形成闭环。
合理推断。 按公司全名进行单源去重适合作为首轮候选生成,不足以判定同一实体。名称变更、品牌名、集团与子公司、中文与英文名都会造成误拆或误并。人工订正平台之所以被提出,是因为规则结果必须接受领域审阅;它未交付意味着后续修订可能继续散落在脚本和临时表里。
重建时应把每次合并保存为“候选边”,记录来源对象、标准对象、名称相似、地址、网站、人员、来源标识等特征与规则版本;人工确认只改变边的状态,不覆盖原始记录。
公司大表:统一的是对象入口,不是所有明细
代码事实。 公司大表后端是一座 Spring MVC WAR 工程,使用 MyBatis-Plus、MySQL、Shiro、缓存、MongoDB 与 Elasticsearch。它既包含用户、角色、资源和日志等通用后台,也包含公司、关键词、数据源与导出接口。核心控制器超过三千行,业务查询、过滤表达式解析、跨库调用和返回组装集中在一个类中。
接口模型可以还原为三段:
- “公司列表”接口接收页码、页大小和过滤器,返回公司名称、类别、地址、简介等列表字段;
- “公司信息”接口按内部标识或名称取公司主对象,并返回应用、专利、法律文书等来源的匹配数量;
- “按来源取详情”接口在用户展开某来源后,才按页查询该来源的详细记录。
过滤器是一种自定义 JSON DSL。日期支持大于、小于、等于、区间和是否为空;数字使用同类操作;字符串支持包含、不包含和是否为空。融资列表先由公司条件得到公司名集合,再用精确集合条件查询融资事件,返回公司、轮次、金额和日期。
代码事实。 README 明确承认名称仍可能重复:传名称匹配多条时只显示第一条,内部标识只是未完成去重前的过渡。这是公司主表最关键的边界——统一入口已经存在,唯一实体并未完全解决。
代码事实。 跨库详情使用适配器分别访问投融资、应用、专利和法律文书等数据;这比复制所有来源到一张宽表更合理。主对象保存稳定标识、通用字段与来源关联,体量大的来源明细按需加载。前端原型也把基本信息、工商、团队与融资分区,专利和法律标签一度仍为禁用状态,说明界面计划大于当时可用数据。
存储迁移:用内容摘要模拟 GridFS 的更新
代码事实。 2019 年迁移脚本从旧键值哈希中分页读取 PDF 页面 HTML,以旧键作为 GridFS 文件标识。由于目标存储不直接支持按该方式更新,脚本遇到重复标识时读取已有文件的摘要;内容相同则跳过,不同则先删除再上传。每批读取一千或五千个键,目标块大小约 15 MiB;后续版本还以最高压缩级别压缩 HTML。
这套逻辑避免了无差别覆盖,但有两个显著风险。第一,删除与重新上传不是事务,进程在两步之间失败会丢文件;第二,一个实验版本把待迁移总量临时写死为两千,若被误用于正式迁移会静默漏数。提交历史后来增加失败捕获、分割和压缩,说明迁移是在运行中逐步修补。
合理推断。 更稳妥的迁移应先写入新版本对象,核对摘要与长度,再原子更新业务引用;迁移清单需记录源键、源摘要、目标标识、状态和重试次数,并在完成后对源与目标做总数及随机内容校验。
DATA:需求池反映了数据项目的筛选成本
文档事实。 数据需求池有 38 条事项,只有 4 条完成、2 条处理中,另有 16 条开放和 16 条取消。需求跨度从招聘、人才、百科、专利和投融资,到区域报告、汽车、海外扩张与年度报告。完成项包括招聘更新、企业列表和人才流动统计;大量事项因来源、口径、成本或优先级没有继续。
这组状态不能简单解释为“完成率低”。它说明需求尚未经过可行性门槛就进入同一项目板。一个可执行数据需求至少应写清业务用途、字段、覆盖期、更新频率、合法来源、预算、验收样本和维护责任;取消时则要保留原因,避免下一轮重新调研同一问题。
能确认的交付、失败与重建重点
可确认交付: XSpider 的云端与端侧联调、心跳和离线预警;基础爬虫的若干增量任务;投融资字段规一、来源内去重、跨来源中间表和一版最终合并;公司大表查询与后续内部工具;旧文档存储向 GridFS 的迁移脚本。
未收口或缺失证据: 受限采集完整源码和规模化设备验收;投融资每日自动同步与人工订正平台;公司唯一实体准确率;跨库接口契约测试;迁移全量核对报告;需求池取消原因。
代码事实: 多个仓库曾把固定服务位置、访问凭据、日志和构建产物写入版本库。本文不公开具体内容;历史凭据应全部失效,配置应迁至受控密钥系统,日志和数据样本则需从代码仓剥离。
这条生产线最值得保留的不是某个爬虫,而是“原始来源—标准记录—实体对象—业务查询”的分层。重建时应为每层提供稳定标识、版本和质量指标,并把覆盖率、字段完整率、重复率、更新延迟、失败恢复与人工裁决共同作为交付物。
证据边界
本文交叉使用六个 Jira 项目:受限采集 20 条、基础爬虫 9 条、来源专项 1 条、投融资合并 20 条、公司大表 2 条、数据需求池 38 条。代码侧核对了公告采集、境外投融资导入、公司大表、公司前端、内部数据工具和 2019 年存储迁移仓。
这些代码来自不同日期和不同部署阶段,不能据此声称曾存在一套单体、统一编排的数据平台。文章所描述的是可以由时间与字段关系拼合的生产链,而不是一份已找到的整体架构说明。