资讯动态

REA模型落地指南:用资源-事件-参与者重构业务事实,打通数据中台与审计追溯

发布时间:2026/10/15 14:59:14 来源:尧图企业网站定制
别急着画表结构。如果你只是需要一个能记账的系统那儿科目余额表就够了但如果你要的是一个能回答这批货是谁买的、为什么买、买完之后又流向了谁的业务事实模型那传统的借贷分录会把你逼疯。这也是我最近在梳理一套内部业务中台时重新把 REAResource-Event-Agent资源-事件-参与者这个老模型翻出来用的原因。这篇文章不打算讲教科书定义我想结合一次完整的落地方案聊聊 REA 到底解决什么问题、怎么从概念映射成表结构、跑起来之后能获得哪些传统模型拿不到的东西以及那些不翻一次车就记不住的坑。1. 为什么放着现成的科目表不用非要碰REA这个老模型1.1 复式记账模型的三个盲区我接触过不少业务系统底层账表几乎都是清一色的复式记账结构凭证、科目、借贷方、金额。这套东西的好处是严谨、有几百年的验证坏处也明显——它只回答了钱怎么流动回答不了业务为什么发生。举个例子。你看到一笔分录借库存商品 5000贷应付账款 5000。这告诉你商品增加了、欠款增加了但你没法直接从这条分录里回答这批货是哪个供应商送的是哪个采购员经手的对应的是哪一张采购订单这笔入库之后货是卖出去了还是报废了传统模型把这些信息塞在摘要、辅助核算和一大堆关联表里查询的时候要从凭证跳到单据、从单据跳到主数据链路断一次就没法追溯了。REA 的出发点正好相反它不把记账当作核心而是把业务事实当作核心。每一次业务发生本质上都是某个参与者对某项资源做了某个动作。把这个事实记录下来凭证只是它的一种投影视角。这个思路对现在的数据中台和业务建模来说比科目余额表好用得多。1.2 REA 模型的历史包袱和现在翻身的原因REA 最早是上世纪八十年代在会计信息系统领域提出的当时的想法很激进会计信息系统不应该只记录借和贷而应该记录完整的业务语义。你要知道那时候的 ERP 都还在萌芽期这套理论其实一直偏学术真正按它落地的大型系统不多。但近几年情况变了。事件驱动架构流行起来大家发现业务系统里最值得沉淀的其实不是状态而是事件数据中台和湖仓一体的建设又要求把跨系统的数据统一成一个共享语义层。REA 本质上就是一种现成的业务本体——它告诉你每个业务事实里应该有哪些角色、哪些对象、哪些关联关系。于是这个老模型又变得非常有实用价值。1.3 先搞清楚边界REA 不是用来替代总账的这里必须先泼一盆冷水。很多人一听 REA 就觉得要把财务总账干掉实际不是。我做完那个项目之后的体会是REA 管的是业务事实层总账管的是价值计量层。一件商品入库REA 记录的是哪个供应商在什么时间交付了哪批货、货进了哪个仓库总账记录的是库存商品增加了多少金额、应付账款增加了多少金额。两者是上下游关系。REA 层负责把业务动作结构化总账层负责把业务动作转化为会计语言。所以不要再问REA 能不能替代复式记账正确的问题是我能不能在业务系统和总账之间加一层 REA 语义模型让所有单据、报表、审计线索都长在同一个事实底座上。这个项目做完之后我可以明确告诉你能而且非常值。2. 把REA拆开看Resource、Event、Agent到底是什么边界在哪2.1 Resource不是库存实物而是能被控制且有价值的东西Resource 是最容易被误解的概念。很多人一听资源就往物料、商品、固定资产上想觉得资源就是实物。实际上 REA 里的 Resource 定义得非常宽钱是资源货是资源一个小时的咨询服务也是资源一项专利授权还是资源。判断标准有两个第一它能否被某个参与者控制第二它是否具有经济价值。能被控制意味着有归属、有责任主体有经济价值意味着它值得被追踪。比如客户的满意度不是 Resource因为你控制不了它但云服务商提供的计算时长是 Resource因为你可以购买、消耗、分配它。我自己的建模习惯是先列所有会被事件改变状态的对象再去掉那些不可控制、无价值的剩下的就是 Resource 候选集。用这个办法筛完通常不会漏也不会滥。2.2 Event业务动作而不是单据状态Event 是 REA 里最核心的构造块也是最容易建模错的地方。REA 把经济事件分成两类Give资源流出和 Receive资源流入。一次采购入库商品进仓库就是 Receive一次付款银行存款减少就是 Give一次销售发货商品流出是 Give同时收到的货款是另一个 Receive。关键边界在于Event 描述的是在某个时点发生的动作而不是单据处于什么状态。订单已创建、订单已审核、订单已完成这些是状态供应商发货、仓库收货、财务付款这些是事件。我见过很多失败的建模就是把订单审批通过当成事件结果整个模型变成了一张状态机表根本跑不出业务语义。所以建模的时候我给自己定了一条铁律如果一个动作没有让至少一个 Resource 发生流入或流出它就不够格成为经济事件。审批、校验、通知这些动作在 REA 框架里更适合建模为约束或流程步骤而不是核心事件。2.3 Agent人和组织以及那条容易被忽略的内外之分Agent 指参与事件的个人或组织比如采购员、供应商、仓库管理员、客户、物流公司。这里有一个特别容易忽略的细节REA 区分内部参与者和外部参与者。内部参与者通常是本组织的员工和部门外部参与者是客户、供应商、承运商这些。这个区分的价值在审计上特别明显。一笔采购入库事件内部参与者是仓库收货员外部参与者是供应商。将来如果要对账、要追溯这批货到底是谁发的、谁接收的这两个 Agent 缺一不可。我只记录入库数量而没有记录参与者那这条事件就失去了大半复用价值。另外Agent 和 Resource 的边界也容易混有时候组织既是参与者又控制着资源。比如供应商既参与了交货这个事件又控制着待交付的订单承诺这个资源。处理办法是同一实体的不同角色放在不同表里建模。供应商作为 Agent 进 agent 表它承诺要交付的货建模成 Commitment 资源而不是混在 Agent 表里。2.4 三条关键连线存量-流量、二元性、控制关系光有 Resource、Event、Agent 三张表是不够的REA 的真正骨架在关系里。标准 REA 有三大关联关系我在落地时每条都直接对应了表字段或关联表。存量-流量关系Stockflow连接 Resource 和 Event表达这个事件让资源增加还是减少。一个收货事件连接库存资源流量方向是流入一个发货事件连接同一批库存资源流量方向是流出。把这种关系建模出来之后资源的余额就可以通过事件的累加推导出来这是 REA 最强大的能力之一。二元性关系Duality连接 Give 事件和 Receive 事件表达用一项资源的流出换取另一项资源的流入。销售发货这个 Give 和收款这个 Receive 之间就有二元性关系采购收货这个 Receive 和付款这个 Give 之间也有二元性关系。这个关系是业务闭环的审计线索。控制关系Control连接 Agent 和 Event表达谁参与了这次事件。这个关系可以细分为谁发起谁执行谁审批不过 REA 标准模型只需要记录参与即可多角色场景可以在关联表上加上参与类型字段。2.5 契约事件与执行事件订单和合同在 REA 里的正确位置最后补一个很多人问的点订单、合同、承诺这些东西算不算 Resource直接说答案在 REA 里它们被建模为 Commitment也就是契约型事件。它和执行的差别是契约描述的是未来将发生的资源流转执行描述的是已经发生的资源流转。我实际操作的时候会把契约和执行分成两套表或者在同一张事件表里用事件类型区分。比如采购订单是契约承诺未来会收到一批货并付出对应的钱采购入库是执行货已经收到钱还没付的话就变成了应付账款。这个区分让预测未来现金流和核对实际业务都变得非常简单。你写查询的时候只要筛选事件类型就能分别看已承诺和已执行的情况。3. 从概念模型到数据库表REA落地的映射方案与表结构设计3.1 建模顺序先画事件链再画资源最后配参与者很多初学者一上来就打开数据库画表这是错的。我建议的建模顺序是先把业务端到端的事件链画出来再标注每个事件涉及哪些资源流最后才补参与者和关联关系。事件链怎么画以采购付款为例供应商报价、下采购订单、供应商发货、仓库收货、质检、财务收票、付款。第一轮先圈出哪些是真正的经济事件收货是库存流入、付款是现金流出、发货是供应商的库存流出在我们这边表现为收货。下采购订单不是事件是契约质检不是 REA 事件因为质检不改变任何 Resource 的流入流出它只是事件的通过条件。画完事件链之后每一个事件旁边的资源就很明显了。收货旁边是商品库存付款旁边是资金。然后再问谁发货、谁收货、谁付款、谁审批。参与者列出来关系也就自然出来了。3.2 五张核心表的结构设计按我在项目里的落地经验最小可用的 REA 表结构是五张表资源表、参与者表、事件表、契约表、关联关系表。事件和资源的关系、事件和参与者的关系可以做成关联表也可以直接用外键字段取决于事件的复杂程度。资源表记录资源的静态属性。比如商品资源的编码、名称、规格、计量单位资金资源的币种、账户服务资源的计价单位。每个资源有一个全局唯一的资源 ID这是我推荐的额外 ID而不是直接用业务编码因为业务编码在跨系统对接时经常不一致。事件表是核心。我的做法是事件表统一保存所有经济事件包含事件类型give/receive/commitment、发生时间、涉及的资源、数量、金额、参与者和关联的契约。为了查询效率我有时候会把 give 和 receive 各放一条记录但通过一个事件对字段把互为二元性的事件绑在一起。契约表保存承诺信息。字段包括契约类型、约定时间、约定数量、约定金额、状态、对应的关联执行事件。这张表的价值在于当你需要预测未来会流入多少库存、流出多少现金时直接查契约表就行不用去推断。关联关系表我一般拆成 event_resource、event_agent 和 event_duality 三张。event_resource 记录每个事件对资源的流量方向和数量event_agent 记录每个事件的参与者角色event_duality 记录事件之间的配对关系。这样虽然多了几张表但好处是查询路径极其清晰而且未来接入新事件类型不用改表结构。3.3 关键设计决策事件表用单表还是分表、金额数值怎么存这里有两个经常被问的设计问题。第一个事件表是全部塞一张大表还是按业务域分表我的答案是先按领域分、在逻辑上统一。比如采购领域的收货事件、销售领域的发货事件、财务领域的付款事件物理上可以放同一张 econ_event 表但通过 event_type 字段区分如果量特别大再按时间或业务域做分区。单表的好处是可以用统一的 SQL 做全链路追踪跨领域分析时不用 join 一堆结构不同的表。坏处是表字段会比较多稍微冗余。到了业务中台这个层面单表加分区是性价比最高的。第二个金额和数量用 decimal 还是 double这个不用犹豫能用 decimal 就不要用 float。你是做业务建模不是做科学计算精度比性能重要。我习惯的模式是金额用 decimal(20,4)数量用 decimal(18,4)而且每条事件行同时冗余记录当时的单价和币种。为什么因为如果将来要做历史金额重估、或者不同币种的对账没有原始单价和币种你根本没法复算。3.4 一版可直接套用的 DDL 示例下面这版结构是从我的模拟项目里简化出来的覆盖了采购、销售、收付款这类最常见的业务。你拿去改改就能用。-- 资源表钱、货、服务都在这里 CREATE TABLE resource ( resource_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, resource_code VARCHAR(64) NOT NULL, resource_name VARCHAR(255) NOT NULL, resource_type VARCHAR(32) NOT NULL, -- MATERIAL / CASH / SERVICE / EQUIPMENT unit_of_measure VARCHAR(32), currency_code VARCHAR(8), -- 仅资金类资源使用 status VARCHAR(16), created_at TIMESTAMP NOT NULL DEFAULT now() ); -- 参与者表人和组织统一存放 CREATE TABLE economic_agent ( agent_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, agent_code VARCHAR(64) NOT NULL, agent_name VARCHAR(255) NOT NULL, agent_type VARCHAR(32) NOT NULL, -- INTERNAL / EXTERNAL agent_category VARCHAR(32), -- EMPLOYEE / DEPARTMENT / SUPPLIER / CUSTOMER contact_info JSONB ); -- 事件表核心业务事件统一入口 CREATE TABLE economic_event ( event_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, event_no VARCHAR(32) NOT NULL, event_type VARCHAR(32) NOT NULL, -- RECEIVE / GIVE / COMMITMENT event_time TIMESTAMP NOT NULL, description VARCHAR(512), status VARCHAR(16) NOT NULL DEFAULT ACTIVE, created_at TIMESTAMP NOT NULL DEFAULT now() ); -- 契约表订单、合同等承诺型事件 CREATE TABLE commitment ( commitment_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, commitment_no VARCHAR(32) NOT NULL, commitment_type VARCHAR(32) NOT NULL, -- PURCHASE_ORDER / SALES_ORDER / CONTRACT counterparty_id BIGINT NOT NULL REFERENCES economic_agent(agent_id), agreed_time TIMESTAMP, agreed_amount DECIMAL(20,4), status VARCHAR(16), created_at TIMESTAMP NOT NULL DEFAULT now() ); -- 事件-资源关联表记录资源流方向和数量 CREATE TABLE event_resource ( event_id BIGINT NOT NULL REFERENCES economic_event(event_id), resource_id BIGINT NOT NULL REFERENCES resource(resource_id), flow_direction VARCHAR(8) NOT NULL, -- INFLOW / OUTFLOW quantity DECIMAL(18,4) NOT NULL, unit_price DECIMAL(20,4), amount DECIMAL(20,4) ); -- 事件-参与者关联表记录谁参与了事件 CREATE TABLE event_agent ( event_id BIGINT NOT NULL REFERENCES economic_event(event_id), agent_id BIGINT NOT NULL REFERENCES economic_agent(agent_id), participation_type VARCHAR(32) NOT NULL, -- INITIATOR / EXECUTOR / SUPPLIER / CUSTOMER participation_time TIMESTAMP ); -- 事件-事件配对表记录二元性关系 CREATE TABLE event_duality ( give_event_id BIGINT NOT NULL REFERENCES economic_event(event_id), receive_event_id BIGINT NOT NULL REFERENCES economic_event(event_id), relationship_type VARCHAR(32) NOT NULL, -- EXCHANGE / CONVERSION created_at TIMESTAMP NOT NULL DEFAULT now() );这套表结构看起来比自己平时乱建的一堆业务表多但你一旦把数据灌进去查询的确定性就出来了。后面所有报表、对账、审计都是在这套结构上做投影不需要再到处补字段。4. 一个完整的采购到付款案例从业务规则到SQL查询4.1 场景与业务规则为了把上面的表结构跑通我拿了一个模拟场景某商贸企业要从供应商那里采购一批商品然后付款给供应商。业务规则是这样采购员先下采购订单约定购入 100 个商品 A单价 50 元仓库收到 100 个商品 A入库财务根据收货记录向供应商付款 5000 元。这里有几个关键点订单是契约不是执行事件收货是执行事件资源流入是商品库存付款是执行事件资源流出是银行存款。如果你按这套规则来建模后续任何一笔数据都能被完整追踪。4.2 事件链拆解与建模先建资源商品 A商品库存计量单位个银行存款资金资源币种 CNY。再建参与者供应商 S外部参与者、采购员 P内部参与者、仓库管理员 W内部参与者、财务人员 F内部参与者。接下来建事件。第一个事件是下订单事件类型是 COMMITMENT关联的契约是订单号 PO-2025-0001约定到货时间是 2025-06-10。第二个事件是收货事件类型是 RECEIVE资源是商品 A流入数量 100关联契约 PO-2025-0001参与人是仓库管理员 W外部参与人供应商 S。第三个事件是付款事件类型是 GIVE资源是银行存款流出金额 5000 元关联契约 PO-2025-0001参与人是财务人员 F。这里要注意付款和收货之间要建立二元性关系。为什么因为这样一来你可以随时回答这笔付款对应的是哪批货这批货对应的钱付清了没有。这个关联就是审计和对账的锚点。4.3 插入模拟数据你直接执行下面几段 INSERT 就能把这套场景跑起来-- 资源 INSERT INTO resource (resource_code, resource_name, resource_type, unit_of_measure) VALUES (ITEM-A, 商品A, MATERIAL, 个); INSERT INTO resource (resource_code, resource_name, resource_type, unit_of_measure, currency_code) VALUES (CASH-CNY, 银行存款, CASH, 元, CNY); -- 参与者 INSERT INTO economic_agent (agent_code, agent_name, agent_type, agent_category) VALUES (SUP-001, 某供应商, EXTERNAL, SUPPLIER); INSERT INTO economic_agent (agent_code, agent_name, agent_type, agent_category) VALUES (EMP-P01, 采购员P, INTERNAL, EMPLOYEE); INSERT INTO economic_agent (agent_code, agent_name, agent_type, agent_category) VALUES (EMP-W01, 仓库管理员W, INTERNAL, EMPLOYEE); INSERT INTO economic_agent (agent_code, agent_name, agent_type, agent_category) VALUES (EMP-F01, 财务人员F, INTERNAL, EMPLOYEE); -- 事件 INSERT INTO economic_event (event_no, event_type, event_time, description) VALUES (EVT-COMMIT-0001, COMMITMENT, 2025-06-01 10:00:00, 采购订单下达); INSERT INTO economic_event (event_no, event_type, event_time, description) VALUES (EVT-RCV-0001, RECEIVE, 2025-06-10 14:30:00, 仓库完成收货); INSERT INTO economic_event (event_no, event_type, event_time, description) VALUES (EVT-PAY-0001, GIVE, 2025-06-11 09:00:00, 财务完成付款); -- 契约 INSERT INTO commitment (commitment_no, commitment_type, counterparty_id, agreed_time, agreed_amount, status) VALUES (PO-2025-0001, PURCHASE_ORDER, 1, 2025-06-10, 5000.0000, FULFILLED);事件和资源、参与者的关联我建议你用脚本批量灌进去这里只演示核心逻辑收货事件对应商品 A流入数量 100单价 50金额 5000付款事件对应银行存款流出金额 5000。收货事件关联仓库管理员 W 和供应商 S付款事件关联财务人员 F。4.4 三个典型查询供应商履约、资源全生命周期、应付余额推导模型建好之后最有价值的时刻就是写查询。第一个典型查询是某供应商的历史履约情况。传统模型里你要把采购订单、入库单、付款单三套表来回 joinREA 模型里你只要过滤事件参与者和事件类型SELECT e.event_no, e.event_type, e.event_time, er.flow_direction, er.quantity, er.amount FROM economic_event e JOIN event_agent ea ON e.event_id ea.event_id JOIN economic_agent a ON ea.agent_id a.agent_id JOIN event_resource er ON e.event_id er.event_id WHERE a.agent_code SUP-001 ORDER BY e.event_time;第二个典型查询是某个资源从进入系统到离开系统的完整链路。比如你想追踪商品 A 从采购入库到销售出库的整个过程只需要按资源过滤所有事件按时间排序就能得到一份完整的资源履历。这个能力在质量追溯、批次管理、合规审计里非常有用而且不用额外建什么追溯表。第三个典型查询是推导应付余额。在 REA 里应付账款等于已承诺要付的金额加上已收货应付的金额减去已付款的金额。如果你把收货事件资源流入和付款事件资源流出按供应商聚合两者的差额就是当前欠款SELECT ea.agent_name, COALESCE(receive_total, 0) - COALESCE(give_total, 0) AS balance_due FROM economic_agent ea LEFT JOIN ( SELECT ea.agent_id, SUM(er.amount) AS receive_total FROM event_agent ea JOIN event_resource er ON er.event_id ea.event_id JOIN economic_event e ON e.event_id er.event_id WHERE er.flow_direction INFLOW GROUP BY ea.agent_id ) AS r ON ea.agent_id r.agent_id LEFT JOIN ( SELECT ea.agent_id, SUM(er.amount) AS give_total FROM event_agent ea JOIN event_resource er ON er.event_id ea.event_id JOIN economic_event e ON e.event_id er.event_id WHERE er.flow_direction OUTFLOW GROUP BY ea.agent_id ) AS g ON ea.agent_id g.agent_id WHERE ea.agent_category SUPPLIER;这套查询能力并不是我硬凑的而是 REA 模型天然支持的只要你把业务事实按资源、事件、参与者拆开任何维度的汇总都只是换个过滤条件的问题。4.5 与现有ERP单据的映射关系很多人在落地 REA 时都会问我们公司已经有 ERP 的采购订单、入库单、付款单了怎么办答案很简单把 ERP 单据作为事件来源REA 表作为语义层。换句话说ERP 单据还在原来的系统里负责流程操作REA 模型从单据里抽取业务事实把事实映射成标准化的资源流和事件流。比如 ERP 的采购订单对应到 Commitment入库单对应到 RECEIVE 事件付款单对应到 GIVE 事件。这样做的好处是你不需要推翻现有系统只需要在数据层加一个转换管道比如 CDC 加消息队列加映射服务就能让所有业务数据进入统一的 REA 语义层。至于有效性验证可以在映射层做如果一个入库单没有关联采购订单就说明来源不清晰应该告警。5. 查完账之后REA模型给报表、审计和数据架构带来的额外收益5.1 能直接支撑的分析报表类型有了 REA 语义层之后很多原来要专门写报表 SQL 的分析场景变成了简单的聚合查询。我列一下我在项目里实际跑过的报表类型供应商对账单按供应商聚合所有收发货和付款事件、资源进销存台账按资源聚合所有流入流出事件、参与者贡献分析按销售员聚合所有销售事件、资金预测按契约表聚合未来收付款计划。这套结构对管理驾驶舱类的需求特别友好。因为事件表里天然有时间字段按天、按周、按月做窗口聚合都很快事件表里有参与者字段按部门、按人员、按供应商切片也很容易。你有多少种分析维度只需要看你有多少种资源和多少种参与者类型。5.2 审计线索为什么 REA 天生不怕对账审计的关键是证据链完整。传统模型下一笔采购业务的证据链分散在订单、入库、发票、付款等多个模块每个模块之间靠单据编号关联一旦某个模块改了数据断链很难发现。REA 的好处是任何一笔业务事实都通过事件-资源-参与者的关系连接在一起而且事件本身是不可变的历史事实我建议你在实现时只允许追加不允许更新和删除。这就意味着审计人员可以沿着事件链一路走到底从付款事件出发找到对应的收货事件再找到对应的契约和参与者每一步都有关联关系每一步都有时间戳。如果发现一笔收货没有对应的契约或者一笔付款没有对应的收货那就是天然的疑点。我在实际项目里把这种校验写成了定期任务跑一个晚上就能把全量数据里的断链找出来这个能力是传统账表很难给的。5.3 在事件驱动架构和数据中台里的定位如果你在搭建数据中台或者做事件驱动改造REA 的价值会进一步放大。事件驱动架构里到处都是订单已创建库存已扣减这类事件但这些事件往往是系统间通信用的字段设计跟业务结果没有强关联。REA 相当于给这些事件提供了一个语义锚点每个事件到底让什么资源的流量发生了变化、谁参与的、和哪个契约相关。我比较推荐的做法是把 REA 语义层作为数据中台里的共享维度模型上游接入各种业务系统的原始事件下游对接指标层和应用层。这样指标定义就有了统一的颗粒度——你不需要分别在订单域、库存域、财务域各定义一遍入库和出库因为它们在 REA 层已经统一了。数据湖里的表可以继续保留原始格式但对外提供分析服务的是这层经过 REA 标准化的模型。6. 落地过程中最容易翻车的几个坑6.1 把单据状态当事件是非常普遍的建模错误我在审别人的 REA 建模稿时见到最多的问题就是把单据状态变化当成经济事件。比如订单审核通过被记成一条事件但这件事没有让任何资源发生流入或流出它只是业务流程里的一道阀门。一旦把这类状态变化混进事件表你的事件表就会变成一张状态日志表而真正的资源流转信息被淹没在里面所有分析查询都会变慢、变乱。怎么避免建模的时候多问一句这条记录能让某个资源的数量或金额发生变化吗如果能才是事件如果不能请不要放在经济事件表里。状态变化可以单独建流程日志表或者放在事件表的补充字段里但不要让它成为核心事件。6.2 余额和库存快照到底要不要冗余我的取舍REA 的纯粹做法是所有余额都从事件推导不存任何余额表。理论上这是最干净的但实操中你会发现每次查询都要实时聚合几百万条事件性能扛不住。我的取舍是核心事件表保留不可变的明细同时定期生成物化视图或快照表来加速查询。比如库存余额我不会每天去重算所有入库出库事件而是按天生成一张库存快照表记录每个资源在某一天的余额。但快照表只作为查询加速用不能作为业务事实的唯一来源。如果快照和事件明细对不上以事件明细为准。这个原则要写进开发规范里不然时间一长大家会开始直接改快照模型就废了。6.3 别为建模而建模事件粒度怎么把握还有一种翻车是过度建模。有人把客户浏览了商品详情页也建成了事件说这是未来的分析素材。对不起这种动作没有引起经济资源的流转你硬建模的结果就是事件表里塞满噪音。REA 从来不追求所有事实都要建模它只关心会改变资源状态的经济事件。事件粒度的把握标准就是前面说的要么发生了资源的流入流出要么形成了对未来资源流转的承诺。浏览、点击、浏览时长、页面停留这些算行为数据应该走行为分析平台不要混进 REA 模型。我见过一个项目因为把行为数据也塞进事件表导致真正做对账的时候数据量暴涨、查询性能一塌糊涂。6.4 和财务系统对接时的映射策略不要硬来最后说一个落地时最现实的坑REA 模型和财务系统的科目体系怎么对接。REA 是按事件和资源组织的财务是按科目和凭证组织的两者天然不是一一对应。我的处理方式是建一个映射规则表把 REA 事件的资源流方向和金额映射到具体的借贷科目上。比如商品入库事件资源流方向是流入金额 5000通过映射规则自动生成借库存商品 5000贷应付账款 5000。这个映射在事件发生时异步执行执行结果写入一张 record_link 表记录事件 ID 和凭证 ID 的关联。这样财务人员看到的是熟悉的凭证业务人员看到的是完整的事件链两边不打架。如果你试图让 REA 直接取代财务凭证那大概率会在月结的时候被团队骂回来。写在最后我在实际项目中最大的体会是REA 不是一个让你照着抄代码的框架而是一套逼你把业务事实想清楚的方法论。它的价值不在于表结构多漂亮而在于当你把所有业务都拆成资源、事件、参与者之后你会发现整个企业的业务逻辑变得前所未有的可解释、可追溯。如果你的团队正在做数据中台、业务中台或者被一堆跨系统的对账问题折磨我建议你先别急着写 SQL找一条核心业务链路按 REA 拆一遍试试大概率会有一种原来业务可以这样被表达的感觉。另外如果你在建模时也遇到过类似的分歧欢迎在评论里聊聊你的取舍方案我也想看看大家在实践里都怎么解决这些边界问题。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