Search code examples
relationshiprdfsparqlowlreasoning

How to infer a sameAs relation between objects with the same name


I want to infer a owl:sameAs relation between objects that have the same value for a property using RDF reasoning.

i.e.

  • object1 dc:title someTitle
  • object2 dc:title someTitle

What would be the code to infer the relation between all objects with matching titles?

Also, can I do that when the properties are not the same?

i.e.

  • object1 dc:title someTitle
  • object2 rdf:title someTitle

Regards


Solution

  • Not in RDF or RDFS

    RDF doesn't have a whole lot of semantics built in, and while RDFS provides some, I don't think that either is enough to get you the kind of reasoning that you're looking for. However, since you're looking to create owl:sameAs links, you might be using an OWL reasoner, in which case this isn't too hard, and it's very easy in SPARQL too. The rest of the answer covers these two cases.

    In OWL

    You just need to declare that the property at hand is an inverse functional (object) property:

    9.2.8 Inverse-Functional Object Properties

    An object property inverse functionality axiom InverseFunctionalObjectProperty( OPE ) states that the object property expression OPE is inverse-functional — that is, for each individual x, there can be at most one individual y such that y is connected by OPE with x.

    A classic example of this is for any type of unique identifier, such as a taxpayer ID number. E.g.,

    ex:hasSSN a owl:InverseFunctionalProperty .
    :JohnDoe :hasSSN :ssnXXX-XX-XXXX .
    :JDoe :hasSSN :ssnXXX-XX-XXXX .
    

    From these, we can infer with OWL reasoning that

    :JohnDoe owl:sameAs :JDoe .
    

    Note that only object properties can be inverse functional (though I think that some reasoners will handle inverse functional datatype properties); this means that you may have to "wrap" some values as I did above, creating an IRI individual :ssnXXX-XX-XXX rather than using the string "XXX-XX-XXXX". See What's the problem with inverse-functional datatype properties? for some discussion about why.

    Now, if you have two different properties, then you could make them both subproperties of some new property, and make the new property inverse functional. For instance

    :hasSSN rdfs:subPropertyOf :hasTaxpayerIDOrSSN .
    :hasTaxpayerID rdfs:subPropertyOf :hasTaxpayerIDOrSSN .
    :hasTaxpayerIDOrSSN a owl:InverseFunctionalProperty .
    

    Then from

    :JohnDoe :hasSSN :ssnXXX-XX-XXXX .
    :JDoe :hasSSN :ssnXXX-XX-XXXX .
    

    you could infer

    :JohnDoe :hasTaxpayerIDOrSSN :ssnXXX-XX-XXXX .
    :JDoe    :hasTaxpayerIDOrSSN :ssnXXX-XX-XXXX .
    

    and from that, that

    :JohnDoe owl:sameAs :JDoe .
    

    In SPARQL

    In SPARQL this is pretty easy, too. First, some data to query:

    @prefix : <urn:ex:> .
    
    :JohnDoe :hasSSN :ssnXXX-XX-XXX .
    :JDoe :hasSSN :ssnXXX-XX-XXX .
    

    Then we can define a simple construct query:

    prefix : <urn:ex:>
    prefix owl: <http://www.w3.org/2002/07/owl#>
    
    construct { ?x owl:sameAs ?y }
    where { ?z ^:hasSSN ?x, ?y }
    
    @prefix :      <urn:ex:> .
    @prefix owl:   <http://www.w3.org/2002/07/owl#> .
    
    :JDoe   owl:sameAs  :JohnDoe , :JDoe .
    
    :JohnDoe  owl:sameAs  :JohnDoe , :JDoe .
    

    If you want to use multiple properties, you can just use an alternation in the property path. Here's data, a query, and the results:

    @prefix : <urn:ex:> .
    
    :JohnDoe :hasSSN :ssnXXX-XX-XXX .
    :JDoe :hasTaxpayerID :ssnXXX-XX-XXX .
    
    prefix : <urn:ex:>
    prefix owl: <http://www.w3.org/2002/07/owl#>
    
    construct { ?x owl:sameAs ?y }
    where { ?z ^(:hasSSN|:hasTaxpayerID) ?x, ?y }
    

    @prefix :      <urn:ex:> .
    @prefix owl:   <http://www.w3.org/2002/07/owl#> .
    
    :JDoe   owl:sameAs  :JDoe , :JohnDoe .
    
    :JohnDoe  owl:sameAs  :JDoe , :JohnDoe .