上一篇讲了前 5 关,泛称被同音误伤、真歧义被当成错字、两字县名的子串、合称拆不开、单字别名越界。它们的共同点是全都不报错,只是给出一个看着像的错答案。
这一篇还是这个主题,只不过错得更安静。5 关里有 3 关来自 295 条那一轮,2 关来自扩到 1,168 条之后。
第 6 关:海南藏族自治州 变成了海南省
青海的海南藏族自治州,被解析成了海南省。
因为省级匹配走的是去后缀短形式"海南",而这个位置其实是一个更长地名的开头。同一批还有个 海南区,内蒙古乌海的,现在能正确落在乌海市。
改法:短形式命中时,检查该位置有没有更长的已知区划名,有就不作数。
第 7 关:南京市 变成了北京市
这关不报错,也不给候选,就是悄悄答错。前面几关好歹还能从"答案荒唐"里看出破绽,这一关的输出非常正常,所以单独写一下。
南京市 和 北京市 逐字比对只差一个字,南和北。我那套"模糊匹配(编辑距离 1)"把前者当成了后者的错字,降了一点置信度就返回北京市。
改法是给模糊匹配加两道闸。命中的那段如果本身就是现行区划名,跳过;拼音对不上(nan-jing-shi 不等于 bei-jing-shi),也跳过。字距 1 但读音完全不同,多半就是另一个词。
第 8 关:西鞍 落到了"西安区×2"
西鞍 是西安的同音错字,纠错方向是对的。但西安的同音候选里既有西安市,也有两个"西安区"。原来的取法是"取第一个能解析的",于是随机落到了低层级而且不相关的候选上。
改法:候选要择优。优先返回唯一解析,也就是西安市;所有候选都只能得到歧义时,才退回去给候选集。
第 9 关:名字对了,码是空的
题量扩到 1,168 条之后,这一关冒出来了。
| 输入 | 修之前 | 问题 |
|---|---|---|
浙江省西湖区 | 浙江省-西湖区 | 串看着对,但 county 码是 null |
河北省桥西区 | ["河北省-桥西区", "河北省-桥西区"] | 候选重复两次,而且都丢了市级 |
第一行尤其麻烦。输出长得没毛病,码却没了。对一个卖码的工具来说,名字对、码没有,等于没交付。
根因是,当输入里只有省、没有市的时候,引擎在全省范围找到县名之后,没有反查这个县到底属于哪个地级市,市级字段和县级码就一起丢了。
改法:反查所属地级再补全。单命中补全,多命中按(市,县)去重展开成候选。
第 10 关:喀什地区 变成了喀什市
同一批里还有一串同类问题。和田地区变成了和田市 / 和田县的候选集,喀什地区变成了喀什市,红河哈尼族彝族自治州变成了红河县,跟州名只是前缀相同。
根因是,全库县级直配比地级匹配先跑,于是"喀什"这两个字先命中了它下辖的县级市。
改法:省未命中时,先做地级全名直配,要求整串相等,然后再走县级直配。整串相等这个限制保住了 杭州市西湖区 这类带下级的输入。
这两批的账
| 项 | 数 |
|---|---|
| 本篇这 5 关 | 每条都补了 3 条以上回归,共 20 条 |
| 累计修掉的解析缺陷 | 10 个 |
| 累计新增回归用例 | 41 条,回归集从 110 条扩到 151 条,全绿 |
| 评测集规模 | 128 → 295 → 1,168 条 |
| 自动生成的历史别名 | 888 条 |
| 旧码到现行码的映射 | 1,928 条 |
引擎和数据在 GitHub:github.com/nbsetsail/r… 。代码 MIT,数据 CC-BY-4.0,署名即可使用。脏地址解析可离线跑,有 CLI。
下一篇讲后面 5 关,涉及层级、时间机器,以及一处根因不在引擎、而在数据本身的问题。