• Nie Znaleziono Wyników

5. Modelowanie i eksploracja grafowych baz danych 69

5.5. Przykładowa implementacja grafowej bazy danych

5.5.2. Implementacja

Aby umo˙zliwi´c u˙zytkownikom komunikacj˛e z baz ˛a danych został stworzony program napisany w j˛ezyku Python 2, wykorzystuj ˛acy frameworkBulbflowwraz z j˛ezykiem zapyta ´n Gremlindo komunikacji z baz ˛a danychNeo4j. Stworzony program umo˙zliwia wyszukanie:

• wszystkich prac danego autora, • wszystkich autorów danej pracy, • najcz˛e´sciej cytowanych prac, • najcz˛e´sciej cytowanych autorów,

• autorów, którzy opieraj ˛a swoje prace na tych samych pracach,

• autorów, którzy opieraj ˛a swoje prace na pracach tych samych autorów.

Tworzenie bazy danych

Na rys. 5.6 pokazano prost ˛a baz˛e danych zło˙zon ˛a z 8 prac i 8 autorów. Baza ta została stworzona za pomoc ˛a skryptu napisanego w j˛ezyku Python 2. W tym celu utworzono 2 klasy odpowiedzialne za wierzchołki w grafie: PaperiPerson

modeluj ˛ace, odpowiednio, publikacje i autorów. Kraw˛edzie w grafie s ˛a modelo-wane przez klasyWroteiCite. KlasaWrotejest przeznaczona do ł ˛aczenia wierz-chołków pochodz ˛acych z klasyPersonz wierzchołkamiPaper, a wi˛ec okre´slenia autorów prac. Kraw˛ed´z klasyWroteskierowana jest w stron˛e wierzchołka klasy

Bartek Grzegorz Marcin Andrzej Wojtek Karol Marek Tomek P2 P0 P1 P4 P3 P5 P6 P7

5.5. Przykładowa implementacja grafowej bazy danych

Paper. KlasaCiteł ˛aczy ze sob ˛a instancje klasyPaper, modeluj ˛ac zale˙zno´sci bi-bliograficzne pomi˛edzy pracami. Wierzchołek odpowiadaj ˛acy pracy, która cytuje drug ˛a prac˛e, jest wyj´sciem kraw˛edzi.

from bulbs . model im port Node , R e l a t i o n s h i p from bulbs . p r o p e r t y im port S tring

class Per son ( Node ):

e l e m e n t _ t y p e = " pe rson "

name = Str ing ( n u l l a b l e = False ) u n i v e r s i t y = S tring ( n u l l a b l e = True )

class Paper ( Node ):

e l e m e n t _ t y p e = " paper "

name = Str ing ( n u l l a b l e = False )

class Wrote ( R e l a t i o n s h i p ): label = " wrote "

class Cite ( R e l a t i o n s h i p ): label = " cite "

Skrypt odpowiedzialny za utworzenie przykładowej bazy danych tworzy naj-pierw wszystkie wierzchołki (zarówno odpowiedzialne za prace jak i za autorów), a nast˛epnie ł ˛aczy je ze sob ˛a, tworz ˛ac zamierzony graf reprezentuj ˛acy niewielk ˛a kolekcje prac naukowych. Przyj˛eto tak ˛a wła´snie metod˛e, gdy˙z nie wymaga ona sprawdzania, czy istnieje ju˙z dany autor w bazie danych przy dodawaniu nowych publikacji. Jednak nic nie stałoby na przeszkodzie, aby została zaimplemento-wana metoda dodaj ˛aca prac˛e i autorów, sprawdzaj ˛aca czy dane prace lub autorzy znajduj ˛a si˛e ju˙z w bazie danych.

#!/ usr / bin / env pytho n # * co ding : utf 8 *

-from l i b r a r y C l a s s e s im port Person , Paper , Wrote , Cite from bulbs . n e o 4 j s e r v e r i mport Graph

impo rt o p e r a t o r impo rt os

def c r e a t e N e w G r a p h ():

p e r s o n L i s t = [" G r z e g o r z " , " Marcin " , " Tomek " , " Bartek " , " A n d r z e j " , " Wo jtek " , " Marek " , " Karol "] p a p e r s L i s t = [" P0 " , " P1 " , " P2 " , " P3 " , " P4 " , " P5 " , " P6 " , " P7 "] p e o p l e L i s t = [[0 , 1] , [0 , 2] , [3 , 4] , [0 , 1 , 2] , [0] , [6 , 7] , [6 , 7] , [5 , 6 , 7]] c i t e L i s t = [ None , [0] , [0 , 1] , [6] , [0 ,1 ,2] , [3 ,4] , [0 ,1 ,2 ,4 ,5] , [4]]

