电商数据抓取:开发人员成本视角:存储方案如何避免字段不统一
电商数据抓取项目最容易低估的成本,通常不是爬虫能否把页面抓下来,而是三个月后还能不能稳定回答“这个价格到底是什么价格”“这个库存对应商品还是 SKU”“两个平台的销量能不能直接比较”。在我参与过的多平台采集项目中,最初用一张宽表加几个 JSON 字段,往往能在几天内跑通;但当平台数量从 2 个增加到 6 个、报表从 3 张增加到 20 张后,开发时间开始大量消耗在改表、补历史数据、解释字段含义和排查异常上。
因此,电商数据抓取的存储设计不能只回答“用 MySQL、文档数据库还是数据湖”,还要回答一个更实际的问题:字段变化、业务标准化、历史追溯和下游查询,分别由哪一层承担成本。本文将从开发人员成本出发,拆解字段不统一的真实来源,比较不同存储方案的长期代价,并给出一套可以从小项目逐步演进的设计方法。
很多团队第一次设计电商采集库时,会先列出商品名称、价格、库存、品牌、类目、销量等字段,然后直接建立一张标准表。这个做法看起来整齐,实际上容易把不确定性提前固化。
不同平台的商品结构并不只是字段名称不同。一个平台可能把价格作为单个数值返回,另一个平台可能同时返回原价、活动价、会员价和券后价;一个平台以商品为库存单位,另一个平台则要求按颜色、尺码等 SKU 维度记录库存。如果业务语义还没有确认,越早固定表结构,后面改表的次数通常越多。
更稳妥的做法是把字段分成三层:原始字段、核心标准字段和平台扩展字段。原始层解决“数据有没有被完整保存”,标准层解决“跨平台能否比较”,扩展层解决“平台特色信息不能丢失”。这不是为了增加架构复杂度,而是把三类不同问题分开。
把 title、name 和 product_name 都映射成 product_name,只是完成了命名统一。真正需要确认的是:这个字段是否都代表商品标题,是否包含品牌前缀,是否包含规格,是否可能被平台截断。
价格字段更能说明问题。price 可能代表当前展示价,也可能代表最低 SKU 价格;salePrice 可能是促销价,但不一定包含优惠券;origin_price 可能是划线价,也可能只是某个活动前的参考价格。名称统一但口径不统一,会比名称完全不同更危险,因为它会制造“看起来可以直接比较”的假象。
把原始结果全部存入 JSON,初期成本较低,但后续查询、类型转换和指标治理的成本会上升;把所有字段都拆成关系型列,查询较稳定,但平台变更和扩展字段接入会变得昂贵;采用标准表加扩展字段,前期需要多做字段字典和映射配置,但长期维护通常更可控。
所以,存储方案没有绝对的“最好”。需要判断的是:项目当前更怕哪种成本,是快速接入成本、改表成本、查询成本、历史回填成本,还是数据解释成本。
| 设计方式 | 初期接入 | 平台变化 | 跨平台分析 | 长期维护 |
|---|---|---|---|---|
| 全部关系型宽表 | 中等 | 改表成本高 | 较方便 | 字段多后明显上升 |
| 全部 JSON 或文档 | 较快 | 接入灵活 | 需要重复清洗 | 查询和口径治理成本高 |
| 标准表加扩展字段 | 中等 | 较平衡 | 较方便 | 适合长期项目 |
| 原始层、标准层、应用层 | 较慢 | 可追溯 | 适合复杂分析 | 治理能力最强,但需要团队能力 |

