neosemantics icon indicating copy to clipboard operation
neosemantics copied to clipboard

Force an RDF datatype property to be represented as edges

Open sbailin opened this issue 4 years ago • 2 comments

I have an ontology (OWL/RDF) in which certain datatype statements are assigned a confidence level, using RDF* (in particular TTL*). For example:

<<DocumentX hasKeyword "interesting">> hasConfidenceLevel 0.43

(I'm eliding namespace prefixes for simplicity).

Unfortunately the embedded triple has a literal ("interesting") as its object, which means that n10s imports it as node Document with property hasKeyword="interesting". And it does not seem to do anything with the containing triple.

So my question is whether there is a way to force hasKeyword to be represented as an edge rather than as a neo4j property. This would be something similar to the existing ability to force rdf:type to be represented as an edge rather than a (neo4j) property.

I know I can tweak the RDF in an ugly way to force this, such that hasKeyword becomes an object property with value a URI rather than a literal, but that seems undesirable.

sbailin avatar Sep 09 '21 01:09 sbailin

There is not a way of configuring the n10s.rdf.import.* methods to convert literals into relationships but you can do it manually by using n10s.rdf.stream.* + n10s.rdf.create.*

Let's say you have this Turtle-star fragment:

@prefix neo4voc: <http://neo4j.org/vocab/sw#> .
@prefix neo4ind: <http://neo4j.org/ind#> .

neo4ind:nsmntx3502 neo4voc:name "n10s" ;
         a neo4voc:Neo4jPlugin ;
         neo4voc:version "3.5.0.2" ;
         neo4voc:releaseDate "03-06-2019" .

<<neo4ind:nsmntx3502 neo4voc:releaseDate "03-06-2019">> neo4voc:hasConfidenceLevel "0.43" .

You import it first using:

call  n10s.rdf.import.inline(<...theRDF above...>, "Turtle-star");

This first pass stores literal properties as node attributes and the metadata neo4voc:hasConfidenceLevel is lost . Now we do a second pass on the same data

call  n10s.rdf.stream.inline(<... the RDF above... >, "Turtle-star") 
yield subject, predicate, object, isLiteral, literalType, literalLang, subjectSPO
where subjectSPO is not null and subjectSPO[1] = "http://neo4j.org/vocab/sw#releaseDate"
call n10s.add.relationship.uris(subjectSPO[0], 
                                subjectSPO[1], [{ key: predicate, val: object }], 
                                "http://neo4j.org/ind#" + apoc.text.urlencode(subjectSPO[2])) yield rel
return rel

This selects metadata on a given predicate (releaseDate in this case, but you could change that to apply to all for example), and creates a node out of the literal value (urlencode for valid uri generation: "http://neo4j.org/ind#" + apoc.text.urlencode(subjectSPO[2])) and then stores the property as a relationship to the newly created node using the n10s.add.relationship.uris method and you can put the metadata on the rel at the same time ([{ key: predicate, val: object }]).

The result is that you have the value stored both as an attribute and as a rel with the metadata. If you want to avoid having it stored twice, you can selectively skip it in the n10s.rdf.import. method using predicate exclusion (adding predicateExclusionList : [ "http://neo4j.org/vocab/sw#releaseDate"] to the params). See manual.

image

Hope this helps.

JB

jbarrasa avatar Mar 20 '22 12:03 jbarrasa

Cross-posted to the Neo4j community site for comments. A topic of general interest.

jbarrasa avatar Mar 20 '22 12:03 jbarrasa