lod-datasets_2011-09-19_1000px

    W poprzednim wpisie zajmowaliśmy sie importem danych. Tym razem pobawimy się SPARQL. Jest to język odgrywający podobną rolę jak SQL w wypadku relacyjnych baz danych. W przypadku SQL mamy do czynienia z formalizacją zapytań dotyczących algebry relacyjnej zbiorów w bazie danych. W wypadku SPQRQL mamy do czynienia z formalizacją zapytań dotyczących algebry wierzchołków grafu. Brzmi ciekawie.

    Baza danych semantycznych, jak już pisaliśmy, ma postać trójek w postaci <S,P,O> gdzie S to subject, P to predykat a O to object. Jeśli w naszych danych ten sam subject ma wiele cech ( Predykatów) to można taki fakt reprezentować w postaci grafu w którym subject i jest wierzchołkiem wyjściowym a obiekty to wartości cech których nazwy to predykaty. Pisałem o takiej konstrukcji kiedy mówiliśmy o ontologiach – czyli formalnym opisie własności obiektu. Zarazem ontologia pokazuje zwykle hierarchię obiektów – jak w biologii – roślina->drzewo->dąb. I w tym przypadku może być podobnie bo ten sam subject może być powiązany z innymi jakimiś zależnościami.

    W poprzednim wpisie sprawdziliśmy jakie cechy ( predykaty) opisują dane w naszym grafie z Projektu Gutenberg. Wśród nich znaleźliśmy miedzy innymi takie: http://purl.org/dc/terms/creator oraz http://purl.org/dc/terms/title co sugeruje autora i tytuł. Sprawdźmy zatem co sie pod tym predykatem kryje. POniższe zapytania były wykonywane za pomocą interfejsu w przeglądarce, zwanego conductorem, który pozwala odpytywać bazę Virtuoso i jest dostępny po jej zainstalowaniu i uruchomieniu pod adresem: http://localhost:8890/conductor/ w sekcji „Linked Data”, SPARQL. Ta sekcja nadaje się do interaktywnych eksperymentów. Do obsługi zapytań programowych ( być może opiszę jej użycie w kolejnych wpisach) używam tzw. endpointu ( końcówki?) http://localhost:8890/sparql i tej właśnie będę używał ( gdyż generuje w wyniku kod html łatwy do umieszczenia na blogu).

    Zacznijmy od prostego zapytania:

