ShEx/Unique UNIQUE

From Semantic Web Standards

Obsolete - please see the ShEx github wiki



UNIQUE

Proposed for 2.1

A UNIQUE constraint takes an optional scope (FOCUS|GRAPH, default: FOCUS) and 1+ predicates, e.g.:

 <T> {
   :fname LITERAL;
   :lname LITERAL;
   :title LITERAL+;
   :homepage IRI
   UNIQUE(GRAPH, :fname, :lname)
   UNIQUE(LANGTAG(:title))
   UNIQUE(GRAPH, :homepage)
 }

UNIQUEs can appear arbitrarily nested in expressions:

 <PersonShape> {
     foaf:givenName .;
     foaf:familyName
     UNIQUE(foaf:given, foaf:family)
   | foaf:name .
     UNIQUE(foaf:name)
 }

UNIQUEs scoped to the FOCUSNODE can be dispatched immediately. Those scoped to the GRAPH or DATASET must have their values noted and associated with the UNIQUE constraint, noting any possible conflicts during insertion.


Shortcomings

It's possible we'd want uniques that span shapes, e.g. if the following data were permissible:

 { <s1> :code "1234"; :dept [ :code "5678" ] .
   <s2> :code "1234"; :dept [ :code "8765" ] }

but this were not:

 { <s1> :code "1234"; :dept [ :code "5678" ] .
   <s2> :code "1234"; :dept [ :code "5678" ] }

There's no way to stipulate uniqueness across repeated properties, e.g. if we wanted to make sure that creators from a.example were unique in the graph but creators from b.example were not:

 schema:
 <S> { :creator PATTERN "^http://a\\.example/",
       :creator PATTERN "^http://b\\.example/"
 }
 failing data:
 { <s1> :creator <http://a.example/1> ; :creator <http://b.example/2> .
   <s2> :creator <http://a.example/3> ; :creator <http://b.example/2> .
 }

Alternative Syntax - on shape

The UNIQUE constraints could go on the shape.

 <T>
   UNIQUE(GRAPH, :fname, :lname)
   UNIQUE(LANGTAG(:title))
   UNIQUE(GRAPH, :homepage)
   {
     :fname LITERAL;
     :lname LITERAL;
     :title LITERAL+;
     :homepage IRI
   }

This makes evaluation of predicates in disjuncts weird, e.g.

 <PersonShape> UNIQUE(foaf:given, foaf:family) UNIQUE(foaf:name)
   { foaf:givenName .; foaf:familyName | foaf:name .}

where the semantics for enforcing UNIQUE(foaf:given, foaf:family) over the data

 { <s> :foaf:name "Bob Smith". }

are a bit weird and "NULL-y".