假设一个团队需要每天抓取三个平台的商品信息,第一阶段只关心商品名称、当前价格、库存和商品链接。工程师很快完成了采集程序,并把每个平台的数据写入同一张表。
平台 A 返回的字段可能是 title、price、stock;平台 B 返回的是 name、salePrice、inventory;平台 C 返回的是 product_name、current_price、sku_stock。最初只要做几条映射规则,系统就能正常入库。
真正的问题通常出现在业务提出第二个需求之后:需要比较不同平台的价格变化,统计缺货商品,按品牌查看商品数量,并把结果同步到管理看板。此时开发人员才发现,三个平台的“价格”和“库存”并不是同一层级的数据。
例如,平台 A 的商品库存是各 SKU 库存的汇总值,平台 B 的 inventory 是可售库存,平台 C 的 sku_stock 只是当前打开规格的库存。字段都填上了,数据却不能直接进行同口径比较。
这是最容易解决的一类问题。只要业务含义一致,就可以通过字段映射把不同来源字段映射到统一名称。例如,title、name 和 product_name 可以统一到 product_title。
同一个价格字段可能出现数字、字符串、带货币符号的文本,甚至带区间表达式的内容。库存字段也可能是整数、空值、“有货”“无货”等状态文本。
这类问题不能只在数据库层面依靠类型转换解决。比如把“有货”转换成 1,把“无货”转换成 0,虽然便于计算,却可能丢失“平台没有公开具体库存数量”这一事实。更合适的做法是同时保存数量字段和库存状态字段。
商品、SPU 和 SKU 是不同的数据粒度。一个商品有多个颜色和尺码时,价格和库存往往应该落在 SKU 层;商品名称、品牌和主图通常属于商品层。如果把所有字段都塞进商品表,后续必然出现重复行、价格覆盖或库存含义混乱。
“销量”是最典型的语义陷阱。月销量、累计销量、近 30 天销量、已售数量和平台排序销量,都可能被简称为销量。即使来源字段名称完全一样,也不能直接合并。
| 业务含义 | 平台 A | 平台 B | 平台 C | 能否直接合并 |
|---|---|---|---|---|
| 商品名称 | title | name | product_name | 通常可以,需确认是否含规格 |
| 当前价格 | price | salePrice | current_price | 不能仅凭名称合并 |
| 原价或参考价 | origin_price | marketPrice | list_price | 需要确认业务定义 |
| 库存 | stock | inventory | sku_stock | 需先确认数据粒度 |
| 销量 | sales | month_sales | sold_count | 通常不能直接合并 |
采集程序验证的是“能不能拿到数据”,而报表验证的是“数据能不能被解释”。前者只要响应不为空、插入没有报错,就容易被认为完成;后者却会追问数据的时间范围、粒度、单位、口径和缺失原因。
这也是很多项目在上线初期看起来顺利,到了数据量增加后开始失控的原因。抓取、解析、存储和分析之间如果没有明确的数据契约,问题会沿着链路向后转移,最后由报表开发人员或业务人员发现。

JSON 很适合保存来源结构不断变化的数据,但它解决的是“怎么先保存下来”,不是“这些字段在业务上代表什么”。如果三个平台都把价格放在 JSON 中,查询时仍然需要分别判断字段路径、数据类型和缺失情况。
当报表需要统计最低价时,SQL 或数据处理脚本可能要同时兼容 price、salePrice、current_price,还要处理字符串和数值。字段没有在存储时统一,成本就会转移到每一个下游查询。
我通常把 JSON 看作原始数据的缓冲层,而不是最终业务模型。它可以保留平台差异,但至少要有一组经过验证的标准字段供下游使用。
万能表常见的样子是:商品名称、品牌、类目、原价、售价、库存、销量、店铺、活动、优惠券、规格、标签、评价等字段全部放在同一张表中。
这种设计在字段数量较少时很方便,但它把不同数据粒度和不同更新频率混在了一起。商品名称可能一天不变,库存可能每小时变化,价格可能随活动变化,评价数量可能在另一套任务中更新。所有字段共用一张表,会导致更新冲突和历史信息丢失。
更严重的是,平台专属字段会不断侵入主表。一个平台增加“预售时间”,另一个平台增加“会员价”,第三个平台增加“物流时效”,最后表结构变成大量空列,开发人员也很难判断每个字段是否仍在使用。
数据比较的前提不是列名相同,而是时间范围、统计粒度、单位和业务口径相同。例如两个平台都返回 stock,一个是商品总库存,另一个是当前 SKU 可售库存,直接相减会产生没有业务意义的结果。
在字段字典中,我建议把“业务含义”和“不可比较条件”一起写进去。比如把 sale_price 定义为“当前页面展示的最低可购买价格,不含未登录会员权益和未领取优惠券”,而不是只写“销售价”。
平台字段变更后,开发人员往往直接修改解析代码,然后重新运行任务。但如果标准字段的逻辑也发生变化,历史数据是否需要重算、报表是否需要标记口径变化、旧版本规则是否需要保留,都不能通过改一行代码自动解决。
尤其是价格字段,如果平台把促销价从单个数字改成对象结构,单纯修复解析逻辑还不够。团队还要确认历史数据中的价格是否仍然代表同一口径,以及价格趋势图是否需要断点说明。
分层存储和数据湖适合数据量较大、历史留存时间长、下游用途多的项目,但并不是所有电商抓取任务都需要复杂的平台化架构。
如果项目只有一个平台、每天几万条记录、只有一个后台查询页面,直接引入对象存储、消息队列、湖表格式和多套调度组件,可能会让运维成本超过字段治理收益。架构复杂度应该由数据生命周期和下游用途驱动,而不是由技术名词驱动。