g = Graph () g . clear () g . a d d _ p r o x y (" pe rson " , P erson ) g . a d d _ p r o x y (" paper " , Paper ) g . a d d _ p r o x y (" wrote " , Wrote ) g . a d d _ p r o x y (" cite " , Cite ) p e r s o n A d d e d = [] p a p e r A d d e d = [] for x in p e r s o n L i s t :

p e r s o n A d d e d . appen d ( g . perso n . crea te ( name = x ) )

for x in p a p e r s L i s t :

p a p e r A d d e d . a ppend ( g . paper . create ( name = x ) )

for i ~ in range ( len ( p a p e r s L i s t )): for x in p e o p l e L i s t [ i ]: g . wrote . cr eate ( p e r s o n A d d e d [ x ] , p a p e r A d d e d [ i ]) if c i t e L i s t [ i ] != None : for x in c i t e L i s t [ i ]: g . cite . cr eate ( p a p e r A d d e d [ i ] , p a p e r A d d e d [ x ]) Trawersowanie

Przeszukiwanie grafowej bazy danych odbywa si˛e za pomoc ˛a przechodzenia z jednego wierzchołka do drugiego poprzez ł ˛acz ˛ace je kraw˛edzie grafu. Zacho-wanie takie jest okre´slane jako trawersoZacho-wanie bazy danych. Obecnie nie istniej ˛a łatwe w obsłudze ani dobrze spopularyzowane frameworki słu˙z ˛ace do tego celu, które wspierałyby j˛ezyk Python. Dlatego wybrano Bulbflow, który umo˙zliwia bezpo´srednie wykonywanie skryptów napisanych w j˛ezykuGremlinz poziomu programu. Pozwala to sprawnie i szybko porusza´c si˛e po grafie. Na potrzeby przykładu zostały napisane nast˛epuj ˛ace skrypty Gremlin-Groovy, wykonuj ˛ace za-ło˙zone zadania:

1. allPapers- funkcja zwraca list˛e warto´sci polanamewszystkich wierzchołków okre´slaj ˛acych publikacj˛e, czyli tych których poleelement_typema warto´s´c

paper.

def a l l P a p e r s () {

retu rn g . V . has ( ’ ele ment_t ype ’ , ’ paper ’). name . t oList () }

2. allPeople - identycznie jak w allPapersz t ˛a ró˙znic ˛a, ˙ze teraz szukani s ˛a autorzy publikacji.

def a l l P e o p l e () {

retu rn g . V . has ( ’ ele ment_t ype ’ , ’ person ’). name . t oList () }

5.5. Przykładowa implementacja grafowej bazy danych 3. personPapersByName - funkcja wyszukuje najpierw wierzchołki nale˙z ˛ace do autorów o zadanym nazwisku, po czym przemieszcza si˛e po wszystkich kraw˛edziach o warto´sci pola label = wrote do prac powi ˛azanych z auto-rami. Na ko ´ncu zwraca tytułu (polename) publikacji.

def p e r s o n P a p e r s B y N a m e ( name ) {

retu rn g . V . has ( ’ ele ment_t ype ’ , ’ person ’) . has ( ’ name ’ , name ). out ( ’ wrote ’). name }

4. authorsOfPaperByName- podobnie jak w przypadkupersonPapersByName

najpierw wyszukuje prace o odpowiednim tytule, po czym przemieszcza si˛e po kraw˛edzi wchodz ˛acej do tych wierzchołków o warto´sci polalabel = wrotedo wierzchołków odpowiedzialnych za ich autorów. Funkcja zwraca warto´sci pólname.

def a u t h o r s O f P a p e r B y N a m e ( name ) {

retu rn g . V . has ( ’ ele ment_t ype ’ , ’ paper ’) . has ( ’ name ’ , name ). in ( ’ wrote ’). name }

5. mostCitedPapers- funkcja dla wszystkich wierzchołków zawieraj ˛acych pu-blikacje wyszukuje ich referencje (out(’cite’)), po czym zlicza ich nazwy

name, a wynik zapisuje w mapiem. def m o s t C i t e d P a p e r s () {

m = [:]

g . V . out ( ’ cite ’). name . g r o u p C o u n t ( m ). t oList () m = m . sort {a , b -> a . value <= > b . value } retu rn m

}

