RDF PIM — odcinek #1: pozyskiwanie danych

Dobra, starczy tych mało przekonujących przykładów dla ludzi posiadanych przez koty — zobaczmy czy ten cały bajzel z SW nadaje się do czegoś naprawdę użytecznego. ;-)

Kiedy myślę o tym, do czego w codziennej praktyce przydałby mi się agent korzystający z zasobów Sieci Semantycznej to zawsze przychodzi mi na myśl zarządzanie informacjami na temat kontaktów, kalendarza, zadań, terminów itd. itp. Takie informacje „osobiste”, czyli wszystko, czego dotyczy pojęcie PIM, są z natury rzeczy pełne najróżniejszych powiązań — kontakty między sobą, zdarzenia między sobą, zdarzenia z kontaktami, zadania z kalendarzem i źródłami w sieci itd. itp. Wyobrażam sobie, że sprytny agent może bardzo pomóc w opanowaniu tych zależności.

RDF bardzo dobrze nadaje się do zapisania danych takich jak dane PIM z co najmniej kilku powodów, w tym:

  • umożliwia łatwe wyrażenie dowolnej liczby dowolnego typu relacji między obiektami/zasobami,
  • ułatwia agregację danych, nawet pochodzących ze źródeł, o których praktycznie nie musimy nic wiedzieć a priori,
  • umożliwia wyszukiwanie zależności między obiektami w modelu i wyciągnie logicznych wniosków na temat ich powiązań.

Nawet bez posiadania w tej chwili agenta pilnującego porządku w kalendarzu i książce adresowej, posiadanie sprawnej bazy danych zawierającej wszystkie informacje i powiązania między nimi jest na pewno kuszące. Niestety takiej bazy nie mam i nie zamierzam jej od zera „wklepywać” przepisując zbiory danych wykorzystywane dotychczas. Jedyne co mogę zrobić to spróbować automagicznie zbudować odpowiedni model RDF z najróżniejszych źródeł, z których przyszło mi korzystać. Na pierwszy ogień pójdą dane, które w tej chwili w jakiejś tam postaci mam pod ręką, a więc kontakty czyli książka adresowa oraz kalendarz.

Disclaimer: Wszystko co od tej chwili będę pisał na temat pozyskiwania danych do bazy RDF PIM (niech to się tak nazywa roboczo) powstaje „na żywca” i nie jest przemyślane więcej niż jeden krok naprzód. Oznacza to, że bardzo łatwo mogę wymyślić coś, co chwilę potem okaże się totalnym błędem. Potraktuję to jak program na żywo — albo dojdę do czegoś przydatnego, albo poniosę sromotną klęskę...

kontakty — krok #1: telefon

Najważniejsza (z mojego osobistego punktu widzenia) lista kontaktów, to wbrew pozorom wcale nie książka adresowa programu pocztowego, tylko lista z telefonu. Mój telefon umożliwia wyeksportowanie wizytówek w formacie vCard (to chyba nic wyjątkowego) zatem ten format musi być punktem zaczepienia.

Przestrzeń nazw wyrażająca vCard w postaci RDF została kiedyś podana przez W3C. W pierwszym podejściu próbowałem dokonać konwersji pliku vCard uzyskanego z telefonu na RDF z wykorzystaniem tej ontologii. Po dwóch dniach zrezygnowałem zmęczony niejasnym podejściem do tematu. Przykładowo telefon domowy dla kontaktu określa istnienie właściwości vCard:TEL wskazującej na obiekt typu vCard:home z numerem telefonu jako rdf:value. Telefon do pracy to również właściwość vCard:TEL tylko dla odmiany wskazuje obiekt typu vCard:work. Telefon typu home lub work? A nie typu telefon? Co jeszcze śmieszniejsze tego samego typu vCard:home jest coś, na co wskazuje vCard:ADR tylko, że tym razem chodzi o adres domowy. Zatem typy w tej ontologii nie określają klas obiektów tylko ich ... rodzaje? Nie chciało mi się to zmieścić w zdroworozsądkowym pojmowaniu opisu rzeczywistości za pomocą RDF. Poddałem się.

Na szczęście znalazłem ontologię vCard (N3, RDF/XML) autorstwa Normana Walsha, która już na pierwszy rzut oka jest dużo bardziej rozsądna. Wszystkie atrybuty kontaktu są tutaj opisane przez klarowne właściwości wskazujące obiekty oczywistych klas jak telefon czy adres. Dużo lepiej, dużo prościej, dużo rozsądniej.