我在做存储选型时,通常先问五个问题,而不是先问“团队更熟悉哪种数据库”。第一,原始响应需要保存多久;第二,标准字段是否需要重新计算;第三,数据是只查询当前状态,还是需要保留历史快照;第四,是否存在跨平台比较;第五,是否会有多个下游系统使用这些数据。
如果只关心商品当前状态,数据模型可以相对简单;如果要分析价格波动、库存变化和活动效果,就必须保存时间维度。当前状态表和历史快照表是两种不同的用途,不能指望用一条覆盖更新语句同时满足两者。
电商采集最先需要明确的是:一行数据到底代表什么。它可以代表一个平台商品、一个 SKU、一次抓取快照、一个价格变化事件,也可以代表一次原始响应。
建议在表设计和数据字典中明确写出粒度,例如:
如果粒度没有定义,字段统一只是表面工作。商品表里出现重复商品、SKU 表里出现商品级字段、价格历史表里保存当前价格,都是粒度混乱的表现。
并不是所有字段都值得立即标准化。标准字段越多,映射、测试、质量监控和文档维护的成本越高。比较实用的做法是把字段分级。
核心字段直接服务于当前业务,例如商品 ID、平台 ID、商品名称、SKU ID、当前价格、库存状态、抓取时间和数据来源。这些字段需要稳定的数据类型和明确的业务定义。
可选字段可能被部分平台提供,例如品牌、材质、发货地、活动标签和物流承诺。它们可以先进入扩展字段,等使用频率和业务价值明确后再升级为标准列。
平台页面上的大量展示字段并不一定有长期价值。对暂时没有查询、分析或业务动作的字段,可以保留在原始层,不必立即纳入标准模型。
这套分级方法的核心,是避免把所有不确定性都转化为固定表结构。只有被多个业务场景反复使用的字段,才值得承担标准化成本。
字段映射表回答“来源字段对应哪个标准字段”,字段字典还要回答“这个标准字段具体是什么意思”。两者不能混为一谈。
| 配置项 | 示例 | 解决的问题 |
|---|---|---|
| 标准字段名 | sale_price | 避免不同团队重复定义名称 |
| 业务含义 | 当前页面可购买的基础价格 | 避免把券后价、会员价混入 |
| 数据类型 | decimal(12,2) | 避免数字和字符串混用 |
| 单位 | 人民币元 | 避免元、分和其他货币混算 |
| 数据粒度 | SKU 级 | 避免商品级和 SKU 级混用 |
| 允许为空 | 是,缺失原因必填 | 区分未知、没有库存和未返回 |
| 规则版本 | v2.1 | 支持历史重算和问题追踪 |
如果平台判断、字段路径、类型转换和默认值都写在采集函数中,随着平台增加,主流程会出现大量条件分支。新增一个字段时,开发人员需要修改代码、补测试、重新部署,还要确认是否影响旧平台。
可以把映射规则保存为配置,示意结构如下:
{
"source_platform": "platform_a",
"source_field": "salePrice",
"standard_field": "sale_price",
"data_type": "decimal",
"unit": "CNY",
"transform": "strip_currency_and_cast",
"nullable": true,
"rule_version": "v2.1",
"effective_from": "2026-01-01"
}
这段配置不是为了让所有清洗逻辑都变成低代码,而是把相对稳定的映射关系与复杂的业务算法分开。字段路径、单位转换、默认值和生效时间适合配置化;复杂的促销价格计算、规格拆解和异常判断仍然可以由代码实现。
标准化规则会变化。例如,第一版把页面展示最低价作为售价,第二版开始区分基础价、会员价和券后价。如果没有规则版本,后续很难解释历史报表为什么发生变化。
原始数据保留的价值就在这里:当业务口径变化时,可以使用新规则重新处理历史原始数据,而不是重新请求平台。重新抓取不仅耗费资源,也可能因为页面变化、商品下架或访问限制而无法恢复历史状态。

