Question

I am using dotnetrdf to send a Sparql CONSTRUCT query and evaluate the resulting IGraph.

For a start, I am trying to find all Uri nodes that represent individuals of a given type, say,

http://www.example.com/InterestingThing

So, I would like to use the GetTriplesWithPredicateObject method, passing http://www.w3.org/1999/02/22-rdf-syntax-ns#type as a predicate and http://www.example.com/InterestingThing as an object. That method expects two objects implementing the INode interface, so I am trying to find the respective nodes with the graph's GetUriNode method.

Problem: The predicate is not found.

When looking at the IGraph object in the debugger, it seems that GetUriNode can find only what is contained in the Nodes enumeration of the graph - and that contains only Uri nodes that have been used as subjects or objects, but none that are used as predicates.

Now, the predicate Uri nodes are evidently there - I can see them when exploring the Triples object of the graph. They appear in the Triple instances that can be retrieved directly from that object, and they can also be found in the PredicateNodes property of the same object.

Interestingly, some querying methods of IGraph such as GetTriplesWithObject or GetTriplesWithPredicate do have overloads that accept a mere Uri instead of an INode - but GetTriplesWithPredicateObject does not.

Now, various possible workarounds are obvious:

  • Use the overload of GetTriplesWithPredicate that takes only a Uri instance, then filter the resulting triples manually.
  • Manually search through all triples to get the desired triples.
  • Manually search through the list of PredicateNodes and find the ones with the searched for Uris.

All of these seem unnecessarily cumbersome, though - as the existing methods suggest at first glance that one should simply be able to use GetUriNode to retrieve two nodes and then pass those to one of the ready-made querying methods such as GetTriplesWithObjectPredicate.

Therefore, my question is:

Am I missing anything, either in the dotnetrdf library or conceptually, in RDF, or is this behavior with the obstacles it poses to developers by design?

Here is a C# test case to reproduce the problem (querying DBpedia):

using System;
using System.Collections.Generic;
using System.Linq;

using VDS.RDF;
using VDS.RDF.Query;

namespace Test
{
    class Program
    {
        public static void Main(string[] args)
        {
            // Querying
            // All entries to analyze are declared to belong to a temporary type, and
            // two properties are mapped to temporary property identifiers.

            Console.WriteLine();

            var endpoint = new SparqlRemoteEndpoint(new Uri("http://dbpedia.org/sparql"));

            string query = "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>\n"
                + "PREFIX ex: <http://www.example.com/>\n"
                + "\n"
                + "CONSTRUCT {\n"
                + "  ?r a ex:record.\n"
                + "  ?r ex:prop1 ?v1.\n"
                + "  ?r ex:prop2 ?v2.\n"
                + "}\n"
                + "WHERE {\n"
                + "  {\n"
                + "    SELECT ?r\n"
                + "    WHERE {\n"
                + "      ?r a dbpedia-owl:Work.\n"
                + "      FILTER(EXISTS { ?r dbpedia-owl:originalLanguage [] } && EXISTS { ?r dbpedia-owl:author/dbpedia-owl:birthPlace [] }).\n"
                + "    } LIMIT 5\n"
                + "  }\n"
                + "  ?r dbpedia-owl:originalLanguage ?v1.\n"
                + "  ?r dbpedia-owl:author/dbpedia-owl:birthPlace ?v2.\n"
                + "}";

            Console.WriteLine(query);
            Console.WriteLine();

            IGraph graph = endpoint.QueryWithResultGraph(query);

            PrintNodes("IGraph.Nodes", graph.Nodes);

            Console.WriteLine("All triples from IGraph.Triples:");
            foreach (var triple in graph.Triples) {
                Console.WriteLine("- S: " + NodeToString(triple.Subject));
                Console.WriteLine("  P: " + NodeToString(triple.Predicate));
                Console.WriteLine("  O: " + NodeToString(triple.Object));
            }
            Console.WriteLine();

            PrintNodes("IGraph.Triples.SubjectNodes", graph.Triples.SubjectNodes);
            PrintNodes("IGraph.Triples.PredicateNodes", graph.Triples.PredicateNodes);
            PrintNodes("IGraph.Triples.ObjectNodes", graph.Triples.ObjectNodes);

            // Graph Analysis
            // The following code tries to retrieve exactly the items of the temporary
            // type "record".

            var typeNode = TryFindUriNode(graph, new Uri(NamespaceMapper.RDF + "type"));
            var recordNode = TryFindUriNode(graph, new Uri("http://www.example.com/record"));

            Console.WriteLine();
            TryFindAllNodes("subjects", graph, graph.Triples.SubjectNodes.OfType<IUriNode>().Select(node => node.Uri));
            TryFindAllNodes("predicates", graph, graph.Triples.PredicateNodes.OfType<IUriNode>().Select(node => node.Uri));
            TryFindAllNodes("objects", graph, graph.Triples.ObjectNodes.OfType<IUriNode>().Select(node => node.Uri));
            Console.WriteLine();

            var createdTypeNode = graph.CreateUriNode(new Uri(NamespaceMapper.RDF + "type"));
            var createdRecordNode = graph.CreateUriNode(new Uri("http://www.example.com/record"));

            if ((typeNode != null) && (recordNode != null)) {
                Console.WriteLine("{0} triple(s) with found predicate and found object.",
                                  graph.GetTriplesWithPredicateObject(typeNode, recordNode).Count());
            }
            if (typeNode != null) {
                Console.WriteLine("{0} triple(s) with found predicate and created object.",
                                  graph.GetTriplesWithPredicateObject(typeNode, createdRecordNode).Count());
            }
            if (recordNode != null) {
                Console.WriteLine("{0} triple(s) with created predicate and found object.",
                                  graph.GetTriplesWithPredicateObject(createdTypeNode, recordNode).Count());
            }
            Console.WriteLine("{0} triple(s) with created predicate and created object.",
                              graph.GetTriplesWithPredicateObject(createdTypeNode, createdRecordNode).Count());
        }

