Files
goods/docs/planning/history/v0.2-go-python-foodfmcg.md
lixu 54175238ad docs: 归档天工·商品标签(OpenGoods)规划文档
新增 docs/planning/ 规划文档归档:
- 00-final-plan: 最终规划(决策+架构+M0~M5任务清单)
- 01-detailed-design-v2.0: 分类/单位/数据库/API/治理/采集/部署/众包
- 02-advanced-topics-v3.0: OpenAPI/全表DDL/数据契约/OFF映射/中国合规/测试/安全/图片/SLA/竞品
- history/: v0.1~v1.0 演进记录
更新 README 为项目介绍并链接规划文档。

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-06-08 06:05:29 +00:00

13 KiB
Raw Permalink Blame History

商品档案公益 API 系统 — 规划方案 (v0.2)

公益网站/服务:采集全网商品信息,对外提供商品参数查询 API。 原则:只收集 + 只提供信息,不涉及任何购买/下单/比价导购。 本版根据你的反馈定稿四件事:① 收录官方标准零售价(MSRP) ② 首批聚焦食品快消Go(系统) + Python(采集) 多语言架构 ④ 附开放数据源清单


0. 你已确认的决策

# 决策 说明
1 价格 = 官方标准零售价 (MSRP) 厂商指导价/官方建议零售价,属静态属性,带来源+时间+币种标注;不收录实时电商售价、不提供购买入口
2 首批品类 = 食品快消 (Food & FMCG) 先把食品的数据模型打磨好(成分、营养、过敏原、规格、保质期…)
3 技术栈 = Go + Python Go 写对外 API/核心服务;Python 写采集/ETL/爬虫;通过 PostgreSQL + 消息队列解耦
4 数据源 = 暂无,后期提供 本版先给出可立即接入的开放数据源清单

1. Go + Python 多语言架构(核心)

这是一个很经典且合理的组合。两端不直接互相调用,而是通过共享数据库 + 消息队列解耦,各自独立部署、独立扩展。

            ┌────────────────────── Python 侧 (采集/数据) ──────────────────────┐
            │                                                                    │
   数据源 ─▶│  采集 Workers (爬虫/适配器)  ─▶  ETL 清洗/标准化/去重  ─▶  入库     │
            │  httpx / Playwright / scrapy     pandas / 规则引擎                  │
            └───────────────────────────┬────────────────────────────────────────┘
                                        │ 写入
                                ┌───────▼────────┐        ┌──────────────┐
                                │  PostgreSQL    │◀──────▶│  对象存储 S3  │ (商品图)
                                │  (商品档案主库) │        └──────────────┘
                                └───────▲────────┘
                                        │ 只读
            ┌───────────────────────────┴────────────────────────────────────────┐
            │                          Go 侧 (对外服务)                            │
            │  公开 API (REST/JSON)  +  Redis 缓存/限流  +  搜索网关  +  OpenAPI    │
            │  Gin/Echo/Chi/标准库                                                 │
            └───────────────────────────┬────────────────────────────────────────┘
                                        │
                              各种软件 / 开发者消费

1.1 职责划分

子系统 语言 职责
公开 API 服务 Go 对外只读 API、限流、缓存、鉴权(可选 API Key)、检索网关、高并发承载
采集 Workers Python 每个数据源一个 adapter,抓取/调用 API、遵守 robots、限速、产出原始数据
ETL / 数据处理 Python 清洗、字段映射、单位归一、实体去重与合并、质量评分
调度 / 队列 Python(worker) + Redis/消息队列 定时任务、增量更新、任务分发
存储 PostgreSQL + Redis + S3 主库 / 缓存+限流 / 图片
检索 初期 PG 全文 → 后期 OpenSearch 商品名/参数搜索与分面

1.2 为什么这样分?

  • Go 做 API:编译型、单二进制部署、并发模型适合高 QPS 的只读公益 API,运维简单。
  • Python 做采集:爬虫/解析/数据处理生态最强(scrapy、playwright、pandas),迭代快。
  • 解耦点 = 数据库Go 端只读主库(或读副本),Python 端负责写入。两端通过稳定的表结构约定协作,互不阻塞;将来任一端换语言/重写都不影响另一端。
  • 契约:用数据库 schema + 一份内部「数据契约文档」固定字段含义,避免两端理解不一致。