关系型宽表适合平台数量少、字段相对稳定、查询条件明确的项目。它的优点是开发人员容易理解,字段类型可以约束,索引和聚合查询也比较直接。
但宽表的成本会随着平台数量和字段差异快速增加。每新增一个平台专属字段,都要决定是增加新列、复用旧列,还是把字段放弃。如果列名相似但语义不同,复用旧列会产生数据污染;如果全部增加新列,表结构会变得臃肿。
宽表还容易把当前状态和历史状态混在一起。每天覆盖价格和库存后,当前查询很方便,但价格趋势、库存波动和异常恢复会变得困难。
全 JSON 方案适合原型验证和平台快速接入。开发人员可以先保存原始结构,避免因为平台字段变化频繁而不断改表。
但全 JSON 不适合直接承载所有长期查询。假设业务每天需要统计不同平台的最低价,查询逻辑就必须处理多个路径、空值、字符串、价格对象和货币单位。随着查询数量增加,每张报表都会重复实现一遍字段治理。
如果团队选择全 JSON,至少要同时建立一张轻量标准表,保存最常用的核心字段。这样可以保留原始灵活性,又不让下游系统直接依赖来源结构。
这是我在中小型多平台项目中更常推荐的折中方案。核心业务字段使用关系型列,平台专属字段、暂未确认语义的属性和低频查询字段使用 JSON 或扩展表保存。
例如,标准商品表可以保存内部商品 ID、平台商品 ID、商品名称、品牌、类目和最近抓取时间;标准 SKU 表保存 SKU ID、规格组合、当前价格、库存数量和库存状态;平台页面上的活动标签、服务承诺和展示属性则进入扩展字段。
这种方案的关键不在于“关系型加 JSON”这几个技术名词,而在于哪些字段可以进入标准层必须有明确规则。如果所有字段最后都塞入扩展字段,仍然会回到全 JSON 的问题。
分层存储适合需要长期留存、多种分析用途和较强追溯能力的项目。原始层保存采集结果,标准层完成字段治理,应用层则为报表、监控、搜索或推荐生成更适合查询的数据集。
以数据分析场景为例,如果团队使用九数云这类分析工具制作跨平台价格、库存或商品结构看板,建议让看板读取稳定的标准层或应用层数据,而不是直接读取各平台原始 JSON。这样平台字段变化时,报表不需要逐个修改数据路径。
这里不意味着必须把所有系统一次性建设得很复杂。一个小项目完全可以从三张表开始:原始采集表、标准商品表和标准 SKU 表。等出现价格趋势、库存预警或多主题分析需求,再增加历史表和应用数据集。
| 项目情况 | 推荐结构 | 优先解决的问题 | 不建议做的事 |
|---|---|---|---|
| 单平台、当前状态查询 | 关系型主表加原始字段 | 类型约束和查询效率 | 过早建设复杂分层 |
| 三到五个平台、需要横向比较 | 标准表加扩展字段 | 核心语义统一 | 把所有差异塞入主表 |
| 多平台、长期历史分析 | 原始层加标准层加历史层 | 追溯、回填和版本管理 | 只保存最新状态 |
| 多个业务系统共同使用 | 分层存储加应用数据集 | 下游解耦和口径统一 | 让每个报表直接解析原始数据 |

