怎么用 这是格式与深度的参考,不是让你照抄的模板。数字全部是示例,直接抄进简历一问就穿——必须换成你自己的真实数据,而且要能说清是怎么测出来的。下面每个模块都有「数字是怎么测的」和「面试追问」两段,写不出那两段的模块就不要往简历上写

面试题库(电商 / 短视频 / 社区 / 本地生活 / 旅游 / 企业服务 多业务场景)

项目背景设定 国际旅游预订平台的房源供给侧服务端,Java + Spring Boot + MySQL + Elasticsearch + MQ。平台自己不拥有酒店,房源来自多家第三方供应商,同一家酒店常常在三四个供应商那里各有一条记录,名称拼写、地址格式、设施描述、照片全都不一样。交易侧(库存、查价、下单)在 旅游 · 后端 · 日历库存与供应商聚合 那一页,这一页只讲交易之前的那一层:把多家供应商的数据变成一份能对外卖的房源库
为什么选这三个模块 这一页在整个题库里是唯一一个「数据治理」类的项目,问题形态和其他页完全不同:其他页在解决并发、连接、一致性,这一页在解决「同一个现实世界的东西,在多个数据源里长得不一样」。这类问题的特点是没有绝对正确的答案,只有可接受的错误率加上人工兜底闭环,这一点很多候选人讲不清。三个模块分别是:实体归一(判断两条记录是不是同一家酒店,比较量怎么降下来)、属性合并(归一之后 N 份属性怎么合成一份,冲突怎么消解)、增量同步(供应商每天推数据,怎么不把线上搞坏)。

