提问人:Darren Cook 提问时间:11/16/2023 更新时间:11/21/2023 访问量:32
这些标签连接/合并是否可以在 Sparql 中高效完成?
Are these label concats/merges possible to do efficiently in Sparql?
问:
从 https://stackoverflow.com/a/57856942/841830 中显示的示例开始,然后将它们分组为每个国家/地区只有一行。(21600 毫秒内有 208 个结果;原来是 19484 毫秒内有 53,546 个结果,所以它并没有减慢太多。
SELECT ?country (GROUP_CONCAT(?label; SEPARATOR=";") AS ?labels) (GROUP_CONCAT(lang(?label); SEPARATOR=";") as ?label_langs) ?countryLabel
WHERE
{
?country wdt:P31 wd:Q6256.
?country rdfs:label ?label .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?country ?countryLabel
请注意,我不能使用,因为标签会合并,但语言代码不会,因此它们将不再处于 1-1 关系中。DISTINCT
举个例子,这是我得到的日本(Q17)的精简版(前16个标签):
日本;Japan;Japó;ژاپن;Japan;Japan;Giappone;ಜಪಾನ್;Japon;Япония;Japan;Hapon;Hapon;Japonia;Japón;Japan;
ja;nl;ca;fa;en;de;it;kn;fr;ru;en-gb;ilo;tl;ro;es;din
最好将语言代码直接附加到每个标签,所以我只有一个字符串。所以它看起来像:
日本@ja;Japan@nl;Japó@ca;ژاپن@fa;Japan@en;Japan@de;Giappone@it;ಜಪಾನ್@kn;Japon@fr;Япония@ry;Japan@en-gb;Hapon@ilo;Hapon@tl;Japonia@ro;Japón@es;Japan@din;
但我真正想要的是以两种方式合并重复项:
- 如果标签和英文标签一样,就不用告诉我了。
- 告诉我所有其他的,并在标签上附上语言代码列表。
所以像这样:
日本@ja;Japó@ca;ژاپن@fa;Giappone@it;ಜಪಾನ್@kn;Japon@fr;Япония@ry;Hapon@ilo,tl;Japonia@ro;Japón@es;
(删除了“日本”的所有实例,并合并了。ilo
tl
当然,我可以在导出后在后处理脚本中完成所有这些操作。 但是我想知道我们可以在不增加查询时间的情况下在 SPARQL 中走多远?
旁白:如果我换成它,它会在 203 毫秒内返回 7151 个结果。原始链接查询在 7776 毫秒内减少到 20,258 个结果。在这两种情况下,它是否运行得更快,因为字符串总数是原始字符串的 40%?或者从根本上比 ??country rdfs:label ?label .
?country skos:altLabel ?label .
skos:
rdfs:
答:
(使用 UninformedUser 的注释作为起点。
首先,要获取单个列,将国家/地区名称和语言代码组合在一起,如下所示:
(GROUP_CONCAT(CONCAT(?label, "@", lang(?label)); SEPARATOR=";") AS ?labels)
顺便说一句,在尝试查询时,很好的提示是将查询作为第一行,以便通过只获取一个国家/地区(在本例中为日本)来使其运行得更快。BIND(wd:Q17 AS ?country)
WHERE{...}
为了将英文标签拉出来,我们将该行替换为所需语言的过滤器。?labels
SERVICE wikibase:label
?country rdfs:label ?en_label
SELECT ?country ?en_label (GROUP_CONCAT(CONCAT(?label, "@", lang(?label)); SEPARATOR=";") AS ?labels)
WHERE
{
?country wdt:P31 wd:Q6256.
?country rdfs:label ?label .
?country rdfs:label ?en_label . FILTER(lang(?en_label) = "en")
# FILTER(str(?label) != str(?en_label))
}
GROUP BY ?country ?en_label
然后,要排除使用英文标签作为国家/地区名称的国家/地区,请取消注释该行。FILTER(str(?label) != str(?en_label))
在我的测试中,它花了 56 秒,并且过滤器超时。在一个国家/地区进行测试时,添加过滤器似乎会使查询时间增加一倍,因此这是有道理的。
UninformedUser 的查询在 2.6 秒内运行,似乎给出了相同的结果:
SELECT ?country ?en_label (GROUP_CONCAT(CONCAT(?label, "@", lang(?label)); SEPARATOR=";") as ?other_labels)
WHERE {
{
SELECT * {
# BIND(wd:Q17 AS ?country)
?country wdt:P31 wd:Q6256.
?country rdfs:label ?en_label .
FILTER(lang(?en_label) = "en")
hint:SubQuery hint:runOnce true .
}
}
hint:Prior hint:runFirst true .
?country rdfs:label ?label .
FILTER(str(?label) != str(?en_label))
}
GROUP BY ?country ?en_label
我假设嵌套被用来提供两个.在这个阶段,我不知道它是否是嵌套的 SELECT,或者在运行时产生如此大的差异。SELECT * {...}
hint
hint:SubQuery
hint:Prior
https://www.wikidata.org/wiki/Wikidata:SPARQL_query_service/query_optimization 也许可以解释这一点。
鉴于到目前为止缺乏答案,当标签相同时,似乎没有办法连接国家/地区代码。例如,对于日本,“Japon”用于法语和其他 15 种语言,“Япония”用于俄语和其他 9 种语言。
评论
SELECT ?country ?en_label (GROUP_CONCAT(CONCAT(?label, "@", lang(?label)); SEPARATOR=";") as ?other_labels) WHERE { {SELECT * { BIND(wd:Q17 AS ?country) ?country wdt:P31 wd:Q6256. ?country rdfs:label ?en_label . FILTER(lang(?en_label) = "en") hint:SubQuery hint:runOnce true . } } hint:Prior hint:runFirst true . ?country rdfs:label ?label . FILTER(str(?label) != str(?en_label)) } GROUP BY ?country ?en_label
BIND()