Limitation on domain and range on Virtual Graph


We have created a prototype with several hierarchies linked by subclassOf and it is working fine. This was possible because we removed domain in the DatatypeProperty (attributes) of each hierarchy and the range in the ObjectProperty (relationships). We used directly RDF file to do it.

We want to make an step forward using Virtual Graphs and we are wondering if we can apply this limitation when mapping. Another less friendly option should be that mapping can´t apply limitation but generate a RDF file that we can edit later to apply the changes

Please, let me now how can I do it, because I could'nt find documentation in both cases

Thank you and regards

Hi Ramon,

Can you expand on what you are trying to accomplish?

We highly recommend using Designer when building a model and adding mappings to Stardog. Designer provides a UI to define attributes and relationships, as well as project resources. Project resources are defined from your data source connections to your Stardog connection. When publishing, the project resources in Designer will be written to your Stardog connection as virtual graphs.

Below is a link to a recent Stardog Demo Day where I recently presented some of the latest Designer features. The video includes an example of how to map relationships in Designer.

Hi Laura

Designer is good for mapping files but our source data is in a database and we are using Virtual Graphs. In additional, the issue we are having is that we have all levels of hierarchy in the same data table with Id and parentId codes and instead of define one class with all instances (that it's very easy with SMS2), we would like to define a class for each iteration belowing to subclassOf (parent level)

Example using RDF:

SMS2 Option:

Hierarchy:Location a owl:Class ;
rdfs:label "Location" .

Hierarchy:1 a Hierarchy:Location ;
rdfs:label "Europe" ;
ParentId:ParenId 0 .

Hierarchy:2 a Hierarchy:Location ;
rdfs:label "Germany" ;
ParentId:ParenId 1 .

Hierarchy:3 a Hierarchy:Location ;
rdfs:label "France" ;
ParentId:ParenId 1 .

Hierarchy:4 a Hierarchy:Location ;
rdfs:label "Paris" ;
ParentId:ParenId 3 .

Option we need:

Hierarchy:Location a owl:Class ;
rdfs:label "Location" .

Hierarchy:Europe a owl:Class ;
rdfs:label "Europe" ;
rdfs:subClassOf Hierarchy:Location .

Hierarchy:Germany a owl:Class ;
rdfs:label "Germany" ;
rdfs:subClassOf Hierarchy:Europe .

Hierarchy:France a owl:Class ;
rdfs:label "France" ;
rdfs:subClassOf Hierarchy:Europe .

Hierarchy:Paris a owl:Class ;
rdfs:label "Paris" ;
rdfs:subClassOf Hierarchy:France .

Hi Ramon,

Designer was purpose-built to help users create virtual graphs for Stardog. Once a data source is defined for a Stardog connection, Designer may be used to define virtual graphs (SMS2 and virtual graph properties). Here's a link to our docs about setting virtual graph properties in Designer, Stardog Designer | Stardog Documentation Latest.

Your data sounds like a great use case for relationships and rules versus subclassOf. From the example provided, I would recommend modeling your data as below:

Below is also a zip of the designer project as an example which can be imported directly as new project, docs link. While the project uses a CSV to source the location data, the project resource could instead be a relational database table that you wanted to make a virtual graph.

As a next step, you could add rules so that locations can also be transitively created (ie locationA locatedIn locationB and locationB locatedIn locationC, then locationA locatedIn locationC).

Hope this helps!
Laura (4.9 KB)

Thank you for the quick response Laura. I´ll take a look and I´ll keep you posted

Hi Laura

After analyzing the solution, your proposal is so good so far...I created a relationship below:

tag:stardog:designer:locations_example:model:locatedIn a owl:ObjectProperty ;
rdfs:domain tag:stardog:designer:locations_example:model:locations ;
rdfs:label "locatedIn" ;
rdfs:range tag:stardog:designer:locations_example:model:locations .

I also created the triples to link the locations ID with parent locations ID, example:
tag:stardog:1:designer:locations_example:data:locations a tag:stardog:designer:locations_example:model:locations ;
rdfs:label "Europe" ;
tag:stardog:designer:locations_example:model:**locatedIn** tag:stardog:5:designer:locations_example:data:locations .

and for more usability I created an additional rule:

locations_example:childOf owl:inverseOf tag:stardog:designer:locations_example:model:locatedIn .

This approach is usefull for me using property paths with recursive search:

select * { ?x locations_example:childOf+ ?y . }

...but I´m using Virtual Graph (cloud version) and I could't find in the documentation how to define Object Properties. I tried different approach without sucess:

  1. I tried to create the simple triple: a owl:ObjectProperty .

error message: All triple patterns are expected to have variable subject or embedded triple

  1. I defined a BIND variable using template:

?locatedIn a owl:ObjectProperty .
BIND(template("") AS ?locatedIn)

error message: Template must reference one or more variables:

  1. parsing a string (without template)

BIND("" AS ?locatedIn)

error message: Unsupported expression in BIND() for variable ?locatedIn. Found ConstantImpl()

  1. Not use of ObjectProperty, just DataProperty

?location is mapping all locations from Database with location id, location name and location Parent id

?location locations_example:locatedIn ?locparentId.

It is working but it is not a relationship, it is a Dataproperty so:

  • Not possible to use property paths with recursive search
  • Not possible to define rule inverseOf
  1. I tried example in documentation:

<<?location a locations_example:Location >> locations_example:locatedIn ?parentId.

it is working when saving SMS2 but it has 2 inconvenients:

  • Instances are not matching locations_example instances


    << locations_example:Location:1 rdf:type locations_example:Location >>
    << locations_example:Location:2 rdf:type locations_example:Location >>

  • Error when using property path
    select * { ?a locations_example:locatedIn ?b ; } --> OK
    select * { ?a locations_example:locatedIn+ ?b ; } --> KO

error message: Failed to run query: com.complexible.stardog.plan.eval.operator.OperatorException: Uncaught error during query evaluation: InvalidTermReplacement: Cannot transform a service node: SERVICE virtual://hierarchy_VG in= out= {
VirtualGraphMongoDBvirtual://hierarchy_VG [#8] {
LogicalFilter(condition=[AND(IS NOT NULL($0), IS NOT NULL($1))])
UnwoundRel(coll=[organization], key=[[$_id]], projection=[orgid=$LocId, locparentid=$LocParentId])
{ $match : {$and : [ {"LocId" : {$exists : true, $ne : null}}, {"LocParentId" : {$exists : true, $ne : null}} ]} }
?a <- <<TEMPLATE({orgid/0}) CONSTANT( CONSTANT(>>
?b <- TEMPLATE({locparentid/1})

could you please provide additional guideance?
Thanks in advance and warm regards

Hi Ramon,

I may be answering the wrong question but the VG mappings are for creating your explicit triples only. Your schema and rules will continue to remain in the local Stardog database. Whatever axioms/rules you define there will be applied to both local and virtual queries.


ummm, got it!!!

The idea is not doing extra work because data is already mapped in VG. Relationship between location and parent location is already identified in source database, so it is not only to define an edge (ObjectProperty) in text editor it is just to avoid create thousend of triples in text editor.

I already used the local definition of the ObjectProperty that it's working fine and it's creating the relationships, but still something wrong:

    hierarchy:locatedIn a owl:ObjectProperty ;
        rdfs:domain hierarchy:Organization ;
        rdfs:label "locatedIn" ;
        rdfs:range hierarchy:Organization .

@Paul, is it possible to use RECURSIVE PATHS with Virtual Graphs?

I´m getting the message below when running this query: SELECT * { ?a (hierarchy:locatedIn)+ ?b }

Failed to run query: com.complexible.stardog.plan.eval.operator.OperatorException: Uncaught error during query evaluation: InvalidTermReplacement: Cannot transform a service node: SERVICE virtual://VG_ORG in= out= {
VirtualGraphMongoDBvirtual://VG_ORG [#8] {
LogicalProject(orgid=[$0], orgparentid=[$1])
LogicalFilter(condition=[AND(IS NOT NULL($0), IS NOT NULL($1))])
UnwoundRel(coll=[organization], key=[[$_id]], projection=[orgid=$OrgId, orgparentid=$OrgParentId, orgparentname=$OrgParentName, orgname=$OrgName])
{ $match : {$and : [ {"OrgId" : {$exists : true, $ne : null}}, {"OrgParentId" : {$exists : true, $ne : null}} ]} },
{$project: {orgid: '$OrgId', orgparentid: '$OrgParentId'} }
?a <- TEMPLATE({orgid/0}))
?b <- TEMPLATE({orgparentid/1}))}}

Thank you

Unfortunately we currently only support recursive property paths for those SQL databases that support common table expressions (CTE). For the remaining backing databases we'll need to evaluate those paths locally (sending separate queries to MongoDB for each "hop"), which is an enhancement request on our backlog.

Depending on how you're running Stardog, you could cache this VG and then the recursive paths would work as the cache is effectively a Stardog database. If this isn't supported with your license, your best bet is to materialize the portion of the VG that you wish to query with recursive property paths.

Is there an available roster of databases that support CTE in the documentation?

Thank you for the clarification and quick answer


That's a good question. I think it's not documented because the intent is for it to work everywhere but if we don't plan to do this soon I agree we should document it.

ATM, supported platforms are MS SQL Server, MySQL/MariaDB, Oracle, Postgres, Snowflake and Teradata.

Totally agree regarding documentation

I think, despite there is not roster, maybe should be good to include a comment somewhere (recursive paths and/or virtual graph) warning about this behaviour

I close the ticket

Thank you again, Paul