Извлечение определенных троек RDF-графа на основе предикатных узлов

Я использую dotnetrdf для отправки Sparql CONSTRUCT запросить и оценить полученный результат IGraph,

Для начала я пытаюсь найти все узлы Uri, которые представляют людей определенного типа, скажем,

http://www.example.com/InterestingThing

Итак, я хотел бы использовать GetTriplesWithPredicateObject метод, прохождение http://www.w3.org/1999/02/22-rdf-syntax-ns#type в качестве предиката и http://www.example.com/InterestingThing как объект. Этот метод ожидает двух объектов, реализующих INode интерфейс, поэтому я пытаюсь найти соответствующие узлы с графиком GetUriNode метод.

Проблема: предикат не найден.

При взгляде на IGraph объект в отладчике, кажется, что GetUriNode можно найти только то, что содержится в Nodes перечисление графа - и которое содержит только узлы Uri, которые использовались в качестве субъектов или объектов, но ни один из них не использовался в качестве предикатов.

Теперь предикатные узлы Uri, очевидно, находятся там - я вижу их при изучении Triples объект графа. Они появляются в Triple экземпляры, которые можно получить непосредственно из этого объекта, и их также можно найти в PredicateNodes свойство того же объекта.

Интересно, что некоторые методы запросов IGraph такие как GetTriplesWithObject или же GetTriplesWithPredicate действительно есть перегрузки, которые принимают простое Uri вместо INode - но GetTriplesWithPredicateObject не.

Теперь различные возможные обходные пути очевидны:

  • Используйте перегрузку GetTriplesWithPredicate это займет всего Uri экземпляра, а затем отфильтруйте полученные тройки вручную.
  • Вручную найдите все тройки, чтобы получить нужные тройки.
  • Ручной поиск по списку PredicateNodes и найти тех, кто искал Урис.

Все это кажется излишне громоздким, хотя - как существующие методы предполагают на первый взгляд, что нужно просто уметь использовать GetUriNode получить два узла и затем передать их одному из готовых методов запроса, таких как GetTriplesWithObjectPredicate,

Поэтому мой вопрос:

Я что-то упускаю, либо в библиотеке dotnetrdf, либо концептуально, в RDF, или это поведение связано с препятствиями, которые оно создает для разработчиков при разработке?

Вот тестовый пример C# для воспроизведения проблемы (запрос 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);
            }
        }
    }
}

Это вывод примера программы:

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.

Как видно, IGraph.Nodes перечисление не включает предикат Uris, такой как http://www.example.com/prop1 или же http://www.w3.org/1999/02/22-rdf-syntax-ns#type, Аналогично, выходные данные показывают, что предикаты не найдены GetUriNode, а предметы и предметы есть.

2 ответа

Решение

Вы можете использовать CreateURINode из INodeFactory (который IGraph расширяется), чтобы создать rdf:type узел, и есть что-то вроде:

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" ))
)

Это похоже на подход, который я бы использовал в Йене, где я бы использовал что-то вроде ResourceFactory.createProperty( http://...ns#type ), (На самом деле, у Йены есть постоянная RDF.type для удобства, который я бы использовал, но этот подход я бы использовал для того, который не был определен как постоянный заранее.)

Такое поведение полностью задуманно, то, что появляется только в положении предиката, считается ребром в графе, а не узлом в графе.

В документации " Работа с графиками" говорится следующее:

Для выбора узлов существуют методы, которые можно использовать для поиска узла из графика (если он существует), которые являются GetXNode() методы, где X - это тип узла, который нужно получить. Обратите внимание, что этот метод возвращает значение только в том случае, если данное значение существует в виде графа в графе, т.е. оно встречается в позиции субъекта / объекта тройки на этом графе.

Примечание. Если вы просто хотите получить экземпляр Node для других применений, независимо от того, существует ли он уже на графике, следует использовать CreateXNode() методы вместо.

Может быть GetEdge() и соответствующий Edges свойство было бы полезно?

Другие вопросы по тегам