6. mostCitedAuthors - działa podobnie jak mostCitedPapers, z tym wyj ˛ at-kiem, ˙ze tym razem wyszukiwani i zliczani s ˛a autorzy prac.

def m o s t C i t e d A u t h o r s () { m = [:]

a ~= g . V . in ( ’ wrote ’). name . g r o u p C o u n t ( m ). t oList () m = m . sort {a , b -> a . value <= > b . value }

retu rn m }

7. sameReferancesAsByName - funkcja wyszukuje autorów prac, którzy pisz ˛ac swoje prace wykorzystuj ˛a te same pozycje bibliograficzne co zadany autor. W tym celu najpierw jest wyszukiwany wierzchołek odpowiedzialny za au-tora z prawidłow ˛a nazw ˛a, po czym zapytanie przesuwa si˛e do referencji jego prac (zapisuj ˛ac do zmiennejxprace, które on sam napisał). Nast˛epnie znaj-dywane s ˛a prace, które wykorzystuj ˛a te same referencje, wykluczaj ˛ac z nich prace zadanego autora (in(’cite’).except(x)). Potem funkcja przesuwa si˛e do wierzchołków odpowiedzialnych za autorów tych prac, zlicza ich wy-st ˛apienia i zapisuje wynik w mapiem. Metodadedupusuwa duplikaty z wy-niku.

def s a m e R e f e r a n c e s A s B y N a m e ( name ) { m = [:]

x = []

g . V . has ( ’ name ’ , name )

. out ( ’ wrote ’). store ( x ) . out ( ’ cite ’)

. in ( ’ cite ’). ex cept ( x ). dedup ()

. in ( ’ wrote ’). name . g r o u p C o u n t ( m ). t oList () m = m . sort {a , b -> a . value <= > b . value }

retu rn m }

8. sameAuthorReferancesAsByName - działa podobnie do funkcji

sameReferancesAsByName. Jej analiz˛e pozostawiono jako proste ´cwiczenie dla czytelnika.

def s a m e A u t h o r R e f e r a n c e s A s B y N a m e ( name ) { m = [:]

x = [] y = []

g . V . has ( ’ name ’ , name ). store ( x ) . out ( ’ wrote ’). store ( y ) . out ( ’ cite ’)

. in ( ’ wrote ’). ex cept ( x ) . out ( ’ wrote ’)

. in ( ’ cite ’). ex cept ( y ). dedup ()

. in ( ’ wrote ’). name . g r o u p C o u n t ( m ). t oList () m = m . sort {a , b -> a . value <= > b . value }

retu rn m }

Wymienione funkcje znajduj ˛a si˛e w plikugremlin.groovy. Same skrypty wy-konywane s ˛a za pomoc ˛a interfejsu udost˛epnionego przezBulbflowprzez odpo-wiednie funkcje, które dalej operuj ˛a na danych np.:

def s a m e R e f e r a n c e s A s B y N a m e ( Name ): g = Graph ()

g . s c r i p t s . up date ( ’ g r e m l i n . groovy ’)

scri pt = g . s c r i p t s . get ( ’ s a m e R e f e r a n c e s A s B y N a m e ’) items = g . g r e m l i n . e x e c u t e ( script , dict ( name = Name )) m = items . c o n t e n t if ( len ( m ) ): s o r t e d _ m = so rted ( m . i t e r i t e m s () , key = o p e r a t o r . i t e m g e t t e r (1)) retu rn s o r t e d _ m else : retu rn None

5.6. Podsumowanie Do ka˙zdej wcze´sniej omówionej funkcji napisanej w groovy została stworzona funkcja w Pythonie, która odbiera, przetwarza i udost˛epnia stworzonemu UI od-powiednie dane. Wszystkie te funkcje umieszczone s ˛a w plikulibrary.py.

Interfejs u˙zytkownika

Na potrzeby demonstracji napisano w Pythonie minimalistyczny konsolowy interfejs u˙zytkownika. Wykorzystuje on bibliotek˛ecursesdo stworzenia menu, które pozwala wybra´c polecenie dla bazy. Klasa menu została pobrana zhttp: //www.promisc.org/blog/?p=33. Funkcje, klasy i metody odpowiedzialne za menu zamieszczono wlibrary.py,menu.py. Odpowiedzi na zapytania s ˛a wy-´swietlane w konsoli. Wywołanie programu znajduje si˛e w plikumainLibrary.py.

Powiązane dokumenty