Graph

The walrus graph module provides a lightweight hexastore implementation. The Graph class uses Redis ZSet objects to store collections of subject - predicate - object triples. These relationships can then be queried in a very flexible manner.

Note

The hexastore logic is expecting UTF-8 encoded values. If you are using Python 2.X unicode text, you are responsible for encoding prior to storing/querying with those values.

For example, we might store things like:

  • charlie – friends – huey

  • charlie – lives – Kansas

  • huey – lives – Kansas

We might wish to ask questions of our data-store like “which of charlie’s friends live in Kansas?” To do this, we will store every permutation of the S-P-O triples, then we can efficiently query using the parts of the relationship we know beforehand.

  • query the “object” portion of the “charlie – friends” subject/predicate.

  • for each object returned, turn it into the subject of a second query whose predicate is “lives” and whose object is “Kansas”.

So we would return the subjects that satisfy the following expression:

("charlie -- friends") -- lives -- Kansas

Let’s go through this simple example to illustrate how the Graph class works.

from walrus import Database

# Begin by instantiating a `Graph` object.
db = Database()
graph = db.graph('people')

# Store my friends.
# "charlie" is subject, "friends" is predicate, "huey" is object.
graph.store('charlie', 'friends', 'huey')

# Can also store multiple relationships at once.
graph.store_many((
    ('charlie', 'friends', 'zaizee'),
    ('charlie', 'friends', 'nuggie')))

# Store where people live.
graph.store_many((
    ('huey', 'lives', 'Kansas'),
    ('zaizee', 'lives', 'Missouri'),
    ('nuggie', 'lives', 'Kansas'),
    ('mickey', 'lives', 'Kansas')))

# We are now ready to search. We'll use a variable (X) to indicate
# the value we're interested in.
X = graph.v.X  # Create a variable placeholder.

# In the first clause we indicate we are searching for my friends.
# In the second clause, we only want those friends who also live
# in Kansas.
results = graph.search(
    {'s': 'charlie', 'p': 'friends', 'o': X},
    {'s': X, 'p': 'lives', 'o': 'Kansas'})

print(results)

# Prints: {'X': {'huey', 'nuggie'}}

In the above example, the result value is a dictionary of variable values that satisfy the search expressions. The search() method is quite powerful!

An even simpler example

Let’s say we wish only to retrieve a list of Charlie’s friends. In this case we do not need to use a variable. We can use the simpler query() method. This method optionally takes a subject, predicate and/or object and, using the provided data, returns all objects that “match” the given pieces.

So to find Charlie’s friends, we would write:

query = graph.query(s='charlie', p='friends')
for result in query:
    print(result['o'])  # Print the object for the corresponding S/P.