icroblogging service Twitter has become a disruptive everyday tool. It is increasingly replacing not only instant messaging clients, but also social bookmarking sites, interest tracking applications, support forums, email, and (to a certain extent) classical blogs. A few simple conventions, together with RDF and SPARQL, can turn your Twitter feeds into rich information streams, which you can then use for a more productive microblogging experience.
The following sections explain how to:
When you are done, return to the main screen by clicking on the logo in the upper left corner. Instead of cronjobs or background processes, the demo simply checks and periodically refreshes your subscriptions when you access the start page. After a few seconds (you might have to reload the page to see the changes), the first items should appear, as shown in Figure 2.
![]() Figure 1. Import settings: Based on the provided information, the demo application imports a selection of microfeeds. |
![]() Figure 2. Initial timeline: So far, the microposts can (only) be filtered by author. |
![]() |
|
| Figure 3. SPARQL API Example: The COUNT feature is not part of the current SPARQL specification yet, but a new W3C Working Group just launched to explore aggregate functions and similar extensions. |
SELECT ?author ?account WHERE {
?post a sioct:MicroBlogPost ;
dc:creator ?author ;
sioc:has_creator ?account ;
content:encoded ?content .
FILTER(REGEX(?content, "Berners-Lee", "i"))
}
Not too spectacular data-wise, but the exciting thing here is the fact that a semantic API lets you retrieve exactly the
elements that you need (see Figure 3). Twitter's search feature can only return a list of posts, SPARQL allows you to
generate a list of persons, or dates, or any other available attribute. This greatly simplifies data integration and
repurposing.
The demo system contains a PHP class (located at code/smr/SMR_RDFExtractor.php) that auto-extracts these elements from the otherwise opaque content and turns them into RDF triples. The converter is based on simple regular expressions and you can extend them with custom patterns (more on this later).
After the granular information is added to the RDF store, you may add respective filters to the main view. The facets are defined in code/smr/options/SMR_Options_DefaultBox.php. You can add entries to the getTabs method, and then write a matching method where the SPARQL pattern with its RDF relation is specified:
![]() |
|
| Figure 4. Filtered Stream: The advanced facets helps you find out who re-tweeted any of your posts, or posts that contain a certain link, or popular links in general. |
function getTabs() {
return array(
[...]
'tags' => array('label' => 'Tags'),
'users' => array('label' => 'Mentioned Users'),
'links' => array('label' => 'Links'),
);
}
function getUsersTabHTML() {
$pattern = '?res smr:mentionedUser ?val . ';
return $this->getFilterList($pattern, 'smr:mentionedUser');
}
function getLinksTabHTML() {
$pattern = '?res smr:link ?val . ';
return $this->getFilterList($pattern, 'smr:link');
}
The application can now generate clickable filter lists (see Figure 4). You can browse your subscriptions in a more fine-grained way,
for example, to discover popular links or socially active users.
SELECT DISTINCT ?name WHERE {
# people mentioned by me
?post sioc:has_creator ?account ;
smr:mentionedUser ?name .
?account rdfs:label "your_twitter_username" .
# people who mentioned me
?post2 sioc:has_creator ?account2 ;
smr:mentionedUser "your_twitter_username" .
?account2 rdfs:label ?name .
}
A single SPARQL operation alone might not be enough, though, especially if you want to inject additional data or
reformat the results. In this case, you can extend the main page with your own tabs. Open
code/smr/SMR_ViewBox.php and add your own entries to the getTabs
method. This works similar to extending the filters, but this time you have to create a view class in
code/smr/custom/ for each new tab:
function getTabs() {
return array(
'all' => array('label' => 'All posts'),
'contacts' => array('label' => 'My Contacts'),
'bookmarks' => array('label' => 'Bookmarks'),
);
}
function getAllTabHTML() {
$tab = Trice::getObject('SMR_Stream_Tab', $this->a, $this->caller);
return $tab->getHTML();
}
function getContactsTabHTML() {
$tab = Trice::getObject('SMR_Custom_ContactsTab', $this->a, $this->caller);
return $tab->getHTML();
}
function getBookmarksTabHTML() {
$tab = Trice::getObject('SMR_Custom_BookmarksTab', $this->a, $this->caller);
return $tab->getHTML();
}
![]() |
|
| Figure 5. Custom Tabs with Bookmarks and Proven Contacts: The bookmark query was aligned with the filtering mechanism, so that you can use facets to narrow down the results. |
Other possible use cases include project reports or a birthday reminder. To a certain extent, you can implement the former based simple tags, but the latter requires the ability to detect and extract the month and calendar day of a person's birthday from a micropost.
You can tweak the regular expressions in the RDFExtractor (code/smr/SMR_RDFExtractor.php) to add support for such typed tags that follow a #key=value pattern. (You actually don't have to write this method yourself, it's already part of the code bundle.) Now you can add something like #birthday #month=08, #todo #priority=A or #done #task="DevX article" #hours=16 to your tweets and let the application extract the classified tags (which use a local my: namespace in the resulting RDF). Create conventions you feel comfortable with and let them evolve.
![]() |
|
| Figure 6. Basic Summary of Working Hours: The report uses SPARQL+ to aggregate working hours and then groups the results by related tags. |
SELECT DISTINCT ?post ?prio ?text WHERE {
?post smr:tag "todo" , "bug" ;
my:priority ?prio ;
content:encoded ?text .
}
ORDER BY ASC(?prio)
or a calculator for working hours:
SELECT ?project SUM(?hours) as ?sum WHERE {
?post my:hours ?hours ;
my:project ?project .
}
GROUP BY ?project
or upcoming birthdays:
SELECT ?text WHERE {
?post content:encoded ?text ;
smr:tag "birthday" ;
my:month "2" ;
my:day ?day .
FILTER(?day > 10)
}
ORDER BY ?day
| DevX is a division of Jupitermedia Corporation © Copyright 2007 Jupitermedia Corporation. All Rights Reserved. Legal Notices |