Blank node skolemization in SPARQL without iteration

441 Views Asked by At

Is it possible to implement blank node skolemization in SPARQL without iteration? It seems to me that iteration is required to skolemize chains of blank nodes, such as:

@prefix : <http://example.com/> .

[ a :A ;
  :p1 [
    a :B
  ]
] .

A SPARQL Update operation for skolemization can start from the blank nodes that appear as subjects only in triples without blank node objects:

DELETE {
  ?b1 ?outP ?outO .
  ?inS ?inP ?b1 .
}
INSERT {
  ?iri ?outP ?outO .
  ?inS ?inP ?iri .
}
WHERE {
  {
    SELECT ?b1 (uuid() AS ?iri)
    WHERE {
      {
        SELECT DISTINCT ?b1
        WHERE {
          ?b1 ?p1 [] .
          FILTER isBlank(?b1)
          FILTER NOT EXISTS {
            ?b1 ?p2 ?b2 .
            FILTER isBlank(?b2)
          }
        }
      }
    }
  }
  ?b1 ?outP ?outO .
  OPTIONAL {
    ?inS ?inP ?b1 .
  }
}

This operation can be repeated until no blank nodes are found in the data:

ASK {
  ?bnode ?p [] .
  FILTER isBlank(?bnode)
}

Is it possible to avoid the iteration and implement the blank node skolemization in a single SPARQL Update operation?

(Also, this approach assumes there are no "orphan" blank nodes (i.e. blank nodes that appear only as objects).)

1

There are 1 best solutions below

0
On

I found a two-step solution skolemising subjects and objects separately and storing the blank node aliases (links between blank nodes and IRIs via owl:sameAs) as intermediate data:

PREFIX :    <http://example.com/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

####################
# Rewrite subjects #
####################

DELETE {
  ?bnode ?p ?o .
}
INSERT {
  ?iri ?p ?o .
  GRAPH :aliases {
    ?bnode owl:sameAs ?iri .
  }
}
WHERE {
  {
    SELECT ?bnode (uuid() AS ?iri)
    WHERE {
      {
        SELECT DISTINCT ?bnode
        WHERE {
          ?bnode ?p [] .
          FILTER isBlank(?bnode)
        }
      }
    }
  }
  ?bnode ?p ?o .
}
;

###################
# Rewrite objects #
###################

DELETE {
  ?s ?p ?bnode .
}
INSERT {
  ?s ?p ?iri .
}
WHERE {
  {
    SELECT ?bnode ?iri
    WHERE {
      {
        SELECT DISTINCT ?bnode
        WHERE {
          [] ?p ?bnode .
          FILTER isBlank(?bnode)
        }
      }
      OPTIONAL {
        GRAPH :aliases {
          ?bnode owl:sameAs ?_iri .
        }
      }
      BIND (coalesce(?_iri, uuid()) AS ?iri)
    }
  }
  ?s ?p ?bnode .
}
;

############################
# Clear blank node aliases #
############################

CLEAR GRAPH :aliases