下面使用一个匿名化的情景案例说明设计差异。假设团队接入三个电商平台,每个平台抓取 80 万个商品记录,其中一部分商品包含多个 SKU。每日抓取一次商品基础信息,每 30 分钟更新价格和库存。业务需要查看当前价格、价格变化、缺货商品和品牌分布。
以下数据是根据类似项目的容量和工时结构整理出的样本推演,不是任何平台的公开统计,也不是对特定客户的承诺。它的用途是帮助团队估算成本构成,而不是得出“某方案固定节省多少百分比”的结论。
| 数据对象 | 每日数量 | 更新频率 | 主要用途 |
|---|---|---|---|
| 商品基础信息 | 约 240 万条采集记录 | 每日一次 | 商品、品牌、类目分析 |
| 价格快照 | 约 1,152 万条采集记录 | 每 30 分钟 | 价格趋势和异常变化 |
| 库存快照 | 约 1,152 万条采集记录 | 每 30 分钟 | 缺货监控和库存变化 |
| 原始响应 | 按实际成功响应计 | 随任务产生 | 追溯、重处理和异常排查 |
如果所有记录直接写入一张商品宽表,当前状态查询会比较简单。但价格和库存以覆盖方式更新后,历史曲线无法自然形成;如果改成每次新增记录,又需要处理商品信息、价格、库存和抓取批次之间的重复关系。
另一个问题是 SKU 层级。某平台的库存字段如果是商品汇总值,另一个平台是 SKU 级值,直接写入同一个 stock 列会让后续库存比较失去基础。开发人员只能额外增加 stock_level、stock_type 或多个特殊字段,表结构开始围绕平台差异膨胀。
一种更可控的设计是建立商品主表、SKU 表、价格历史表、库存历史表、原始数据表和字段映射表。商品主表只保存商品身份和相对稳定的信息,价格与库存变化放入各自的历史表,平台差异放入扩展字段。
核心字段可以按以下方式设计:
这样做以后,某个平台把库存从整数改成“有货”时,不需要破坏标准库存数量列。系统可以把数量保留为空,把库存状态设为“有货”,同时在原始层保存原始值,并将该记录送入质量检查队列。
在数据规模较小、字段还未稳定时,直接连接原始表进行探索是可以接受的。但当团队使用九数云这类数据分析工具制作多个主题看板时,建议把数据源切换到标准层或应用层。
原因很实际:如果每个看板都自己解析平台 A、平台 B 和平台 C 的 JSON 字段,价格和库存的计算口径会逐渐分叉。一个看板使用当前价,另一个看板使用最低 SKU 价,第三个看板把缺失库存当作 0,最后业务看到的是三组互相矛盾的结果。
应用层可以提供已经统一的商品价格表、库存状态表和品牌分析表。看板只负责展示和筛选,不再承担来源字段解释工作。这样分析工具的价值才能体现在业务洞察,而不是重复执行数据清洗。
在这个情景中,全部 JSON 方案的初始接入可以较快完成,但跨平台价格对比、库存趋势和异常追踪需要在查询层反复写转换逻辑。标准表加扩展字段在第一周会多出字段字典、映射测试和数据质量规则,但后续新增平台时,改动范围更容易被控制。
如果团队预计未来只保留当前状态,不做历史分析,价格历史表和库存历史表可以暂缓;如果业务明确需要价格趋势和缺货预警,那么历史层应该在第一版就设计好,否则后面补历史数据往往只能从重新抓取开始。

数据契约不需要一开始写成几十页文档,但必须明确核心字段的含义、类型、单位、粒度和缺失规则。建议先从最常用的 10 到 20 个字段开始,而不是试图覆盖页面上的全部字段。
字段契约至少包含以下内容:
原始数据表的目标不是让业务直接查询,而是保留重处理和排错所需的信息。至少应该保存平台标识、来源链接或接口标识、原始响应、抓取时间、采集批次、采集器版本和处理状态。
如果原始响应体积较大,可以采用对象存储保存正文,在数据库中保存对象地址、哈希和元数据。无论采用哪种方式,都需要确保标准化失败后能够定位到原始输入。
商品表和 SKU 表应尽量保存稳定、经常使用且语义明确的字段。不要为了追求一张表查询方便,把价格历史、库存变化、活动信息和评价统计全部放进去。
内部 ID 和平台 ID 要同时保留。平台商品 ID 用于追溯来源,内部 ID 用于跨平台关联。两者不能互相替代,因为同一个商品在不同平台可能使用不同 ID,而平台 ID 也可能因店铺、站点或商品变体而重复。
字段映射表应当支持一个标准字段对应多个平台来源字段,也要支持同一个来源字段根据上下文进入不同标准字段。例如同样叫 price,在商品页可能代表最低展示价,在 SKU 页可能代表具体规格价格。
质量规则建议覆盖以下类型:
最忌讳的是清洗失败后直接写入默认值。价格解析失败就写成 0,库存解析失败就写成 0,虽然任务不会报错,但下游会把异常数据当成真实业务数据。
更好的做法是保存原始值、异常类型、异常原因、规则版本和处理状态。异常队列不一定要求人工逐条处理,可以先按平台、字段和错误类型聚合,优先处理影响记录量最大的异常。
应用层不是简单复制标准表,而是根据业务查询目的组织数据。例如价格监控应用表可以只保留商品 ID、SKU ID、平台、当前价、前次价格、价格变化比例和抓取时间;库存预警应用表则重点保存库存状态、连续缺货次数和最近更新时间。
通过应用层,报表和分析工具不需要理解复杂的原始结构,也不会因为标准层增加一个平台字段而改变查询逻辑。

