Search code examples
prologrdfsparqlallegrograph

can I do this in AllegroGraph prolog?


I have an RDF file and I need to extract some information from it in a single line.

Now, I'm using AllegroGraph with Prolog query engin :

(select (?result)
      (q ?a !rdfs:label ?alabel)
      (q ?b !rdfs:label ?blabel)
      (lisp ?result (string+ ?alabel " AND " ?blabel))) 

to get the results in a single line:

 "{a1} AND {b1}" 
 "{a1} AND {b2}" 
 "{a2} AND {b1}" 
 "{a2} AND {b2}" 

Now, I need to group all the rows of ?result in a single line with the string "OR". so i get:

 "{a1} AND {b1} OR {a1} AND {b2} OR {a2} AND {b1} OR {a2} AND {b2}" 

Is there any function in prolog to do this?


Solution

  • The fact that you've only got a* on the left and b* on the right means that you've got some other selection condition than just having a label. Given data like this:

    @prefix : <http://example.org/>.
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
    
    :a1 a :ClassA ; rdfs:label "a1" .
    :a2 a :ClassA ; rdfs:label "a2" .
    :b1 a :ClassB ; rdfs:label "b1" .
    :b2 a :ClassB ; rdfs:label "b2" .
    

    you can select ?a and ?b by their classes (:ClassA and :ClassB), and then extract their labels as well, with a pattern like:

    ?a a :ClassA ; rdfs:label ?alabel .
    ?b a :ClassB ; rdfs:label ?blabel .
    

    Then you can get the {alabel} AND {blabel} with a bind and a concat:

    bind( concat( "{", ?alabel, "} AND {", ?blabel, "}" ) as ?AandB )
    

    Using these, a query like

    prefix : <http://example.org/>
    prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    
    select ?AandB { 
     ?a a :ClassA ; rdfs:label ?alabel .
     ?b a :ClassB ; rdfs:label ?blabel .
     bind( concat( "{", ?alabel, "} AND {", ?blabel, "}" ) as ?AandB )
    }
    

    will get you the kind of results that you can already get:

    -------------------
    | AandB           |
    ===================
    | "{a2} AND {b2}" |
    | "{a2} AND {b1}" |
    | "{a1} AND {b2}" |
    | "{a1} AND {b1}" |
    -------------------
    

    The trick now is to use group_concat and an implicit group to combine all these into a string, with a separator of " OR ":

    prefix : <http://example.org/>
    prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    
    select ( group_concat( ?AandB ; separator=" OR ") as ?string ) where { 
     ?a a :ClassA ; rdfs:label ?alabel .
     ?b a :ClassB ; rdfs:label ?blabel .
     bind( concat( "{", ?alabel, "} AND {", ?blabel, "}" ) as ?AandB )
    }
    

    to get a result:

    ----------------------------------------------------------------------
    | string                                                             |
    ======================================================================
    | "{a2} AND {b2} OR {a2} AND {b1} OR {a1} AND {b2} OR {a1} AND {b1}" |
    ----------------------------------------------------------------------
    

    If you like, you can even get rid of the bind, and just put the concat expression right into the group_concat. You might find that easier to read (less jumping around) or harder to read (big one-liner), but at least it's good to have options:

    prefix : <http://example.org/>
    prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    
    select ( group_concat( concat( "{",?alabel,"} AND {",?blabel,"}" ) ; separator=" OR ") as ?string ) where { 
     ?a a :ClassA ; rdfs:label ?alabel .
     ?b a :ClassB ; rdfs:label ?blabel .
    }
    

    There are some other examples of group_concat floating around on StackOverflow that might be useful to you as well: