Search code examples
xmlsparqlowlontologyrdfs

In SPARQL SELECT, keep only one record when their values are equals but in opposite order (the first is x,y and the second is y,x)


I'm learning SPARQL and I'm trying to do a query on a movie ontology I wrote myself. I would like to extract from it all the the actors who worked together in a movie, so I wrote this:

PREFIX  exID: <http://example.org/#> 
PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?actorName1 ?actorName2 
WHERE {     
    ?actor rdfs:label ?actorName1 .
    ?actor exID:recitaIn ?movie .
    {
        SELECT DISTINCT ?actorName2 ?movie2 
        WHERE {
            ?actor2 rdfs:label ?actorName2 .
            ?actor2 exID:recitaIn ?movie2 .
        }
    }
    FILTER (?movie = ?movie2 && ?actorName1 != ?actorName2)
} 

Now this works, but not really in the way I want, because it writes two times the same actors but in opposite order. To be more clear, this will have as output:

actorName1 actorName2
"Jack Nicholson" "Leonardo DiCaprio"
"Leonardo DiCaprio" "Jack Nicholson"

but I would like to have just one of this two rows because they represents conceptually the same thing. How can I accomplish this?

I will leave the significant part of the ontology here:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ontology [
  <!ENTITY xsd "http://www.w3.org/2001/XLMSchema#">
]>

