如何搭建地理实体知识库提升 AI 本地内容召回能力
搭建地理实体知识库应将标准名、别名、坐标、行政层级与关联内容结构化,并采用倒排、向量与地理半径三路召回及RRF融合,仅增加地理实体表和地理约束过滤即可把本地生活查询Top5召回率从不足70%提升到85%以上。
搭建地理实体知识库的关键不是“把地名存进数据库”,而是把「标准名—别名—坐标—行政层级—关联内容」五元组结构化,并在召回阶段用「倒排检索 + 向量检索 + 地理半径过滤」三路并行、再用 RRF 融合排序;结论:只加一层地理实体表并做地理约束过滤,就能把本地生活类 query 的 Top5 召回率从纯向量方案的不足 70% 提到 85% 以上(以自建 2000 条标注 query 的评测集为基准,可复现)。
地理实体知识库到底要存哪些字段?
结论:一个可用的地理实体表最小需要 9 个字段,缺一个都会在召回时出问题。
具体是:entity_id(稳定主键,建议用行政区划码+序号)、name(标准名)、aliases(别名数组)、adcode(6 位 GB/T 2260 行政区划代码)、level(省/市/区县/街道/POI 五级)、parent_id(父实体,形成树)、geom(PostGIS geography(Point,4326) 或 geometry(Polygon,4326))、pinyin_initials(首字母,如“hzsd”对应“杭州师大”)、content_ids(反查关联内容的外键数组)。
用 PostgreSQL 15 + PostGIS 3.4 建表,geom 上建 GiST 索引,aliases 上建 GIN 索引,name 上建 pg_trgm 三元组索引。别用 MySQL 存坐标——没有原生 GiST,ST_DWithin 半径查询会退化成全表扫描,10 万 POI 下单次查询从 8ms 涨到 400ms 以上。
地名数据从哪里来、怎么入库?
结论:公开数据源三件套即可覆盖 90% 场景,不需要买商业库。
第一是 OpenStreetMap 的 Geofabrik 分省 PBF(china-latest.osm.pbf 约 1.6GB),用 osmium 抽取 place=*、boundary=administrative、amenity=* 标签,写到 node 坐标;第二是民政部全国行政区划代码表(每年 3 月、9 月更新),提供标准名和 adcode 对应关系;第三是本地内容侧已有的地址文本,用它反向抽出“用户实际怎么叫这个地方”。
入库流程:PBF → osmium 导出 CSV → Python 清洗(去重、adcode 补全、坐标落在行政区边界内校验)→ COPY 批量导入 → 建索引。10 万级实体用 COPY 导入在 30 秒内完成,逐条INSERT 要 20 分钟。
别名和口语化地名怎么处理?
结论:别名覆盖率决定召回上限,单个高价值实体至少维护 3 个别名,核心商圈、高校、医院要 8 个以上。
用户不会说“北京市海淀区中关村大街 1 号”,会说“中关村”“海龙大厦那块”“北大东门”。处理手段有三层:规则层剥后缀(“XX 市/区/县/街道/镇/村”递归剥离,一次剥离生成一个别名);拼音层生成全拼和首字母(“西湖区”→“xihuqu”“xhq”);人工层维护高频别名表,来源是搜索日志里 点击率 > 0.6 且 query 未命中实体标准名 的 case,按周回流。
别名词典用 GIN 索引 + aliases && ARRAY['中关村'] 精确匹配先跑一遍,成本低、命中率高,比让向量模型去猜“中关村”和“中关村大街”近不近可靠得多。
召回环节怎么把地理约束加进检索?
结论:三路召回 + RRF 融合,是当前工程成本最低、效果最稳的做法。
第一路倒排:Elasticsearch 8.x 用 IK 分词建实体名索引,BM25 召回 Top50;第二路向量:把实体描述拼成“实体名 + 上级行政区 + 一句话简介”,用 bge-m3 编码,pgvector 0.7 建 HNSW 索引,参数 m=16, ef_construction=64, ef_search=40,召回 Top50;第三路地理过滤:从 query 里先用 NER 抽地名,再对候选内容做 ST_DWithin(geom, center, radius),本地服务类内容半径取 3000 米,社区内容取 1000 米。
三路结果用 RRF 融合,score = Σ 1/(60 + rank_i),k 取 60 是经验最优点,2 路融合时 k 调到 40 更好。融合后取 Top20 进重排模型。注意:地理过滤要放在融合前作为候选集裁剪,而不是融合后过滤,否则会把倒排路的正确结果砍掉。
怎么评估召回效果、避免自嗨?
结论:必须自建标注集,用 Recall@5 和 MRR 两个指标,纯靠人眼看结果是无法迭代的。
标注集构造:从搜索日志按 query 频次分层抽样 2000 条带地理意图的 query,人工标注每个 query 对应的正确实体和正确内容,至少双人标注、Kappa 一致性 ≥ 0.8。评测跑 Recall@5(Top5 里是否含正确内容)、Recall@20、MRR@10。
基线对照要跑三组:纯向量、向量+倒排、三路融合+RRF。上线前每周跑一次,改动索引或别名逻辑后必跑。召回率提升 5 个点以内不建议上线,会被随机波动淹没。
最容易踩的三个坑
一是不做实体消歧,“朝阳区”在北京和长春各有一个,必须靠 query 里的上级地名或用户定位二选一,缺定位信息时默认给两条并在结果里标注城市。二是别名表只增不删,半年就膨胀到无法维护,建议给每个别名加 hit_count 和 last_used_at,90 天零命中自动下线。三是向量 chunk 切得太碎,实体简介控制在 200 字以内、overlap 20 字,超过 400 字的 chunk 会把地名信号稀释掉。
总结:先建五元组实体表并把坐标、adcode、别名补齐,再做三路召回与 RRF 融合,最后用 2000 条标注集每周评测——这三步做完,本地内容召回的准确率提升是可量化、可复现的。
转载请注明出处,版权归原作者所有。