Datatype properties represented as edges? (cross post from GitHub)

I copied this from a GitHub issue because I thought it could be useful for others.

The question was: "is there a way to force a literal property to be represented as an edge rather than as a neo4j node property so we can associate metadata to it. This would be something similar to the existing ability to force rdf:type to be represented as an edge rather than a (neo4j) property."

And the answer:

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