Example 2: Asserting and retracting triples

In this example we show how to create resources describing two people, Bob and Alice, by asserting triples into the repository. The example also retracts and replaces a triple. Assertions and retractions to the triple store are executed by add() and remove() methods belonging to the connection object, which we obtain by calling the ag_connect() function described in Example 1: Creating a repository and triple indices.

Before asserting a triple, we have to generate the URI values for the subject, predicate and object fields. The AllegroGraph Python client API predefines a number of classes and predicates for the RDF, RDFS, XSD, and OWL ontologies. RDF.TYPE is one of the predefined predicates we will use.

The add() and remove() methods take an optional contexts argument that specifies one or more subgraphs that are the target of triple assertions and retractions. When the context is omitted, triples are asserted/retracted to/from the default graph. In the example below, facts about Alice and Bob reside in the default graph.

The second example begins by calling ag_connect() to create the appropriate connection object, which is bound to the variable conn.

from franz.openrdf.connect import ag_connect

conn = ag_connect('python-tutorial', create=True, clear=True)

The next step is to begin assembling the URIs we will need for the new triples. The createURI() method generates a URI from a string. These are the subject URIs identifying the resources “Bob” and “Alice”:

alice = conn.createURI("http://example.org/people/alice")
bob = conn.createURI("http://example.org/people/bob")

Bob and Alice will be members of the “person” class (rdf type person).

person = conn.createURI("http://example.org/ontology/Person")

Both Bob and Alice will have a “name” attribute.

name = conn.createURI("http://example.org/ontology/name")

The name attributes will contain literal values. We have to generate the Literal objects from strings:

bobsName = conn.createLiteral("Bob")
alicesName = conn.createLiteral("Alice")

The next line prints out the number of triples currently in the repository - we expect that to be zero, since we have not yet added any triples and the connect function should have removed any existing statements from the repository.

print("Triple count before inserts:", conn.size())
Triple count before inserts: 0

Now we assert four triples, two for Bob and two more for Alice, using the connection object’s add() method. After the assertions, we count triples again (there should be four) and print out the triples for inspection.

from franz.openrdf.vocabulary import RDF

# alice is a person
conn.add(alice, RDF.TYPE, person)
# alice's name is "Alice"
conn.add(alice, name, alicesName)
# bob is a person
conn.add(bob, RDF.TYPE, person)
# bob's name is "Bob":
conn.add(bob, name, bobsName)

print("Triple count:", conn.size())
for s in conn.getStatements(None, None, None, None):
    print(s)

The None arguments to the getStatements() method say that we don’t want to restrict what values may be present in the subject, predicate, object or context positions. Just print out all the triples.

This is the output at this point. We see four triples, two about Alice and two about Bob

Triple count: 4
(<http://example.org/people/alice>, <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>, <http://example.org/ontology/Person>)
(<http://example.org/people/alice>, <http://example.org/ontology/name>, "Alice")
(<http://example.org/people/bob>, <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>, <http://example.org/ontology/Person>)
(<http://example.org/people/bob>, <http://example.org/ontology/name>, "Bob")

We see two resources of type “person,” each with a literal name.

The next step is to demonstrate how to remove a triple. Use the remove() method of the connection object, and supply a triple pattern that matches the target triple. In this case we want to remove Bob’s name triple from the repository. Then we’ll count the triples again to verify that there are only three remaining.

conn.remove(bob, name, bobsName)
print("Triple count:", conn.size())
Triple count: 3

A potentially less verbose way of adding triples is to use the addData() method of the connection object with a string containing triples in Turtle, N-Triples or another RDF format.

Let us see how the data used in this example could be added using addData(). We will also wrap the whole process in a function that we’ll use later:

def add_bob_and_alice(conn):
   conn.addData("""
       @base <http://example.org/> .

       <people/alice> a <ontology/Person> ;
                      <ontology/name> "Alice" .
       <people/bob> a <ontology/Person> ;
                    <ontology/name> "Bob" .
   """)

The string used here is in the Turtle format. It is also possible to use other formats by passing the rdf_format argument to addData().

We should check if the new function behaves as expected by creating a fresh connection (recall that the clear parameter causes all existing triples to be deleted):

with ag_connect('python-tutorial', clear=True) as conn:
    add_bob_and_alice(conn)
    print("Triple count:", conn.size())
Triple count: 4