我是SPARQL的新手,并且图形数据库作为一个整体查询所以请原谅任何无知,但我正在尝试使用存储在Fueski中的一些数据编写基本输出,并且我正在努力理解处理重复行的最佳实践至于各种概念之间存在的基数。
我将用一个简单的例子来表达我的观点。
数据集
这是我目前正在处理的数据类型和关系的代表性样本;
基于这种结构,我产生了以下三元组(N-Triple格式);
<http://www.test.com/ontologies/Author/JohnGrisham> <http://www.test.com/ontologies/property#firstName> "John" .
<http://www.test.com/ontologies/Author/JohnGrisham> <http://www.test.com/ontologies/property#lastName> "Grisham" .
<http://www.test.com/ontologies/Author/JohnGrisham> <http://www.test.com/ontologies/property#hasWritten> <http://www.test.com/ontologies/Book/TheClient> .
<http://www.test.com/ontologies/Author/JohnGrisham> <http://www.test.com/ontologies/property#hasWritten> <http://www.test.com/ontologies/Book/TheFirm> .
<http://www.test.com/ontologies/Book/TheFirm> <http://www.test.com/ontologies/property#name> "The Firm" .
<http://www.test.com/ontologies/Book/TheFirm> <http://www.test.com/ontologies/property#soldBy> <http://www.test.com/ontologies/Retailer/Foyles> .
<http://www.test.com/ontologies/Book/TheFirm> <http://www.test.com/ontologies/property#soldBy> <http://www.test.com/ontologies/Retailer/Waterstones> .
<http://www.test.com/ontologies/Book/TheClient> <http://www.test.com/ontologies/property#name> "The Client" .
<http://www.test.com/ontologies/Book/TheClient> <http://www.test.com/ontologies/property#soldBy> <http://www.test.com/ontologies/Retailer/Amazon> .
<http://www.test.com/ontologies/Book/TheClient> <http://www.test.com/ontologies/property#soldBy> <http://www.test.com/ontologies/Retailer/Waterstones> .
<http://www.test.com/ontologies/Retailer/Amazon> <http://www.test.com/ontologies/property#name> "Amazon" .
<http://www.test.com/ontologies/Retailer/Waterstones> <http://www.test.com/ontologies/property#name> "Waterstones" .
<http://www.test.com/ontologies/Retailer/Foyles> <http://www.test.com/ontologies/property#name> "Foyles" .
渲染输出格式
现在我要做的是渲染一个页面,其中显示所有作者,显示所有书籍和销售这些单独书籍的零售商的详细信息。所以像这样(suedo代码);
for-each:Author
<h1>Author.firstName + Author.lastName</h1>
for-each:Author.Book
<h2>Book.Name</h2>
Sold By:
for-each:Book.Retailer
<h2>Retailer.name</h2>
SPARQL
为了让渲染工作,我的想法是我需要作者的名字和姓氏,然后是他们拥有的所有书籍名称以及这些书籍销售的各种零售商名称,因此我提出了以下SPARQL;
PREFIX p: <http://www.test.com/ontologies/property#>
SELECT ?authorfirstname
?authorlastname
?bookname
?retailername
WHERE {
?author p:firstName ?authorfirstname;
p:lastName ?authorlastname;
p:hasWritten ?book .
OPTIONAL {
?book p:name ?bookname;
p:soldBy ?retailer .
?retailer p:name ?retailername .
}
}
这提供了以下结果;
不幸的是,由于行的重复,我的基本渲染尝试无法按预期生成输出,实际上它正在为查询返回的每一行渲染一个新的“作者”部分。
我想我想要了解的是应该如何进行这种渲染。
渲染器是否应该将数据重新组合回它想要去的图表形式(我真的看不出这是怎么回事)
SPARQL是否无效 - 有没有办法在SPARQL语言中做我想做的事情?
我刚做错了吗?
修订 - 对GROUP_CONCAT进行更详细的分析
在查看我可以使用的选项时,我遇到了GROUP_CONCAT,但经过一段时间的玩游戏后决定它可能不是给我想要的东西,可能不是最好的路线。原因是:
数据大小
虽然我在这篇文章中运行我的示例的数据集很小但只包含3个概念和一个非常有限的数据集我在现实世界中运行的实际概念和数据远远大于连接结果将产生的结果极长的分隔字符串,特别是对于描述等自由格式列。
失去上下文
在尝试group_concat时,我很快意识到我无法理解group_concat列中各种数据元素的相关内容。我可以通过上面的书籍示例来说明这一点。
SPARQL
PREFIX p: <http://www.test.com/ontologies/property#>
select ?authorfirstname
?authorLastName
(group_concat(distinct ?bookname; separator = ";") as ?booknames)
(group_concat(distinct ?retailername; separator = ";") as ?retailernames)
where {
?author p:firstName ?authorfirstname;
p:lastName ?authorLastName;
p:hasWritten ?book .
OPTIONAL {
?book p:name ?bookname;
p:soldBy ?retailer .
?retailer p:name ?retailername .
}
}
group by ?authorfirstname ?authorLastName
这产生了以下输出;
firstname = "John"
lastname = "Grisham"
booknames = "The Client;The Firm"
retailernames = "Amazon;Waterstones;Foyles"
正如您所看到的,这产生了一个结果行但,您无法再了解各种数据元素的相关性。哪些零售商适合哪本书?
非常感谢任何帮助/指导。
当前解决方案
基于下面推荐的解决方案,我使用了密钥的概念来提供各种数据集,但是我稍微调整了一下,以便我使用每个概念的查询(例如作者,书籍和零售商),然后使用在我的渲染器中汇总结果的键。
作者结果
firstname lastname books
--------------------------------------------------------------------------------
1 John Grisham ontologies/Book/TheClient|ontologies/Book/TheFirm
预订结果
id name retailers
-------------------------------------------------------------------------------------------------------
1 ontologies/Book/TheClient The Client ontologies/Retailer/WaterStones|ontologies/Retailer/Amazon
2 ontologies/Book/TheFirm The Firm ontologies/Retailer/WaterStones|ontologies/Retailer/Foyles
零售商结果
id name
--------------------------------------------------
1 ontologies/Retailer/Amazon Amazon
2 ontologies/Retailer/Waterstones Waterstones
3 ontologies/Retailer/Foyles Foyles
我在渲染器中执行的操作是使用ID从各种结果集中提取结果...
for-each author a : authors
output(a.firstname)
for-each book b : a.books.split("|")
book = books.get(b) // get the result for book b (e.g. Id to Foreign key)
output(book.name)
for-each retailer r : book.retailers.split("|")
retailer = retailers.get(r)
output(retailer.name)
如此有效地将各种不同的结果集拼接在一起并呈现它。
目前这似乎工作正常。
答案 0 :(得分:1)
我发现从代码中的SPARQL结果中构造对象更容易,而不是尝试形成每个相关资源只返回一行的查询。
我会使用资源的URI来识别哪些行属于哪个资源(在本例中为author),然后根据所述URI合并结果行。
对于JS应用程序,我使用代码here从SPARQL结果中构造对象。
对于复数值,我在变量名中使用__
来表示应该从值构造一个对象。例如,所有带有前缀为?book__
的变量的值都将变为一个对象,其中变量的名称的其余部分作为对象属性的名称,每个对象由{{1}标识}。因此,拥有?book__id
和?book__id
的值会导致作者的属性?book__name
,例如book
(如果有多本书,则为此类对象的列表)。
例如,在这种情况下,我将使用以下查询:
author.book = { id: '<book-uri>', name: 'book name'}
在应用程序代码中,我将构建看起来像这样的JavaScript对象(JavaScript表示法):
PREFIX p: <http://www.test.com/ontologies/property#>
SELECT ?id ?firstName ?lastName ?book__id ?book__name
?book__retailer
WHERE {
?id p:firstName ?firstName;
p:lastName ?lastName;
p:hasWritten ?book__id .
OPTIONAL {
?book__id p:name ?book__name;
p:soldBy/p:name ?book__retailer .
}
}
答案 1 :(得分:0)
我认为,这是一个可以打击任何关系数据库的常见问题。正如你所说GROUP_CONCAT
在许多情况下都很有用,但却失去了保真度。
我找到了一个你可能感兴趣的解决方案。假设你想构建一个通过作者循环的视图或结果树,然后为每个作者构建他们的书籍,然后为每个作者构建零售商。
SELECT DISTINCT ?authorname ?bookname ?retailername {
...
} ORDER BY ?authorname ?bookname ?retailername
这会给你这样的结果:
author book retailer
-----------------------------
1 author1 book1 retailer1
2 author1 book1 retailer2
3 author1 book2 retailer2
4 author2 book3 retailer2
5 author2 book3 retailer3
...
由于订购,可以逐步完成
get next result
currentauthor = author in result
print currentauthor
while author in next result = currentauthor:
get next result
currentbook = book in result
print currentauthor
while book in next result = currentbook:
get next result
print retailer in result