        private static string NodeToString(INode node)
        {
            return string.Format("{0} ({1})", node, node.GetType().Name);
        }

        private static void PrintNodes(string title, IEnumerable<INode> nodes)
        {
            Console.WriteLine(title + ":");
            foreach (var node in nodes) {
                Console.WriteLine("- " + NodeToString(node));
            }
            Console.WriteLine();
        }

        private static INode TryFindUriNode(IGraph graph, Uri uri)
        {
            var result = graph.GetUriNode(uri);
            if (result == null) {
                Console.WriteLine(uri.ToString() + " was NOT found by IGraph.GetUriNode.");
            } else {
                Console.WriteLine(uri.ToString() + " WAS found by IGraph.GetUriNode.");
            }
            return result;
        }

        private static void TryFindAllNodes(string title, IGraph graph, IEnumerable<Uri> uris)
        {
            Console.WriteLine("Trying to find all " + title + ":");
            foreach (Uri uri in uris) {
                TryFindUriNode(graph, uri);
            }
        }
    }
}

This is the output of the sample program:

PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>
PREFIX ex: <http://www.example.com/>

CONSTRUCT {
  ?r a ex:record.
  ?r ex:prop1 ?v1.
  ?r ex:prop2 ?v2.
}
WHERE {
  {
    SELECT ?r
    WHERE {
      ?r a dbpedia-owl:Work.
      FILTER(EXISTS { ?r dbpedia-owl:originalLanguage [] } && EXISTS { ?r dbpedia-owl:author/dbpedia-owl:birthPlace [] }).
    } LIMIT 5
  }
  ?r dbpedia-owl:originalLanguage ?v1.
  ?r dbpedia-owl:author/dbpedia-owl:birthPlace ?v2.
}

IGraph.Nodes:
- http://dbpedia.org/resource/Electra_(Sophocles) (UriNode)
- http://dbpedia.org/resource/Peer_Gynt (UriNode)
- http://dbpedia.org/resource/Pictures_from_the_Insects'_Life (UriNode)
- http://dbpedia.org/resource/The_Field (UriNode)
- http://dbpedia.org/resource/The_Lady_from_the_Sea (UriNode)
- http://www.example.com/record (UriNode)
- http://dbpedia.org/resource/Ancient_Greek (UriNode)
- http://dbpedia.org/resource/Colonus (UriNode)
- http://dbpedia.org/resource/Norwegian_language (UriNode)
- http://dbpedia.org/resource/Skien (UriNode)
- http://dbpedia.org/resource/Norway (UriNode)
- http://dbpedia.org/resource/Czech_language (UriNode)
- http://dbpedia.org/resource/Kingdom_of_Bohemia (UriNode)
- http://dbpedia.org/resource/Bohemia (UriNode)
- http://dbpedia.org/resource/Mal%C3%A9_Svato%C5%88ovice (UriNode)
- http://dbpedia.org/resource/Austria-Hungary (UriNode)
- http://dbpedia.org/resource/English_language (UriNode)
- http://dbpedia.org/resource/Irish_Free_State (UriNode)
- http://dbpedia.org/resource/Listowel (UriNode)
- http://dbpedia.org/resource/County_Kerry (UriNode)

