使用Sparql创建URI的最佳方法(如自动增量)

使用Sparql创建URI的最佳方法(如自动增量),sparql,rdf,Sparql,Rdf,我目前正在编写一个通过用户输入创建新项目(数据)的服务。为了将这些项目保存在RDF图形存储中(目前通过Sparql 1.1使用Sesame),我需要向数据添加主题URI。我的方法是使用一个为每个新项目递增的数字。例如: <http://example.org/item/15> dct:title "Example Title" . <http://example.org/item/16> dct:title "Other Item" . dct:title“示例标题”。

我目前正在编写一个通过用户输入创建新项目(数据)的服务。为了将这些项目保存在RDF图形存储中(目前通过Sparql 1.1使用Sesame),我需要向数据添加主题URI。我的方法是使用一个为每个新项目递增的数字。例如:

<http://example.org/item/15> dct:title "Example Title" .
<http://example.org/item/16> dct:title "Other Item" .
dct:title“示例标题”。
dct:标题“其他项目”。
通过Sparql为新项目(如MySQL/MongoDB中的自动激励)获取递增数字的最佳方法是什么?或者发出一些数据,端点通过模板自动创建URI(就像为空白节点创建URI一样)。 但我不想使用空白节点作为这些项目的主题。
有比使用递增数字更好的解决方案吗?我的用户不关心URI。。。。我不想处理通过散列数据和将散列作为主题的一部分而创建的冲突。

假设项目的类是
http://example.org/ontology/Example
,查询将变为以下内容。注意:必须逐个插入项,因为每个事务只计算一个新URI

PREFIX dct: <http://purl.org/dc/terms/>
INSERT {
    GRAPH <http://example.com> {
        ?id dct:title "Example Title" ;
            a <http://example.org/ontology/Example> .
    } .
} WHERE {
    SELECT ?id WHERE {
        {
            SELECT (count(*) AS ?c) WHERE {
                GRAPH <http://example.com> { ?s a <http://example.org/ontology/Example> }
            }
        }
        BIND(IRI(CONCAT("http://example.org/item/", STR(?c))) AS ?id)
    }
}
前缀dct:
插入{
图表{
?id dct:标题“示例标题”;
A.
} .
}在哪里{
选择?id在哪里{
{
选择(计数(*)为?c)其中{
图{?sa}
}
}
绑定(IRI(CONCAT)(“http://example.org/item/,STR(?c)))AS?id)
}
}

(使用RDF4J 2.2.2使用GraphDB 8.4.0进行测试)

您说除了自动递增的数字,您还可以选择其他选项。一个好的选择是使用

如果您根本不在乎URI是什么样子,那么可以使用以下函数:

INSERT {
    ?uri dct:title "Example Title"
}
WHERE {
    BIND (UUID() AS ?uri)
}
这将生成类似于
的URI

如果您希望在自己的命名空间中有HTTP URI,可以使用:

这将生成类似于
http://example.org/item/73cd4307-8a99-4691-a608-b5bda64fb6c1


UUID非常好。碰撞风险可以忽略不计。这些函数是SPARQL标准的一部分。唯一的缺点是它们又长又丑。

如果你在更新过程中维护一个指定的计数器,那么沿着这些线做的事情就可以了

首先在数据集中插入一个计数器

insert data {
    graph <urn:counters> {<urn:Example> <urn:count> 1 }
}
插入数据{
图{1}
}
然后,典型的更新应该如下所示:

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
delete {
    #remove the old value of the counter
    graph <urn:counters> {<urn:Example> <urn:count> ?old}
} 
insert {
    #update the new value of the counter
    graph <urn:counters> {<urn:Example> <urn:count> ?new}

    # add your new data using the constructed IRI
    GRAPH <http://example.com> {
        ?id dct:title "Example Title" ;
            a <http://example.org/ontology/Example> .
    } .
} where {
    # retrieve the counter
    graph <urn:counters> {<urn:Example> <urn:count> ?old}

    # compute the new value
    bind(?old+1 as ?new)    

    #construct the IRI
    bind(IRI(concat("http://example.org/item/", str(?old))) as ?id)
}
前缀rdfs:
删除{
#删除计数器的旧值
图{?old}
} 
插入{
#更新计数器的新值
图{?新}
#使用构造的IRI添加新数据
图表{
?id dct:标题“示例标题”;
A.
} .
}在哪里{
#取回柜台
图{?old}
#计算新值
绑定(?旧+1为新)
#构建IRI
绑定(IRI(concat)(“http://example.org/item/“,str(?old)))作为?id)
}

这很聪明。如果同时删除和创建资源,则该方法将不起作用。如果在可序列化隔离级别以下执行事务,则可能会发生冲突。这种方法确实很聪明。如果像答案中那样实现,客户机不知道创建了哪个资源(因为sparql只回答~“Success”)。不幸的是,sparql中没有Select Update查询支持,需要将此请求拆分为两个请求。为了缩短长度,可以在上面使用哈希。例如,
BIND(IRI(CONCAT)(“http://example.org/item/,MD5(struid())作为?uri)
。不是真的更漂亮,但是结果字符串会更短。冲突的风险仍然可以忽略不计。这种方法很好,以防它被分成三个请求。一个获取当前计数器(因此它在请求的客户端中可用),一个递增计数器,一个使用请求的计数器插入数据。如果像答案中那样实现,客户机将无法知道创建了哪个资源并进一步处理它(因为sparql只回答~“Success”)。这确实是sparql(不支持选择更新查询)的一个缺点。@Roy将更新拆分为3个不同的简单更新将阻止其原子性。对于主要问题,关于在更新后使用某种方法来标识创建的id,总有一个解决方法。例如,如果在客户端维护一种唯一的外部“请求ID”,则可以将这些ID与创建的ID相关联,然后使用这些ID查找已添加的内容。您可以将请求id的值作为更新的一部分传递,例如,包括在
where
子句
VALUES?rq_id{“abscedf”}
中,并添加类似
?id?rq_id
的语句。您所描述的是一种解决方法,这是正确的。但它似乎不适合当前的web架构范例。例如,它不适用于UUID应答,如果有多个客户端通过扩展存储客户端(服务)访问存储,则它不可用。拥有第三方id创建服务的另一种选择就像打破轮子上的蝴蝶一样……同时跟踪一个类的所有主题,并在insert上区分这些主题。@Roy Sparql 1.1的早期草案是在大约10年前提出的,因此期望它与现代web架构保持同步是有点不可行的。如果您有一个固定的模式,解决这个问题的一种方法是构建一个轻量级GraphQL服务,该服务与RDF存储交互,以满足您的特定需求,并将其公开给您的客户,或者等到某个第三方(供应商或社区)为您的问题提供一个可靠的可用解决方案。
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
delete {
    #remove the old value of the counter
    graph <urn:counters> {<urn:Example> <urn:count> ?old}
} 
insert {
    #update the new value of the counter
    graph <urn:counters> {<urn:Example> <urn:count> ?new}

    # add your new data using the constructed IRI
    GRAPH <http://example.com> {
        ?id dct:title "Example Title" ;
            a <http://example.org/ontology/Example> .
    } .
} where {
    # retrieve the counter
    graph <urn:counters> {<urn:Example> <urn:count> ?old}

    # compute the new value
    bind(?old+1 as ?new)    

    #construct the IRI
    bind(IRI(concat("http://example.org/item/", str(?old))) as ?id)
}