2. 食品快消数据模型(细化)

食品参数差异大,沿用 核心字段 + JSONB 灵活属性 + 营养结构化子表。字段设计大量参考 Open Food Facts(成熟的食品开放库)。

2.1 商品主表 product

{
  "id": "uuid",
  "gtin": "6901234567892",            // 条码(主键标识), EAN-13/UPC/EAN-8
  "name": "示例牌 巧克力榛子酱 400g",
  "brand": "示例牌",                   // -> brand
  "manufacturer": "示例食品有限公司",   // 生产商
  "category": "食品/酱料/巧克力酱",     // -> category 树 (可对齐 GS1 GPC / OFF categories)
  "net_content": {"value": 400, "unit": "g"},   // 净含量
  "country_of_origin": "中国",
  "shelf_life": {"value": 12, "unit": "月"},     // 保质期
  "storage": "常温避光保存",
  "images": ["S3_URL", ...],
  "msrp": { ... },                    // 官方标准零售价, 见 2.3
  "food": { ... },                    // 食品专属结构化字段, 见 2.2
  "attributes": [ {"key":"","value":"","unit":""} ],  // 其余灵活参数(JSONB)
  "identifiers": {"ean":"", "upc":"", "off_id":""},
  "sources": [ {"source":"", "url":"", "fetched_at":"", "fields":["msrp"]} ],
  "quality_score": 0.0,
  "status": "active|merged|deprecated",
  "created_at": "", "updated_at": ""
}

2.2 食品专属字段 food(结构化)

{
  "ingredients_text": "白砂糖, 棕榈油, 榛子(13%), ...",   // 配料表原文
  "ingredients": [ {"name":"白砂糖","rank":1}, ... ],     // 解析后(可选)
  "allergens": ["坚果", "大豆", "乳"],                    // 过敏原
  "additives": ["E322 卵磷脂"],                           // 添加剂
  "nutriments": {                                         // 营养成分(每100g/100ml)
    "energy_kj": 2252, "energy_kcal": 539,
    "fat_g": 30.9, "saturated_fat_g": 10.6,
    "carbohydrates_g": 57.5, "sugars_g": 56.3,
    "protein_g": 6.3, "salt_g": 0.107
  },
  "nutrition_basis": "per_100g",                          // per_100g | per_100ml | per_serving
  "serving_size": "15g",
  "is_vegetarian": null, "is_vegan": null,                // 可空
  "nutri_score": "C",                                     // 若引用 OFF
  "labels": ["无添加", "清真"]                             // 认证/标签
}

2.3 官方标准零售价 msrp(重点)

{
  "amount": 29.90,
  "currency": "CNY",
  "type": "msrp",                      // 仅 msrp/官方指导价; 不存实时电商成交价
  "region": "CN",                      // 适用地区(价格随地区不同)
  "source": "厂商官网/官方价目表",
  "source_url": "https://...",
  "effective_date": "2026-01-01",      // 价格生效/采集时间
  "note": "官方建议零售价, 实际售价以零售商为准; 本站不提供购买"
}

设计要点:价格是带时间戳的历史快照而非实时报价;明确 type=msrp、标注地区与来源;响应里附免责说明。坚决不出现购买/跳转链接。

2.4 辅助实体

brand / manufacturer / category(品类树) / source(数据来源登记) / attribute_definition(参数字典: 标准名·别名·单位) / merge_log(实体合并记录, 保留溯源)。


3. 可立即接入的开放数据源清单(食品快消)

按"合规性 / 可用性"排序。这些可作为种子数据 + 采集 adapter 的首批对象

数据源 内容 许可 接入方式 备注
Open Food Facts 全球食品(成分/营养/过敏原/Nutri-Score/图片) ODbL(数据)+DbCL+CC-BY-SA(图) REST API + 每夜全量 dump(CSV/MongoDB, ~9GB) 食品首选;可贡献回写;限速 15 req/min/IP(读)
USDA FoodData Central 美国食品营养成分(含 Branded 品牌库) CC0(公共领域) REST API(需免费 key) + JSON/CSV 下载 营养数据权威;商业可用
GS1 / Verified by GS1(中国商品信息服务平台) 条码→品牌/规格/厂商(官方登记) 受限(需企业/接口授权) 网页查询 + API(≤1000 GTIN/次) 条码→商品最权威来源;2亿+条;中国数据首选
brocade.io 开放 GTIN/条码产品库 开源/开放 免费 REST(免鉴权读) 数据量有限,可作补充
3023data 等条码接口 中国物品编码+UPC+ISBN 商业(0.005~0.02元/次) REST API 付费,作兜底补全,非首选
各国监管公开数据 食品备案/标签/能效等 多为公开 各平台 后续按需逐个评估合规