模块一:多源房源的实体归一

  1. 多源房源的实体归一(分块降比较量 + 多特征相似度 + 三档判定 + 人工审核闭环 + 映射持久化)★★★
    简历这样写 多供应商房源的实体归一与映射治理(地理网格加名称指纹分块 + 名称/地址/坐标/联系方式多特征加权打分 + 自动通过与自动拒绝双阈值加中间档转人工 + 审核结论回流为正负样本 + 映射关系版本化持久化):同一家酒店在多家供应商处各有一条异构记录,若两两比较则比较量随记录数平方增长,因此先用地理网格与名称指纹做分块,只在同块内比较,把比较量降到可接受量级;再用名称相似度、地址相似度、坐标距离、电话与邮箱等多特征加权打分;判定采用双阈值三档——高于上阈值自动建立映射、低于下阈值自动排除、中间档进人工审核队列,审核结论回流为样本用于阈值调优;映射关系版本化持久化并可回滚,误合并可定点拆分。上线后需人工审核的比例收敛到中间档一个可控区间,误合并(把两家不同酒店合成一家)由人工审核与可拆分机制兜住,未出现无法恢复的错误映射
    展开完整拆解
    为什么要这么设计

    先说清问题:平台不拥有酒店,房源来自多家供应商。同一家酒店,供应商 A 叫「北京王府井希尔顿欢朋酒店」,供应商 B 叫「Hampton by Hilton Beijing Wangfujing」,供应商 C 叫「希尔顿欢朋(王府井店)」,地址格式各不相同,坐标差几十米,电话可能一个带区号一个不带。如果不做归一,用户搜「王府井希尔顿欢朋」会看到三个几乎一样的结果,价格还各不相同,这既是体验灾难,也让「同一家酒店的最低价」这个核心功能压根做不出来

    所以必须做实体归一:判断多条记录是否指向现实世界里同一家酒店,把它们映射到一个平台侧的房源 ID 上。

    第一个要解决的是规模。最朴素的做法是两两比较,但比较量随记录数的平方增长——十万条记录就是五十亿次比较,每次还要算字符串相似度,压根跑不完。所以必须先做分块:只在「有可能是同一家」的候选集内比较。我们用地理网格加名称指纹做分块——两家酒店如果相距几公里,压根不用比名称。分块是这类问题的第一性手段,它把平方级降到可接受量级,这一步没做对后面全是空谈。

    第二个是怎么判断相似。单靠名称不行(同一品牌不同门店名字极像,「希尔顿欢朋北京王府井」和「希尔顿欢朋北京朝阳」只差几个字,但是两家店);单靠坐标也不行(供应商给的坐标精度差异大,同一栋楼里可能有两家不同的酒店)。所以要多特征加权:名称相似度、地址相似度、坐标距离、电话与邮箱等强标识。强标识(电话、邮箱)一旦匹配,权重应该压倒性地大,因为它们几乎不会碰巧相同。

    第三个,也是这类问题最关键的认知:不存在一个阈值能同时避免漏合并和误合并。阈值调高,漏合并多(同一家酒店在平台上有两条,价格比不了);阈值调低,误合并多(两家不同的酒店被合成一家,用户订了 A 店结果到了 B 店,这是恶性事故)。这两类错误的代价严重不对称。

    所以设计是双阈值三档:高于上阈值自动建立映射,低于下阈值自动排除,中间那一段进人工审核队列。这个设计承认了「机器判不准」这件事,把不确定性交给人,而不是强行让机器给一个二元答案。面试里这一点是最能体现判断力的地方——很多人会去纠结「用什么算法能判得更准」,而实际的工程解法是「把判不准的部分识别出来交给人,并且让人的结论回流去改进机器」。

    最后是可恢复性。误合并一定会发生,所以映射关系必须版本化并且可以定点拆分——不能是一个不可逆的合并操作。

    整体链路
    分块(第一性手段:把平方级比较降下来) │ ├─ 地理网格:按坐标划格,只在同格与相邻格内比较 │ 相距几公里的酒店压根不用比名称 │ ├─ 名称指纹:品牌词 + 归一化后的关键词做倒排 │ 「希尔顿欢朋」这类品牌词是很强的分块键 │ ├─ 取两种分块的并集作为候选对 │ 单一分块键会漏(坐标错得远、名称差异大) │ └─ 分块没做对,后面全是空谈 十万条两两比较是五十亿次,跑不完 特征提取与归一化(比较之前必须先洗) │ ├─ 名称:去品牌后缀、全半角、大小写、繁简、空格 ├─ 地址:拆成省市区街道门牌,分层比较 ├─ 坐标:算球面距离 ├─ 电话:去区号与分隔符,留纯数字 └─ 归一化规则本身要版本化 规则一改,历史打分结果就不可复现 多特征加权打分 │ ├─ 强标识命中(电话、邮箱、供应商互认的编码) │ → 权重压倒性地大,几乎不会碰巧相同 │ ├─ 名称相似度(编辑距离 / 词集合相似度) ├─ 地址相似度(分层比较,门牌号权重高) ├─ 坐标距离(近距离才有区分力,远了直接否) │ └─ 加权得到一个综合分 权重初值靠人工标注的样本集调出来 双阈值三档判定(核心:承认机器判不准) │ ├─ 分数 >= 上阈值 → 自动建立映射 ├─ 分数 < 下阈值 → 自动排除,不再比较 │ ├─ 两阈值之间 → 进人工审核队列 │ 带上两条记录的全部字段与差异高亮 │ 审核员看到的是「哪里像、哪里不像」 │ └─ 两类错误的代价严重不对称 漏合并 → 同一酒店两条,比不了最低价(体验问题) 误合并 → 订了 A 店到了 B 店(恶性事故) → 所以上阈值要保守,宁可多送人工 人工审核闭环(人的结论要回流,不能只用一次) ├─ 审核结论落库为正负样本 ├─ 样本累积后重新调权重与阈值 ├─ 高频争议模式反哺归一化规则 └─ 没有回流的人工审核,等于人力被白白消耗 映射关系持久化(必须可拆) ├─ 平台房源 ID ←→ 供应商记录 ID 的多对一映射 ├─ 映射带来源、建立方式(自动/人工)、时间、操作人 ├─ 版本化,支持定点拆分与回滚 └─ 误合并一定会发生,不可逆的合并是设计缺陷
    分步拆解
    1. 先做分块,这是唯一能让问题变可解的一步。两两比较是平方级,十万条就是五十亿次比较还要算字符串相似度,压根跑不完。分块没做对,后面所有的算法讨论都是空谈。
    2. 用地理网格加名称指纹两套分块键,取并集。单一分块键必然漏——只按坐标分块会漏掉坐标标错的,只按名称分块会漏掉名称差异大的。
    3. 只在同格与相邻格内比较。相邻格是必须的,否则正好在格子边界两侧的同一家酒店永远比不到。
    4. 比较之前必须先归一化。名称去品牌后缀与全半角大小写繁简、地址拆成省市区街道门牌、电话去区号与分隔符。不归一化直接比,相似度算出来毫无意义。
    5. 归一化规则本身要版本化。规则一改,历史打分结果就不可复现,出现争议时无法解释当初为什么判成了这样。
    6. 多特征加权,不能单靠名称或坐标。单靠名称:同品牌不同门店名字极像但是两家店;单靠坐标:供应商坐标精度差异大,同一栋楼可能有两家酒店。
    7. 强标识(电话、邮箱、互认编码)的权重要压倒性地大。因为它们几乎不会碰巧相同,命中就基本可以定案。
    8. 地址要分层比较,门牌号权重最高。省市区相同说明不了什么(一个城区几百家酒店),门牌号相同才是强信号。
    9. 坐标距离只在近距离范围内有区分力。超过一定距离直接判否,不要让它参与加权——远距离的分数差异没有意义。
    10. 判定用双阈值三档,不要用单阈值二分。这是整个模块最重要的设计。不存在一个阈值能同时避免漏合并和误合并,承认这一点比调算法重要。
    11. 上阈值要保守,宁可多送人工。因为两类错误代价严重不对称:漏合并是体验问题(同一酒店两条,比不了最低价),误合并是恶性事故(用户订了 A 店到了 B 店)
    12. 人工审核界面要给差异高亮,不是把两条记录扔给审核员。要直接呈现「哪些字段像、哪些不像」,否则审核效率极低。
    13. 审核结论必须回流成正负样本。样本累积后重新调权重与阈值,高频争议模式反哺归一化规则。没有回流的人工审核等于人力被白白消耗,而且系统永远不会变好。
    14. 映射关系版本化并支持定点拆分。带来源、建立方式(自动还是人工)、时间、操作人。误合并一定会发生,不可逆的合并操作本身就是设计缺陷。
    关键决策与取舍

    为什么用双阈值三档而不是单阈值二分,这是这个模块最该讲的判断。单阈值意味着强迫机器对每一对记录给出「是」或「不是」,但现实里有一大批记录就是判不准的——两家同品牌的酒店在同一条街上,名称差三个字,坐标差两百米,机器给出的分数一定落在中间,无论阈值定在哪都会错一批。三档的价值在于把「判不准」这件事显式表达出来,交给人,并且让人的结论回流改进机器。取舍是引入了人工成本,而且中间档的量必须控制住——如果一半的对都进人工,这个方案就不可用。所以要持续监控中间档的比例,它是这个系统健康度的核心指标

    阈值往哪边偏,取决于两类错误的代价对比。我们把上阈值定得保守(宁可漏合并,宁可多送人工),因为漏合并只是体验差(用户看到两条相似结果、比不了最低价),误合并是「订了 A 店到了 B 店」的恶性事故——用户在异国深夜到了一家不是自己订的酒店,这个后果不是退款能解决的。代价不对称时,阈值必须往代价小的那一侧偏,这不是保守,是算过账的选择。

    为什么先投入做分块而不是先调算法。这是一个优先级判断:再好的相似度算法,在跑不完的比较量下都没有意义。分块把问题从「不可解」变成「可解」,收益是量级的;而算法调优是在可解范围内提高准确率,收益是百分点级的。做这类问题时先看规模再看准确率,顺序反了会浪费很多时间。

    踩过的坑:误合并把两家同品牌酒店合成一家,用户订错了店。同一条街上的两家同品牌门店,名称只差门店后缀,坐标差两百米,早期阈值偏低直接自动合并了,结果两家店的房型和价格混在一起,用户订了便宜的那家却被安排到另一家。修法有三条:上阈值调保守门店后缀词做成强区分特征(「王府井店」和「朝阳店」这类后缀一旦不同,直接大幅降分)、映射支持定点拆分让运营能立刻纠正。教训是:做实体归一时必须先想清「合错了怎么恢复」,可恢复性要和准确率一起设计,只追求准确率而没有回退路径,出一次事就没法收拾。

    踩过的坑二:人工审核的结论没有回流,审核队列越来越长。审核员每天判几百对,判完就存个结果,系统一点没变好,第二天来的还是同样类型的争议。修法是把审核结论落成正负样本,定期重新调权重与阈值,并把高频争议模式反哺归一化规则(比如发现大量争议来自「大厦/广场/中心」这类通用词干扰,就把它们加入停用词)。教训是:任何「机器判不准转人工」的设计,都必须带一条从人回到机器的反馈路径,否则人工是纯消耗,系统的准确率永远停在上线那天。

    踩过的坑三:归一化规则改了,历史判定结果无法复现。调整了名称归一化的停用词表,之前的打分全都对不上了,运营质疑某个映射为什么当初被自动通过时,我们复算出来的分数和当时不一样,解释不清。修法是归一化规则版本化,打分记录里存规则版本教训是:凡是参与自动决策的规则都要版本化并记录在决策结果上——这和金额计算要快照规则版本是同一条原则,只要事后可能被质疑,就要能复现。

    没做的部分:没有引入图片相似度做辅助判定。理论上同一家酒店的照片会高度重合,是很强的信号,但涉及图像特征提取与向量检索,成本和链路都重,当时优先做了文本与地理特征。也没做跨语言的名称匹配(中文名与英文名的对应),这块靠供应商提供的多语言字段和人工审核兜着。

    数字是怎么测的

    比较量的下降:这是分块效果的直接度量。报「不分块的理论比较次数」与「分块后的实际比较次数」的对比,以及跑完一轮全量归一的耗时。用量级对比而不是百分比——从平方级降到可接受量级,说清数量级比说「下降 99%」更有信息量。

    准确率必须用人工标注的评测集,不能用线上数据自评。做法是抽样人工标注一批「确定是同一家」和「确定不是同一家」的记录对作为评测集,然后报在这个集上的表现。关键是要分开报两类错误:漏合并率和误合并率。只报一个「准确率」是在掩盖问题,因为两类错误的代价完全不同,合成一个数字就看不出保守的阈值策略是否生效。

    中间档(进人工)的比例:这是这个系统健康度的核心指标,要持续监控。报的是它稳定在哪个区间,以及审核队列是否收敛(进的比处理的多就会越积越长)。如果中间档占比过高,方案就不可用,这个数字必须诚实报。

    人工审核的产出:报审核量、平均处理时长、以及回流样本带来的阈值调整次数。最后这个数字很值得报——它证明反馈闭环真的在运转,而不是写了个队列没人用。

    误合并的处理:发现的误合并笔数(绝对数)以及是否都能通过定点拆分恢复。诚实的表述是「出现过若干笔误合并,均可通过拆分恢复」,而不是声称没有误合并。

    不要报「实体归一准确率 99.9%」。这个数字高度依赖评测集的构造方式(评测集里简单样本多还是难样本多,结果差很远),而且它掩盖了两类错误的不对称性正确表述是「分块把比较量降到什么量级、在人工标注的评测集上漏合并与误合并各是什么水平、中间档送人工的比例稳定在多少、误合并可定点拆分恢复」——四个可核查的事实,比一个准确率有说服力得多。

    面试追问
    Q:怎么判断两条记录是同一家酒店? A:多特征加权打分,不能单靠任何一个特征。单靠名称不行——同品牌不同门店名字极像(「希尔顿欢朋北京王府井」和「希尔顿欢朋北京朝阳」只差几个字,却是两家店);单靠坐标也不行——供应商坐标精度差异很大,而且同一栋楼里可能有两家不同的酒店。所以用四类特征:强标识(电话、邮箱、供应商互认编码,权重要压倒性地大,因为几乎不会碰巧相同)、名称相似度地址相似度(分层比较,门牌号权重最高,省市区相同说明不了什么)、坐标距离(只在近距离有区分力,超过阈值直接判否,不参与加权)。比较之前必须先归一化:名称去品牌后缀与全半角大小写繁简、地址拆成省市区街道门牌、电话去区号和分隔符,不归一化直接比相似度毫无意义。还有一个细节很重要:门店后缀词要做成强区分特征,「王府井店」和「朝阳店」一旦不同就大幅降分——我们就是在这里踩过误合并的坑。
    Q:十万条记录两两比较跑不完,怎么办? A:分块,这是唯一能让问题变可解的一步。两两比较是平方级,十万条就是五十亿次比较,每次还要算字符串相似度,压根跑不完。分块的思路是只在「有可能是同一家」的候选集内比较:用地理网格(按坐标划格,只比同格与相邻格——相邻格必须带上,否则正好在格子边界两侧的同一家酒店永远比不到)和名称指纹(品牌词加归一化关键词做倒排,品牌词是很强的分块键),取两种分块的并集。为什么要两套并取并集:单一分块键必然漏——只按坐标会漏掉坐标标错的,只按名称会漏掉名称差异大的。我想强调的是优先级判断:先做分块再调算法。再好的相似度算法在跑不完的比较量下都没有意义;分块把问题从「不可解」变成「可解」,收益是量级的,算法调优是百分点级的。做这类问题先看规模再看准确率,顺序反了会浪费很多时间。
    Q:阈值定多少?判错了怎么办? A:我的答案是不要用单阈值二分,用双阈值三档。因为不存在一个阈值能同时避免漏合并和误合并——现实里有一大批记录就是判不准的(同品牌的两家店在同一条街上,名称差三个字、坐标差两百米),机器给的分数一定落在中间,阈值定在哪都会错一批。三档是:高于上阈值自动建映射、低于下阈值自动排除、中间档进人工审核队列。它的价值在于把「判不准」显式表达出来交给人,而不是强迫机器给二元答案。阈值往哪边偏取决于代价对比:我们把上阈值定得保守,因为漏合并只是体验差(用户看到两条相似结果、比不了最低价),误合并是「订了 A 店到了 B 店」的恶性事故——用户在异国深夜到了一家不是自己订的酒店,退款解决不了。代价不对称时阈值必须往代价小的一侧偏。另外映射必须版本化且支持定点拆分——误合并一定会发生,不可逆的合并操作本身就是设计缺陷。
    Q:人工审核队列越来越长怎么办? A:先说我们踩过的坑:审核员每天判几百对,判完就存个结果,系统一点没变好,第二天来的还是同样类型的争议。问题是缺一条从人回到机器的反馈路径。修法三条:审核结论落成正负样本样本累积后重新调权重与阈值高频争议模式反哺归一化规则——比如我们发现大量争议来自「大厦/广场/中心」这类通用词干扰相似度,就把它们加进停用词表,这一类争议直接消失了。教训是:任何「机器判不准转人工」的设计,都必须带一条从人回到机器的反馈路径,否则人工是纯消耗,系统准确率永远停在上线那天。另外中间档的比例是这个系统健康度的核心指标,要持续监控——如果一半的对都进人工,这个方案就不可用了。还有一点是审核界面:不能把两条记录原样扔给审核员,要直接高亮「哪些字段像、哪些不像」,否则审核效率极低,队列自然会积压。

