如何用OverPass查询语言获取城镇及州/省名称?
获取指定半径内城镇并确保返回州/省名称的解决方案
问题背景
我开发了一个Node.js工具,用来获取用户位置100英里(160934米)范围内的城镇/城市,但返回结果里只有部分地点的wikipedia标签包含州/省信息,无该标签的地点就拿不到对应行政区域信息,加admin_level过滤也没解决问题。
原查询代码:
// Overpass API endpoint const overpassUrl = 'https://overpass-api.de/api/interpreter'; // Query to retrieve both cities and towns within a radius const overpassQuery = ` [out:json]; ( node["place"="town"](around:160934,${userLat},${userLon}); node["place"="city"](around:160934,${userLat},${userLon}); ); out body; >; out skel qt; `;
原请求处理代码:
// Make the HTTP request to the Overpass API using fetch fetch(overpassUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ data: overpassQuery }) }) .then(response => { // Error handling here and... return response.json(); }) .then(data => { data.elements.forEach(node => { node.distance = calculateDistance(userLat, userLon, node.lat, node.lon); }); // Process the JSON data // Sort the results by distance const sortedResults = data.elements.sort((a, b) => a.distance - b.distance); console.log(data); }) .catch(error => console.error('Error:', error));
解决方法
依赖wikipedia标签不可靠,正确的做法是通过Overpass API的反向关联查询,直接获取城镇所属的州/省级行政区域(对应admin_level,不同国家层级有差异,比如美国州是admin_level=4,中国省是admin_level=2)。
1. 修改Overpass查询语句
调整查询,让它同时获取城镇节点和它们所属的行政区域关系:
const overpassQuery = ` [out:json]; // 先获取目标范围内的城镇/城市节点 ( node["place"="town"](around:160934,${userLat},${userLon}); node["place"="city"](around:160934,${userLat},${userLon}); ); // 反向获取这些节点所属的行政区域关系(匹配常见的州/省层级) out body; >; relation["admin_level"~"2|4"]["boundary"="administrative"]; out body; `;
这里admin_level~"2|4"是兼容不同国家的行政层级,你可以根据目标区域调整(比如只查美国就用admin_level="4")。
2. 处理返回结果,匹配城镇对应的州/省
在数据处理阶段,把每个城镇和对应的行政区域关联起来:
fetch(overpassUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ data: overpassQuery }) }) .then(response => { if (!response.ok) throw new Error('Network response was not ok'); return response.json(); }) .then(data => { // 分离城镇节点和行政区域关系 const towns = data.elements.filter(el => el.type === 'node' && (el.tags.place === 'town' || el.tags.place === 'city')); const adminRegions = data.elements.filter(el => el.type === 'relation' && el.tags.boundary === 'administrative'); // 给每个城镇匹配对应的州/省 const townsWithRegion = towns.map(town => { // 找到包含该城镇节点的行政区域(通过relation的members) const region = adminRegions.find(rel => rel.members.some(member => member.type === 'node' && member.ref === town.id) ); return { ...town, distance: calculateDistance(userLat, userLon, town.lat, town.lon), stateProvince: region ? region.tags.name : 'Unknown' // 提取行政区域名称 }; }); // 按距离排序 const sortedResults = townsWithRegion.sort((a, b) => a.distance - b.distance); console.log(sortedResults); }) .catch(error => console.error('Error:', error));
关键说明
admin_level的取值:不同国家的行政层级定义不同,比如:- 美国:州是
admin_level=4 - 中国:省是
admin_level=2 - 欧盟部分国家:州/大区是
admin_level=4
- 美国:州是
- 如果查询范围跨多个国家,可以保留
admin_level~"2|4"来覆盖主流情况,后续可以根据地点的国家标签(tags.country)进一步筛选对应层级。
内容的提问来源于stack exchange,提问作者Zlatan Omerović
相关产品推荐
相关产品推荐