<rdf:RDF    
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:owl ="http://www.w3.org/2002/07/owl#"
    xmlns:xsd ="http://www.w3.org/2001/XLMSchema#"

    xml:base="http://example.org/"
    xmlns:exID="http://example.org/#"
 >

    <!--    Ontology Properties -->
    <owl:Ontology rdf:about=""> 
    </owl:Ontology>

    <!--    Class declarations  -->
    <owl:Class rdf:about="#Regista">
        <rdfs:label xml:lang="it">Regista</rdfs:label>
        <rdfs:label xml:lang="en">Director</rdfs:label>
        <rdfs:comment xml:lang="it">Responsabile artistico e tecnico di un'opera</rdfs:comment>
        <rdfs:comment xml:lang="en">Artistic and technical manager of a creative work</rdfs:comment>
    </owl:Class>

    <owl:Class rdf:about="#Troupe">
        <rdfs:label xml:lang="it">Troupe</rdfs:label>
        <rdfs:label xml:lang="en">Troupe</rdfs:label>
        <rdfs:comment xml:lang="it">L'insieme delle figure professionali, tecniche, artistiche ed amministrative che realizzano un film</rdfs:comment>
        <rdfs:comment xml:lang="en">The group of professional, technical and artistics figures which realize a movie</rdfs:comment>
    </owl:Class>

    <owl:Class rdf:about="#Cast">
        <rdfs:subClassOf rdf:resource="#Troupe" />
        <rdfs:label xml:lang="it">Cast</rdfs:label>
        <rdfs:label xml:lang="en">Cast</rdfs:label>
        <rdfs:comment xml:lang="it">L'insieme degli attori che compaiono nel film</rdfs:comment>
        <rdfs:comment xml:lang="en">Ensemble of the actors who appear in the movie</rdfs:comment>
    </owl:Class>

    <owl:Class rdf:about="#Attore">
        <rdfs:subClassOf rdf:resource="#Cast" />
        <rdfs:label xml:lang="it">Attore</rdfs:label>
        <rdfs:label xml:lang="en">Actor</rdfs:label>
        <rdfs:comment xml:lang="it">Rappresenta un personaggio in un'opera creativa</rdfs:comment>
        <rdfs:comment xml:lang="en">Portrays a character in a creative work</rdfs:comment>
    </owl:Class>
    
    <owl:Class rdf:about="#Film">
        <rdfs:label xml:lang="it">Film</rdfs:label>
        <rdfs:label xml:lang="en">Movie</rdfs:label>
        <rdfs:comment xml:lang="it">Un lavoro di arte visuale utilizzato per simulare esperienze che comunica idee, storie, percezioni, sentimenti, bellezza o atmosfera tramite l'utilizzo di immagini in movimento.</rdfs:comment>
        <rdfs:comment xml:lang="en">A work of visual art used to simulate experiences that communicate ideas, stories, perceptions, feelings, beauty, or atmosphere through the use of moving images.</rdfs:comment>
    </owl:Class>
    
    <owl:Class rdf:about="#Pellicola">
        <rdfs:label xml:lang="it">Pellicola</rdfs:label>
        <rdfs:label xml:lang="en">Movie</rdfs:label>
        <owl:equivalentClass rdf:resource="#Film" />
    </owl:Class>

    <owl:Class rdf:about="#Attore_Comico">
        <rdfs:label xml:lang="it">Attore Comico</rdfs:label>
        <rdfs:label xml:lang="en">Comic Actor</rdfs:label>
        <rdfs:comment xml:lang="it">Un attore che prova a intrattenere il pubblico facendolo ridere</rdfs:comment>
        <rdfs:comment xml:lang="en">An actor who seeks to entertain an audience by making them laugh</rdfs:comment>
        <rdfs:subClassOf rdf:resource="#Attore" />
    </owl:Class>
    
    <owl:Class rdf:about="#Attore_Drammatico">
        <rdfs:label xml:lang="it">Attore Drammatico</rdfs:label>
        <rdfs:label xml:lang="en">Dramatic Actor</rdfs:label>
        <rdfs:comment xml:lang="it">Un attore specializzato in ruoli dal forte sviluppo psicologico ed emotivo</rdfs:comment>
        <rdfs:comment xml:lang="en">An actor specialized in roles with an huge psychological and emotional development</rdfs:comment>
        <rdfs:subClassOf rdf:resource="#Attore" />
    </owl:Class>


    <!--    Properties declarations -->
    <owl:ObjectProperty rdf:about="#dirige">
        <rdfs:domain rdf:resource="#Regista" />
        <rdfs:range rdf:resource="#Film" />
    </owl:ObjectProperty>
    
    <owl:ObjectProperty rdf:about="#compareIn">
        <rdfs:domain rdf:resource="#Attore" />
        <rdfs:range rdf:resource="#Film" />
    </owl:ObjectProperty>

    <owl:ObjectProperty rdf:about="#recitaIn">
        <rdfs:subPropertyOf rdf:resource="#compareIn" />
    </owl:ObjectProperty>


    <!--    Instances   -->    
    <rdf:Description rdf:about="theWolfOfWallStreet">
        <rdfs:label>The Wolf Of Wall Street</rdfs:label>
        <rdf:type rdf:resource="#Film"/>
    </rdf:Description>

    <rdf:Description rdf:about="theDeparted">
        <rdfs:label>The Departed</rdfs:label>
        <rdf:type rdf:resource="#Film"/>
    </rdf:Description>

    <rdf:Description rdf:about="gangsNY">
        <rdfs:label>Gangs of New York</rdfs:label>
        <rdf:type rdf:resource="#Film"/>
    </rdf:Description>

    <rdf:Description rdf:about="aviator">
        <rdfs:label>The Aviator</rdfs:label>
        <rdf:type rdf:resource="#Film"/>
    </rdf:Description>

    <rdf:Description rdf:about="killersFlowerMoon">
        <rdfs:label>Killers of the Flower Moon</rdfs:label>
        <rdf:type rdf:resource="#Film"/>
    </rdf:Description>

    <rdf:Description rdf:about="shutterIsland">
        <rdfs:label>Shutter Island</rdfs:label>
        <rdf:type rdf:resource="#Film"/>
    </rdf:Description>

    <rdf:Description rdf:about="diCaprio">
        <rdfs:label>Leonardo di Caprio</rdfs:label>
        <rdf:type rdf:resource="#Attore_Drammatico"/>
        <rdf:type rdf:resource="#Attore_Comico"/>
        <exID:recitaIn rdf:resource="theWolfOfWallStreet"/>
        <exID:recitaIn rdf:resource="theDeparted"/>
        <exID:recitaIn rdf:resource="gangsNY"/>
        <exID:recitaIn rdf:resource="aviator"/>
        <exID:recitaIn rdf:resource="shutterIsland"/>
        <exID:recitaIn rdf:resource="killersFlowerMoon"/>
    </rdf:Description>

    <rdf:Description rdf:about="nicholson">
        <rdfs:label>Jack Nicholson</rdfs:label>
        <rdf:type rdf:resource="#Attore_Drammatico"/>
        <rdf:type rdf:resource="#Attore_Comico"/>
        <exID:recitaIn rdf:resource="theDeparted"/>
    </rdf:Description>

    <rdf:Description rdf:about="scorsese">
        <rdfs:label>Martin Scorsese</rdfs:label>
        <rdf:type rdf:resource="#Regista"/>
        <exID:dirige rdf:resource="theWolfOfWallStreet"/>
        <exID:dirige rdf:resource="theDeparted"/>
        <exID:dirige rdf:resource="gangsNY"/>
        <exID:dirige rdf:resource="shutterIsland"/>
        <exID:dirige rdf:resource="aviator"/>
        <exID:dirige rdf:resource="killersFlowerMoon"/>
    </rdf:Description>
    
    <owl:AllDifferent>
        <owl:distinctMembers rdf:parseType="Collection">
            <exID:Attore rdf:about="diCaprio" />
            <exID:Attore rdf:about="nicholson" />
       </owl:distinctMembers>
    </owl:AllDifferent>
    
</rdf:RDF>

Solution

  • The correct answer for my problem was in the comment by UninformedUser:

    ?actor rdfs:label ?actorName1 .     
    ?actor exID:recitaIn ?movie .
    ?actor2 rdfs:label ?actorName2. 
    ?actor2 exID:recitaIn ?movie .
    

    Without any subquery at all. This will correctly display:

    actorName1 actorName2
    "Jack Nicholson" "Leonardo DiCaprio"

    as output, without any duplicates.