模块二:静态信息的合并与冲突消解

  1. 静态信息的合并与冲突消解(字段级可信度 + 按字段择源 + 人工修正最高优先 + 图片去重 + 合并结果可溯源)★★★
    简历这样写 多源房源静态信息的合并与冲突消解(字段级供应商可信度矩阵 + 按字段独立择源而非整条择源 + 人工修正层独立存储且不被同步覆盖 + 图片感知哈希去重 + 每个字段留存来源与时间可溯源):实体归一后同一房源持有多份异构属性,放弃「整条记录择优」改为「按字段独立择源」,并维护字段级可信度矩阵(同一供应商在名称、设施、图片上的可信度并不相同);把人工修正独立成一层且优先级最高,同步流程只更新供应商层,修正不会被下一次同步覆盖;图片用感知哈希跨供应商去重并按清晰度与主体择优排序;每个对外字段留存来源供应商与更新时间,客诉与纠错时可定位到具体数据源。上线后「运营刚改好的字段第二天被同步冲掉」的问题因修正层不参与同步覆盖而不再出现,重复图片在跨供应商合并后由哈希去重收敛
    展开完整拆解
    为什么要这么设计

    实体归一之后,一个平台房源 ID 下挂着三四份来自不同供应商的属性:名称、地址、星级、设施列表、房型描述、政策(能否带宠物、几点入住)、照片。它们互相冲突——A 说有免费停车,B 说没有;A 说 14 点入住,B 说 15 点;照片有一半是重复的(同一张房间照片被两个供应商都提供了,只是分辨率不同)。

    要对外展示,必须合并成一份。第一版的做法是整条记录择优:给每个供应商打一个总的可信度分,取分最高的那家的数据作为主数据,其他的丢掉。这个做法简单,但错得很实际——供应商的可信度不是一个数,它是分字段的。有的供应商是酒店集团直连,名称和政策非常准,但照片是几年前的;有的供应商是聚合商,照片新且多,但设施列表明显是机器抓的,错误率高。用整条择优,就等于为了拿到准确的名称而接受了过期的照片。

    所以第一个设计是按字段独立择源,并维护一个字段级的可信度矩阵(供应商 × 字段 → 可信度)。名称取 A 的、照片取 B 的、政策取 A 的、设施取多家取交集或并集(取决于字段语义)。这个矩阵的初值靠人工抽检定,之后靠纠错反馈调整。

    第二个设计来自一个很疼的坑。运营人工修正过的字段,第二天被供应商同步冲掉了。运营发现某家酒店的地址写错了,手动改对,结果当晚的同步任务又把供应商的错误地址写了回去,第二天用户还是导航到错的地方。根因是人工修正和供应商数据存在同一个字段上,同步就是覆盖。

    修法是把数据分层:供应商层(每家一份原始数据)、修正层(人工改的)、对外层(合并结果)同步只更新供应商层,永远不碰修正层;合并时修正层优先级最高。这样人工修正是稳定的,而且供应商的原始数据也没丢(后面纠错、追责、重新合并都要用)。这个分层是这个模块最值得讲的设计——它把「谁能写哪一层」这件事定死了,而不是靠流程约定。

    第三个是图片去重。跨供应商的照片大量重复,但字节不同(分辨率、压缩、水印不同),没法用文件哈希去重。用感知哈希(对图像内容做哈希,视觉相似的图哈希也相近)能跨分辨率识别出同一张图,然后在重复组里按清晰度和有无水印择优

    最后是可溯源。每个对外字段要记住它来自哪家供应商、什么时候更新的。因为客诉一定会来(「你们写的有停车场,我到了没有」),能定位到具体数据源才能去找供应商纠错,也才能调整可信度矩阵。没有溯源,纠错就只能靠猜。

    整体链路
    数据分层(这是整个模块的骨架,先定死谁能写哪层) │ ├─ 供应商层:每家一份原始数据,互不覆盖 │ 同步只写这一层 │ 原始数据不能丢,纠错与追责都要用它 │ ├─ 修正层:人工改过的字段,独立存储 │ 同步永远不碰这一层 │ → 这一条是踩过坑之后加的,见「关键决策」 │ └─ 对外层:合并结果,供搜索与详情页读取 由供应商层 + 修正层按规则合并产出 字段级择源(放弃整条择优) │ ├─ 维护可信度矩阵:供应商 × 字段 → 可信度 │ 同一家供应商在不同字段上的可信度并不相同 │ 直连集团:名称与政策准,照片可能过期 │ 聚合商 :照片新且多,设施列表错误率高 │ ├─ 按字段各自取可信度最高的来源 │ 名称 → A 照片 → B 政策 → A │ ├─ 部分字段不是「择一」而是「聚合」 │ 设施列表 → 按字段语义取交集或并集 │ 交集更保守(少写,避免承诺没有的东西) │ 并集更丰富(多写,但可能写上不存在的设施) │ → 涉及对用户承诺的字段一律取交集 │ └─ 合并优先级:修正层 > 可信度最高的供应商 > 其他 图片合并与去重(不能用文件哈希) │ ├─ 跨供应商照片大量重复,但字节不同 │ 分辨率、压缩率、水印都不一样 │ → 文件哈希压根去不掉重 │ ├─ 用感知哈希:对图像内容做哈希 │ 视觉相似的图哈希也相近,可跨分辨率识别 │ ├─ 重复组内择优:清晰度高、无水印、主体完整 └─ 排序:外观 → 大堂 → 房型 → 设施 房型图要和房型关联,不能混在一起 可溯源(客诉与纠错的前提) ├─ 每个对外字段记录:来源供应商 + 更新时间 ├─ 客诉时能定位到「这条信息是哪家给的」 ├─ 据此向供应商纠错,并调整可信度矩阵 └─ 没有溯源,纠错只能靠猜 纠错闭环 ├─ 客诉与运营纠错 → 写修正层(立即生效) ├─ 同时回传给供应商,要求修正源头 ├─ 同类错误累积 → 下调该供应商该字段的可信度 └─ 修正层长期堆积说明源头没治,要推动供应商
    分步拆解
    1. 先把数据分成三层:供应商层、修正层、对外层。这是整个模块的骨架。先定死「谁能写哪一层」,而不是靠流程约定——约定一定会被绕过。
    2. 同步只写供应商层,每家一份,互不覆盖。原始数据不能丢,后面纠错、追责、重新合并都要用它。
    3. 修正层独立存储,同步永远不碰。这是踩过坑之后加的:运营改对的地址被当晚同步又冲回了错的
    4. 对外层是合并产出,不允许直接编辑。要改就改修正层,保证合并逻辑是唯一的产出路径。
    5. 放弃整条记录择优,改为按字段独立择源。因为供应商的可信度不是一个数,它是分字段的——直连集团名称准但照片旧,聚合商照片新但设施列表错误率高。整条择优等于为了名称准而接受照片旧。
    6. 维护「供应商 × 字段 → 可信度」矩阵。初值靠人工抽检定,之后靠纠错反馈调整。
    7. 区分「择一字段」和「聚合字段」。名称、地址、入住时间是择一;设施列表这类是聚合。
    8. 涉及对用户承诺的字段一律取交集,不取并集。设施列表取并集会写上不存在的设施(「有停车场」但实际没有),那是承诺违约;取交集会少写一些,但不会骗人。宁可少写,不可乱承诺。
    9. 合并优先级固定为:修正层 > 可信度最高的供应商 > 其他。写死这个顺序,不要让它可配置——可配置的优先级最后一定会被配成互相矛盾的。
    10. 图片去重不能用文件哈希,要用感知哈希。跨供应商的同一张照片分辨率、压缩率、水印都不同,字节完全不一样,文件哈希压根去不掉重。
    11. 重复组内按清晰度、有无水印、主体完整度择优。选出一张作为代表,其余不对外。
    12. 房型图必须和房型关联,不能混进公共图池。否则用户在房型 A 下看到房型 B 的照片,是很常见的投诉来源。
    13. 每个对外字段留存来源供应商与更新时间。客诉时能定位到「这条信息是哪家给的」,没有溯源,纠错只能靠猜
    14. 把纠错做成闭环:写修正层立即生效,同时回传供应商要求修正源头。只改自己这边,源头还在持续推错的数据。
    15. 同类错误累积就下调该供应商该字段的可信度。让可信度矩阵随时间变准,而不是一次定终身。
    16. 监控修正层的规模。修正层长期堆积说明源头治理没做——它应该是个薄层,厚了就是信号。
    关键决策与取舍

    为什么按字段择源而不是整条择优,代价是什么。整条择优简单:给每家一个总分,取最高的那家。但它的问题很实际——没有一家供应商在所有字段上都最好。按字段择源能在每个字段上取到最好的数据,代价是合并出来的这份数据「现实中不存在于任何一家供应商」,所以一旦出错,排查要跨多个来源,这也正是为什么必须做字段级溯源。另一个代价是可信度矩阵的维护成本(供应商数乘字段数),缓解手段是只对重要字段精细维护,其余字段用供应商的默认可信度

    设施列表取交集而不是并集,这是个有明确方向的选择。并集能让页面看起来内容更丰富(对转化有好处),但会写上实际不存在的设施——用户因为「有免费停车」订了,到店发现没有,这不是信息误差,是承诺违约,在有消费者保护法规的市场是有实质风险的。交集会少写一些卖点,转化可能略低。取舍是明确的:宁可少写,不可乱承诺。这个判断和「超时按不可售处理」是同一个取向——面对不确定,往「不承诺」的方向偏。

    踩过的坑:运营人工修正的字段被同步冲掉了。运营发现某家酒店地址错误,手动改对,当晚同步任务又把供应商的错误地址写了回去,第二天用户还是导航到错的地方,运营改了三次以为自己没保存成功。根因是人工修正和供应商数据存在同一个字段上,同步就是覆盖。修法是分层:同步只写供应商层,修正层独立且优先级最高教训是:当一份数据有多个写入方时,必须给它们各自的存储层并定义合并优先级,而不是让它们抢同一个字段——「谁后写谁赢」在有自动化写入方参与时,人永远赢不了。

    踩过的坑二:图片用文件哈希去重,一张没去掉。跨供应商的同一张房间照片,分辨率、压缩、水印各不相同,字节层面完全不同,文件哈希算出来全不一样。详情页上同一个房间出现四张几乎一样的照片,用户以为图片加载重复了。修法是换感知哈希教训是:去重的哈希粒度要和「重复」的业务定义对齐——业务说的重复是「视觉上是同一张」,那就得用内容哈希而不是字节哈希。这个判断在文本去重(洗稿检测)上也一样。

    踩过的坑三:房型图混进公共图池,用户看到别的房型的照片。合并时把所有图片放进一个池子按质量排序,结果标准间的详情页展示了套房的照片,用户到店后投诉「和图片不符」。修法是房型图必须带房型关联,只在对应房型下展示;只有确实是公共区域的图才进公共池教训是:合并数据时不能丢掉字段的归属维度,图片不只是「一张图」,它是「某个房型的一张图」,丢了这个维度合并就出错。

    没做的部分:没做多语言内容的自动生成与校验(把中文描述译成多语言并保证专有名词一致)。当时靠供应商提供的多语言字段加人工,覆盖不全的语言就回退到英文。也没做设施描述的语义归一(「免费 Wi-Fi」「无线网络免费」「WIFI 免费」映射到同一个设施项),这块只做了关键词规则,没有做语义模型。

    数字是怎么测的

    修正层被覆盖的问题:这是确定性验证。构造场景——人工修正某字段,然后跑一次全量同步,检查该字段仍是修正后的值。改造前每次同步都会被冲掉,改造后不会。这类问题用「能不能复现」描述比用数字描述更有说服力。

    图片去重效果:合并前后的图片数量对比,以及抽样人工检查「剩下的图里还有没有视觉重复」。要说明抽样量。另外可以报感知哈希的阈值是怎么定的——调太松会把不同房间的相似照片误去掉,这个边界值得讲。

    字段准确率:必须抽样人工核验(打电话给酒店或对照官网),报核验样本量和发现的错误数。用绝对数不用比率——「抽检 200 家发现 N 处字段错误」比「准确率 98%」信息量大得多,因为前者能追问「是哪些字段错、错在哪家供应商」。

    可信度矩阵的调整:因纠错反馈而下调过可信度的「供应商 × 字段」组合数。这个数字证明反馈闭环在运转,而不是矩阵上线后就没动过。

    修正层的规模趋势:这是个健康度指标。修正层应该是个薄层,如果它持续增厚,说明源头治理没做。报它的规模和趋势,比报一个静态的准确率更能说明治理有没有效果。

    不要报「房源信息准确率 99%」。「准确」在这里压根没有统一定义(设施列表少写一项算不算错?照片是去年的算不算错?),而且这个数字无法核查——要核查就得给每家酒店打电话。正确表述是「抽检多少家、发现哪些类型的错误、修正层规模与趋势、可信度矩阵调整了多少次」。也不要报「零投诉」,信息类投诉不可能没有。

    面试追问
    Q:三家供应商对同一家酒店的描述不一样,你信谁? A:按字段分别信,不整条择优。我们第一版是整条择优——给每家供应商一个总可信度分,取最高的那家做主数据。错在「供应商的可信度不是一个数,它是分字段的」:直连酒店集团的供应商名称和政策非常准,但照片可能是几年前的;聚合商照片新且多,但设施列表明显是机器抓的、错误率高。整条择优等于为了拿到准确的名称而接受了过期的照片。所以改成维护「供应商 × 字段 → 可信度」矩阵,按字段独立择源,名称取 A、照片取 B、政策取 A。代价是合并出来的这份数据「现实中不存在于任何一家供应商」,出错时排查要跨多个来源——这正是必须做字段级溯源的原因:每个对外字段都记住来自哪家、什么时候更新的,客诉时能定位到具体数据源去纠错,并据此下调该供应商该字段的可信度。
    Q:运营手动改过的数据,第二天同步会不会被覆盖? A:这正是我们踩过的坑,而且很疼。运营发现某家酒店地址错误,手动改对,当晚同步任务又把供应商的错误地址写了回去,第二天用户还是导航到错的地方——运营改了三次,以为自己没保存成功。根因是人工修正和供应商数据存在同一个字段上,同步就是覆盖。修法是数据分三层供应商层(每家一份原始数据,同步只写这一层,原始数据不能丢,纠错追责都要用)、修正层(人工改的,独立存储,同步永远不碰)、对外层(合并产出,不允许直接编辑)。合并优先级写死为:修正层 > 可信度最高的供应商 > 其他,不做成可配置——可配置的优先级最后一定会被配成互相矛盾的。教训是:当一份数据有多个写入方时,必须给它们各自的存储层并定义合并优先级,而不是让它们抢同一个字段——「谁后写谁赢」在有自动化写入方参与时,人永远赢不了。另外要监控修正层的规模:它应该是个薄层,持续增厚说明源头治理没做。
    Q:几家供应商的照片大量重复,怎么去重? A:不能用文件哈希,要用感知哈希。我们一开始用文件哈希,一张都没去掉——跨供应商的同一张房间照片,分辨率、压缩率、水印各不相同,字节层面完全不一样,哈希自然全不同。结果详情页上同一个房间出现四张几乎一样的照片,用户以为是图片加载重复了。感知哈希是对图像内容做哈希,视觉相似的图哈希也相近,能跨分辨率识别出同一张图;然后在重复组内按清晰度、有无水印、主体完整度择优选一张代表。教训是去重的哈希粒度要和「重复」的业务定义对齐——业务说的重复是「视觉上是同一张」,那就得用内容哈希而不是字节哈希,这个判断在文本去重和洗稿检测上也一样。还有一个相关的坑:早期把所有图片放进一个池子按质量排序,结果标准间的详情页展示了套房的照片,用户到店投诉「和图片不符」。合并数据时不能丢掉字段的归属维度——图片不只是「一张图」,它是「某个房型的一张图」。
    Q:设施列表几家给的不一样,取并集还是交集? A:涉及对用户承诺的字段一律取交集,这是个有明确方向的选择。并集能让页面看起来内容更丰富,对转化有好处;但它会写上实际不存在的设施——用户因为页面写着「有免费停车」才订的,到店发现没有,这不是信息误差,是承诺违约,在有消费者保护法规的市场有实质的合规风险。交集会少写一些卖点、转化可能略低,但不会骗人。宁可少写,不可乱承诺。这个判断和我们在可售性上「超时按不可售处理」是同一个取向——面对不确定,往「不承诺」的方向偏。不过要区分字段类型:不是所有字段都这样处理。名称、地址、入住时间是择一字段(按可信度取一个来源);设施列表这类是聚合字段;而聚合字段里还要再分——涉及承诺的取交集,纯描述性的(比如周边景点介绍)可以取并集,因为写多了不构成承诺。先判断字段语义,再决定合并策略。