All triples from IGraph.Triples:
- S: http://dbpedia.org/resource/Electra_(Sophocles) (UriNode)
  P: http://www.w3.org/1999/02/22-rdf-syntax-ns#type (UriNode)
  O: http://www.example.com/record (UriNode)
- S: http://dbpedia.org/resource/Electra_(Sophocles) (UriNode)
  P: http://www.example.com/prop1 (UriNode)
  O: http://dbpedia.org/resource/Ancient_Greek (UriNode)
- S: http://dbpedia.org/resource/Electra_(Sophocles) (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Colonus (UriNode)
- S: http://dbpedia.org/resource/Peer_Gynt (UriNode)
  P: http://www.w3.org/1999/02/22-rdf-syntax-ns#type (UriNode)
  O: http://www.example.com/record (UriNode)
- S: http://dbpedia.org/resource/Peer_Gynt (UriNode)
  P: http://www.example.com/prop1 (UriNode)
  O: http://dbpedia.org/resource/Norwegian_language (UriNode)
- S: http://dbpedia.org/resource/Peer_Gynt (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Skien (UriNode)
- S: http://dbpedia.org/resource/Peer_Gynt (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Norway (UriNode)
- S: http://dbpedia.org/resource/Pictures_from_the_Insects'_Life (UriNode)
  P: http://www.w3.org/1999/02/22-rdf-syntax-ns#type (UriNode)
  O: http://www.example.com/record (UriNode)
- S: http://dbpedia.org/resource/Pictures_from_the_Insects'_Life (UriNode)
  P: http://www.example.com/prop1 (UriNode)
  O: http://dbpedia.org/resource/Czech_language (UriNode)
- S: http://dbpedia.org/resource/Pictures_from_the_Insects'_Life (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Kingdom_of_Bohemia (UriNode)
- S: http://dbpedia.org/resource/Pictures_from_the_Insects'_Life (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Bohemia (UriNode)
- S: http://dbpedia.org/resource/Pictures_from_the_Insects'_Life (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Mal%C3%A9_Svato%C5%88ovice (UriNode)
- S: http://dbpedia.org/resource/Pictures_from_the_Insects'_Life (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Austria-Hungary (UriNode)
- S: http://dbpedia.org/resource/The_Field (UriNode)
  P: http://www.w3.org/1999/02/22-rdf-syntax-ns#type (UriNode)
  O: http://www.example.com/record (UriNode)
- S: http://dbpedia.org/resource/The_Field (UriNode)
  P: http://www.example.com/prop1 (UriNode)
  O: http://dbpedia.org/resource/English_language (UriNode)
- S: http://dbpedia.org/resource/The_Field (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Irish_Free_State (UriNode)
- S: http://dbpedia.org/resource/The_Field (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Listowel (UriNode)
- S: http://dbpedia.org/resource/The_Field (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/County_Kerry (UriNode)
- S: http://dbpedia.org/resource/The_Lady_from_the_Sea (UriNode)
  P: http://www.w3.org/1999/02/22-rdf-syntax-ns#type (UriNode)
  O: http://www.example.com/record (UriNode)
- S: http://dbpedia.org/resource/The_Lady_from_the_Sea (UriNode)
  P: http://www.example.com/prop1 (UriNode)
  O: http://dbpedia.org/resource/Norwegian_language (UriNode)
- S: http://dbpedia.org/resource/The_Lady_from_the_Sea (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Skien (UriNode)
- S: http://dbpedia.org/resource/The_Lady_from_the_Sea (UriNode)
  P: http://www.example.com/prop2 (UriNode)
  O: http://dbpedia.org/resource/Norway (UriNode)

IGraph.Triples.SubjectNodes:
- http://dbpedia.org/resource/Electra_(Sophocles) (UriNode)
- http://dbpedia.org/resource/Peer_Gynt (UriNode)
- http://dbpedia.org/resource/Pictures_from_the_Insects'_Life (UriNode)
- http://dbpedia.org/resource/The_Field (UriNode)
- http://dbpedia.org/resource/The_Lady_from_the_Sea (UriNode)