Pozostaje zatem jedynie przekonwertować plik vCard na jakiś strawny format RDF. Nawet nie wiem czy istnieją jakieś mechanizmy konwertujące vCard na RDF; żadnego takiego narzędzia sobie nie przypominam, więc postanowiłem to zrobić „łopatologicznie” za pomocą prostego skryptu[1] w Ruby: vcard2n3.rb. Efektem działania tego programiku jest lista kontaktów vCard w formacie N3 (uznałem, że w tym przypadku szkoda czasu i energii na RDF/XML). Jedyny potencjalny problem mogą tutaj stanowić identyfikatory — z braku lepszego pomysłu zostały one stworzone na podstawie nazwy z wyciętymi znakami, które mi się w tym miejscu nie podobają (co nie znaczy, że nie są dozwolone); czas pokaże na ile jest to zły pomysł.

kontakty — krok #2: Thunderbird

W drugiej kolejności interesuje mnie książka adresowa programu pocztowego. Tak się złożyło, że od roku używam głównie programu Mozilla Thunderbird, a ten jak na złość nie oferuje eksportu do formatu vCard. Powstaje zatem kolejny problem — konwersja z jakiegoś formatu oferowanego przez Thunderbirda, niech to będzie LDIF. Konwersję tę wykonuję analogicznie jak poprzednio skryptem[2] w Ruby: mozldif2n3.rb. Informacje zamieszczane w książce adresowej Thunderbirda miejscami wychodzą poza zakres vCard, zatem tym razem oprócz ontologii vCard skorzystałem również z foaf (na szczęście w RDF używanie różnych słowników w jednym modelu jest całkowicie naturalne i bezproblemowe). Oczywiście problem z identyfikatorami jest tu taki sam jak poprzednio, albo i większy, bo niektóre wpisy w książce adresowej zawierają tylko e-mail...

kontakty — krok #3: rozpaczliwa próba łączenia

Uzyskane pliki RDF należy teraz połączyć w jeden model, co samo w sobie jest dosyć banalne. ZakładamPodejrzewam jednak, że w obu otrzymanych powyżej listach kontaktów niektóre osoby się powtarzają, więc dobrze by było przy okazji ten fakt „wyłapać”. Jedyny w miarę pewny sposób jaki widzę, to porównanie adresu e-mail. Niestety nie mam zwyczaju na bieżąco uzupełniać adresów e-mail w telefonie, więc książka adresowa pozyskana z telefonu jest w tym względzie mocno niekompletna, ale być może coś „się znajdzie”...

Połączenie wykonuję oczywiście przy pomocy cwm. Reguła odpowiedzialna za „sklejenie” wizytówek o identycznym adresie e-mail może wyglądać np. tak:

@prefix log: <http://www.w3.org/2000/10/swap/log#>.
@prefix v: <http://nwalsh.com/rdf/vCard#>.

{ ?x a v:VCard . ?y a v:VCard .
?x log:notEqualTo ?y .
?x v:email ?m . ?y v:email ?m
} => { ?x = ?y } .

Po sklejeniu RDF-ów

cwm --n3 personal.n3 collected.n3 Whole\ Phonebook.n3 --think=rules.n3 --closure=e > kontakty.n3

otrzymuję w miarę elegancki model RDF.

Niestety w świecie Sieci Semantycznej, tak jak wszędzie, działa reguła GIGO, zatem dane wynikowe nie są jakoś olśniewająco lepsze od danych wejściowych. Szczególnie żałuję, że nie utrzymałem dyscypliny nazewnictwa kontaktów w telefonie — mam teraz kilka wizytówek z imieniem w miejscu nazwiska, albo bez nazwiska w ogóle, nie wspominając już o nazwach instytucji... W każdym razie podstawy są nie najgorsze; mimo że zdecydowanie wymagają „wyczyszczenia”, to wygląda to na model, na którym można zacząć budować coś użytecznego. :-)

Czas pokaże...

[1][2] Przedstawiony program uwzględnia przypadki występujące w moich danych i nie jest uniwersalnym konwerterem vCard lub LDIF do N3. Dla mnie działa, ale nie gwarantuję, że nadaje się to do czegokolwiek innego. Równocześnie zastrzegam, że nie jestem programistą Ruby i na przedstawiony program pod żadnym pozorem nie należy patrzeć jako na reprezentacyjny przykład programowania w tym języku.

Komentarze

Brak komentarzy do tego wpisu.

 

Uwaga: Ze względu na bardzo intensywną działalność spambotów komentowanie zostało wyłączone po 60 dniach od opublikowania wpisu. Jeżeli faktycznie chcesz jeszcze skomentować skorzystaj ze strony kontaktowej.