模块三:增量同步与变更影响面控制

  1. 增量同步与变更影响面控制(变更分级 + 异常批次拦截 + 关键字段人工确认 + 灰度生效与回滚 + 幂等重放)★★★
    简历这样写 供应商数据同步的变更治理与异常批次拦截(按字段分级的变更处理策略 + 批次级异常检测阈值拦截 + 关键字段变更转人工确认 + 灰度生效与批次级回滚 + 批次号加记录版本幂等重放):供应商每日推送全量与增量数据,早期照单全收导致一次异常推送即可污染线上房源库,因此把变更按字段分级(价格库存类高频直通、静态描述类低频入库、名称地址等关键字段转人工确认);在批次层面做异常检测——单批次内关键字段变更占比、下架占比、坐标位移量超过阈值即整批拦截并告警而非逐条放行;变更采用灰度生效并保留批次级回滚,同步以批次号加记录版本为幂等键支持安全重放。上线后一次供应商侧的编码错误推送在批次校验环节被拦下,未进入线上;误同步的批次可整批回滚而无需逐条修复
    展开完整拆解
    为什么要这么设计

    供应商每天推数据,有的推全量文件,有的推增量事件。第一版的处理很朴素:收到就写库。这个做法在供应商数据正常时没问题,但供应商也会出错,而且出错的时候是成批出错

    真实发生过一次:某供应商的导出程序编码配置错了,一次推送里几千家酒店的名称全变成了乱码。我们照单全收,几分钟后线上搜索结果里大批酒店名称是乱码,用户投诉涌进来。回滚的时候才发现更麻烦——我们没有批次概念,改动是逐条落库的,只能从备份里捞,恢复花了几个小时。

    这件事教出三个设计。

    第一,变更要分级,不能所有字段一个待遇。价格和库存是高频变更(一天几十次),必须直通,加人工环节业务就跑不动了;静态描述类(设施、周边介绍)低频,正常入库;名称、地址、坐标这类关键字段,改错的后果严重且改动本应极少,所以转人工确认。分级的依据是「变更频率」乘「改错的后果」——高频且后果小的直通,低频且后果大的转人工。

    第二,也是最重要的:要在批次层面做异常检测,而不是只在单条上做校验。单条校验只能发现「这条数据格式不对」,发现不了「这一批数据整体不对」——乱码名称每一条单独看格式都合法。但如果统计整批:一次推送里 30% 的酒店都改名了,这在正常业务里几乎不可能发生,它是供应商出错的强信号。所以要做批次级阈值:关键字段变更占比、下架占比、坐标位移量,超过阈值整批拦截并告警,而不是逐条放行

    这一条的思路值得单独说:异常检测的粒度要和异常发生的粒度一致。供应商是成批出错的,那就得在批次粒度上检测。在单条粒度上无论怎么加校验都拦不住成批的错误。

    第三,变更必须可整批回滚。没有批次概念的话,出事只能从备份恢复。所以每次同步生成一个批次号,所有变更挂在批次下,保留变更前的值,回滚就是按批次反向应用。

    另外还有幂等重放:同步任务会失败重试、也会需要手动重跑,幂等键用批次号加记录版本,重放不会产生重复变更也不会把新数据覆盖回旧的。

    整体链路
    接收(先落原始,再处理) │ ├─ 供应商推送 → 原始文件/事件先落存储,生成批次号 │ 不要边收边处理。原始数据留着,出问题要复查 │ ├─ 解析成统一的变更记录:房源 + 字段 + 旧值 + 新值 └─ 全量推送要先算差异,转成变更记录 全量直接覆盖等于放弃了变更审计能力 单条校验(只能发现格式问题) ├─ 必填、类型、枚举、坐标范围、字符集 ├─ 不通过的单条打标记,不阻塞整批 └─ 注意:单条校验发现不了「整批都不对」 乱码名称每一条单独看格式都是合法的 批次级异常检测(这一层是核心,拦的是成批出错) │ ├─ 统计整批的变更画像 │ 关键字段(名称/地址/坐标)变更占比 │ 下架 / 停售占比 │ 坐标平均位移量 │ 价格变更幅度分布 │ ├─ 任一指标超阈值 → 整批拦截 + 告警 + 转人工 │ 一次推送里三成酒店改名,正常业务几乎不可能 │ → 它是供应商出错的强信号,不是业务变化 │ └─ 异常检测的粒度要和异常发生的粒度一致 供应商成批出错,就必须在批次粒度上检测 单条粒度无论怎么加校验都拦不住 变更分级(按「频率 × 改错后果」定策略) │ ├─ 高频且后果小 → 直通 │ 价格、库存、房态 │ 加人工环节业务就跑不动了 │ ├─ 低频且后果小 → 正常入库 │ 设施、周边介绍、房型描述 │ └─ 低频且后果大 → 转人工确认 名称、地址、坐标、星级 改动本应极少,出现就值得看一眼 灰度生效(不要一次全量切) ├─ 变更先对小比例流量生效,观察投诉与关键指标 ├─ 无异常再全量生效 └─ 关键字段变更建议直接走人工确认,不靠灰度兜 回滚(必须能整批回) ├─ 每个变更记录保留旧值,挂在批次号下 ├─ 回滚 = 按批次反向应用 ├─ 支持「回滚整批」与「回滚批内某几条」 └─ 没有批次概念,出事就只能从备份捞 我们花过几个小时,这一条是买来的 幂等重放 ├─ 幂等键 = 批次号 + 记录版本 ├─ 重复投递不产生重复变更 └─ 重放不会把新数据覆盖回旧值 版本比对:只在版本更新时才写
    分步拆解
    1. 原始推送先落存储再处理,不要边收边写库。原始数据留着,出问题时要复查「供应商到底推了什么」,这是划分责任的依据。
    2. 每次同步生成批次号,所有变更挂在批次下。没有批次概念,出事就只能从备份捞——我们为此花过几个小时。
    3. 全量推送也要先算差异转成变更记录,不要直接覆盖。直接覆盖等于放弃了变更审计和回滚能力。
    4. 变更记录要存「房源 + 字段 + 旧值 + 新值」。旧值是回滚的前提,也是异常检测的输入。
    5. 单条校验做格式类检查,不通过的打标记但不阻塞整批。一条坏数据不该拖垮整批的正常更新。
    6. 但要清楚单条校验的局限:它发现不了「整批都不对」。乱码名称每一条单独看格式都合法——这是我们被打穿的地方。
    7. 加批次级异常检测,这一层是核心。统计整批的变更画像:关键字段变更占比、下架占比、坐标平均位移、价格变更幅度分布。
    8. 任一指标超阈值就整批拦截并告警,不要逐条放行。一次推送里三成酒店改名,在正常业务里几乎不可能发生,它是供应商出错的信号而不是业务变化。
    9. 记住这条思路:异常检测的粒度要和异常发生的粒度一致。供应商是成批出错的,就必须在批次粒度检测;在单条粒度上无论怎么加校验都拦不住成批错误。
    10. 变更按「频率 × 改错后果」分级。高频且后果小的直通(价格库存,加人工业务就跑不动);低频且后果小的正常入库;低频且后果大的转人工确认(名称、地址、坐标——改动本应极少,出现就值得看一眼)。
    11. 灰度生效:变更先对小比例流量生效,观察后再全量。关键字段建议直接走人工确认而不是靠灰度兜——灰度只能减少影响面,拦不住错误本身。
    12. 回滚要支持「整批回滚」和「批内部分回滚」两种粒度。有时只是批里某几条判断错了,不必整批回。
    13. 幂等键用「批次号 + 记录版本」。同步任务会失败重试,也会需要手动重跑。
    14. 重放要做版本比对,只在版本更新时才写。否则重放旧批次会把新数据覆盖回旧值,这是比不重放更糟的结果。
    15. 拦截和人工确认都要有 SLA 与兜底。拦下来没人看,等于把「数据错」换成了「数据不更新」,后者时间长了也是问题。
    关键决策与取舍

    批次级异常检测的阈值怎么定,这是个纯权衡。阈值紧:正常的业务波动(供应商做了一次批量的房型整理、某个城市集中调价)会被误拦,运营要频繁处理误报,最后会要求把阈值放宽甚至关掉。阈值松:拦不住真正的异常。我们的做法是先用历史数据回放定初值——把过去几个月的批次跑一遍,看阈值定在哪能拦住已知的那几次事故又不误拦正常批次;然后按供应商分别设阈值,因为不同供应商的推送习惯差异很大(有的每天小量增量,有的每周一次大批量整理)。用一套全局阈值套所有供应商,一定会同时出现误拦和漏拦。

    为什么关键字段转人工,而不是靠灰度兜。灰度能减少影响面(只有小比例用户看到错数据),但它拦不住错误本身,而且关键字段的错误在灰度期间未必能被观测到——地址错了,用户要到出行那天才发现,灰度窗口早过了。所以对「错误的发现滞后于灰度窗口」的字段,灰度是无效的防护,必须前置人工确认。取舍是人工环节引入延迟,缓解手段是这类字段的正常变更量本来就很小(酒店不会天天改名),人工成本可控。

    踩过的坑:供应商编码配置出错,一次推送几千家酒店名称变乱码,照单全收上了线。几分钟内线上搜索结果里大批酒店名是乱码,投诉涌进来。更麻烦的是回滚——当时没有批次概念,改动是逐条落库的,只能从备份捞,恢复花了几个小时。修法三条:批次级异常检测(这类问题在批次画像上极其明显)、批次号加旧值保留支持整批回滚关键字段转人工确认教训是最重要的那条:异常检测的粒度必须和异常发生的粒度一致。我们之前所有的校验都在单条粒度,而供应商是成批出错的,单条校验对成批错误结构上就无能为力——不是校验写得不够严,是层次不对。

    踩过的坑二:重放旧批次把新数据覆盖回了旧值。同步任务失败后手动重跑了一个旧批次,那期间已经有更新的数据进来了,重放把它们盖回去了,表现是「明明改过的数据又变回去了」。修法是幂等键加版本比对,只在版本更新时才写教训是:幂等不等于可安全重放——幂等保证「重复执行结果一致」,但如果中间有别的写入,重复执行就会覆盖它;要安全重放还需要版本或时间戳的单调性检查。这个区别很容易被混过去。

    踩过的坑三:批次被拦下来之后没人处理,数据几天没更新。拦截做好了,告警也发了,但没有指定责任人和处理时限,告警在群里刷过去就没了,直到运营反馈「某家供应商的价格好像很久没动了」。修法是给拦截队列加责任人、处理时限和超时升级教训是:拦截机制必须配处理闭环,否则只是把「数据错」换成了「数据不更新」,后者时间长了同样是故障,而且更隐蔽。

    没做的部分:没做供应商数据质量的自动评分与对外通报(把检测结果定期反馈给供应商并纳入合作评估)。这更多是商务流程而不是技术,当时只做到内部记录。也没做跨供应商的交叉校验(同一家酒店在 A 和 B 处的信息突然分叉,说明其中一家出错了)——这个思路很好但需要成熟的实体归一作为前提,当时归一的覆盖率还不够。

    数字是怎么测的

    拦截效果:实际拦下的异常批次数量与它们的类型(编码错误、批量误下架、坐标整体偏移)。这个数字比任何比率都有说服力——「上线以来拦下 N 个异常批次,其中一次是供应商编码错误导致几千家名称异常」是具体、可核查、能追问的。

    误拦率:这个必须主动报,否则会被追问。报被拦截后人工判定为「实际正常」的批次占比诚实地承认有误拦,并说明阈值是按供应商分别调的,比声称没有误拦可信。误拦率过高会导致运营要求关掉拦截,所以它是这个机制能不能活下来的关键指标。

    阈值是怎么定的:这一点要主动讲——用历史批次数据回放,把过去几个月的批次跑一遍,看阈值定在哪能拦住已知事故又不误拦正常批次。「用历史数据回放定阈值」这个方法本身就是个加分项,比说「凭经验定的」强得多。

    回滚能力:确定性验证——人为同步一个错误批次,然后执行整批回滚,检查所有字段恢复到变更前的值。报的是「可整批回滚,无需逐条修复」这个能力,以及回滚一个批次的耗时。

    重放安全性:确定性验证——同步批次 A,再有新数据写入,然后重放批次 A,检查新数据没有被覆盖回旧值。这是踩过坑之后必须固化的用例。

    人工确认队列:报关键字段变更的日均量、处理时长、以及超时升级触发的次数关键字段的变更量本来就应该很小(酒店不会天天改名),如果这个量很大,说明分级分错了或者上游有问题。

    不要报「数据同步准确率 100%」或「零污染」。供应商数据本身就有错,我们能做的是拦住成批的异常,单条的错误一定会漏过去正确表述是「拦下了哪几类异常批次、误拦率多少、阈值如何用历史数据回放确定、可整批回滚」——把能力边界说清楚,比声称零污染可信得多。

    面试追问
    Q:供应商推来一批脏数据,怎么防止污染线上? A:关键是在批次层面做异常检测,而不是只在单条上做校验。我们被打穿过一次:某供应商导出程序编码配置错了,一次推送里几千家酒店名称全变成乱码,我们照单全收,几分钟后线上搜索结果大批乱码,投诉涌进来。问题在于我们所有的校验都在单条粒度——而乱码名称每一条单独看格式都是合法的。修法是加批次级异常检测:统计整批的变更画像(关键字段变更占比、下架占比、坐标平均位移、价格变更幅度分布),任一指标超阈值就整批拦截并告警一次推送里三成酒店改名,在正常业务里几乎不可能发生,它是供应商出错的强信号而不是业务变化。我想强调的教训是:异常检测的粒度必须和异常发生的粒度一致。供应商是成批出错的,单条校验对成批错误结构上就无能为力——不是校验写得不够严,是层次不对。这个思路我后来在别的地方也用上了。
    Q:拦截的阈值怎么定?会不会误拦? A:会误拦,这个必须承认,而且误拦率是这个机制能不能活下来的关键指标——误拦太多,运营会要求把阈值放宽甚至关掉,那就等于没做。阈值定法上我们用历史批次回放:把过去几个月的批次跑一遍,看阈值定在哪能拦住已知的那几次事故、又不误拦正常批次。然后按供应商分别设阈值,因为不同供应商的推送习惯差异很大——有的每天小量增量,有的每周一次大批量整理,用一套全局阈值套所有供应商,一定会同时出现误拦和漏拦误拦的典型来源是正常的业务批量操作:供应商做了一次房型整理、某城市集中调价,这些在画像上和异常很像,所以拦截后要有人工快速判定通道。还有一个配套的坑我们踩过:拦截做好了、告警也发了,但没指定责任人和处理时限,告警在群里刷过去就没了,直到运营反馈「某家供应商价格好像很久没动了」。拦截机制必须配处理闭环,否则只是把「数据错」换成了「数据不更新」,后者更隐蔽。
    Q:所有字段都走人工确认吗?业务能受得了? A:不能,所以要分级,分级依据是「变更频率 × 改错的后果」。高频且后果小的直通:价格、库存、房态,一天变几十次,加人工环节业务直接跑不动。低频且后果小的正常入库:设施列表、周边介绍、房型描述。低频且后果大的转人工确认:名称、地址、坐标、星级——这类改动本应极少(酒店不会天天改名),出现就值得看一眼,所以人工成本可控。为什么关键字段不靠灰度兜而要前置人工:灰度能减少影响面,但拦不住错误本身,而且关键字段的错误发现滞后于灰度窗口——地址错了,用户要到出行那天才发现,灰度早结束了。所以对「错误发现滞后于灰度窗口」的字段,灰度是无效的防护。这个判断我觉得是分级设计里最实质的一条:不是按字段重要性分,而是按「错误多久能被发现」来分——能快速发现的可以用灰度,发现滞后的必须前置拦。
    Q:同步失败要重跑,会不会把数据搞乱? A:会,而且我们踩过一个很容易被混过去的坑。同步任务失败后手动重跑了一个旧批次,那期间已经有更新的数据进来了,重放把它们盖回了旧值,表现是「明明改过的数据又变回去了」。教训是:幂等不等于可安全重放。幂等保证的是「重复执行结果一致」,但如果中间有别的写入,重复执行就会覆盖它。要安全重放还需要版本或时间戳的单调性检查——我们的幂等键是「批次号 + 记录版本」,并且加了版本比对:只在版本更新时才写,旧批次重放时版本不新就跳过。配套还有回滚能力:每个变更记录保留旧值并挂在批次号下,回滚就是按批次反向应用,支持整批回滚和批内部分回滚两种粒度。这一条是买来的经验——乱码那次事故我们没有批次概念,改动是逐条落库的,只能从备份捞,恢复花了几个小时所以全量推送也要先算差异转成变更记录,不要直接覆盖,直接覆盖等于放弃了审计和回滚能力。

没有匹配的内容,换个关键词试试。

项目拆解 · 房源映射与内容治理(后端)· 共 3 个模块 · 数字均为示例,需替换成自己项目的真实数据