Memoria 开发记录 28:地点检索不能迷信 POI——行政区字段与高德解析边界
前言
相册里的地点搜索非常容易被“地图服务能搜到”误导。用户输入“青岛市”,高德 POI 搜索当然能返回结果,但返回的可能是“青岛市人民政府”,而不是行政区青岛市本身。
如果应用把所有地点都交给 POI 搜索,就会把行政区、景区、商圈、学校、建筑物混成一类。短期看召回变多,长期会让搜索边界变得不可控。
地点检索必须先区分:用户要的是行政范围,还是一个具体地点。
行政区和 POI 是两种不同语义
行政区是范围:
中国
山东省
青岛市
市南区
POI 是点或小区域:
五四广场
夫子庙
某某学校
某个酒店
某个商场
行政区适合匹配照片已经写入的 country/province/city/district/adcode 字段。POI 则需要结合 POI ID、AOI ID、地址文本、坐标中心和半径。
把行政区送去 POI search,可能会返回政府机关、火车站、酒店或其他同名地点。这不是“召回更强”,而是把查询含义改掉了。
为什么不能靠本地硬编码判断所有地点
地点名称非常复杂,不能靠少量后缀硬编码解决。比如“西海岸”可以是新区,也可以是更宽泛的区域概念;“景区”“街区”“校区”也不是行政区。为了迎合某个测试样例写规则,很容易制造另一个错误。
更稳妥的分工是:
- LLM 负责从自然语言中区分行政区、POI、景区、校区、商圈等意图;
- 客户端只做少量确定性修正,例如明显的“某某市”不应被当成 POI;
- Amap 负责解析具体 POI 的中心点和行政信息;
- 本地搜索执行最终边界。
这样避免把测试案例写进业务规则,也避免把所有判断都推给远程服务。
行政区不需要远程 place search
这次修复的一个关键点是:country/province/city/district 不再调用 Amap place/text。行政区查询直接保留原始结构,进入本地字段匹配。
青岛市:
type = city
aliases = 青岛市 / 青岛
match local city/adcode/geoTextTokens
五四广场:
type = poi
resolve by Amap place/geocode
use POI/AOI/center radius
这样“青岛市”不会被错误解析成“青岛市人民政府”,也不会因为高德 place/text 网络波动导致整个检索失败。
地图 API 失败不能让搜索崩掉
移动端搜索不能假设地图 API 永远稳定。实际调试中,Lambda 从 AWS 区域访问高德 place/text 可能出现 fetch 超时,而 regeo 正常。这说明不同上游接口、不同区域、不同网络路径都有失败可能。
代理层因此增加了:
- Amap 请求短超时;
- 简单重试;
- IPv4 优先;
place/text失败后 fallback 到geocode/geo;- 明确的 502 错误体;
- 客户端日志输出状态码和响应体。
搜索系统也应该允许地点解析失败后退回本地文本匹配,而不是把用户看到的结果变成空白。
半径和兄弟 POI 的取舍
POI 搜索还有一个常见问题:照片定位可能偏移。用户在夫子庙景区拍照,系统可能定位到附近某个青年旅舍。如果地点匹配过于严格,会搜不出合理结果;如果过于宽松,又会把完全无关的兄弟 POI 混进来。
更实际的策略是:
- 景区、校园、商圈等区域型地点使用合理半径;
- 允许一定定位偏移;
- 不能跨城市或几十公里错配;
- 用语义和时间进一步约束;
- 不为了单个 case 写特化规则。
地点检索追求的是“合理可解释”,不是地图数据库意义上的绝对精确。
总结
地点搜索的核心不是调用一次 POI API,而是先理解地点类型,再选择合适的本地或远程匹配方式。
关键经验包括:
- 行政区和 POI 不能混成一类;
- 行政区应优先使用本地结构化字段;
- POI 才需要远程解析中心点、ID 和半径;
- 远程 place search 失败不能让检索整体失败;
- 地点半径要容忍定位偏移,但不能跨城市误匹配;
- 不应为了个别测试样例写硬编码规则。
对应提交:eea8e41、d217919、ea4638a、07c235e。
浙公网安备 33010602011771号