2

我在 ndjson 文件中有一个大约 300.000 个 wikidata id 的列表(例如 Q1347065、Q731635 等)

{"Q1347065": ""}
{"Q731635": ""}
{"Q191789": ""} ... etc

我想要的是获取每个id的标签,并形成一个键值字典,例如

{"Q1347065":"epiglottitis", "Q731635":"Mount Vernon", ...}等等

在 id 列表变得如此庞大之前,我使用的是一个 Wikidata python 库(https://pypi.org/project/Wikidata/

from wikidata.client import Client
import ndjson

client = Client()
with open("claims.ndjson") as f, open('claims_to_strings.json', 'w') as out:
    claims = ndjson.load(f)

    l = {} 
    for d in claims: 
        l.update(d)

    for key in l:
        v = client.get(key)
        l[key] = str(v.label)

    json.dumps(l, out)

但它太慢了(1000 个 id 大约需要 15 小时)。有没有比我一直在做的更快的实现这一目标的另一种方法?

4

1 回答 1

1

在回答之前:我不知道你的意思是什么json.dumps(r, out);我假设你想要json.dump(l, out)

我的回答是对Wikidata Query Service使用以下 SPARQL 查询:

SELECT ?item ?itemLabel WHERE {
  VALUES ?item { wd:Q1347065 wd:Q731635 wd:Q105492052 }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

同时询问多个标签。

这大大加快您的执行时间,因为您的瓶颈是连接数,并且使用这种方法,id -> 标签映射完全在服务器端完成。

import json
import ndjson
import re
import requests

def wikidata_query(query):
    url = 'https://query.wikidata.org/sparql'
    try:
        r = requests.get(url, params = {'format': 'json', 'query': query})
        return r.json()['results']['bindings']
    except json.JSONDecodeError as e:
        raise Exception('Invalid query')

with open("claims.ndjson") as f, open('claims_to_strings.json', 'w') as out:
    claims = ndjson.load(f)

    l = {} 
    for d in claims: 
        l.update(d)
    
    item_ids = l.keys()
    sparql_values = list(map(lambda id: "wd:" + id, item_ids))
    item2label = wikidata_query('''
        SELECT ?item ?itemLabel WHERE {
        VALUES ?item { %s }
        SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
    }''' % " ".join(sparql_values))

    for result in item2label :
        item = re.sub(r".*[#/\\]", "", result['item']['value'])
        label = result['itemLabel']['value']
        l[item] = label
    
    json.dump(l, out)

我猜您无法对所有 300.000 个项目进行一次查询,但您可以轻松找到支持的最大接受 ID 数,并根据该数字拆分您的原始 ID 列表。

于 2021-02-16T11:06:01.390 回答