这些标签连接/合并是否可以在 Sparql 中高效完成?

Are these label concats/merges possible to do efficiently in Sparql?

提问人:Darren Cook 提问时间:11/16/2023 更新时间:11/21/2023 访问量:32

问:

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;

但我真正想要的是以两种方式合并重复项:

  1. 如果标签和英文标签一样,就不用告诉我了。
  2. 告诉我所有其他的,并在标签上附上语言代码列表。

所以像这样:

日本@ja;Japó@ca;ژاپن@fa;Giappone@it;ಜಪಾನ್@kn;Japon@fr;Япония@ry;Hapon@ilo,tl;Japonia@ro;Japón@es;

(删除了“日本”的所有实例,并合并了。ilotl

当然,我可以在导出后在后处理脚本中完成所有这些操作。 但是我想知道我们可以在不增加查询时间的情况下在 SPARQL 中走多远?

旁白:如果我换成它,它会在 203 毫秒内返回 7151 个结果。原始链接查询在 7776 毫秒内减少到 20,258 个结果。在这两种情况下,它是否运行得更快,因为字符串总数是原始字符串的 40%?或者从根本上比 ??country rdfs:label ?label .?country skos:altLabel ?label .skos:rdfs:

SPARQL 维基数据

评论

0赞 UninformedUser 11/16/2023
不确定我是否理解,但这样的事情会省略与英语标签具有相同词典形式的标签: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
1赞 UninformedUser 11/16/2023
请注意,这仅供日本(Q17)测试之用,您可以删除该条款。顺便说一句,您还应该添加一些过滤器以省略维基数据中的历史国家/地区 - 如果那些BIND()
1赞 Darren Cook 11/16/2023
@UninformedUser 如果这是一个答案而不是评论,那就太好了。(它也更容易阅读!

答:

0赞 Darren Cook 11/21/2023 #1

(使用 UninformedUser 的注释作为起点。

首先,要获取单个列,将国家/地区名称和语言代码组合在一起,如下所示:

(GROUP_CONCAT(CONCAT(?label, "@", lang(?label)); SEPARATOR=";") AS ?labels)

顺便说一句,在尝试查询时,很好的提示是将查询作为第一行,以便通过只获取一个国家/地区(在本例中为日本)来使其运行得更快。BIND(wd:Q17 AS ?country)WHERE{...}

为了将英文标签拉出来,我们将该行替换为所需语言的过滤器。?labelsSERVICE 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 * {...}hinthint:SubQueryhint:Prior

https://www.wikidata.org/wiki/Wikidata:SPARQL_query_service/query_optimization 也许可以解释这一点。

鉴于到目前为止缺乏答案,当标签相同时,似乎没有办法连接国家/地区代码。例如,对于日本,“Japon”用于法语和其他 15 种语言,“Япония”用于俄语和其他 9 种语言。