neosemantics
neosemantics copied to clipboard
Force an RDF datatype property to be represented as edges
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.
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.
Hope this helps.
JB
Cross-posted to the Neo4j community site for comments. A topic of general interest.