如何通过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
相关产品推荐
相关产品推荐

