You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过SPARQL获取带经纬度的维基数据实体本地数据集

问题需求

我需要获取所有关联经纬度的维基数据ID数据集,用于快速匹配从大规模语料NER任务中提取的200多万个地点,避免多次API调用,因此计划搭建本地查询数据集。

此前使用Stack Overflow推荐的数据集不完整,未覆盖小说中的多数地点(例如“Mount Etna”和“Sicily (Italy)”)。尝试用SPARQL获取带经纬度的唯一实体JSON文件,但当前查询无法正常运行,代码如下:

from SPARQLWrapper import SPARQLWrapper, JSON
import sys

user_agent = "Wikidata-Service Python/%s.%s" % (sys.version_info[0], sys.version_info[1])
endpoint_url = "https://query.wikidata.org/sparql"
sparql = SPARQLWrapper(endpoint_url, agent=user_agent)

sparql.setReturnFormat(JSON)

# something here is clearly wrong
sparql.setQuery("""
    PREFIX wd: <http://www.wikidata.org/entity/>
    PREFIX wdt: <http://www.wikidata.org/prop/direct/>
    PREFIX ps: <http://www.wikidata.org/prop/statement/>
    PREFIX psv: <http://www.wikidata.org/prop/statement/value/>
    PREFIX p: <http://www.wikidata.org/prop/>
    
    SELECT DISTINCT ?item ?itemLabel ?lat ?long
    WHERE {
# also not sure that P625 is what I want
        ?item wdt:P625 . 
        ?item p:P625 ?statement .
        ?statement psv:P625 ?coordinate_node .
        ?coordinate_node wikibase:geoLatitude ?lat .
        ?coordinate_node wikibase:geoLongitude ?long .
        SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
    }
    """
)

# this is only to print out results
try:
    count = 0
    ret = sparql.queryAndConvert()
    for r in ret["results"]["bindings"]:
        count += 1
        #print(r)
    print("Results: ", str(count))
except Exception as e:
    print(e)

解决方案

1. SPARQL查询修正

  • P625属性确认:wdt:P625确实是维基数据中标记“坐标位置”的标准属性,完全符合你的需求。
  • 冗余结构简化:原查询同时使用了直接属性wdt:P625和statement层级的嵌套查询,既冗余又会降低效率。可以通过geof:lat/geof:long函数直接从坐标值中提取经纬度,无需拆分statement节点。

修正后的SPARQL查询:

PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX geof: <http://www.opengis.net/ont/geosparql#>

SELECT DISTINCT ?item ?itemLabel ?lat ?long
WHERE {
  ?item wdt:P625 ?coord .
  BIND(geof:lat(?coord) AS ?lat)
  BIND(geof:long(?coord) AS ?long)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}

对应修正后的Python代码:

from SPARQLWrapper import SPARQLWrapper, JSON
import sys

user_agent = "Wikidata-Service Python/%s.%s" % (sys.version_info[0], sys.version_info[1])
endpoint_url = "https://query.wikidata.org/sparql"
sparql = SPARQLWrapper(endpoint_url, agent=user_agent)

sparql.setReturnFormat(JSON)

sparql.setQuery("""
    PREFIX wd: <http://www.wikidata.org/entity/>
    PREFIX wdt: <http://www.wikidata.org/prop/direct/>
    PREFIX geof: <http://www.opengis.net/ont/geosparql#>
    
    SELECT DISTINCT ?item ?itemLabel ?lat ?long
    WHERE {
      ?item wdt:P625 ?coord .
      BIND(geof:lat(?coord) AS ?lat)
      BIND(geof:long(?coord) AS ?long)
      SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
    }
""")

try:
    count = 0
    ret = sparql.queryAndConvert()
    for r in ret["results"]["bindings"]:
        count += 1
        # 可在此处将结果写入本地文件/数据库
        # print(f"ID: {r['item']['value']}, Label: {r['itemLabel']['value']}, Lat: {r['lat']['value']}, Long: {r['long']['value']}")
    print("Results: ", str(count))
except Exception as e:
    print(e)

2. 全量数据获取优化

由于你需要处理百万级别的地点匹配,SPARQL查询全量数据可能会因超时或请求限制失败。更高效的方式是:

  • 直接下载维基数据的全量RDF转储文件,使用rdflib或Apache Jena等工具批量提取所有带有wdt:P625属性的实体。
  • 将提取出的ID、标签、经纬度存储到本地数据库(如SQLite、PostgreSQL),构建索引后即可实现快速查询匹配。

内容的提问来源于stack exchange,提问作者Annie K. Lamar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 01:35:17