IGraph.Triples.PredicateNodes:
- http://www.w3.org/1999/02/22-rdf-syntax-ns#type (UriNode)
- http://www.example.com/prop1 (UriNode)
- http://www.example.com/prop2 (UriNode)

IGraph.Triples.ObjectNodes:
- http://www.example.com/record (UriNode)
- http://dbpedia.org/resource/Ancient_Greek (UriNode)
- http://dbpedia.org/resource/Colonus (UriNode)
- http://dbpedia.org/resource/Norwegian_language (UriNode)
- http://dbpedia.org/resource/Skien (UriNode)
- http://dbpedia.org/resource/Norway (UriNode)
- http://dbpedia.org/resource/Czech_language (UriNode)
- http://dbpedia.org/resource/Kingdom_of_Bohemia (UriNode)
- http://dbpedia.org/resource/Bohemia (UriNode)
- http://dbpedia.org/resource/Mal%C3%A9_Svato%C5%88ovice (UriNode)
- http://dbpedia.org/resource/Austria-Hungary (UriNode)
- http://dbpedia.org/resource/English_language (UriNode)
- http://dbpedia.org/resource/Irish_Free_State (UriNode)
- http://dbpedia.org/resource/Listowel (UriNode)
- http://dbpedia.org/resource/County_Kerry (UriNode)

Trying to find all subjects:
http://dbpedia.org/resource/Electra_(Sophocles) WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Peer_Gynt WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Pictures_from_the_Insects'_Life WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/The_Field WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/The_Lady_from_the_Sea WAS found by IGraph.GetUriNode.
Trying to find all predicates:
http://www.w3.org/1999/02/22-rdf-syntax-ns#type was NOT found by IGraph.GetUriNode.
http://www.example.com/prop1 was NOT found by IGraph.GetUriNode.
http://www.example.com/prop2 was NOT found by IGraph.GetUriNode.
Trying to find all objects:
http://www.example.com/record WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Ancient_Greek WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Colonus WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Norwegian_language WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Skien WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Norway WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Czech_language WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Kingdom_of_Bohemia WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Bohemia WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Mal‚_Svatonovice WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Austria-Hungary WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/English_language WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Irish_Free_State WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/Listowel WAS found by IGraph.GetUriNode.
http://dbpedia.org/resource/County_Kerry WAS found by IGraph.GetUriNode.

http://www.w3.org/1999/02/22-rdf-syntax-ns#type was NOT found by IGraph.GetUriNode.
http://www.example.com/record WAS found by IGraph.GetUriNode.
5 triple(s) with created predicate and found object.
5 triple(s) with created predicate and created object.

As can be seen, the IGraph.Nodes enumeration does not include the predicate Uris such as http://www.example.com/prop1 or http://www.w3.org/1999/02/22-rdf-syntax-ns#type. Likewise, the output shows that predicates are not found by GetUriNode, while subjects and objects are.

Was it helpful?

Solution

You can use CreateURINode from INodeFactory (which IGraph extends) to create the rdf:type node, and have something like:

graph.GetTriplesWithPredicateObject(
  graph.CreateUriNode( UriFactory.createUri( "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" )), ,
  graph.CreateUriNode( UriFactory.createUri( "http://www.example.com/InterestingThing" ))
)

This is similar to the approach I'd take in Jena, where I'd use something like ResourceFactory.createProperty( http://...ns#type ). (Actually, Jena has a constant RDF.type for convenience that I'd use, but this is the approach I'd use for one that wasn't defined as a constant ahead of time.)

OTHER TIPS

This behaviour is entirely by design, something that appears only in the predicate position is considered an edge in the graph rather than a node in the graph.

As the Working with Graphs documentation states the following:

To select Nodes there are methods which can be used to find a Node from a Graph (if it exists) which are the GetXNode() methods where X is the type of the node to be retrieved. Note that this method only returns a value if the given value exists as a node in the Graph i.e. it occurs in the Subject/Object position of a triple in this graph.

Note: If you just want to get a Node instance for other usages regardless of whether it already exists in the Graph you should use the CreateXNode() methods instead.

Maybe a GetEdge() and corresponding Edges property would be useful?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top