族谱数据建模笔记——从Family模型到Relation模型的迁移

族谱数据建模笔记——从Family模型到Relation模型的迁移

一开始,我以为这事儿很简单

去年开始做一个族谱管理工具,第一反应是:这不就是个树形结构吗?每个人有父母、有子女,用一张Person表加一张Family表,齐活。

毕竟国外的家谱软件都这么干的,GEDCOM标准也是这个思路。我当时心想:人家用了这么多年,肯定没问题。

于是愉快地搭了第一版模型:

Person: id, name, gender, birth, death
Family: id, husband_id, wife_id
Child: family_id, person_id

逻辑很清晰:一个Family对应一对夫妻,孩子挂在Family下面。查询"张大爷的子女"就是找到张大爷所在的Family,然后查这个Family下的所有Child。

写了个Demo,录了二十几条测试数据——完美运行。

然后真实数据来了。

Family模型的三个致命假设

第一个踩坑的是过继

数据里有个人叫张德厚,从小过继给了他二叔。按Family模型,Child表里他只能属于一个Family。我把他挂在二叔的Family下,那亲生父亲那边就查不到他了。反过来也是一样。

我当时想了个取巧的办法:在亲生父亲Family里也挂一条Child记录,加个字段标记"过继"。查询的时候按需过滤。

勉强算是解决了。但心里不太舒服——数据结构在说谎。同一个人在两个Family里各有一行,这不是数据冗余,是数据不一致的定时炸弹。

第二个踩坑的是兼祧,这个直接让取巧方案崩了。

数据里有个叫张启明的,一个人兼祧两房。大伯房给他娶了房媳妇,生了个儿子,儿子归大伯房。亲父房又给他娶了房媳妇,又生了儿子,儿子归亲父房。

按Family模型,张启明只能有一个Family——那他的两个媳妇放哪?只有一个Family的话,两个媳妇全塞进去,两房子女全混在一起。大伯房的儿子和亲父房的儿子没法区分,世系图上两房后代缠成一团。

这时候我才意识到,Family模型有三个隐含假设,全部在我的场景里不成立:

假设一:一个人一生只属于一个核心家庭。 过继人员同时属于两个家庭,兼祧人员也同时属于两个家庭。

假设二:一个核心家庭只有一对配偶。 兼祧人员在各房各有配偶,直接打破了这个假设。

假设三:所有子女归属同一个家庭单位。 兼祧的两房子女归属不同房系,不能混在一起。

这三个假设在西方核心家庭的场景里是成立的,但放到中国宗族场景里,全碎。

重构:不要Family了

问题出在"家庭"这个聚合单元上。它强行把"夫妻关系"和"子女关系"捆在一起,导致一个人只能有唯一的家庭归属。

想通了这一点,方案就有了:放弃Family表,让人和人直接建立关系。

新模型变成:

Person: id, name, gender, generation, ...
Relation: person_a_id, person_b_id, relation_type, branch_id, meta

relation_type是关系类型枚举:父亲、母亲、配偶、子女、过继子、入赘夫等等。branch_id是可选的房系归属。

过继怎么表达?张德厚有两条Relation:

  • 张德厚 → 亲生父亲:relation_type=父子
  • 张德厚 → 过继父亲:relation_type=过继子

世系图展示时,亲生关系画实线、过继关系画虚线,两边都能看到。比之前"在备注里写明过继情况"强了不止一个档次。

兼祧怎么表达?张启明和两个媳妇各有一条配偶Relation,每条携带不同的branch_id。子女通过母亲的branch_id归属到对应房系,数据结构本身就区分清楚了。

我在知烛这个项目里最终用的就是这个方案。核心表就两张,但逻辑上比Family模型灵活太多。

迁移过程中的兼容性处理

从老模型迁到新模型的时候,旧数据怎么处理是个现实问题。我之前录的那二十几条测试数据虽然不多,但如果以后有人从GEDCOM导进来数据,GEDCOM本身就是Family模型的,怎么转换?

处理思路是这样:

导入GEDCOM时,先按标准解析出Family和Child。然后遇到一个Family,不创建Family记录,而是:

  • 解析出husband和wife,生成两条配偶Relation(person_a是夫、person_b是妻,互相持有对方的反向Relation)
  • 遍历Family下的所有Child,每个Child生成一条父子Relation(子→夫)和一条母子Relation(子→妻)
  • 房系信息(如果有的话)写入Relation的branch_id字段

GEDCOM里过继和兼祧的信息通常写在NOTE字段里,格式不统一。这部分暂时不做自动解析,导入后标记为待处理,让人工确认。

反向导出也是类似的逻辑:遍历Person的所有Relation,按husband-wife-child聚合还原成Family结构再写回GEDCOM。多房系的情况会有信息丢失——GEDCOM本身就不支持这个维度,没辙。

一点体会

回过头看,最大的教训是:不要默认别人的数据模型能套用到你的场景里。

西方家谱软件用了几十年的Family模型,在它们的场景下是完全合理的——核心家庭、一夫一妻、子女清晰。但中国宗族是多房系、多归属、多配偶并存的复杂网络结构,那个模型从根上就不适配。

好在关系型数据库足够灵活。只要把"关系"本身当一等公民、拆出来独立建模,大部分复杂场景都能自然表达。代码没多写几行,但数据结构的正确性保证了后续所有功能都不会跑偏。

这事给我的另一个体会是:修数据模型要趁早。如果等数据录了几万人再来改底层结构,代价就完全不一样了。

posted @ 2026-07-24 23:08  颠倒是非大法师  阅读(0)  评论(0)    收藏  举报