如何 "rotate" SPARQL 结果为 "loop"?
How to "rotate" SPARQL results in a "loop"?
问题
我想 select 答案的每个元素的大小为 n 的任意子集。
对于一个特定的元素,比如莱比锡市,我可以在 DBpedia 中这样解决 (http://www.dbpedia.org/sparql):
示例查询单个元素
select ?p
{
?p dbo:birthPlace dbr:Leipzig.
} limit 3
输出单元素
http://dbpedia.org/resource/Walter_Ulbricht
http://dbpedia.org/resource/Anita_Berber
http://dbpedia.org/resource/Martin_Benno_Schmidt
但我想旋转输出并对所有(或一定数量的)城市执行此操作:
期望输出多个元素
City Person1 Person2 Person3
dbr:Leipzig dbr:Walter_Ulbricht dbr:Anita_Berber dbr:Martin_Benno_Schmidt
dbr:Bonn dbr:Anton_Schumacher dbr:Hermann_Wallich dbr:Fritz_Simrock
dbr:Paris dbr:Adrien-Marie_Legendre dbr:André_Malraux dbr:Anselme_Payen
...
我尝试通过以下查询解决此问题:
SELECT ?city SAMPLE(?p1) SAMPLE(?p2) SAMPLE(?p3)
{
?city ^dbo:birthPlace ?p1,?p2,?p3.
?city a dbo:City.
FILTER(?p1<?p2&&?p2<?p3) # prevent permutations and duplicates
} GROUP BY ?city # only one line per city
LIMIT 10
但是我不确定这是否是最好的解决方案,我有几个问题:
- 随着 n 的增加,这种编写查询的方式变得很麻烦,有没有更优雅的选择(例如使用子查询)?
- 此查询是否提供了我想要的所有结果,即它是否对整行进行了采样,或者它是否通过分别对每个变量进行采样然后跳过有效解决方案而丢失了结果?
- 如果它 return 我会通过重复单个元素查询得到的所有结果,它是否具有相同的效率,还是 运行 在过滤掉它们之前通过大量排列?如果不是,有没有更高效的写法?
这是一个相当优雅和高效的解决方案:
- 在子查询中,使用
GROUP BY
和 group_concat
聚合将一个城市的所有人的 URI 合并为一个长字符串。
- 在子查询之外,使用字符串函数拆分长字符串并取前 n 项。
在此处完成前 100 个城市,每个城市有 5 人:
SELECT ?c ?p1 ?p2 ?p3 ?p4 ?p5 {
{
SELECT ?c (group_concat(?p; separator=' ') AS ?list1) {
{
SELECT ?c { ?c a dbo:City } LIMIT 100
}
OPTIONAL { ?p dbo:birthPlace ?c }
}
GROUP BY ?c
}
BIND (if(?list1, strAfter(?list1, ' '), undef) AS ?list2)
BIND (if(?list2, strAfter(?list2, ' '), undef) AS ?list3)
BIND (if(?list3, strAfter(?list3, ' '), undef) AS ?list4)
BIND (if(?list4, strAfter(?list4, ' '), undef) AS ?list5)
BIND (if(?list1, if(contains(?list1, ' '), IRI(strBefore(?list1, ' ')), IRI(?list1)), undef) AS ?p1)
BIND (if(?list2, if(contains(?list2, ' '), IRI(strBefore(?list2, ' ')), IRI(?list2)), undef) AS ?p2)
BIND (if(?list3, if(contains(?list3, ' '), IRI(strBefore(?list3, ' ')), IRI(?list3)), undef) AS ?p3)
BIND (if(?list4, if(contains(?list4, ' '), IRI(strBefore(?list4, ' ')), IRI(?list4)), undef) AS ?p4)
BIND (if(?list5, if(contains(?list5, ' '), IRI(strBefore(?list5, ' ')), IRI(?list5)), undef) AS ?p5)
}
问题
我想 select 答案的每个元素的大小为 n 的任意子集。
对于一个特定的元素,比如莱比锡市,我可以在 DBpedia 中这样解决 (http://www.dbpedia.org/sparql):
示例查询单个元素
select ?p
{
?p dbo:birthPlace dbr:Leipzig.
} limit 3
输出单元素
http://dbpedia.org/resource/Walter_Ulbricht
http://dbpedia.org/resource/Anita_Berber
http://dbpedia.org/resource/Martin_Benno_Schmidt
但我想旋转输出并对所有(或一定数量的)城市执行此操作:
期望输出多个元素
City Person1 Person2 Person3
dbr:Leipzig dbr:Walter_Ulbricht dbr:Anita_Berber dbr:Martin_Benno_Schmidt
dbr:Bonn dbr:Anton_Schumacher dbr:Hermann_Wallich dbr:Fritz_Simrock
dbr:Paris dbr:Adrien-Marie_Legendre dbr:André_Malraux dbr:Anselme_Payen
...
我尝试通过以下查询解决此问题:
SELECT ?city SAMPLE(?p1) SAMPLE(?p2) SAMPLE(?p3)
{
?city ^dbo:birthPlace ?p1,?p2,?p3.
?city a dbo:City.
FILTER(?p1<?p2&&?p2<?p3) # prevent permutations and duplicates
} GROUP BY ?city # only one line per city
LIMIT 10
但是我不确定这是否是最好的解决方案,我有几个问题:
- 随着 n 的增加,这种编写查询的方式变得很麻烦,有没有更优雅的选择(例如使用子查询)?
- 此查询是否提供了我想要的所有结果,即它是否对整行进行了采样,或者它是否通过分别对每个变量进行采样然后跳过有效解决方案而丢失了结果?
- 如果它 return 我会通过重复单个元素查询得到的所有结果,它是否具有相同的效率,还是 运行 在过滤掉它们之前通过大量排列?如果不是,有没有更高效的写法?
这是一个相当优雅和高效的解决方案:
- 在子查询中,使用
GROUP BY
和group_concat
聚合将一个城市的所有人的 URI 合并为一个长字符串。 - 在子查询之外,使用字符串函数拆分长字符串并取前 n 项。
在此处完成前 100 个城市,每个城市有 5 人:
SELECT ?c ?p1 ?p2 ?p3 ?p4 ?p5 {
{
SELECT ?c (group_concat(?p; separator=' ') AS ?list1) {
{
SELECT ?c { ?c a dbo:City } LIMIT 100
}
OPTIONAL { ?p dbo:birthPlace ?c }
}
GROUP BY ?c
}
BIND (if(?list1, strAfter(?list1, ' '), undef) AS ?list2)
BIND (if(?list2, strAfter(?list2, ' '), undef) AS ?list3)
BIND (if(?list3, strAfter(?list3, ' '), undef) AS ?list4)
BIND (if(?list4, strAfter(?list4, ' '), undef) AS ?list5)
BIND (if(?list1, if(contains(?list1, ' '), IRI(strBefore(?list1, ' ')), IRI(?list1)), undef) AS ?p1)
BIND (if(?list2, if(contains(?list2, ' '), IRI(strBefore(?list2, ' ')), IRI(?list2)), undef) AS ?p2)
BIND (if(?list3, if(contains(?list3, ' '), IRI(strBefore(?list3, ' ')), IRI(?list3)), undef) AS ?p3)
BIND (if(?list4, if(contains(?list4, ' '), IRI(strBefore(?list4, ' ')), IRI(?list4)), undef) AS ?p4)
BIND (if(?list5, if(contains(?list5, ' '), IRI(strBefore(?list5, ' ')), IRI(?list5)), undef) AS ?p5)
}