Playing with RDF

I’ve been playing with the master branch of tracker and i’m loving it – it looks like its finally reached the stage where I won’t just turn it straight off after a fresh install.

It now brings GNOME an RDF store with a SPARQL interface. Powerful joo-joo, but kinda scary if you haven’t seen it before. Most conversations about it lead to words like graphs, triples, ontologies… My eyes start to gloss over.. I need to learn by doing. So i’ve been playing with writing some python wrappers to hide tracker and just provide a familiar pythonic interface.

Any object type that tracker knows about will be available in python via the wonders of introspection. All properties of the class are available, with docstrings explaining the intent of the property and its type. Obviously you can get, set and delete and do simple queries. And behind the scenes are SPARQL queries in all their glory. Theres a lot still to do, but enough done that I can synchronise my address book to Tracker with Conduit (see my tracker branch).

So far it looks something like this (but its subject to very rapid change):

import tralchemy
from tralchemy.nco import Contact

# add a contact
c = Contact.create()
c.fullname = "John Carr"
c.firstname = "John"
c.nickname = "Jc2k"
c.commit()

# find all the people called John
for c in Contact.get(firstname="John"):
  print c.uri, c.fullname

# subscribe to any contact changes
def callback(subjects):
  print subjects
Contact.notifications.connect("SubjectsAdded", callback)

# Will probably be just:
Contact.added.connect(callback)

While get() is a nice way to do simple queries, what if you wanted to do something a little more complicated. It always feels messy when you have SQL or SPARQL nested in other code. Existing SQL ORM tools are a great place to start at avoiding this, but i quite like the LINQ style generator-to-SPARQL. Something like:


q = Query(Contact.firstname for Contact in Store if Contact.nickname == 'Jc2k')

or


q = Query(c.firstname for c in Store if c is Contact and c.nickname == 'Jc2k')

Hmm decisions. Hope to implement similar abstractions in JavaScript, C# (via LINQ) and Vala (via Magic). Anyone wanna share their cloning tech?

Tags: , , , ,

7 Responses to “Playing with RDF”

  1. engla says:

    that’s neat and all that. I’m still using tracker 0.6.6, which is a ridiculously fast C-written search system. I was really impressed when I found out about tracker. Now the new versions, 0.7 and that are long coming.. I’m afraid they are not so fast and lean and mean anymore. How is it? Does it use lots of memory or cpu. Do you (ever!) notice it running.

    I’ve got an old mac, 1.2 GHz and I never notice tracker running on this laptop, a truly epic feat for this functionality.

  2. Patrys says:

    I think you might want to implement something similar to django.db.models.Q

  3. John Carr says:

    @engla: As far as i’m aware tracker 0.7 should be pretty good too, but you’d be better asking in #tracker for specifics.

    @Patrys: I’m certainly looking to similiar things for inspiration. Hadn’t thought of django though. Thanks for the pointer.

  4. Natan Yellin says:

    That looks pretty neat. I’m working on a Tracker-based backend for GNOME Zeitgeist so I definitely will give your code a look to see if I can pick up any ideas. :)

  5. John Carr says:

    @Natan Yellin: Wicked cool! I have a lot of ideas for improving them, but not much time to implement them. Feel free to poke me in #tracker (Jc2k).

  6. James Henstridge says:

    The existing ORMs for SQL databases might be a good starting point.

    With Storm, the last example could be written something like:

    result = Store.find(Contact.firstname, Contact.nickname == ‘Jc2k’)

    It would determine what tables need to be queried based on what you are selecting and what WHERE clauses you use.

  7. John Carr says:

    @James Henstridge: Indeed, I was looking at Storm and SQLObject and others. I quite like the look of Storm.