RDF Graphs

The Graph and MutableGraph traits define how you interact with RDF graphs in Sophia.

Using graphs

RDF graphs are sets of triples, so the most common thing you need to do with a graph is to iterate over its triples. This is achieved with the Graph::triples method:

use sophia::api::prelude::*;
use sophia::inmem::graph::LightGraph;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let g = LightGraph::new();
for result in g.triples() {
	let triple = result?;
	// do something with t;
}
Ok(()) }

Notice that Graph::triples yields Results, as some implementations of Graph may fail at any point of the iteration.

When only a subset of the triples in the graph are of interest, you will want to use the Graph::triples_matching method:

use sophia::api::{ns::rdf, prelude::*, term::SimpleTerm};
use sophia::inmem::graph::LightGraph;

let graph = LightGraph::new();
// Utility closure to recognize IRIs in the schema.org namespace
let in_schema_org = |t: SimpleTerm| -> bool {
	t.iri()
	 .map(|iri| iri.as_str().starts_with(("http://schema.org/")))
	 .unwrap_or(false)
};
// Iter over all instances of schema.org types
graph
	.triples_matching(Any, [rdf::type_], in_schema_org)
	.map(|res| { let [s, _, o] = res.unwrap().to_spo(); (s, o)})
	.for_each(|(instance, typ)| {
		// do something 
	})

Graph::triples_matching accepts a large variety of parameters, which will be described in more detail in the next chapter.

Graph also provide methods to iterate over all subjects, predicate and object in the graph, as well as over all unique terms of a certain kind (Graph::iris, Graph::blank_nodes, Graph::literals, etc.).

Finally, it is possible to check whether a graph contains a specific triple with the method Graph::contains.

Mutating graphs

Any implementation of Graph that can be mutated should also implement MutableGraph, which comes with additional methods for modifying the graph. Individual triples can be added to the graph (resp. removed from the graph) with MutableGraph::insert (resp. MutableGraph::remove). Inserting (resp. removing) a triple that is already (resp. not) present in the graph will be essentially a noop.

use sophia::{api::{ns::rdf, prelude::*}, iri::*};
/// Example: increment the rdf:value of a given subject
fn f<G: MutableGraph>(mut g: G) -> Result<(), Box<dyn std::error::Error>> {
let s = Iri::new_unchecked("https://example.org/foo");
let old_value: i32 = g.triples_matching([s], [rdf::value], Any)
	.next()
	.unwrap()?
	.o()
	.try_into_term()?;
g.remove(s, rdf::value, old_value)?;
g.insert(s, rdf::value, old_value + 1)?;
Ok(()) }

Batch modifications can also be performed on mutable graphs:

The parameters of remove_matching and retain_matching are similar to those of Graph::triples_matching and are described in more detail in the next chapter.

Useful types implementing Graph

Recipies for constructing graphs

Constructing and populating an empty graph

use sophia::{api::{ns::{Namespace, rdf}, prelude::*}, inmem::graph::FastGraph};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut g = FastGraph::new();
let ex = Namespace::new_unchecked("https://example.org/ns#");
let alice = ex.get_unchecked("alice");
let s = Namespace::new_unchecked("http://schema.org/");
g.insert(
	&alice,
	rdf::type_,
	s.get_unchecked("Person")
)?;
g.insert(
	&alice,
	s.get_unchecked("name"),
  "Alice"
)?;
Ok(()) }

Constructing a graph from a triple source1

use sophia::{api::prelude::*, inmem::graph::FastGraph, iri::Iri};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let big_graph = FastGraph::new();
// Extract all triples about 'alice' from big_graph in a new graph
let alice = Iri::new_unchecked("https://example.org/ns#alice");
let graph: FastGraph = big_graph
	.triples_matching([alice], Any, Any)
	.collect_triples()?;
Ok(()) }

NB: Only types implementing CollectibleGraph can actually be constructed with the collected_triples method as above. However, most types implementing Graph should implement CollectibleGraph.

Constructing a graph from a file

use sophia::{api::prelude::*, inmem::graph::FastGraph, iri::Iri};
use std::{io::BufReader, fs::File};
use sophia::turtle::parser::turtle;

fn main() -> Result<(), Box<dyn std::error::Error>> {
dbg!(std::env::current_dir());
let f = BufReader::new(File::open("../sophia_doap.ttl")?);
let graph: FastGraph = turtle::parse_bufread(f)
	.collect_triples()?;
Ok(()) }

For more about parsing (and serializing), see the corresponding chapter.


1

a TripleSource is a fallible stream of triples, such as those returned by Graph::triples or Graph::triples_matching, or those returned by parsers. In particular, any iterator of Result<T, E> where T: Triple is a TripleSource.