建议采用关系型基础表加原始 JSON。先把商品 ID、商品名称、当前价格、库存状态、链接和抓取时间结构化,其他字段保存在原始层。
这个阶段不必急着建设完整字段中台,但要提前记录数据粒度和原始来源。即使暂时只有一个平台,也应避免让下游报表直接读取解析脚本产生的临时字段。
建议尽快建立标准字段字典、平台映射表和标准商品、SKU 表。平台专属字段可以放在扩展字段中,先不要为了完整覆盖而增加大量固定列。
如果业务已经开始比较价格、库存或销量,必须把这些字段的口径写清楚。特别是销量和价格,不能因为字段名称相似就自动合并。
建议从当前状态表升级为当前状态加历史快照。价格和库存最好分开建模,因为它们的变化频率、业务含义和查询方式不同。
如果存储压力较大,可以考虑只记录变化事件,而不是每次重复保存完全相同的值。但采用变化事件前要确认业务是否需要完整时间点快照,否则后续可能无法还原某个时间点的状态。
建议建设标准层和应用层,让分析工具只消费经过统一口径处理的数据集。以九数云这类分析工具为例,价格监控、品牌分析和库存预警可以分别使用应用数据集,但这些数据集应共享同一套商品、平台和时间维度定义。
不要让每张看板自己判断“空库存是否等于 0”“促销价是否包含优惠券”“商品销量属于哪个时间范围”。这些判断应该在标准层或指标层统一完成。
建议把原始数据、标准数据、历史数据和应用数据分开管理,并为不同数据设置保留周期。原始响应可以根据追溯需求设置较长保留时间,应用层则可以只保留满足查询的聚合结果。
当高频快照达到数亿行级别后,分区、归档、压缩、去重和查询范围控制会成为实际问题。此时是否使用数据湖、列式存储或专门的分析数据库,应根据查询模式和团队运维能力评估。