select ?creator, ?title
 from <http://gutenberg.new>
 where{
 ?s <http://purl.org/dc/terms/creator> ?creator.
 ?s <http://purl.org/dc/terms/title> ?title.} limit 10

    Klauzula limit 10 ogranicza ilość wyświetlanych wyników. Po uruchomieniu uzyskałem następujący wynik ( tabela poniżej jest przeklejonym html-em z endpointu Virtuoso):

creator title
http://www.gutenberg.org/2009/agents/3579 Poetry
http://www.gutenberg.org/2009/agents/41561 Poetry
http://www.gutenberg.org/2009/agents/38898 Sermons
http://www.gutenberg.org/2009/agents/546 Essays
http://www.gutenberg.org/2009/agents/1486 Essays
http://www.gutenberg.org/2009/agents/1440 Essays
http://www.gutenberg.org/2009/agents/5466 Etiquette
http://www.gutenberg.org/2009/agents/9318 Etiquette
http://www.gutenberg.org/2009/agents/998 Meditations
http://www.gutenberg.org/2009/agents/34332 Games

    O ile sekcja title być może wydaje sie sensowna o tyle widać ze zobaczyliśmy identyfikator autora a nie jego imię i nazwisko. Pewnym mankamentem jest także fakt że musieliśmy pisać długie nazwy predykatów. Sprawdzając po raz kolejny zbiór predykatów znajdujemy inny niż http://purl.org/dc/terms/creator predykat http://www.gutenberg.org/2009/pgterms/name . Spróbujemy go użyć. Poniższe query zawiera definicję „przestrzeni adresowych” spakowaną w dogodną formę deklaracji prefix, co pozwala na bardziej czytelną postać samego querry. Zmieniłem też „sposób wędrówki po grafie, tym razem nie zaczynamy od autora ale od książki ( linia ?s pp:title ?title)

prefix pp: <http://purl.org/dc/terms/>
 prefix gg: <http://www.gutenberg.org/2009/pgterms/>
 select ?ID, ?autor, ?title
 where{
 ?s pp:title ?title.
 ?s pp:creator ?ID.
 ?ID gg:name ?autor.
 }
 order by ?autor
 limit 10

    Wynik zapytania to:

ID autor title
http://www.gutenberg.org/2009/agents/3425 „Colored Quartet” (name unknown) Pharoah’s Army Got Drownded
http://www.gutenberg.org/2009/agents/37381 A Gentleman of Elvas [pseud.] A Narrative of the expedition of Hernando de Soto into Florida published at Evora in 1557
http://www.gutenberg.org/2009/agents/42956 A’Beckett, Gilbert Abbott The Comic History Of England
http://www.gutenberg.org/2009/agents/4360 A-No. 1 The Trail of the Tramp
By A-No. 1, the Famous Tramp, Written by Himself from Actual Experiences of His Own Life
http://www.gutenberg.org/2009/agents/31385 A. L. O. E. The Crown of Success
http://www.gutenberg.org/2009/agents/31385 A. L. O. E. Hebrew Heroes
A Tale Founded on Jewish History
http://www.gutenberg.org/2009/agents/31385 A. L. O. E. The Rambles of a Rat
http://www.gutenberg.org/2009/agents/31385 A. L. O. E. The Haunted Room
A Tale
http://www.gutenberg.org/2009/agents/31385 A. L. O. E. The Spanish Cavalier
A Story of Seville
http://www.gutenberg.org/2009/agents/38745 A.E. The Hero in Man

    Oczywiście kolumna ID nie jest nam do niczego potrzebna, możemy więc ją całkowicie opuścić w prezentacji dalszych zapytań. Cóż to za dziwny autor A.L.O.E.? Sprawdźmy jakie jeszcze książki napisał. Możemy w tym celu użyć komendy filter jak w poniższym przykładzie ( proszę zwrócić uwagę, że musiałem skopiować A. L. O. E. ze spacjami w środku. prościej byłoby zrobić to samo za pomocą ID):

 prefix pp: <http://purl.org/dc/terms/>
 prefix gg: <http://www.gutenberg.org/2009/pgterms/>
 select ?autor, ?title
 where{
 ?s pp:title ?title.
 ?s pp:creator ?ID.
 ?ID gg:name ?autor.
 filter ( ?autor = 'A. L. O. E.')
 }
 order by ?title

Oto wynik:

autor title
A. L. O. E. Hebrew Heroes
A Tale Founded on Jewish History
A. L. O. E. The Crown of Success
A. L. O. E. The Haunted Room
A Tale
A. L. O. E. The Rambles of a Rat
A. L. O. E. The Spanish Cavalier
A Story of Seville

    Jak widać A. L. O. E. jest autorem kilku pozycji. Ciekawe jak wygląda sprawa z innymi autorami. Poniższe query pokazuje tych którzy są autorami więcej niż 5-ciu pozycji, na dodatek posortowaliśmy autorów od najbardziej płodnych czyli w kolejności malejącej ilości dzieł. No i dla czytelności ograniczyłem ilość wyników do 10-ciu ( a kto ciekawy zobaczy więcej u siebie):

 prefix pp: <http://purl.org/dc/terms/>
 prefix gg: <http://www.gutenberg.org/2009/pgterms/>
select ( count(?s) as ?ilosc ), ?creator
 from <http://gutenberg.new>
 where{
 ?s pp:title ?tytul.
 ?s pp:creator ?ID.
 ?ID gg:name ?creator.
 }
 group by ?creator
 having ( count(?s) > 5 )
 order by desc(?ilosc)

A wynik to:

ilosc creator
2774 Various
672 Anonymous
306 Shakespeare, William
215 Lytton, Edward Bulwer Lytton, Baron
212 Twain, Mark
170 Ebers, Georg
163 Dickens, Charles
150 Unknown
143 Verne, Jules
134 Parker, Gilbert

    Jak widać można bawić sie SPRQL-em całkiem podobnie jak SQL. SPARQL, ma całkiem podobne jak SQL składnie i dyrektywy ( select, insert itp.), ale pośród nich sa tez i takie których w SQL nie ma. Jedną z nich jest dyrektywa CONSTRUCT, która w odróżnieniu od pokazanych powyżej, które zwracają „raport” z wykonania, zwraca w wyniku graf, a wiec plik rdf ( w jednej z zadanych postaci, a jest ich wiele od pliku z trojkami, przez html, na rdf-ie w składni xml, czy jsonie skończywszy).

Użyjemy klauzuli CREATE by wykreować sobie następujący graf. Z przykładów powyżej widać że wielu autorów ma na swoim koncie więcej niż jedno dzieło. Oczywiście wśród nich sa i tacy co maja na swoim koncie dzieła pisane we współpracy z innymi autorami. Poniższe query zwraca pozycje z Gutenberga w kolejności od największej ilości autorów do najmniejszej:

 prefix pp: <http://purl.org/dc/terms/>
 prefix gg: <http://www.gutenberg.org/2009/pgterms/>
select ?s, ( count(?ID) as ?ilosc )
 from <http://gutenberg.new>
 where{
 ?s pp:title ?title.
 ?s pp:creator ?ID
 }
 group by ?s
 order by desc(?ilosc)

    Jak widać dzieło http://www.gutenberg.org/ebooks/40718 czyli ( proszę klinknąć!) – „Atlantic Narratives: Modern Short Stories; Second Series by Mary Antin et al.” ma aż 24 autorów. Byłoby zabawnie zatem zobaczyć graf w którym wierzchołkami byliby autorzy ( ich identyfikatory uzupełnone etykieta nazwiska), zaś krawędź między wierzchołkami oznaczałaby że autorzy ci napisali razem książkę. Zapytanie takie wymaga by wykluczyć złączenia „autora z siebie samym” stąd klauzula FILTER w zapytaniu:

prefix pp: <http://purl.org/dc/terms/>
 prefix gg: <http://www.gutenberg.org/2009/pgterms/>
 PREFIX : <Author>
construct { ?ID1 :Name ?autor1. ?ID1 :WroteTogetherWith ?ID2. } where{
 ?s pp:title ?title.
 ?s pp:creator ?ID1.
 ?s pp:creator ?ID2.
 ?ID1 gg:name ?autor1.
 ?ID2 gg:name ?autor2.
 filter(?ID1 != ?ID2)
 }
 order by ?ID1

    Zwrócę uwagę że w deklaracji CONSTRUCT powyżej mamy następujące elementy ( definicja grafu):

  1. pole ID1 które podaje unikalny numer wierzchołka
  2. pole autor jako object które podaje nazwę – etykietę – wierzchołka, którą jest oczywiście imię i nazwisko
  3. pole WroteTogetherWith które podaje współautorów piszących z danym autorem ID1
  4. zdefiniowałem sobie globalny i domyślny PREFIX <Author> który jest dołączany wszędzie tam gdzie używam dwukropka „:” bez określenia innego prefiksu – czyli w predykatach :Name oraz :WroteTogetherWith które sa tworzone w wynikowym grafie.

Wynik ( fragment), w postaci pliku trujek, wygląda tak:

Subject Item
n2:1
AuthorName
United States
AuthorWroteTogetherWith
n2:396 n2:141
Subject Item
n2:65
AuthorName
Shakespeare, William
AuthorWroteTogetherWith
n2:39948 n2:9129 n2:6042 n2:407 n2:39704
Subject Item
n2:216
AuthorName
Anonymous
AuthorWroteTogetherWith
n2:37263 n2:42275 n2:16 n2:583 n2:1919 n2:3592 n2:38998 n2:146 n2:26322 n2:39598

Ten sam fragment w postaci listy HTML jest taki:

itp. itd.
     W następnym odcinku, jeśli w ogóle nastąpi ;-) zobaczymy jak wyglądałby graf który na podstawi tych danych można narysować.