如何用SPARQL实现Wikidata艺术品单一流派/材质查询?
SPARQL查询Wikidata:避免艺术品多流派/材质导致的重复行问题
需求背景
要查询1870年之后创作的艺术品,获取艺术品本体、图片、创作时间、创作者标签、艺术流派标签、材质标签。但一件艺术品可能关联多个流派或使用多种材质,导致查询结果出现重复行。希望每个艺术品仅返回一组(任意一个)流派/材质,无需手动去重,此前尝试用COUNT+HAVING限制结果但出现超时问题。
原查询语句
SELECT DISTINCT ?artwork ?image ?time ?creatorLabel ?movementLabel ?materialLabel WHERE { ?artwork wdt:P31 wd:Q3305213 ; wdt:P571 ?time ; wdt:P18 ?image . OPTIONAL { ?artwork wdt:P170 ?creator } OPTIONAL { ?artwork wdt:P135 ?movement. } OPTIONAL { ?artwork wdt:P186 ?material. } FILTER(?time > "1870-01-01T00:00:00"^^xsd:dateTime) SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } # 获取对应语言标签,无则用英文 } LIMIT 100
可行解决方案
方法1:使用SAMPLE()聚合函数(推荐,性能优)
SAMPLE()会从多值结果中随机选取一个值,配合GROUP BY对每个艺术品分组,确保每个艺术品仅返回一行结果。这种方式无需遍历所有多值计数,性能远优于COUNT+HAVING,不会触发超时。
修改后的查询语句:
SELECT ?artwork ?image ?time ?creatorLabel (SAMPLE(?movementLabel) AS ?movementSample) (SAMPLE(?materialLabel) AS ?materialSample) WHERE { ?artwork wdt:P31 wd:Q3305213 ; wdt:P571 ?time ; wdt:P18 ?image . OPTIONAL { ?artwork wdt:P170 ?creator } OPTIONAL { ?artwork wdt:P135 ?movement. } OPTIONAL { ?artwork wdt:P186 ?material. } FILTER(?time > "1870-01-01T00:00:00"^^xsd:dateTime) SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } } GROUP BY ?artwork ?image ?time ?creatorLabel LIMIT 100
- 说明:
GROUP BY指定所有需要保持唯一的字段(艺术品本体、图片、时间、创作者标签),SAMPLE()分别为流派和材质选取任意一个标签。
方法2:筛选仅含单个流派/材质的艺术品
如果需求是只返回确实只有一个流派或一种材质的艺术品(而非任意取一个),可以用EXISTS+NOT EXISTS进行存在性检查,这种方式比COUNT聚合更高效:
查询语句示例:
SELECT DISTINCT ?artwork ?image ?time ?creatorLabel ?movementLabel ?materialLabel WHERE { ?artwork wdt:P31 wd:Q3305213 ; wdt:P571 ?time ; wdt:P18 ?image . OPTIONAL { ?artwork wdt:P170 ?creator } # 仅筛选只有一个流派的艺术品 OPTIONAL { ?artwork wdt:P135 ?movement. FILTER EXISTS {?artwork wdt:P135 ?m1} FILTER NOT EXISTS {?artwork wdt:P135 ?m2 FILTER (?m1 != ?m2)} } # 仅筛选只有一种材质的艺术品 OPTIONAL { ?artwork wdt:P186 ?material. FILTER EXISTS {?artwork wdt:P186 ?mat1} FILTER NOT EXISTS {?artwork wdt:P186 ?mat2 FILTER (?mat1 != ?mat2)} } FILTER(?time > "1870-01-01T00:00:00"^^xsd:dateTime) SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } } LIMIT 100
- 说明:通过
NOT EXISTS排除存在多个不同流派/材质的艺术品,仅保留单值条目。
为什么COUNT+HAVING会超时?
Wikidata数据集规模极大,COUNT聚合需要遍历每个艺术品的所有关联流派/材质并计数,计算开销极高,容易触发查询超时。而上述两种方法要么仅选取单个值(SAMPLE()),要么通过存在性检查快速过滤(EXISTS),计算量远小于聚合计数。
内容的提问来源于stack exchange,提问作者K3it4r0
相关产品推荐
相关产品推荐