参考用开源项目(架构/数据模型借鉴,非数据源)

  • Open Food Facts Server (Product Opener) — 食品库的完整实现,可学其字段与流程
  • UnoPIM / PCMT / brocade.io — 开源 PIM / 商品主数据系统,借鉴建模与去重

建议:先用 Open Food Facts 全量 dump 作种子数据(直接有海量真实食品),再用 GS1/USDA 做补全与校验。这样 MVP 阶段就有真实可查的数据。


4. 公开 API 契约(Go 实现,只读)

GET /api/v1/products/barcode/{gtin}     # ★最常用: 条码查档案
GET /api/v1/products/{id}               # 内部ID查
GET /api/v1/products/search             # ?q=&brand=&category=&allergen_free=&page=&size=&fields=
GET /api/v1/products/{id}/nutriments    # 仅营养
GET /api/v1/products/{id}/msrp          # 仅官方零售价(含来源/时间/免责)
GET /api/v1/brands  |  /categories      # 品牌 / 品类树
GET /api/v1/sources/{id}                # 数据来源透明说明
GET /healthz  |  /api/v1/openapi.json   # 健康检查 / 机读文档

约定:版本化 /v1/;统一响应 {data, meta(分页), sources(溯源)};分页 + fields= 裁剪;匿名按 IP 限流,可选免费 API Key 提配额;CDN+Redis 缓存(参数变化慢,命中率高);数据采用开放许可(CC BY / ODbL,注意 OFF 的 ODbL 传染性);无任何购买/交易端点


5. 合规与边界(公益项目重点)

  • 数据源许可要分清OFF 是 ODbL(衍生数据库需同样开放+署名),USDA 是 CC0(最宽松)。混用时要按最严格许可对外标注,避免许可冲突。
  • 爬取守 robots.txt / 服务条款,礼貌限速,标明 User-Agent 身份。
  • 只采客观参数;营销文案/评测原文不照搬(链接来源即可)。
  • 无个人数据(PII),只处理商品信息。
  • 站点显著声明:仅提供信息、不提供购买、不构成消费建议;价格为官方指导价历史快照。
  • 提供权利方纠错/下架联系渠道。

6. 里程碑(仍不写代码,仅规划,供确认)

阶段 目标 关键产出
M0 工程地基 仓库骨架 Go API 骨架 + Python 采集骨架 + PostgreSQL + Docker Compose + CI + 数据契约文档
M1 数据模型 食品 schema 主表/食品字段/MSRP/辅助实体 的迁移与字典
M2 种子数据 有真实数据 导入 Open Food Facts dump(食品子集) + USDA 营养补全
M3 MVP API (Go) 可查询 条码/ID/搜索/营养/MSRP + OpenAPI 文档 + 限流缓存
M4 采集管线 (Python) 自动更新 1~2 个 adapter(OFF API / GS1) + ETL + 去重 + 质量评分 + 调度
M5 开放与规模化 上线 搜索引擎 + CDN + API Key + 众包纠错后台 + 开发者文档站 + 开放数据许可

7. 待你确认/补充

  1. 价格范围:确认只收「官方指导价 (MSRP)」、不碰实时电商价?(建议是)
  2. OFF 的 ODbL 许可:可接受(意味着我们对外的数据库也要用 ODbL 并署名 OFF)?还是更想用 CC0 来源(USDA)为主以保持宽松?
  3. 种子数据:同意先导入 Open Food Facts 食品 dump 作为启动数据吗?
  4. Go Web 框架偏好Gin / Echo / Chi / 标准库 net/http,有偏好吗?(无偏好我默认 Chi 或标准库,轻量)
  5. 地域范围:首批面向中国市场商品,还是中外都收?(影响优先用 GS1-China 还是 OFF 全球库)

你确认后,我把它定为 v1.0 规划,并据此拆成可执行的工程任务清单(仍按你的节奏,需要我动手写代码时再开始)。