全 JSON 方案可以让团队很快接入新平台,适合验证业务价值。但如果业务很快进入跨平台分析阶段,之前省下的建模时间会转化为查询适配和指标治理时间。
标准表加扩展字段需要更早确认核心语义,初期看起来慢一些,但能够把经常查询的字段固定下来。它不是牺牲灵活性换稳定性,而是只对高价值字段施加约束。
只保存当前状态,存储成本和查询复杂度都较低,但无法回答“价格何时变化”“库存连续缺货多久”“平台改价后多久恢复”等问题。
保存所有高频快照,分析能力更强,但数据量和存储成本会快速增长。可以根据业务选择完整快照、变化事件或按小时聚合,关键是不要在项目上线后才发现历史数据从未保存。
原始数据全部保留有利于追溯,但原始响应的体积、敏感信息、存储周期和访问权限都需要管理。对于不影响业务判断、又没有重处理价值的页面字段,可以设置更短保留周期或只保留摘要。
如果原始层需要保存商品页面快照,还应考虑存储压缩、哈希去重和分层归档。原始数据不是越多越好,而是要能支持关键问题的复核和重处理。
分层架构可以降低字段变化和历史回填风险,但也会增加任务编排、数据质量、权限和运维工作。如果团队只有一名开发人员,复杂架构可能变成无人维护的系统负担。
比较合理的演进路径是先建立原始表和标准表,再根据真实需求增加历史层、应用层和质量监控。每增加一层,都应该对应一个已经发生的业务需求,而不是为了“架构完整”提前建设。
开发人员成本通常比存储介质费用更容易被忽略。评估时至少要把以下项目纳入:
一个低价数据库并不一定意味着低成本。如果每次平台升级都需要开发人员手工修复数据、重新跑历史任务并解释报表差异,数据库节省的费用很快会被人力成本抵消。
电商数据抓取中,字段不统一无法被完全消除。不同平台有不同的商品结构、促销规则、库存口径和展示方式,试图把所有差异强行压成一套字段,最后通常会得到一套含义模糊的“伪标准”。
更成熟的做法是明确边界:哪些字段必须统一,哪些字段只保留原始值,哪些字段需要进入扩展层,哪些字段暂时不值得治理。统一的不是所有名称,而是核心业务语义、数据粒度、单位、时间口径和异常处理方式。
从开发成本角度看,最值得投入的并不是一开始选择最复杂的数据库,而是建立一套能够持续演进的路径:原始层保留变化,标准层保证可用,扩展层承载差异,应用层服务查询,字段映射和规则版本负责追溯。
下一步可以先不要改造全部系统,选择价格、库存或商品名称这三个最常用字段,完成一次小范围试点:写出字段字典,梳理三个平台的来源差异,建立标准表和原始表,记录一次字段变更的处理过程。试点能够跑通后,再决定是否增加历史层、应用层或更复杂的存储架构。
如果一个方案只能让第一次抓取更快,却无法让新增平台、字段变更和历史回填更可控,那么它只是降低了今天的开发成本,把账单留给了未来。对于电商数据系统,真正划算的存储设计不是最灵活,也不是最复杂,而是能够让字段变化被看见、被解释、被修复,并且不会反复侵入下游业务。
我原以为字段不统一只是把 title 改成 product_name 这么简单,接入几个平台后才发现,价格、库存和规格的业务含义都可能不同。现在我更关心的是,这些差异究竟会在哪些环节增加开发成本,以及能不能在存储设计阶段提前控制。
字段不统一通常不是单纯的命名问题,而是名称、类型、层级和业务语义同时发生变化。比如平台A使用 price 表示当前售价,平台B的 salePrice 可能是促销价,平台C的 price 则可能包含货币符号或区间价格。三个字段看起来都像“价格”,但直接合并后,报表口径很容易出错。
在一次多平台商品采集项目中,我们最初把字段差异都塞进采集代码,通过大量 if/else 完成转换。首个平台接入很快,但当平台数量从2个增加到5个后,一个字段变更往往要同时修改解析器、数据库表、清洗脚本和报表查询。真正消耗时间的不是首次接入,而是后续排查和回填。
差异类型示例容易产生的成本 名称不同title、name、product_name重复配置映射 类型不同99.00、¥99、促销价对象清洗和类型转换 层级不同商品价格、SKU价格数据模型调整 语义不同销量、月销量、累计销量报表口径错误 我的判断是,字段统一应该先从业务语义开始,而不是从数据库列名开始。
先定义“当前可售价格”“可售库存”“近30天销量”等标准含义,再配置来源字段和转换规则,能够避免把不同指标仅凭名称相似强行合并。因此,存储设计至少要保留三类信息:原始字段、标准字段和转换规则版本。
这样平台字段变化时,可以定位是采集失败、映射失效还是业务口径发生变化,而不是只能面对一条无法解释的异常数据。
我测试过把不同平台的原始结果全部写进 JSON,前期确实不用频繁改表,接入速度很快。但到了需要按平台比较价格、筛选库存和统计历史变化时,查询越来越复杂,我想知道 JSON 的灵活性到底把成本推迟到了哪里。
JSON 更省的是早期接入成本,不一定更省全生命周期成本。它适合保存平台原始响应和变化频繁的扩展字段,但如果直接把所有业务数据都放在 JSON 中,字段类型、查询口径和索引策略会逐渐失控。一次实际测试中,我们对约12万条商品记录同时采用结构化字段和 JSON 字段保存。
按平台、价格区间和库存状态查询时,结构化字段的 SQL 比较直接;而从 JSON 中筛选价格,需要处理字段缺失、字符串转数字和不同路径结构。开发人员每增加一个查询条件,都要先确认不同平台的数据路径是否一致。
方案初期接入跨平台查询字段变更长期判断 全部关系型宽表中好改表成本较高适合字段稳定项目 全部 JSON快较复杂接入灵活适合原型和原始留存 标准列加 JSON 扩展中较好可控适合长期多平台项目 我更推荐“结构化核心字段加 JSON 扩展字段”的折中方案。
商品ID、平台商品ID、SKU、标准价格、库存、抓取时间和数据状态应使用明确类型的列保存;平台专属标签、页面展示属性和暂时没有统一口径的字段,则放入 JSON 或扩展表。需要特别注意的是,JSON 不是字段治理方案。
它只能让结构变化暂时不阻塞写入,却不能自动解决“这个价格到底代表什么”或“库存是商品级还是 SKU 级”的问题。如果下游一定要查询、统计或跨平台比较,核心业务字段仍然应该尽早标准化。
我现在接入的平台不算多,但已经遇到新增字段要改表、历史数据无法回填、报表依赖平台字段的问题。我的目标不是追求最复杂的架构,而是想找到一套小团队也能落地、同时不会把维护成本推给未来的方案。
对多数多平台采集项目而言,最实用的不是在关系型数据库和数据湖之间二选一,而是建立“原始层、标准层、应用层”的轻量分层。小团队不需要一开始就搭建复杂平台,可以先用原始表和标准表实现边界隔离,等查询和历史分析需求增加后再扩展应用层。
原始层保存抓取时的真实结果,包括来源平台、接口或页面标识、原始响应、抓取批次、采集器版本和抓取时间。原始数据不应被标准化结果覆盖,因为规则调整或清洗错误发生后,只有保留原始记录,才有机会重新处理历史数据。
标准层负责统一跨平台真正需要比较的字段,例如内部商品ID、平台商品ID、SKU ID、商品名称、标准价格、可售库存、抓取时间和数据状态。这里要明确数据粒度,不能把商品级价格和 SKU 级价格混在同一张逻辑表中。应用层面向具体用途生成数据集,例如价格监控表、库存预警表或日报宽表。
这样报表不必直接依赖原始平台字段,平台字段变化时,主要修改映射和标准化流程,而不是逐个改动所有下游查询。
数据层保存内容主要价值 原始层原始响应、来源、批次、采集器版本追溯和重新处理 标准层统一商品、SKU、价格、库存字段跨平台查询和统计 应用层报表、监控、搜索专用数据隔离业务查询变化 我建议至少拆出商品表、SKU表、原始数据表、字段映射表和价格库存历史表。
当前状态可以放在商品或 SKU 主表中,但价格和库存如果需要分析变化趋势,就不能只覆盖旧值,而应按抓取批次或时间保存历史快照。这种设计的核心不是表越多越专业,而是让每类变化有明确去处:平台原始结构变化留在原始层,跨平台业务口径变化进入标准层,报表需求变化在应用层解决。
边界清楚后,新增一个平台通常只需要增加采集器和映射规则,不必重新设计整个数据库。
我以前评估方案时只看数据库采购费用和服务器配置,结果项目上线后,真正耗时的是字段映射、异常排查、历史回填和报表适配。现在我想建立一套更实际的评估方法,判断哪个方案在半年或一年后仍然可维护。
评估存储方案时,不能只比较数据库的部署费用,还要计算新平台接入、字段变更、数据修复、历史回填、查询开发和质量监控等工程成本。很多“便宜”的方案只是把成本从建库阶段转移到了后续维护阶段。我通常会用一个小型试点来评估,而不是先凭技术偏好定方案。
选取2到3个平台,抽取商品、SKU、价格、库存和规格等核心数据,然后模拟三个变化:新增一个平台专属字段、修改一个价格字段类型、增加一个跨平台价格查询。记录每个变化需要修改多少文件、多少张表和多少条 SQL。
评估项目需要观察的问题风险信号 新增平台是否只需增加映射配置必须复制大量解析逻辑 字段变更能否定位影响范围只能依靠报表异常发现 历史回填是否保留原始数据和规则版本只能重新抓取全部数据 跨平台查询核心字段是否统一类型和口径每个平台都要写一套 SQL 异常排查是否记录失败原因和样本只能查看最终空值 可以把总成本粗略拆成:初始建设成本,加上平台接入成本、字段变更成本、数据修复成本和下游查询成本。
这个模型不需要假装精确到某个百分比,但能帮助团队看清楚某种方案究竟节省了哪一部分工作,又把哪一部分工作推迟了。如果只有一个平台、字段稳定、查询简单,关系型表通常最直接。如果平台数量持续增加,但业务口径仍在探索,可以采用原始 JSON 加少量标准字段。
若已经需要跨平台比较和长期报表,更适合采用标准字段表加扩展字段,并配套映射表和版本管理。上线前我会重点检查四件事:增加字段是否必须改表,平台字段变化是否能被监控,清洗失败是否有异常队列,以及规则更新后能否重新处理历史数据。只要这四个问题没有答案,存储方案即使初期运行正常,后续维护成本也很可能失控。


读者评论
文章把字段不统一的成本讲得比较具体,尤其是价格、库存和销量的口径差异。对多平台项目来说,先保留原始数据,再建立标准字段,确实比一开始做万能宽表更稳妥。
文中对 JSON 和关系型存储的比较较为客观,没有简单判断哪种方案最好。不过实际落地还要结合团队的数据治理能力、查询频率和历史数据规模,分层设计并非所有小项目都需要一开始就采用。
从开发维护角度看,文章强调字段字典、数据粒度和变更影响范围,这些内容很有参考价值。特别是把商品、SPU、SKU 分开管理,可以减少库存和价格被覆盖的问题。