Skip to content

A little bit of tagging

Wednesday, 30 January 2008  |  trueg

For many Nepomuk is a rather abstract thing. So I will not try to explain it as a project again. I will just show what I have been up to. Randomly...

Tagging and KIO

We all know KIO and we all love it (At least I think we all do, right?). Now it was pretty obvious to create a KIO slave that allows to navigate the Nepomuk tags as folders. Writing this was not that hard. Just listing the tags and doing some plain magic around that:

QList tags = Nepomuk::Tag::allTags();
foreach(Nepomuk::Tag tag, tags ) {
    doMagic(tag);
}

So no problem there:

[image:3240 align=middle width=400]

However, now that we can browse the tags in Dolphin, we can also rate them in Dolphin. And this is where the trouble starts: The tag URLs used in the tags KIO slave differ from their original resource URIs (remember: Nepomuk uses RDF for storage and, thus, each resource has a unique URI). The original URI looks like nepomuk://foobar while the tags KIO slave of course uses tags:/<tag name>. This is a problem since now Dolphin will store ratings and comments for the tags under the tags URI and not the original one. (this is due to the fact that KIO does not allow to have different URLs for navigation and identification, maybe this could be tackled in KDE 4.x or 5.0?)

So what to do? The simple answer is called alignment. At least that is what we call it in Nepomuk. It references a service that aligns multiple resources that actually refer to the same entity. In general this can become arbitrarily complicated. In our case, however, we can use the brute force way and simply replace tag URIs.

So now we have a kded module in playground/base/nepomuk-kde (BTW: this is where all the experimental stuff happens) that does exactly that. To give you and idea of how something like this looks a bit of code:

QString query = QString( "select distinct ?tag ?name where { "
                         "?tag a <%1> . "
                         "?tag <%2> ?name . "
                         "FILTER(!REGEX(STR(?tag),'^tags:/')) . }" )
                .arg( Soprano::Vocabulary::NAO::Tag().toString() )
                .arg( Nepomuk::Resource::labelUri() );
QList tagsToChange = sopranoModel()->executeQuery( query, Soprano::Query::QueryLanguageSparql ).allBindings();
foreach( Soprano::BindingSet set, tagsToChange ) {
   QUrl oldUri = set["tag"].uri();
   QString name = set["name"].toString();
   QUrl newUri = "tags:/" + name;

   QList tagStatements = sopranoModel()->listStatements( oldUri, Soprano::Node(), Soprano::Node() ).allStatements();
   foreach( Soprano::Statement s, tagStatements ) {
      sopranoModel()->removeStatement( s );
      s.setSubject( newUri );
      sopranoModel()->addStatement( s );
   }

   tagStatements = sopranoModel()->listStatements( Soprano::Node(), Soprano::Node(), oldUri ).allStatements();
   foreach( Soprano::Statement s, tagStatements ) {
      sopranoModel()->removeStatement( s );
      s.setObject( newUri );
      sopranoModel()->addStatement( s );
   }
}

This is basically how you do more advanced Nepomuk data handling. Using Soprano + SPARQL. Sadly SPARQL does not officially support update queries yet but it is a pretty new technology and we will get there.

Well, that's pretty much it. It changes the tag URIs and that results in a merge of the tag annotations with the original resource. It is a bit simple but does the job. And as a side effect: when you execute a search result that is a tag you directly come to the tags KIO slave and thus, the tagged resource. Fun, he? Ok, more on search next time.