Spis tre艣ci
I Wst臋p
Wst臋p
Dzia艂alno艣膰 ka偶dej firmy wi膮偶e si臋 z tworzeniem i zapami臋tywaniem du偶ej ilo艣ci danych r贸偶nego rodzaju - o klientach, rynkach, sprzeda偶y. W przypadku du偶ych firm ilo艣膰 tych danych jest ogromna i stale ro艣nie. Oczywi艣cie dane te nie s膮 gromadzone bez powodu - ich staranna analiza dostarcza wielu informacji i cz臋sto u艂atwia podejmowanie strategicznych dla firmy decyzji. W praktyce okazuje si臋 jednak, 偶e im wi臋ksza liczba danych, tym trudniejszy dost臋p do nich. Jeste艣my wprawdzie w stanie je magazynowa膰, jednak ich ilo艣膰 uniemo偶liwia efektywne odszukiwanie i przegl膮danie niezb臋dnych informacji. Eksperci szacuj膮, 偶e w du偶ych firmach decydenci maj膮 dost臋p do bardzo niewielkiej cz臋艣ci zgromadzonej informacji, a przecie偶 w艂a艣nie ona stanowi podstaw臋, przy podejmowaniu wa偶nych decyzji. Zjawisko to okre艣la si臋 czasem „uwi臋zieniem danych”.
Magazyn danych (hurtownia danych, ang. data warehouse) jest pr贸b膮 rozwi膮zania tego problemu - wydobycia z ogromnych baz danych niezb臋dnej wiedzy. Hurtownie przechowuj膮 informacj臋, analizowan膮 p贸藕niej z wykorzystaniem technik OLAP (przetwarzanie analityczne na bie偶膮co - On-Line Analitycal Processing), a przechowywana informacja ma zwykle charakter wielowymiarowy. Hurtownie danych s膮 wi臋c praktycznym wykorzystaniem trzech nowoczesnych trend贸w rozwojowych obejmuj膮cych:
przetwarzanie analityczne na bie偶膮co (OLAP - on-line anaytical processing),
wielowymiarowe bazy danych,
odkrywanie wiedzy.
Cel i zakres pracy
Celem pracy jest zaprojektowanie i implementacja systemu hurtowni danych o okre艣lonych wymaganiach. Najwa偶niejsze przedstawiono poni偶ej:
W odr贸偶nieniu od istniej膮cych i dzia艂aj膮cych na rynku system贸w OLAP, chcieliby艣my, aby nasz system utrzymywa艂 przez ca艂y czas pracy aktualne dane - czyli dba艂 o ich sp贸jno艣膰 z danymi zawartymi w 藕r贸d艂owych bazach danych. Cecha ta staje si臋 po偶膮dana poniewa偶 od aktualnej informacji zgromadzonej w hurtowni zale偶膮 strategiczne decyzje dotycz膮ce rozwoju firmy.
Wym贸g aktualno艣ci danych w magazynie stawia kolejne wymaganie - efektywno艣膰 procesu aktualizacji danych w magazynie. Po偶膮dane jest zminimalizowanie czasu mi臋dzy zmian膮 danych w 藕r贸d艂owych bazach danych, a aktualizacj膮 danych w magazynie. Dlatego przyj臋li艣my, 偶e dane w magazynie powinny by膰 sk艂adowane przyrostowo (inkrementalnie) - oznacza to aktualizowanie magazynu jedynie o nowe informacje, uwzgl臋dniaj膮c jego poprzedni膮 zawarto艣膰.
Praktyka pokazuje, 偶e gotowe oprogramowanie wymaga piel臋gnacji, a praca nad projektem ko艅czy si臋 dopiero w momencie zaprzestania jego u偶ywania. Dlatego podstawow膮 cech膮 umo偶liwiaj膮c膮 u偶ytkowanie systemu i dostosowywanie do zmieniaj膮cych si臋 warunk贸w jego pracy jest 艂atwo艣膰 jego rozbudowy. Chodzi przede wszystkim o mo偶liwo艣膰 obs艂ugi nowych standard贸w baz danych oraz mo偶liwo艣膰 wykorzystania informacji magazynowych w tworzonych na potrzeby firmy aplikacjach.
Architektura systemu
Na poni偶szym rysunku przedstawiono schemat systemu umo偶liwiaj膮cego spe艂nienie podanych wymaga艅:
Otoczenie systemu stanowi膮 藕r贸d艂owe bazy danych (na rysunku 藕r贸d艂a) i z nich czerpane s膮 informacje, kt贸re magazynujemy. Miejscem ich magazynowania jest magazyn danych (ang. data warehouse). Jak wida膰 na rysunku, ca艂o艣膰 systemu sk艂ada si臋 z czterech modu艂贸w. Modu艂 integratora jest odpowiedzialny, za sk艂adowanie danych w magazynie. Nie odwo艂uje si臋 on jednak bezpo艣rednio do 藕r贸d艂owych baz danych, lecz za po艣rednictwem modu艂贸w pomocniczych. Monitor zajmuje si臋 „艣ledzeniem” zmian w 藕r贸d艂owej bazie danych i informowaniem o tym integratora. Na tej podstawie integrator wykonuje aktualizacj臋 magazynu. U偶ywa w tym celu modu艂u wrappera, jako po艣rednika w odwo艂aniach do baz danych. Integrator nie musi wi臋c zna膰 szczeg贸艂贸w implementacyjnych zwi膮zanych z 藕r贸d艂owymi bazami danych. Wszystkie informacje z艂o偶one w magazynie s膮 dost臋pne dla u偶ytkownika za pomoc膮 modu艂u query processora. Stanowi on interfejs, mi臋dzy magazynem a u偶ytkownikiem - transformuje zapytania u偶ytkownika, wykonuje je i dostarcza gotowe wyniki.
Z przyj臋tych wcze艣niej za艂o偶e艅 wynika przydzia艂 dla ka偶dej 藕r贸d艂owej bazy danych osobnej pary monitor / wrapper. Jedynie te modu艂y komunikuj膮 si臋 bezpo艣rednio z bazami 藕r贸d艂owymi, wi臋c jedynie one musz膮 zna膰 odpowiednie protoko艂y komunikacji i sposoby wymiany danych. Umo偶liwia to uniezale偶nienie systemu od system贸w zastosowanych w 藕r贸d艂owych bazach danych. Je偶eli chcemy rozbudowa膰 nasz system o obs艂ug臋 nie znanego standardu bazy danych, musimy dopisa膰 te dwa modu艂y.
Zakres pracy obejmuje zaprojektowanie i implementacj臋 czterech modu艂贸w systemu:
modu艂 monitora,
modu艂 wrappera,
modu艂 integratora,
modu艂 query processora.
Zak艂adamy opracowanie jednej pary monitor / wrapper dla systemu zarz膮dzania baz膮 danych firmy Oracle. Zak艂adamy r贸wnie偶, 偶e magazyn danych opiera膰 si臋 b臋dzie r贸wnie偶 na systemie firmy Oracle. Cz臋艣ci膮 pracy jest opracowanie ujednoliconych protoko艂贸w komunikacji mi臋dzy poszczeg贸lnymi modu艂ami a tak偶e postaci naszego magazynu - jego s艂ownika i cz臋艣ci magazynowej.
Podzia艂 zada艅
Projektuj膮c nasz system, podzielili艣my si臋 zadaniami w nast臋puj膮cy spos贸b:
modu艂 wrappera - Daniel Krawiec,
modu艂 monitora - Pawe艂 Orzechowski,
modu艂 integratora - Krzysztof Ostrowski,
modu艂 query processora - Arkadiusz Ka藕mierowski.
Zadania opracowania specyfikacji odpowiednich protoko艂贸w komunikacyjnych i postaci magazynu przypadaj膮 tw贸rcom modu艂贸w z nich korzystaj膮cych, tak wi臋c:
za opracowanie specyfikacji protoko艂u u偶ywanego do komunikacji mi臋dzy integratorem i monitorem odpowiedzialni s膮 Pawe艂 Orzechowski i Krzysztof Ostrowski,
za opracowanie specyfikacji protoko艂u u偶ywanego do komunikacji mi臋dzy integratorem i wrapperem odpowiedzialni s膮 Daniel Krawiec i Krzysztof Ostrowski,
za opracowanie og贸lnej struktury magazynu (jego relacji) odpowiedzialni s膮 Arkadiusz Ka藕mierowski i Krzysztof Ostrowski,
opracowania programu u艂atwiaj膮cego u偶ytkownikowi skonfigurowanie s艂ownika magazynu podj膮艂 si臋 Krzysztof Ostrowski.
Wyb贸r j臋zyk贸w programowania i narz臋dzi programistycznych, u偶ywanych do tworzenia danego modu艂u nale偶y do jego tw贸rcy.
Przetwarzanie analityczne w trybie on-line (OLAP)
Wprowadzenie
S艂owo OLAP (ang. On-Line Analytical Processing) po raz pierwszy pojawi艂o si臋 w literaturze w roku 1993 (artyku艂 E.F. Codd & Associates Providing OLAP to User-Analysts: An IT Mandate). Mimo kilkuletniej historii samego terminu o 偶adnej z jego definicji nie mo偶na powiedzie膰, 偶e zosta艂a powszechnie przyj臋ta i jest przez wszystkich uznawana. Gdy m贸wimy - OLAP, my艣limy zwykle - narz臋dzie do wygodnej i szybkiej analizy danych z r贸偶nych obszar贸w dzia艂alno艣ci przedsi臋biorstwa. Najwa偶niejsz膮, a zarazem jedyn膮 zgodnie podawan膮 przez wszystkie popularne definicje, cech膮 technologii OLAP jest wielowymiarowo艣膰.
Zadaniem OLAP jest dostarczenie - w jak najefektywniejszy spos贸b - informacji strategicznej dla danego przedsi臋biorstwa i prezentowanie jej zgodnie z ludzkimi schematami poznawczymi. W du偶ej cz臋艣ci obecnych system贸w informatycznych jest za du偶o danych, a za ma艂o informacji niezb臋dnej by odpowiedzie膰 na nurtuj膮ce kierownik贸w i analityk贸w pytania. Odpowiedzi te s膮 niejednokrotnie kluczem do utrzymania si臋 firmy na wymagaj膮cym, zmieniaj膮cym si臋 w szybkim tempie rynku. Narz臋dzia OLAP zalicza si臋 do kategorii oprogramowania nazywanej systemami wspomagania decyzji; SWD (ang. DSS - Decision Support Systems), kt贸ra obejmuje opr贸cz aplikacji wywodz膮cych si臋 z nurtu bazodanowego - jak OLAP - r贸wnie偶 te powsta艂e w oparciu o zaawansowane modelowanie matematyczne. Uzupe艂nieniem powy偶szych s膮 narz臋dzia Data Mining czyli eksploracji danych - r贸wnie偶 operuj膮ce na hurtowniach danych - kt贸rych zadaniem jest odkrywanie pewnych wzorc贸w, schemat贸w czy trend贸w trudnych do spostrze偶enia innymi metodami. 艁膮cznie, narz臋dzia te wraz z technologi膮 hurtowni danych nosz膮 miano Business Intelligence (termin Gartner Group) a ich zadaniem jest zamiana 藕r贸d艂owych danych w warto艣ciow膮 informacj臋 i dostarczanie jej w r臋ce u偶ytkownika w celu szybszego podejmowania w艂a艣ciwych decyzji. Przewa偶nie u偶ytkownik贸w takich narz臋dzi jest w firmie (lub jej dziale) kilku, kilkunastu. ostatnio jednak panuje trend do rozmieszczania oprogramowania klienckiego OLAP na biurkach pracownik贸w ni偶szego szczebla jak na przyk艂ad szef贸w kom贸rek przedsi臋biorstwa tak by mogli stale kontrolowa膰 swoj膮 pozycj臋 finansow膮 na tle ca艂ej organizacji. Hurtownie danych i systemy OLAP wzajemnie si臋 uzupe艂niaj膮. Hurtownie gromadz膮 dane i odpowiednio nimi zarz膮dzaj膮, OLAP przekszta艂ca te dane w strategiczn膮 informacj臋.
Wielowymiarowa perspektywa oraz du偶a interakcyjno艣膰 analiz wyr贸偶nia narz臋dzia OLAP spo艣r贸d innych rodzaj贸w oprogramowania analitycznego. Uwa偶a si臋, 偶e model ten jest bliski schematowi informacyjnemu cz艂owieka i stanowi naturalny spos贸b prezentacji i poruszania si臋 w艣r贸d danych dotycz膮cych organizacji i jej dzia艂alno艣ci. Przeci臋tny u偶ytkownik system贸w wspomagania decyzji dyrektor, kierownik czy analityk nie b臋d膮cy przecie偶 specjalist膮 od baz danych, z trudem porusza si臋 w艣r贸d schemat贸w relacyjnych czy polece艅 SQL S膮 to dla niego poj臋cia obce i stanowi膮ce dodatkowy balast utrudniaj膮cy uchwycenie istoty rzeczy.
W przypadku OLAP 艂atwiej jest ogarn膮膰 przedsi臋biorstwo czy organizacj臋 jako ca艂o艣膰 a dzi臋ki prostocie i szybko艣ci analizy zmniejsza si臋 zagubienie w informacji i mo偶liwo艣膰 jej b艂臋dnej interpretacji. Dzi臋ki zgromadzeniu danych w jednym miejscu, w postaci jednej, wsp贸lnej, wielowymiarowej kostki przedsi臋biorstwo mo偶e by膰 ogl膮dane i analizowane przez wszystkich maj膮cych uprawniony dost臋p (to wa偶na cecha odr贸偶niaj膮ca OLAP od aplikacji typu EIS gdzie dost臋p do nich mieli przewa偶nie tylko kierownicy wysokiego szczebla). Ten podobny, standardowy spos贸b prezentacji danych i informacji stanowi wsp贸lny mianownik dla tego typu analiz. Informacja mo偶e by膰 st膮d wydobywana pod r贸偶nymi k膮tami widzenia - w zale偶no艣ci od tego czy analizy dokonuje kierownik pewnego produktu czy szef marketingu. Ich spojrzenia s膮 r贸偶ne ale korzystaj膮 oni ze wsp贸lnego modelu poj臋ciowego przedsi臋biorstwa
Cechy OLAP
Wielowymiarowo艣膰 nie jest nowym poj臋ciem. Postrzegamy 艣wiat jako tr贸jwymiarowy - aby okre艣li膰 po艂o偶enie przedmiotu podajemy jego odleg艂o艣膰, czy jest na lewo, czy na prawo, wy偶ej czy ni偶ej. Zwykle kojarzymy lini臋 z jednym wymiarem, p艂aszczyzn臋 - z dwoma, przestrze艅 - z trzema. Pr贸bujemy wyobra偶a膰 sobie czas jako czwarty wymiar. W modelach niekt贸rych zjawisk fizycznych jako pi膮ty wymiar traktuje si臋 mas臋 (wzgl臋dnie energi臋). Matematyka - w przeciwie艅stwie do ludzkiej percepcji - nie zna ogranicze艅 na liczb臋 wymiar贸w (rozwi膮za艅 uk艂adu r贸wna艅 z n niewiadomymi szuka si臋 w przestrzeni n-wymiarowej).
Podstaw膮 modelu OLAP s膮:
wymiary - opisuj膮 kluczowe aspekty dzia艂ania organizacji jak czas, produkt, us艂uga, geografia, klient, kana艂y dystrybucyjne, personel, 艣rodki trwa艂e itd.,
miary - warto艣ci (przewa偶nie) liczbowe stanowi膮ce przedmiot analiz takie jak sprzeda偶, liczba sztuk, liczba awarii, liczba reklamacji, liczba impuls贸w.
Koncepcyjnie model ten przedstawia si臋 jako hiperkostk臋, kt贸ra w swoim wn臋trzu zawiera miary natomiast wymiary stanowi膮 jej brzegi. Poniewa偶 wszelkie analizy, por贸wnania, zestawienia dotycz膮 r贸偶nych poziom贸w szczeg贸艂owo艣ci wymiary posiadaj膮 przewa偶nie wewn臋trzn膮 hierarchiczn膮 struktur臋 (jedn膮 lub kilka w zale偶no艣ci od potrzeb) u艂atwiaj膮c膮 przechodzenie od og贸艂u do szczeg贸艂u i z powrotem.
Wymiary
Podobnie jak w przypadku terminu OLAP, nie istnieje powszechnie przyj臋ta i stosowana definicja wymiaru. Taki stan rzeczy wynika g艂贸wnie z faktu, 偶e rynek narz臋dzi tej klasy jest bardzo m艂ody i dopiero rodz膮 si臋 porz膮dkuj膮ce go standardy, a to z kolei powoduje, 偶e wymiary w kontek艣cie poszczeg贸lnych narz臋dzi r贸偶ni膮 si臋 mi臋dzy sob膮 funkcjonalno艣ci膮. Bardzo og贸lna a zarazem prosta definicja wymiaru pojawi艂a si臋 na pocz膮tku niniejszego artyku艂u - wymiar to zbi贸r element贸w klasyfikuj膮cy dane.
Najcz臋艣ciej u偶ywane wymiary maj膮 struktur臋 drzewa element贸w. Takie drzewo nazywane jest hierarchi膮 wymiaru, a grupa element贸w po艂o偶onych na tej samej g艂臋boko艣ci w drzewie - poziomem hierarchii. Wymiar mo偶e zawiera膰 wi臋cej ni偶 jedn膮 hierarchi臋 (nale偶y w贸wczas ustali膰, kt贸ra hierarchia ma by膰 hierarchi膮 domy艣ln膮), co pozwala zdefiniowa膰 r贸偶ne sposoby przechodzenia „od og贸艂u do szczeg贸艂u” (od sumy dla wszystkich produkt贸w do warto艣ci dla soku jab艂kowego, etc.). Struktura wymiaru nie mo偶e zawiera膰 cykli, dlatego za pomoc膮 hierarchii (drzew) mo偶na przedstawi膰 dowolne prawid艂owe powi膮zania mi臋dzy elementami w wymiarze.
Zwi膮zki mi臋dzy elementami zwykle maj膮 charakter statyczny. Definiuje si臋 je bezpo艣rednio, a wi臋c poprzez wskazanie dw贸ch element贸w: rodzica i potomka. Czasem jednak wygodnie jest zdefiniowa膰 zwi膮zki dynamiczne, czyli takie, w kt贸rych zaistnienie mi臋dzy dwoma elementami relacji rodzic-potomek, zale偶y od spe艂nienia ustalonego warunku. Przyk艂adem dynamicznej hierarchii mo偶e by膰 podzia艂 wszystkich produkt贸w na trzy grupy (wg zysku wygenerowanego w 1998 roku): zysk poni偶ej 1聽mln, zysk od 1聽mln do 10聽mln, zysk powy偶ej 10聽mln. Warto w tym miejscu zaznaczy膰, 偶e kryterium podzia艂u musi opiera膰 si臋 wy艂膮cznie na zawarto艣ci bazy danych, a nie mo偶e zale偶e膰 od aktualnie ogl膮danego przez u偶ytkownika zestawienia.
Elementom wymiaru mo偶na przypisywa膰 atrybuty. Ze wzgl臋du na przeznaczenie wyr贸偶nia si臋 dwa rodzaje atrybut贸w: opisowe (tekstowe - adres klienta, numeryczne - waga produktu, inne - data rozpocz臋cia sprzeda偶y produktu) i aliasy. Atrybuty opisowe dostarczaj膮 dodatkowych (rzadko zmieniaj膮cych si臋 lub o ma艂o interesuj膮cej z punktu widzenia analizy historii) danych do sporz膮dzania raport贸w oraz s艂u偶膮 do generowania zapyta艅 wewn膮trz wymiaru (na przyk艂ad: poka偶 dane dla produkt贸w o wadze powy偶ej 1 kg). Aliasy stanowi膮 alternatywny w stosunku do g艂贸wnych nazw spos贸b identyfikowania element贸w w wymiarze. Cecha ta nabiera ogromnego znaczenia przy tworzeniu aplikacji wieloj臋zycznych (u偶ytkownik mo偶e wybra膰, czy chce si臋 pos艂ugiwa膰 polskimi, angielskimi, czy niemieckimi nazwami produkt贸w - oczywi艣cie o ile nazwy w podanych j臋zykach zosta艂y wcze艣niej zdefiniowane).
Niekt贸re narz臋dzia wyr贸偶niaj膮 wymiary kategorii danych (nazywane te偶 wymiarami miar) oraz wymiary czasu. W ka偶dej kostce musi znale藕膰 si臋 dok艂adnie jeden wymiar kategorii danych i co najwy偶ej jeden wymiar czasu. Wymiar kategorii danych definiuje typy danych przechowywanych w kostce (najcz臋艣ciej dane numeryczne, czasem - tekstowe) i jest silnie zwi膮zany ze sposobem, w jaki system przechowuje dane zawarte w kostce na dysku i w pami臋ci operacyjnej. Wymiar czasu podczas analizy jest domy艣lnie umieszczany w kolumnach tabeli, a na wykresie na osi X, dodatkowo wspomagane jest prezentowanie danych narastaj膮co, na przyk艂ad od pocz膮tku roku.
Model hiperkostki
Kostka to przestrze艅 danych zbudowana za pomoc膮 co najmniej dw贸ch wymiar贸w. W typowych zastosowaniach liczba wymiar贸w w kostce nie przekracza 10. Kostki zwykle przechowuj膮 dane numeryczne, rzadziej - tekstowe. Zestawienie danych kostki ogl膮dane przez u偶ytkownika nazywane jest widokiem. W widoku wyr贸偶nia si臋 wymiary w wierszach, wymiary w kolumnach oraz wymiary tytu艂owe.
Dane widoku stanowi膮 podzbi贸r danych kostki. Istniej膮 dwa mechanizmy zaw臋偶ania zbioru danych:
dla wymiar贸w w wierszach i kolumnach - wyb贸r podzbioru element贸w wymiaru (zwanego te偶 zestawem element贸w),
dla wymiar贸w tytu艂owych - rzutowanie kostki na pojedyncze elementy wymiaru.
Poszczeg贸lni producenci troszcz膮 si臋 o to, by analizowanie danych stawa艂o si臋 coraz 艂atwiejsze i jednocze艣nie jak najbardziej efektywne. St膮d wiele system贸w klasy OLAP z jednej strony oferuje u偶ytkownikowi proste mechanizmy tworzenia modeli i przelewania danych z system贸w ewidencyjnych, z drugiej - zapewnia p艂ynn膮 zmian臋 formy wy艣wietlania danych (tabela, wykres, mapa) oraz wspomaga tworzenie dynamicznych raport贸w o bogatej szacie graficznej.
Oczywi艣cie analizy sprzeda偶y nie s膮 jedyn膮 dziedzin膮 zastosowa艅 technologii OLAP. Narz臋dzia wielowymiarowe u偶ywane s膮 tak偶e w analizach finansowych, planowaniu strategicznym, sprawozdawczo艣ci bankowej, a z zastosowa艅 nietypowych - mog膮 s艂u偶y膰 na przyk艂ad do badania skuteczno艣ci reklamy.
Podzia艂 system贸w OLAP
OLAP jest dzisiaj postrzegany jako kluczowa technologia dostarczania danych do analiz w wydajny i jednocze艣nie intuicyjny spos贸b. Sam termin OLAP nie jest stary, niemniej historia narz臋dzi tego typu si臋ga dwadzie艣cia lat wstecz, kiedy to firma Express tworzy艂a sw贸j pierwszy produkt, a niekt贸rzy jego korzeni doszukuj膮 si臋 w j臋zyku APL, opieraj膮cym si臋 o wielowymiarowe struktury danych, stworzonym ju偶 ponad trzydzie艣ci lat temu. Dzisiaj po firmie Express zachowa艂a si臋 jedynie nazwa produktu, znajduj膮cego si臋 obecnie w ofercie jednego z gigant贸w rynku baz danych, a termin OLAP mo偶emy us艂ysze膰 wsz臋dzie, cz臋sto z r贸偶nymi, poprzedzaj膮cymi go literkami: ROLAP, MOLAP czy HOLAP. Rdze艅 wsz臋dzie pozostaje ten sam: OLAP, a wraz z nim to na czym najbardziej zale偶y u偶ytkownikom: intuicyjno艣膰 modelu, proste tworzenie raport贸w, analiz i zapyta艅 „ad hoc”, jednym zdaniem - „dobry interfejs analityczny”. I tak naprawd臋 na tym podobie艅stwa si臋 ko艅cz膮. Poza interfejsem s膮 bowiem jeszcze 藕r贸d艂a danych oraz prawdziwe potrzeby u偶ytkownika.
ROLAP
Na pocz膮tek przyjrzyjmy si臋 „R” jak „relational” czyli „relacyjny”. Relacyjne bazy danych jako 藕r贸d艂o danych dla system贸w analitycznych wydaj膮 si臋 rozwi膮zaniem najprostszym. Prawie ka偶da firma ma system ewidencyjny oparty o tak膮 baz臋 danych, zatem nic 艂atwiejszego ni偶 kupi膰 interfejs, kt贸ry przedstawi dane w uj臋ciu wielowymiarowym, zrozumia艂ym dla analityka. Niestety, chocia偶 wielu sprzedawc贸w twierdzi, 偶e aby otrzyma膰 upragniony system analityczny wystarczy pod艂膮czy膰 do istniej膮cej w firmie bazy danych ich produkty, to jednak wdro偶enie systemu typu ROLAP prawie zawsze wi膮偶e si臋 co najmniej ze stworzeniem kopii bazy operacyjnej. Dlaczego? Powod贸w jest wiele.
Istnieje wiele wymog贸w formalnych dla takich baz. Okazuje si臋 bowiem, 偶e dla systemu OLAP dane trzeba przedstawi膰 w specjalny spos贸b, kt贸ry nazywa si臋 uk艂adem „gwiazdy” lub „p艂atka 艣niegu”. Polega to na tym, 偶e jednemu z wymiar贸w odpowiada tablica fakt贸w (niestety najcz臋艣ciej mo偶e by膰 tylko jedna), a pozosta艂e wymiary przechowywane s膮 w dodatkowych tablicach. Hierarchie s膮 budowane na dwa sposoby: dla uk艂adu gwiazdy s膮 przechowywane w kolumnach, a w schemacie p艂atka 艣niegu - w kolejnych tablicach. Trudno powiedzie膰 jednoznacznie, kt贸re rozwi膮zanie jest lepsze. W pierwszym zyskujemy na pr臋dko艣ci, w drugim na pami臋ci dyskowej i trzeba du偶ego do艣wiadczenia, 偶eby odnale藕膰 z艂oty 艣rodek. Mo偶na oczywi艣cie wym贸g stosowania odpowiedniej struktury zgrabnie omin膮膰, stosuj膮c wirtualne widoki utworzone na znormalizowanej bazie danych. Mo偶na tego dokona膰 buduj膮c je bezpo艣rednio na serwerze bazy danych lub definiuj膮c w samym programie. Jednak pr贸ba wygenerowania kilku raport贸w sprawi, 偶e odrzucimy ten, jak偶e wygodny na pierwszy rzut oka spos贸b, ze wzgl臋d贸w wydajno艣ciowych. Dzieje si臋 tak dlatego, 偶e zbudowanie niekt贸rych skomplikowanych wielowymiarowych raport贸w wymaga wykonania wielokrotnie zagnie偶d偶onych zapyta艅. Pozostaje zatem replikacja do dedykowanych struktur.
Potrzeba tworzenia drugiej bazy danych wynika r贸wnie偶 z innych przes艂anek. Od system贸w analitycznych wymaga si臋 du偶ej wydajno艣ci bez zaburzania pracy operacyjnej bazy danych, co powoduje konieczno艣膰 tworzenia oddzielnych zoptymalizowanych struktur, takich jak opisane powy偶ej. Cz臋sto istnieje potrzeba zasilania systemu z wielu 藕r贸de艂, a nawet aplikacji lokalnych, cho膰by w przypadku wielooddzia艂owych firm, pos艂uguj膮cych si臋 z powod贸w historycznych, r贸偶nymi systemami. Nowa, sp贸jna analityczna baza danych jest w贸wczas jedynym rozwi膮zaniem. Kolejnym bardzo istotnym powodem takiej duplikacji jest konieczno艣膰 oczyszczenia i uzupe艂nienia danych do analiz. Opr贸cz tego, 偶e w ka偶dej bazie istnieje niewielki procent przypadkowo niesp贸jnych danych, to dodatkowych problem贸w nastr臋czaj膮 pola wype艂niane opcjonalnie, kt贸re dla u偶ytkownik贸w systemu analitycznego mog膮 mie膰 du偶e znaczenie. Podobnie ma si臋 rzecz z dopasowywaniem danych, czy to spowodowanym u偶ywaniem r贸偶nych standard贸w zapisu w oddzia艂ach (na przyk艂ad plan贸w kont ksi臋gowych), czy to potrzeb膮 uzupe艂nienia systemu o dodatkowe dane (demograficzne lub statystyczne). Inn膮 przyczyn膮 tworzenia oddzielnej bazy danych mo偶e by膰 fakt, 偶e dane w systemach 藕r贸d艂owych s膮 od艣wie偶ane z r贸偶n膮 cz臋stotliwo艣ci膮 (na przyk艂ad w jednym raz na miesi膮c, a w innym raz na tydzie艅), tymczasem analizy musz膮 opiera膰 si臋 na zawsze sp贸jnych danych. Przyczyn konieczno艣ci tworzenia drugiej bazy danych mo偶na wymieni膰 wi臋cej: potrzeba analiz danych historycznych, kt贸re cz臋sto nie s膮 przechowywane w bazach operacyjnych, czy niezbyt mile widziana potrzeba zapisu do nich dodatkowych informacji z zewn臋trznych 藕r贸de艂.
Podsumowuj膮c, przy wdro偶eniu systemu ROLAP, niemal zawsze trzeba stworzy膰 drug膮 baz臋 danych, wy艂膮cznie do cel贸w analitycznych. Oznacza to po prostu zbudowanie hurtowni danych, cho膰by tematycznej. Jest to oczywiste dla tych, kt贸rzy takow膮 posiadaj膮 lub s膮 w trakcie jej tworzenia, ale nie dla nie艣wiadomych nabywc贸w samego systemu OLAP.
Mimo to, systemy ROLAP s膮 bardzo popularne. Ich wyb贸r jest „naturalny”, poniewa偶 u偶ytkownicy posiadaj膮 ju偶 operacyjn膮, relacyjn膮 baz臋 danych lub, co jest silniejszym powodem, posiadaj膮 hurtowni臋 danych zrealizowan膮 w tej technologii. Ogromn膮 zalet膮 rozwi膮zania opartego na relacyjnej bazie danych jest niemal nieograniczona pojemno艣膰 systemu. Dotyczy ona zar贸wno danych (poddawanych analizom), jak i metadanych - element贸w wymiar贸w analitycznych, czy samych wymiar贸w. Niestety, wraz ze wzrostem wielko艣ci, maleje wydajno艣膰 takiej bazy danych. Powsta艂o wiele sposob贸w na omini臋cie tej wady, pocz膮wszy od wspominanych ju偶, opartych na denormalizacji, struktur gwiazdy i p艂atka 艣niegu (kt贸re dodatkowo dobrze odwzorowuj膮 struktury wielowymiarowe), a偶 po u偶ywanie skomplikowanych narz臋dzi, kt贸re jednak wymagaj膮 du偶ego wysi艂ku zwi膮zanego z ich wdro偶eniem i bardzo cz臋sto efekty ich u偶ycia nie s膮 satysfakcjonuj膮ce. Kolejny problem z wydajno艣ci膮 pobierania danych w systemach relacyjnych polega na niedostatkach SQL, kt贸ry nie posiada mo偶liwo艣ci przeprowadzania wielowymiarowych oblicze艅 w pojedynczym zapytaniu. Konieczne jest u偶ywanie z艂o偶onych, wielokrotnie powtarzanych zapyta艅. Producenci narz臋dzi pr贸buj膮 w r贸偶ny spos贸b omija膰 ten problem. Najprostszym jest stosowanie tablic agregacji, przechowuj膮cych przeliczone uprzednio podsumowania. Spos贸b ten powoduje jednak rozrost bazy i nie sprawdza si臋 przy cz臋sto zmieniaj膮cych si臋 danych. Podobnie - przy cz臋stym uaktualnianiu danych nie sprawdza si臋 przechowywanie raz pozyskanych informacji w pami臋ci operacyjnej serwera lub stacji klienckiej, cho膰 bardzo zwi臋ksza wydajno艣膰 systemu.
MOLAP
Dla przeciwwagi, o wiele wydajniejsze, lecz znacznie mniej pojemne s膮 wielowymiarowe bazy danych (ang. Multidimensional, st膮d litera „M” na pocz膮tku terminu MOLAP). Zastosowanie w nich zoptymalizowanych struktur, dopasowanych do wielowymiarowych oblicze艅 powoduje, 偶e ich prymat pod wzgl臋dem szybko艣ci przetwarzania analitycznego jest nie do podwa偶enia tak, jak przewaga baz relacyjnych pod wzgl臋dem potencjalnej ilo艣ci analizowanych danych. Ze wzgl臋du na zastosowanie odmiennej technologii, systemy MOLAP zawsze wymagaj膮 drugiej bazy danych (wielowymiarowej w艂a艣nie). Wbrew obiegowej opinii, coraz cz臋艣ciej zapewniaj膮 wielodost臋p oraz bardzo dobry system zabezpiecze艅 i kontroli dost臋pu. Stosowanie serwer贸w OLAP, jak nazywa si臋 wielowymiarowe bazy danych, jest coraz popularniejsze, tak ze wzgl臋du na ich wydajno艣膰, jak i na 艂atwo艣膰 budowy modeli (cz臋sto jest to wykonalne dla ko艅cowego u偶ytkownika) oraz prostej administracji. Ponadto bazy takie niemal nie wymagaj膮 dostrajania. Jednak i tutaj w ci膮gu kilku lat zdo艂a艂y si臋 ju偶 wykszta艂ci膰 dwie podklasy narz臋dzi: przechowuj膮ce podczas pracy dane na dysku (ang. Disk based MDB) oraz w pami臋ci operacyjnej (ang. RAM based MDB lub RAM Cubes). S膮 one na tyle r贸偶ne, 偶e nale偶y je rozpatrywa膰 osobno.
Dyskowe bazy wielowymiarowe zdecydowan膮 wi臋kszo艣膰 informacji przechowuj膮 w plikach o specyficznej strukturze i u偶ywaj膮 stosunkowo niewiele pami臋ci operacyjnej, te drugie pami臋膰 dyskow膮 u偶ywaj膮 jedynie do przechowywania danych pomi臋dzy sesjami oraz dla bezpiecze艅stwa. Pierwsze maj膮 wi臋ksz膮 pojemno艣膰, drugie s膮 znacznie szybsze. Wychodz膮c z za艂o偶enia, 偶e pami臋膰 RAM jest oko艂o 150 razy szybsza od dysku, ale r贸wnocze艣nie oko艂o 60 razy dro偶sza, 艂atwo obliczy膰, 偶e pami臋膰 operacyjna oferuje lepszy stosunek ceny do wydajno艣ci przetwarzania. Niestety - ograniczenia sprz臋towe powoduj膮, 偶e zakup dodatkowych ko艣ci RAM jest nieop艂acalny lub cz臋sto niemo偶liwy. Ponadto szybko艣膰 przetwarzania w bazach dyskowych mo偶e by膰 zwi臋kszana, ze wzgl臋du na brak ogranicze艅 co do zajmowanej pami臋ci. Jedn膮 z dost臋pnych metod jest stosowanie rozbudowanych metod indeksowania, znacznie usprawniaj膮cych dost臋p do danych, co nie jest mo偶liwe w bazach danych operuj膮cych w silnie ograniczonej pami臋ci RAM. Drugim sposobem jest prekalkulacja - wsadowe przeliczanie danych. Grozi ono jednak eksplozj膮 bazy danych, czyli nag艂ym wzrostem zaj臋to艣ci pami臋ci dyskowej. Pomimo 偶e coraz cz臋艣ciej stosowane s膮 zabezpieczenia, ograniczaj膮ce ryzyko takiego zdarzenia, to jednak i dzisiaj jest ono realnym zagro偶eniem. Prekalkulacja nie jest r贸wnie偶 wskazana w modelach dynamicznych, ze wzgl臋du na to, 偶e zajmuje du偶o czasu, co dla cz臋sto zmieniaj膮cych si臋 danych mo偶e znacznie spowalnia膰 prac臋 systemu, a staje si臋 nie do przyj臋cia w przypadku baz danych o wi臋cej ni偶 pi臋ciu wymiarach i danych bardzo rozsianych.
W przypadku dyskowych baz wielowymiarowych daje si臋 zauwa偶y膰 znana z baz relacyjnych zale偶no艣膰 - im szybsza baza, tym wi臋cej miejsca zajmuje na dysku. Natomiast systemy pracuj膮ce w pami臋ci operacyjnej swoj膮 szybko艣膰 zawdzi臋czaj膮 wydajno艣ci pami臋ci RAM, a na dysku zajmuj膮 stosunkowo niewiele miejsca. Jest to pod tym wzgl臋dem rozwi膮zanie bardzo wygodne i co wi臋cej, w bardzo wielu przypadkach, wystarczaj膮ce, cho膰 na pierwszy rzut oka ograniczenie w postaci okre艣lonej pami臋ci RAM wydaje si臋 by膰 powa偶ne. Rozwa偶my pojemno艣膰 modelu wielowymiarowego dla 500 MB RAM. Typowy system MOLAP bazuj膮cy na pami臋ci operacyjnej potrzebuje od 10 do 15 bajt贸w na liczb臋 (dla por贸wnania w dyskowych: 50 - 100 bajt贸w, a cz臋sto i wi臋cej, ze wzgl臋du na indeksowanie i prekalkulacj臋). Daje to pojemno艣膰 rz臋du 45 milion贸w kom贸rek. W wi臋kszo艣ci zastosowa艅, rozsianie danych analitycznych jest znacznie wi臋ksze od 99%. Wynika z tego teoretyczna pojemno艣膰 rz臋du 5 miliard贸w danych, co odpowiada du偶emu modelowi finansowemu. Analogiczna baza dyskowa, w najlepszym przypadku b臋dzie zajmowa艂a oko艂o 2,5 GB przy znacznie gorszej wydajno艣ci. Pozostaje pytanie, czy 500MB RAM to du偶o, czy ma艂o? Wydaje si臋, 偶e nie jest to zbyt wiele, poza tym rozbudowane systemy dyskowych baz wielowymiarowych, czy serwery baz relacyjnych wymagaj膮 por贸wnywalnej lub wi臋kszej ilo艣ci pami臋ci operacyjnej. Zatem wyb贸r systemu powinien zale偶e膰 od innych kryteri贸w ni偶 potrzebna ilo艣膰 czy cena pami臋ci operacyjnej i dyskowej.
HOLAP
Pr贸by po艂膮czenia technologii relacyjnej i wielowymiarowej (w obydwu wydaniach), zaowocowa艂y liter膮 „H”, powsta艂y systemy hybrydowe, HOLAP. Mamy tutaj do czynienia niemal z tyloma technikami realizacji takich po艂膮cze艅, ile tego typu produkt贸w jest dost臋pnych na rynku. Istnieje nawet narz臋dzie (a raczej jest ci膮gle zapowiadane) 艂膮cz膮ce technologi臋 relacyjn膮 z wielowymiarow膮 - dyskow膮, z jednoczesn膮 mo偶liwo艣ci膮 przechowywania danych w strukturach wielowymiarowych w pami臋ci operacyjnej zar贸wno na serwerze jak i na stacji klienckiej.
Najpopularniejszym rozwi膮zaniem w systemach hybrydowych jest u偶ywanie relacyjnej bazy danych jako 藕r贸d艂a danych i jednoczesne przechowywanie najcz臋艣ciej przetwarzanych informacji w strukturach wielowymiarowych w pami臋ci operacyjnej (RAM Cubes) na stacjach klienckich. Jest to po艂膮czenie najwydajniejszych strategii z punktu widzenia rozmiaru i szybko艣ci. Oczywiste jest jednak, 偶e tego typu rozwi膮zanie dziedziczy i wady swoich sk艂adnik贸w - pozyskanie nowych danych jest powolne, a ilo艣膰 pami臋ci na stacji roboczej zwykle ograniczona, co zmniejsza obszar szybkiej analizy. Zdarza si臋, 偶e dodatkowo niekt贸re, regularnie u偶ywane, dane przechowywane s膮 w wielowymiarowych plikach dyskowych (Disk Cubes), co mo偶e poprawia膰 w niekt贸rych wypadkach szybko艣膰 pozyskiwania i przetwarzania danych, ale znakomicie komplikuje struktur臋 systemu oraz utrudnia jego utrzymanie i administracj臋.
Mimo tego, 偶e producenci narz臋dzi hybrydowych stanowczo sugeruj膮, 偶e ich systemy 艂膮cz膮 pojemno艣膰 system贸w relacyjnych z wydajno艣ci膮 wielowymiarowych, to nie jest to do ko艅ca prawd膮. Ze wzgl臋du na u偶ycie relacyjnych baz danych jako podstawowego 藕r贸d艂a danych pierwsza cz臋艣膰 stwierdzenia jest niepodwa偶alna, druga - nieco przesadzona. Owszem, wydajno艣膰 systemu hybrydowego jest zazwyczaj wi臋ksza ni偶 analogicznego, opartego tylko na bazie relacyjnej, ale nie mo偶e r贸wna膰 si臋 z szybko艣ci膮 przetwarzania baz wielowymiarowych, szczeg贸lnie je偶eli spojrzymy z punktu widzenia ca艂o艣ci przechowywanych danych, a nie tylko wycinka aktualnie analizowanego na stacji klienckiej. Bior膮c pod uwag臋 r贸wnie偶 to, 偶e systemy hybrydowe dziedzicz膮 wady ROLAP - ograniczone mo偶liwo艣ci zapisu, trudno艣ci w administracji - nie nale偶y s膮dzi膰, 偶e wyeliminuj膮 one narz臋dzia wielowymiarowe tam, gdzie nie zagrozi艂y im relacyjne. Niew膮tpliwie jednak nale偶y z uwag膮 podej艣膰 do nich jako niezwykle skutecznych „przyspieszaczy” system贸w relacyjnych.
Na koniec wada, kt贸ra ma szans臋 by膰 wyeliminowana w niedalekiej przysz艂o艣ci. System hybrydowy jest albo konfigurowany przez cz艂owieka, albo konfiguruje si臋 sam. Do niedawna „inteligencja” autokonfiguracji system贸w hybrydowych, mechanizmy wyboru, w jakich strukturach powinny by膰 przechowywane poszczeg贸lne obszary danych by艂y niezadowalaj膮ce. Jednak ostatnio pojawiaj膮ce si臋 na rynku systemy sprawiaj膮, 偶e mo偶na mie膰 nadziej臋 na rych艂膮 popraw臋 w tym zakresie, co znacz膮co u艂atwi艂oby prac臋 u偶ytkownikom.
Zako艅czenie
Przedstawiony podzia艂 system贸w analitycznych klasy OLAP jest ju偶 podzia艂em klasycznym. Nie mo偶na r贸wnie偶 podwa偶a膰 jego zasadno艣ci, przeciwnie, wady i zalety poszczeg贸lnych sposob贸w przechowywania danych powinny by膰 wa偶nymi kryteriami branymi pod uwag臋 przy doborze narz臋dzi tego typu. Istnieje jednak wiele innych, istotnych cech, kt贸re nie powinny by膰 bagatelizowane. Od strony technologicznej wa偶ne mog膮 by膰 szczeg贸艂y architektury systemu, a nie tylko rodzaj 藕r贸d艂a danych. Drugim, zupe艂nie innym aspektem, kt贸ry nie mo偶e zosta膰 pomini臋ty jest satysfakcja u偶ytkownika. Na pocz膮tku stwierdzi艂em, 偶e aplikacje klienckie wszystkich narz臋dzi OLAP s膮 podobne. W rzeczywisto艣ci maj膮 one podobn膮 funkcjonalno艣膰, ale cz臋sto r贸偶ni膮 si臋 znacznie i w艂a艣nie takie r贸偶nice mog膮 zadecydowa膰, czy dany system b臋dzie lubiany i ch臋tnie wykorzystywany przez u偶ytkownik贸w. Jest to prawda cz臋sto nie brana pod uwag臋 przez informatyk贸w delegowanych do wyboru narz臋dzia. W swoim zapale sk艂aniaj膮cym ich do wyboru najlepszego (technologicznie) rozwi膮zania, bagatelizuj膮 oni u偶ytkownik贸w. Zbyt cz臋sto okazuje si臋, 偶e prawdziwe powodzenie takiego wdro偶enia zale偶a艂o w艂a艣nie od tego. Niestety - w贸wczas zwykle jest ju偶 za p贸藕no.
Magazyny danych (data warehouse)
Wprowadzenie
Ka偶dego dnia wielkie i ma艂e firmy generuj膮 ogromne ilo艣ci danych, dotycz膮cych wszystkich aspekt贸w ich dzia艂alno艣ci, odnotowuj膮 miliony fakt贸w o klientach, produktach, operacjach i pracownikach. Ale w wi臋kszo艣ci przypadk贸w dane te s膮 zapami臋tywane w pami臋ciach wielu r贸偶nych system贸w komputerowych czyni膮c dost臋p do nich prawie niemo偶liwym. Fenomen ten bywa okre艣lany mianem „uwi臋zienia danych”.
Eksperci szacuj膮, 偶e jedynie niewielka cz臋艣膰 informacji gromadzonych, przetwarzanych i zapami臋tywanych w instytucji znajduje si臋 w zasi臋gu decydent贸w. Z chwil膮, gdy rynek technologii przetwarzania i prezentacji danych niemal codziennie eksploduje nowymi rozwi膮zaniami, jedynie cz臋艣膰 os贸b odpowiedzialnych za opracowywanie strategii informatycznej przedsi臋biorstwa zdaje sobie spraw臋 z faktu, 偶e przewa偶aj膮ca cz臋艣膰 ich organizacji cierpi na niedoinformowanie.
Nowe rozwi膮zanie technologiczne, kt贸rego celem jest udost臋pnienie informacji pracownikom firmy podejmuj膮cym najwa偶niejsze decyzje, przyj臋艂o si臋 okre艣la膰 mianem „hurtowni danych”. Hurtownia danych wyros艂a z szeregu pr贸b powtarzanych przez badaczy i organizacje w celu zapewnienia ich instytucjom elastyczno艣ci, skuteczno艣ci i nadania w艂a艣ciwego znaczenia szeregowi danych, reprezentuj膮cemu jedne z najcenniejszych aktyw贸w firmy. Do艣wiadczenia wyniesione z tych pr贸b pozwoli艂y bran偶y informatycznej zidentyfikowa膰 kluczowe problemy wymagaj膮ce rozwi膮zania.
Hurtownie danych maj膮 spowodowa膰 uwolnienie informacji gromadzonych w operacyjnych bazach danych w celu po艂膮czenia ich z informacjami maj膮cymi swoje 藕r贸d艂o w innym miejscu firmy lub poza ni膮. Coraz wi臋cej przedsi臋biorstw czerpie informacje r贸wnie偶 z zewn臋trznych baz danych. Dotyczy to m.in. danych demograficznych, ekonometrycznych, o konkurencji, trendach dotycz膮cych zakup贸w, itp. Internet umo偶liwia ka偶dego dnia dost臋p do coraz wi臋kszej ilo艣ci informacji.
Definicja hurtowni danych
Tw贸rca teorii hurtowni danych B.聽Immon definiuje hurtowni臋 jako tematycznie zorientowan膮, sp贸jn膮, chronologiczn膮 i niezmienn膮 kolekcj臋 danych. Z kolei S.聽Kelly, k艂ad膮c g艂贸wny nacisk na problemy biznesowe, okre艣la hurtowni臋 jako struktur臋 niezale偶n膮 od systemu operacyjnego, przeznaczon膮 dla u偶ytkownik贸w, kt贸rzy potrzebuj膮 nie tyle g艂臋bokiej wiedzy informatycznej, co ekonomicznej, dalej m贸wi膮c, 偶e struktura hurtowni powinna odpowiada膰 modelowi organizacji, by膰 niezmienna i odzwierciedla膰 stan organizacji w czasie.
Pracownicy firmy SAS Institute, M.聽Kornacki i J.聽Szyller, charakteryzuj膮 hurtowni臋 danych jako infrastruktur臋 informatyczn膮 sk艂adaj膮c膮 si臋 z systematycznie archiwizowanych, uporz膮dkowanych tematycznie informacji (zazwyczaj pochodz膮cych ze 藕r贸de艂 zewn臋trznych) i opisuj膮cych je metadanych oraz zestawu aplikacji umo偶liwiaj膮cych dalsz膮 analityk臋.
Do zrozumienia istoty poj臋cia „hurtownia danych” niezb臋dne jest u艣wiadomienie sobie zada艅, kt贸re ma ona spe艂nia膰.
Funkcje hurtowni danych
Hurtownie danych ukierunkowane s膮 zwykle na kierownictwo (tworz膮 najistotniejszy cz艂on system贸w wspomagania decyzji - SWD) i ich zastosowanie ma na celu odci膮偶enie operacyjnych baz danych, przeznaczonych przede wszystkim do obs艂ugi proces贸w produkcyjnych i klient贸w. Dzi臋ki temu nast臋puje wi臋c rozdzielenie sfery informacji wykonawczych od sfery informacji decyzyjnych. Generalnym zadaniem hurtowni danych jest uj臋cie w postaci ujednoliconej istotnych (krytycznych) informacji biznesowych w skali firmy oraz udost臋pnienie ich do potrzeb wydajnej analizy wielowymiarowej, zapyta艅 i raportowania.
Potrzeba ujednolicenia informacji w skali firmy jest ewidentna, zwa偶ywszy, i偶 s膮 one zwykle rozproszone po wielu aplikacjach, przechowywane w r贸偶nych formatach i cz臋sto, mimo takich samych nazw, reprezentuj膮 inn膮 tre艣膰.
Przyczynami pojawienia si臋 hurtowni danych s膮 wi臋c niedostatki stosowanych system贸w informatycznych (z艂a jako艣膰 danych i niewystarczaj膮cy stopie艅 zintegrowania, niewydolno艣膰 obs艂ugi w zakresie analiz informacji) oraz potrzeba posiadania globalnych informacji w skali firmy.
Hurtownia danych jawi si臋 jako metoda scalania danych operacyjnych, rozproszonych po r贸偶nych aplikacjach i komputerach wewn膮trz firmy oraz „艣ci膮ganych” (zwykle kupowanych) z otoczenia zewn臋trznego (np. informacje demograficzne niezb臋dne w wypadku hurtowni marketingowo-klientowskiej).
Niewydolno艣膰 obs艂ugi informacyjnej w systemach aplikacyjnych polega na tym, i偶 przetwarzanie z艂o偶onych zapyta艅 (raport贸w) powoduje znaczne spowolnienie operacji wykonywanych w trybie on-line, a wi臋c na przyk艂ad obs艂ugi okienkowej klient贸w. Dotyczy to szczeg贸lnie 偶膮da艅 wymagaj膮cych przegl膮dni臋cia ca艂ych baz danych, obejmuj膮cych miliardy (GB), a nawet biliony (TB) znak贸w.
Hurtownia danych jest wi臋c ca艂kowicie odr臋bn膮 (ale dzia艂aj膮c膮 w ramach istniej膮cego systemu) zorientowan膮 tematycznie baz膮 danych wraz z towarzysz膮cymi jej aplikacjami. Powinna by膰 regularnie zasilana danymi pochodz膮cymi z przer贸偶nych 藕r贸de艂 (baz transakcyjnych, system贸w billingowych, zbior贸w tekstowych i binarnych).
Ka偶d膮 porcj臋 danych, kt贸r膮 zasilamy hurtowni臋 mo偶na por贸wna膰 do fotografii wybranych informacji b臋d膮cych podstaw膮 do wyci膮gania istotnych informacji dotycz膮cych dzia艂alno艣ci firmy w okre艣lonym przedziale czasu. Tak te偶 hurtownia danych powinna by膰 przede wszystkim systemem s艂u偶膮cym do dostarczania informacji zarz膮dczej.
Najbardziej krytyczne i z艂o偶one funkcje hurtowni danych to integracja i transformacja danych operacyjnych w dane analityczne. Wymaga to zbierania danych z najr贸偶niejszych 藕r贸de艂 oraz przekszta艂canie ich do analitycznego formatu danych hurtowni. Po za艂adowaniu danych do hurtowni s膮 one dost臋pne i mog膮 by膰 analizowane z u偶yciem arkuszy kalkulacyjnych lub innych narz臋dzi analitycznych.
O ile og贸lne zasady scalania i przekszta艂cania danych dla cel贸w analitycznych pozostaj膮 sta艂e o tyle konkretna implementacja musi by膰 dostosowana do konkretnych potrzeb. Wymaga to zidentyfikowania potrzebnych analiz, zdefiniowania format贸w danych, zlokalizowania 藕r贸de艂 informacji.
Architektura hurtowni danych
Realizacja hurtowni danych wykracza z regu艂y poza mo偶liwo艣ci realizacji w ramach jednego cyklu RAD (Rapid Application Development) i wymaga podzia艂u projektu na kilka przyrost贸w, odpowiadaj膮cych r贸偶nym obszarom analizy. Co wi臋cej, rozw贸j hurtowni danych jest przedsi臋wzi臋ciem, kt贸re raz rozpocz臋te trwa tak d艂ugo, jak d艂ugo rozwijaj膮 si臋 potrzeby informacyjne organizacji oraz ewoluuje 艣rodowisko system贸w podstawowych, stanowi膮cych 藕r贸d艂a danych dla hurtowni.. System budowany w cyklu przyrostowym wymaga dobrze zdefiniowanej architektury, inaczej niemo偶liwe jest zachowanie kontroli nad jego rozwojem. Chaotyczna rozbudowa hurtowni, danych 藕r贸d艂owych, brak punktu odniesienia umo偶liwiaj膮cego zaplanowanie kolejnych przyrost贸w i modyfikacji sprawia, 偶e adaptacja systemu do zmian biznesowych staje si臋 coraz trudniejsza i coraz bardziej kosztowna. W przypadku hurtowni danych, definicja architektury obejmuje dokumentacj臋 strategii biznesowych, korporacyjny model danych, dokumentacj臋 system贸w 藕r贸d艂owych, model systemu zasilania i model technologii wykorzystywanej do implementacji i wdro偶enia systemu. Model technologii jest szczeg贸lnie istotny w wypadku zastosowa艅 korporacyjnych, wymagaj膮cych integracji rozwi膮za艅 r贸偶nych dostawc贸w - od 艣rodowiska raportowania i analiz interakcyjnych (OLAP) poprzez baz臋 danych dla korporacyjnej hurtowni danych, do systemu transformacji i czyszczenia danych 藕r贸d艂owych. Dobrze zdefiniowana architektura znacz膮co upraszcza proces projektowania i budowy kolejnych przyrost贸w systemu. Daje te偶 dobre podstawy do dyskutowania z u偶ytkownikami takiego planu realizacji kolejnych przyrost贸w, kt贸ry zapewni szybkie osi膮gni臋cie strategicznych korzy艣ci z budowanego rozwi膮zania. Definicja architektury pozwala nie tylko uzyska膰 lepsz膮 jako艣膰 rozwi膮zania i lepsze jego dopasowanie do biznesu. W d艂u偶szej perspektywie, zdefiniowanie architektury zwi臋ksza wydajno艣膰 ca艂ego procesu budowy hurtowni dzi臋ki temu, 偶e w poszczeg贸lnych iteracjach zminimalizowany jest obszar prac koncepcyjnych na korzy艣膰 implementacji funkcjonalno艣ci rozwi膮zania.
W ci膮gu kilku najbli偶szych lat nale偶y oczekiwa膰 rozwoju technologii i zastosowa艅 hurtowni danych na niespotykan膮 dotychczas skal臋. Oznacza to, 偶e stratedzy, plani艣ci i u偶ytkownicy hurtowni danych musz膮 rozwija膰 umiej臋tno艣ci wyboru strategii i metod zapewniaj膮cych efektywne wykorzystanie technologii.
Metody i narz臋dzia
J臋zyk SQL i relacyjne bazy danych
Najcz臋艣ciej u偶ywanymi obecnie systemami baz danych s膮 systemy relacyjne. Stosowane wcze艣niej bezy nierelacyjne stwarza艂y wiele problem贸w - wymaga艂y od programist贸w i administrator贸w szczeg贸艂owej wiedzy na temat rozmieszczenia danych i struktury samej bazy. To z kolei utrudnia艂o rozbudowy i modyfikacje aplikacji. Mo偶na powiedzie膰, 偶e relacyjne systemy baz danych umo偶liwiaj膮 prac臋 na wy偶szym poziomie - wszystkie operacje na danych s膮 wykonywane za pomoc膮 Systemu Zarz膮dzania Baz膮 Danych (SZBD, ang. database management system). Komunikacja z tym systemem odbywa si臋 za po艣rednictwem j臋zyka wysokiego poziomu. Niekt贸re produkty u偶ywaj膮 w艂asnych j臋zyk贸w, jednak za standard we wszystkich znacz膮cych systemach uznano SQL.
Od 1986 roku SQL jest oficjalnym standardem zatwierdzonym przez Mi臋dzynarodowe Stowarzyszenie Normalizacyjne ISA i jego ameryka艅ski odpowiednik - Ameryka艅ski Narodowy Instytut Normalizacji (ANSI). Poprzedni oficjalny standard by艂 ratyfikowany na wsp贸lnym gruncie pomi臋dzy istniej膮cymi produktami, jednak ko艅cowa posta膰 zale偶a艂a od tw贸rc贸w danego systemu. Badania i do艣wiadczenia z j臋zykiem rozwijaj膮 go i doprowadzaj膮 do tworzenia nowych standard贸w, odpowiadaj膮cych rozwojowi system贸w zarz膮dzania bazami danych - m.聽in. unowocze艣niony standard SQL聽92.
SQL nie jest jedynym j臋zykiem wysokiego poziomu mog膮cym s艂u偶y膰 do komunikacji z SZBD. Nie musi by膰 on r贸wnie偶 koniecznie uznany za najlepszy. Jego si艂a wynika jednak z popularno艣ci. Sta艂 si臋 standardem i ka偶dy znacz膮cy produkt musi umie膰 si臋 nim pos艂ugiwa膰. Jest warunkiem sukcesu. Z tego powodu, jak r贸wnie偶 z systemu, na kt贸rym opiera si臋 nasz magazyn, wynika u偶ywanie SQL'a - w komunikacjach z bazami danych, w komunikacji z u偶ytkownikiem. Z tych powod贸w zdecydowali艣my si臋 zamie艣ci膰 skr贸towy opis najwa偶niejszych zasad SQL'a i relacyjnych baz danych.
Geneza j臋zyka. Jego funkcja w SZBD
J臋zyk SQL (Structured Query Language - strukturalny j臋zyk zapyta艅) zosta艂 opracowany przez firm臋 IBM w latach siedemdziesi膮tych. SQL jest standardem w systemach zarz膮dzania baz膮 danych m.in. firm Oracle, INGRES, Informix, Sybase, SQLbase, Microsoft SQL Server, Paradox, Access, Approach, a tak偶e w produktach firmy IBM: DB2, SQL/DS.
Typowy system relacyjnych baz danych sk艂ada si臋 nie tylko z systemu zarz膮dzania baz膮 danych. SZBD okre艣lany jest cz臋sto jako „ty艂 bazy danych” (back end) lub jej „silnik” (engine). W odpowiedzi na instrukcje j臋zyka SQL wyszukuje on lub modyfikuje dane i odpowiada za ich przechowywanie. Systemy relacyjnych baz danych maj膮 te偶 zwykle wbudowane narz臋dzia zwane „frontem bazy danych” (front end), kt贸re u艂atwiaj膮 komunikacj臋 z SZBD. S膮 to np. formularze, generatory raport贸w, j臋zyki czwartej generacji (4GL), graficzne j臋zyki zapyta艅, czy generatory interfejsu u偶ytkownika. Wszystkie te narz臋dzia wymagaj膮 SZBD do wykonywania r贸偶nych operacji, sam SZBD odpowiada natomiast za przechowywanie, organizacj臋 i wyszukiwanie danych, a tak偶e za ich integralno艣膰 i ochron臋.
Sposoby u偶ycia SQL'a
Sam SQL s艂u偶y jedynie do komunikacji z baz膮 danych - zwykle nie pisze si臋 w nim samodzielnych program贸w. U偶ywamy go na trzy sposoby:
interaktywny SQL - u偶ywany do wprowadzania albo wyszukiwania informacji w bazie danych, u偶ytkownik wpisuje zapytanie i otrzymuje wynik (drukowany na ekran, drukark臋, itp.),
statyczny SQL - jest to sta艂y kod SQL napisany przed wykonaniem (i zwykle kompilacj膮) w艂a艣ciwego programu napisanego w j臋zyku wysokiego poziomu (C/C++, COBOL),
dynamiczny SQL - jest to kod SQL'a generowany przez aplikacj臋 w czasie jej wykonywania; jest u偶ywany zamiast statycznego SQL'a gdy jego kod nie mo偶e by膰 okre艣lony podczas pisania programu, poniewa偶 zale偶y od warunk贸w nie znanych w tym czasie (np. od wyboru u偶ytkownika).
Zasady SQL'a i relacyjnych baz danych
Relacyjne bazy danych i j臋zyk SQL s膮 oparte na kilku prostych zasadach:
Wszystkie warto艣ci danych s膮 typ贸w prostych. W przeciwie艅stwie do j臋zyk贸w programowania wysokiego poziomu w SQL'u nie ma tablic, wska藕nik贸w, czy wektor贸w.
Wszystkie dane w relacyjnej bazie s膮 zapisane w dwuwymiarowej tablicy relacji. Tablica sk艂ada si臋 z wierszy (rows) - zwanych inaczej krotkami oraz z kolumn (columns) - zwanych inaczej atrybutami. Tablica mo偶e nie zawiera膰 偶adnych wierszy, ale musi posiada膰 przynajmniej jeden atrybut.
Po wprowadzeniu danych do bazy mo偶na wykonywa膰 r贸偶ne operacje - arytmetyczne, logiczne - na warto艣ciach z r贸偶nych kolumn oraz 艂膮czy膰 odpowiadaj膮ce sobie wiersze.
Operacje s膮 definiowane logicznie, a nie poprzez pozycje wiersza w tablicy. Pytaj膮c baz臋 o wiersze pytamy np. o takie wiersze, dla kt贸rych x聽=聽5, a nie o wiersze nr聽1, 3 itd. W samej bazie zgromadzone wiersze s膮 dowolnie uporz膮dkowane. Kolejno艣膰 ich odczytywania nie musi by膰 taka sama jak kolejno艣膰, w jakiej zosta艂y wprowadzone do bazy.
Poniewa偶 nie mo偶na identyfikowa膰 wierszy za pomoc膮 ich pozycji, mo偶na zdefiniowa膰 w relacji klucz g艂贸wny (primary key), wskazuj膮c jedn膮, lub wi臋cej kolumn. Je偶eli wybierzemy jako klucz g艂贸wny np. dwie kolumny, to ka偶dy wiersz w bazie b臋dzie musia艂 mie膰 t臋 par臋 warto艣ci unikaln膮.
艁膮czenie tablic
Dwie tablice pozostaj膮 zawsze oddzielne w bazie danych, ale mo偶emy powi膮za膰 warto艣膰 ka偶dego klucza obcego jednej relacji z kluczem - rodzicem drugiej tablicy. Operacj臋 wyszukiwania informacji w bazie danych nazywamy zapytaniem (query), a operacj臋 艂膮czenia ze sob膮 dw贸ch (lub wi臋cej) tablic, poprzez powi膮zania kolumn jednej tablicy z kolumnami drugiej - z艂膮czeniem (join). Z艂膮czenie klucza obcego z kluczem - rodzicem nazywane jest z艂膮czeniem naturalnym, poniewa偶 zostaje ono wbudowane w struktur臋 bazy. 艁膮czy ono informacje, kt贸re zosta艂y rozdzielone podczas wstawiania danych.
Grupa po艂膮czonych tablic modeluj膮ca pewn膮 rzeczywisto艣膰 nazywana jest schematem relacji (schema). Wed艂ug oficjalnego standardu SQL'a opis schematu (ilo艣膰 tablic, kolumn w tablicy itd.) powinien by膰 umieszczony w specjalnej grupie tablic o nazwie Information_Schema (informacja o schemacie). W niekt贸rych systemach tablice te okre艣la si臋 mianem katalogu (catalog), lecz termin ten w standardowym SQL'u ma nieco inne znaczenie. Opis schematu nazywamy metadan膮 (metadata) - jest to informacja o danych.
W艂a艣cicielem schematu jest „u偶ytkownik” (w rzeczywisto艣ci jest to identyfikator uprawnie艅 oznaczaj膮cy u偶ytkownika). U偶ytkownik umieszcza w schemacie obiekty (objects). Ka偶dy obiekt posiada swoj膮 nazw臋 i sta艂y identyfikator. Obiektem mo偶e by膰 np. tablica, ale nie tylko. U偶ytkownik mo偶e udost臋pnia膰 swoje tablice innym osobom. Za pomoc膮 uprawnie艅 (privileges) pozwalamy u偶ytkownikom wykonywa膰 r贸偶ne operacje na obiektach, a zabraniamy innych. Do ustalania uprawnie艅 s艂u偶膮 instrukcje GRANT i REVOKE.
Podstawy j臋zyka SQL
SQL jest j臋zykiem nieproceduralnym. Oznacza to, 偶e napisany w nim program nie m贸wi jak wykona膰 zadanie (krok po kroku), lecz co chcemy uzyska膰. Spos贸b rozwi膮zania pozostawia SZBD. Jest to zgodne z filozofi膮 relacyjnych baz danych - nie musimy si臋 interesowa膰 jak SZBD wykonuje zadania, traktujemy go jako „czarn膮 skrzynk臋”.
Przyk艂adowe zapytanie:
SELECT *
FROM Klienci
WHERE miasto = `Praga'
oznacza: wybierz wszystkie wiersze (znak `*' w pierwszej linijce) z tablicy Klienci (klauzula FROM) dla kt贸rych atrybut `miasto' ma warto艣膰 `Praga'. Najbardziej interesuj膮ca jest tu klauzula WHERE - w niej podajemy warunki, jakie musi spe艂ni膰 wiersz, aby zosta艂 wybrany. W wyniku otrzymamy wszystkie wiersze, kt贸re spe艂niaj膮 wymagane warunki. Je艣li interesuje nas tylko jeden wiersz, zwykle powinni艣my odszuka膰 go korzystaj膮c z klucza g艂贸wnego. Bez jego znajomo艣ci nigdy nie wiemy ile wierszy otrzymamy w wyniku. Ukazuje to wa偶n膮 cech臋 j臋zyka - operuje on na dowolnie du偶ych zbiorach danych. Instrukcje przetwarzaj膮 ca艂y zbi贸r danych (set-at-a-time) w odr贸偶nieniu od wi臋kszo艣ci j臋zyk贸w proceduralnych, przetwarzaj膮cych pojedyncze dane (item-at-a-time).
Inn膮 cech膮 SQL'a jest tr贸jwarto艣ciowa logika (3VL). W wi臋kszo艣ci j臋zyk贸w wyra偶enie logiczne mo偶e by膰 prawdziwe (TRUE) lub fa艂szywe (FALSE). SQL zezwala na wprowadzenie do tablicy warto艣ci NULL (warto艣膰 nieokre艣lona). Znacznik ten jest wpisywany automatycznie, podczas wstawiania wiersza, w kolumnach, w kt贸rych nie podano warto艣ci (je艣li ograniczenia na to zezwalaj膮). Gdy u偶yjemy warto艣ci NULL w por贸wnaniu, wynik nie b臋dzie ani prawdziwy, ani fa艂szywy, lecz przyjmie warto艣膰 nieokre艣lon膮 (UNKNOWN). Jest to jeden z bardziej kontrowersyjnych aspekt贸w SQL'a.
Instrukcje SQL'a s膮 pogrupowane wed艂ug funkcji. W standardzie SQL u偶ywa si臋 najcz臋艣ciej trzech grup instrukcji. S膮 to:
J臋zyk definicji danych (DDL - Data Definition Language), kt贸ry zawiera wszystkie instrukcje s艂u偶膮ce do definiowania schemat贸w i nale偶膮cych do nich obiekt贸w. Najwa偶niejsze instrukcje, to: CREATE SCHEMA, CREATE TABLE, CREATE VIEW, CREATE ASSERTION, CREATE DOMAIN.
J臋zyk manipulowania danymi (DML - Data Manipulation Language) zawieraj膮cy wszystkie instrukcje s艂u偶膮ce do przechowywania, modyfikowania i wyszukiwania danych w tablicach. Najwa偶niejsze instrukcje to: SELECT, INSERT, UPDATE, DELETE. Polecenie SELECT s艂u偶y do formu艂owania zapyta艅 i jest najbardziej z艂o偶on膮 instrukcj膮 j臋zyka.
Instrukcje sterowania danymi, kt贸re kontroluj膮 uprawnienia u偶ytkownika umo偶liwiaj膮ce wykonywanie okre艣lonych operacji na obiektach (w standardzie 92 cz臋sto uwa偶a si臋 je za cz臋艣膰 DDL). Najwa偶niejsze instrukcje w tej grupie to GRANT i REVOKE.
G艂贸wnym, praktycznym znaczeniem podzia艂u na kategorie jest to, 偶e standard nie pozwala na mieszanie instrukcji DDL i DML w jednej transakcji. Jednak wi臋kszo艣膰 produkt贸w na to pozwala.
Metody dost臋pu do baz danych z poziomu j臋zyk贸w programowania wysokiego poziomu
Open Database Connectivity (ODBC)
ODBC jest obecnie najbardziej rozpowszechnionym standardem dost臋pu do baz danych. Standardowo mechanizm ten jest wbudowany w systemy operacyjne platformy win32 (Windows 98, NT). Ide膮 standardu, opartego na bibliotekach X/OPEN jest dostarczenie programi艣cie funkcji operuj膮cych na 藕r贸dle danych. Przez 藕r贸d艂o danych rozumiemy odpowiednio skonfigurowany sterownik ODBC, umo偶liwiaj膮cy dost臋p do serwera bazy danych, dla kt贸rego ten sterownik zosta艂 stworzony.
Biblioteki ODBC zawieraj膮 funkcje niskiego poziomu, dlatego cz臋sto tworzy si臋 biblioteki wy偶szego poziomu korzystaj膮ce z ODBC (klazy MFC firmy Microsoft, czy Borland Database Enginy dawnej firmy Borland, obecnie Inprise). Programy korzystaj膮ce z ODBC s膮 niezale偶ne od konkretnego produktu stanowi膮cego serwer bazy danych. Korzystaj膮 one z po艣rednika, kt贸rym jest sterownik ODBC i po zmianie sterownika mog膮 korzysta膰 z systemu innego producenta.
Standard ODBC jest obecnie szeroko rozpowszechniony, dlatego te偶 dost臋pne s膮 sterowniki do niemal wszystkich system贸w zarz膮dzania baz膮 danych.
Java Database Connectiviy (JDBC)
JDBC (Java DataBase Connectivity) to zbi贸r klas i funkcji napisanych w j臋zyku Java, przeznaczonych do korzystania z informacji zawartych w bazach danych, a konkretnie, do przetwarzania i wykonywania zapyta艅 SQL. Jest narz臋dziem pozwalaj膮cym na pisanie program贸w bez u偶ywania 偶adnych dodatkowych bibliotek, gdy偶 znajduje si臋 w standardowym pakiecie JDK (Java Development Kit) firmy Sun. JDBC umo偶liwia skierowanie zapytania do dowolnej relacyjnej bazy danych (np.: Oracle, Sybase, Informix) przy wykorzystaniu jednakowego interfejsu dla ka偶dej z nich. Jest to bardzo wygodnym rozwi膮zaniem z punktu widzenia programisty, gdy偶 jeden program napisany przy wykorzystaniu JDBC posiada mo偶liwo艣膰 obs艂ugi zapyta艅 do kilku baz danych - wystarczy zmieni膰 sterownik. To rozwi膮zanie pozwala na du偶膮 „oszcz臋dno艣膰 kodu” - programista nie musi pisa膰 oddzielnego programu dla ka偶dego rodzaju bazy danych. Poza tym JDBC posiada wa偶n膮 cech臋, kt贸ra jest „wizyt贸wk膮” Javy - przenaszalno艣膰 na r贸偶ne platformy systemowe. Reasumuj膮c: JDBC pozwala programi艣cie napisa膰 jeden program, kt贸ry b臋dzie dzia艂a艂 z dowoln膮 baz膮 danych na dowolnej platformie.
W chwili obecnej najbardziej rozpowszechnionym interfejsem dost臋pu do baz danych jest ODBC. Jak na jego tle wygl膮da JDBC? Po pierwsze JDBC jest prostsze - programowanie przy u偶yciu ODBC wymaga pewnego zaawansowania, a wykonanie prostego zapytania wymaga u偶ycia skomplikowanych funkcji; po drugie ODBC u偶ywa interfejsu j臋zyka C, przez co posiada ograniczenia dotycz膮ce przeno艣no艣ci.
W naszej pracy interfejs JDBC zosta艂 u偶yty przy tworzeniu modu艂贸w integratora oraz monitor贸w. Postanowili艣my skorzysta膰 ze sterownika typu most JDBC-ODBC (pozosta艂e typy to: Native API - Java, Java Network - All Java, Native Protocol - All Java; nie b臋dziemy si臋 jednak na nich koncentrowa膰, gdy偶 nie zosta艂y u偶yte w naszej pracy). Jest to jedyny sterownik dostarczany standardowo z pakietem JDK. Jest to jedyny sterownik, kt贸ry umo偶liwia po艂膮czenie z wieloma r贸偶nymi bazami danych. ODBC, podobnie jak JDBC, definiuje tylko spos贸b dost臋pu do bazy danych - kod pozostaje niezale偶ny od zastosowanego serwera bazy danych. Most t艂umaczy wywo艂ania JDBC na wywo艂ania ODBC i przekazuje je do sterownika ODBC zainstalowanego w systemie. W tym momencie odpowiedzialno艣膰 za komunikacj臋 z serwerem bazy danych przejmuje ODBC. Wad膮 tego sterownika jest dodanie kolejnej warstwy na drodze zapytania z aplikacji do bazy danych. Wprowadza to dodatkowy narzut czasowy spowodowany konieczno艣ci膮 prze艂o偶enia wywo艂a艅 JDBC na ODBC. Do zalet tego sterownika nale偶y zaliczy膰 to, 偶e mo偶e on by膰 zastosowany do komunikacj膮 z serwerem bazy danych, do kt贸rego nie jest osi膮galny sterownik JDBC. Jako zalet臋 nale偶y r贸wnie偶 uzna膰 cen臋 sterownika (sterowniki s膮 dostarczane przez producent贸w system贸w zarz膮dzania bazami danych a nie przez firm臋 Sun - autora Javy) - jest on darmowy.
Teraz kr贸tko opiszemy podstawowe operacje JDBC. Pierwsz膮 czynno艣ci膮, jak膮 programista musi wykona膰, chc膮c korzysta膰 z interfejsu JDBC, jest zaimportowanie pakietu java.sql. Nast臋pnie nale偶y za艂adowa膰 i zarejestrowa膰 sterownik JDBC - to druga konieczna czynno艣膰. Po trzecie trzeba nawi膮za膰 po艂膮czenie z baz膮 danych. Po wykonaniu tych trzech punkt贸w programista mo偶e ju偶 tworzy膰 i wykonywa膰 zapytania oraz odczytywa膰 ich wyniki. Czwart膮 konieczn膮 czynno艣ci膮 jest zamkni臋cie zapytania i po艂膮czenia z baz膮 danych. Jak wida膰, korzystanie z JDBC jest bardzo proste.
Interfejs JDBC wymaga od programisty znajomo艣ci j臋zyka SQL (Structured Query Language). Jest to tak uznany i powszechny, 偶e nie spos贸b go pomin膮膰 przy omawianiu metod dost臋pu do baz danych z poziomu j臋zyk贸w oprogramowania. Standard ten zawiera, opr贸cz opisu formatu zapyta艅 do serwera bazy danych, polecenia dotycz膮ce definiowania danych (DDL - Data Definition Language) i operowania na nich (DML -Data Manipulation Language). Jakkolwiek SQL zosta艂 uznany przez ANSI jako standard j臋zyka dla system贸w zarz膮dzania bazami danych, to wi臋kszo艣膰 producent贸w oprogramowania dostarcza w艂asne rozszerzenia tego j臋zyka, jak np. SQLplus firmy Oracle. JDBC s艂u偶y do odpowiedniego przedstawienia serwerowi bazy danych zapytania w j臋zyku SQL. Na poziomie aplikacji klienta nie jest dokonywana 偶adna kontrola sk艂adni zapytania - ewentualne b艂臋dy pojawi膮 si臋 dopiero przy wykonywaniu zapytania przez serwer bazy danych.
JDBC jest prostym i wygodnym oraz przenaszalnym narz臋dziem pozwalaj膮cym na korzystanie z informacji zawartych w bazach danych. Dlatego po艂owa naszej pracy powsta艂a w oparciu o w艂a艣nie ten interfejs.
Oracle Call Interface (OCI)
Oracle Call Interface (OCI) to zestaw bibliotek do艂膮czonych do pakietu Oracle, s艂u偶膮cych do komunikacji ze 藕r贸d艂ow膮 baz膮 danych, wykonywania zapyta艅, definiowania danych, dost臋pu do danych. Zastosowanie OCI u艂atwi艂o dost臋p do 藕r贸d艂owej bazy danych Oracle a tak偶e stanowi艂o zalet臋 w postaci przeno艣no艣ci tego modu艂u na inne platformy sprz臋towe i systemy operacyjne. Programista u偶ywaj膮cy bibliotek OCI ma do wyboru kilka j臋zyk贸w programowania: Ada, C, COBOL, FORTRAN, PL/I.
Wa偶niejsze poj臋cia zwi膮zane z OCI
context area - bufor pami臋ci wykorzystywany przez Oracle'a do przechowywania i przetwarzania informacji zwi膮zanej z wykonaniem pojedynczego wyra偶enia SQL,
cursor data area (CDA) - 64-bajtowy obszar danych w programie u偶ytkownika skojarzony (powi膮zany) z context area,
logon data area (LDA) - 64 bajtowy obszar danych w naszym programie, kt贸ry Oracle wykorzystuje kiedy programista 艂膮czy si臋 z baz膮 danych. LDA jest przekazywana jako parametr w kilku funkcjach OCI.
select-list item - kolumna lub wyra偶enie w zapytaniu SQL okre艣laj膮ce dane wyj艣ciowe, np. w zapytaniu:
select ENAME, ROUND (SYSDATE) - ROUND (HIREDATE) from emp
mamy dwie select-list item ENAME i (ROUND (SYSDATE) - ROUND (HIREDATE))
Struktura programu OCI
Pisz膮c program u偶ywaj膮c OCI musimy pami臋ta膰 o pewnej strukturze tego programu, kt贸ra pozwoli na poprawn膮 jego prac臋. Musimy wyr贸偶ni膰 kilka g艂贸wnych punkt贸w z jakich musi si臋 sk艂ada膰 nasz program:
po艂膮czenie z jedn膮 lub wi臋ksz膮 ilo艣ci膮 baz danych,
otwarcie kursor贸w potrzebnych dla naszego programu,
przetwarzanie wyra偶enia SQL w celu otrzymania danych wyj艣ciowych,
zamkni臋cie kursor贸w po zako艅czeniu przetwarzania,
od艂膮czenie si臋 od bazy danych.
W celu po艂膮czenia si臋 z baz膮 danych wywo艂ujemy funkcj臋 OLON (jedna baza) lub ORLON (kilka baz danych). Aby po艂膮czy膰 si臋 z ORACLE musimy zdefiniowa膰 w naszym programie obszar danych zwany (logon data area - LDA). Po pod艂膮czeniu do bazy danych nast臋pnie musimy zdefiniowa膰 kursor, b臋d膮cy struktur膮 danych zwi膮zanych z przetwarzanym poleceniem (cursor data area - CDA). Do otwarcia kursora s艂u偶y funkcja oopen(). Nast臋pnym krokiem jest przetworzenie wyra偶enia. Przed przetworzeniem wyra偶enia musimy sprawdzi膰 jego poprawno艣膰. U偶ywamy w tym celu funkcji osql3(). Kolejnym krokiem jest powi膮zanie adresu zmiennych wyst臋puj膮cych w naszym programie ze specyficznym placeholder'em poprzez zastosowanie funkcji obndrv() oraz zdefiniowanie typ贸w i danych wyj艣ciowych (funkcja odefin()). Teraz mo偶emy przetworzy膰 zapytanie - oexec() - i zebra膰 dane wyj艣ciowe - ofetch(). Gdy ju偶 otrzymali艣my wyniki przetwarzanego wyra偶enia, przed od艂膮czeniem si臋 od bazy - funkcja ologof() - musimy zamkn膮膰 kursor (kursory) poprzez wywo艂anie funkcji oclose(). Struktur臋 programu OCI mo偶na przedstawi膰 na schemacie:
Na przedstawionym rysunku query oznacza zapytanie (instrukcja SELECT), re-execute ponowne wykonanie polecenia, re-bind ponowne wi膮zanie zmiennych programowych z wyra偶eniem j臋zyka SQL, natomiast execute others - wykonanie kolejnych polece艅.
Komunikacja sieciowa
Protok贸艂 TCP/IP
Ze wzgl臋du na wykorzystanie protoko艂u TCP/IP do komunikacji mi臋dzy modu艂ami systemu, postanowili艣my zamie艣ci膰 kr贸tki opis pewnych aspekt贸w zwi膮zanych z tym protoko艂em. Poza og贸lnym opisem, zdecydowali艣my si臋 zamie艣ci膰 dok艂adniejszy opis zagadnie艅 zwi膮zanych z tworzeniem naszej pracy - warstwy aplikacji protoko艂u i zasady numeracji IP.
Architektura protoko艂贸w TCP/IP
Architektura protoko艂贸w TCP/IP jest troch臋 odmienna od modelu ISO/OSI. Mamy tutaj do czynienia z czterowarstwowym hierarchicznym modelem protoko艂贸w TCP/IP:
|
warstwa aplikacji |
warstwa transportowa |
warstwa Internet |
warstwa dost臋pu do sieci |
|
Dane generowane przez programy aplikacyjne s膮 przekazywane w d贸艂 stosu je艣li maj膮 by膰 przesy艂ane poprzez sie膰 i w g贸r臋 stosu przy odbiorze. Ka偶da warstwa stosu dodaje do danych przekazywanych z warstwy wy偶szej informacje steruj膮ce w postaci nag艂贸wk贸w. Nag艂贸wek dodany w warstwie wy偶szej jest traktowany jako dane w warstwie ni偶szej.
Warstwy protoko艂贸w TCP/IP u偶ywaj膮 r贸偶nych nazw do okre艣lania przekazywanych danych. Aplikacje stosuj膮ce w warstwie transportowej protok贸艂 TCP nazywaj膮 swoje dane strumieniem. Z kolei TCP nazywa swoje dane segmentem. Aplikacje wykorzystuj膮ce w warstwie transportowej protok贸艂 UDP okre艣laj膮 swoje dane jako wiadomo艣ci, a dane protoko艂u UDP to pakiety. W warstwie Internet protok贸艂 IP traktuje swoje dane jako bloki zwane datagramami. W najni偶szej warstwie bloki danych to ramki lub pakiety w zale偶no艣ci od u偶ywanego protoko艂u.
Warstwa dost臋pu do sieci jest najni偶sz膮 warstw膮 w hierarchii architektury protoko艂贸w TCP/IP. W warstwie tej do datagram贸w IP dodaje si臋 nag艂贸wki oraz zako艅czenie i w ten spos贸b otrzymuje si臋 ramki przesy艂ane w sieci. Funkcje tej warstwy odpowiadaj膮 w przybli偶eniu funkcjom trzech najni偶szych warstw modelu ISO/OSI. Do komunikacji w sieciach rozleg艂ych lub przez 艂膮cza szeregowe mog膮 by膰 stosowane takie protoko艂y jak X.25, PPP (Point-to-Point Protocol) lub SLIP (Serial Line IP). Te dwa ostatnie protoko艂y zosta艂y specjalnie opracowane do przesy艂ania datagram贸w IP poprzez szeregowe 艂膮cza dwupunktowe. Protok贸艂 SLIP zazwyczaj jest stosowany do 艂膮czenia pojedynczych komputer贸w poprzez 艂膮cza szeregowe. Natomiast w sieciach rozleg艂ych zalecane jest stosowanie protoko艂u PPP.
Warstwa Internet znajduje si臋 powy偶ej warstwy dost臋pu do sieci. Podstawowym protoko艂em tej warstwy jest IP. Protok贸艂 ten jest odpowiedzialny za przesy艂anie pakiet贸w zwanych datagramami mi臋dzy u偶ytkownikami sieci. Jest to protok贸艂 bezpo艂膮czeniowy, co oznacza, 偶e datagramy s膮 przesy艂ane przez sie膰 bez kontroli poprawno艣ci ich dostarczenia. W efekcie datagram mo偶e zosta膰 zgubiony w sieci, przek艂amany lub zniekszta艂cony. Protok贸艂 IP jest przeznaczony do sieci o bardzo dobrej jako艣ci i niezawodno艣ci 艂膮czy transmisyjnych. Drugim protoko艂em tej warstwy jest ICMP 艣ci艣le zwi膮zany z IP. S艂u偶y on do przesy艂ania komunikat贸w o nieprawid艂owo艣ciach w pracy sieci. Protok贸艂 pozwala na przesy艂anie wiadomo艣ci steruj膮cych mi臋dzy w臋z艂ami sieci. Wiadomo艣ci te dotycz膮 sterowania przep艂ywem, testowania po艂膮cze艅, wskazania alternatywnych po艂膮cze艅 i wykrywania niedost臋pnych u偶ytkownik贸w.
Warstwa transportowa zapewnia bezpo艣rednie po艂膮czenie mi臋dzy ko艅cowymi u偶ytkownikami (systemami) wymieniaj膮cymi informacje. Do najwa偶niejszych protoko艂贸w tej warstwy zaliczamy TCP oraz UDP. Protok贸艂 TCP jest protoko艂em po艂膮czeniowym umo偶liwiaj膮cym wykrywanie b艂臋d贸w na obu ko艅cach po艂膮czenia. Ma on mo偶liwo艣膰 ustanowienia i utrzymania po艂膮czenia wirtualnego mi臋dzy dwoma u偶ytkownikami w celu przesy艂ania danych, sterowania przep艂ywem, przesy艂ania potwierdze艅 oraz kontroli i korekcji b艂臋d贸w. Protok贸艂 UDP jest protoko艂em bezpo艂膮czeniowym, nie posiadaj膮cych mechanizm贸w sprawdzania poprawno艣ci dostarczenia danych do miejsca przeznaczenia. Segmenty TCP jak i pakiety UDP w celu ich dalszego przes艂ania s膮 umieszczane wewn膮trz datagramu IP.
Warstwa aplikacyjna
Warstwa aplikacji zawiera procesy wykorzystuj膮ce protoko艂y TCP lub UDP. Protoko艂y tej warstwy dostarczaj膮 u偶ytkownikom r贸偶nych us艂ug. Do najbardziej znanych protoko艂贸w warstwy aplikacji korzystaj膮cych z TCP nale偶膮:
TELNET dla us艂ug terminalowych. Pozwala na rozpocz臋cie sesji poprzez sie膰.
TFTP (Trivial File Transfer Protocol) dla prostych us艂ug transferu plik贸w. Jest to uproszczona wersja protoko艂u FTP.
FTP (File Transfer Protocol) dla transferu plik贸w. Umo偶liwia interakcyjne przesy艂anie plik贸w.
SMTP (Simple Mail Transfer Protocol) dla wymiany poczty elektronicznej. Umo偶liwia prac臋 w trybie zapami臋taj i prze艣lij (store-and-forward) pomi臋dzy systemami poczty korzystaj膮cymi z serwer贸w pocztowych.
Natomiast do bardziej znanych protoko艂贸w warstwy aplikacji korzystaj膮cych z protoko艂u UDP nale偶膮:
DNS (Domain Name Service) do zamiany adres贸w IP na nazwy urz膮dze艅 sieciowych.
RIP (Routing Information Protocol) do wymiany informacji zwi膮zanych z aktualizacj膮 regu艂y doboru tras w w臋z艂ach sieci.
NFS (Network File System) do wsp贸艂dzielenia plik贸w przez wiele komputer贸w do艂膮czonych do sieci. Jest to rozproszony system plik贸w dzia艂aj膮cych wed艂ug modelu klient-serwer.
Ka偶da aplikacja korzystaj膮ca z protoko艂贸w TCP/IP jest identyfikowana za pomoc膮 numeru portu. Z kolei protoko艂y transportowe s膮 okre艣lone za pomoc膮 numer贸w protoko艂贸w. Pozwala to 艂膮czy膰 dane generowane przez r贸偶ne aplikacje z kilkoma protoko艂ami transportowymi i z kolei te protoko艂y z protoko艂em IP. Takie podej艣cie daje mo偶liwo艣膰 multipleksacji danych, czyli np. umo偶liwia r贸wnoczesn膮 komunikacj臋 wielu aplikacji z TCP. W Internecie niekt贸re numery port贸w s膮 zarezerwowane i wst臋pnie przypisane do tzw. dobrze znanych us艂ug (mog膮 przyjmowa膰 numery od 0 do 255). Dobrze znane us艂ugi to np. takie protoko艂y sieciowe jak FTP lub TELNET. Protoko艂y TCP/IP u偶ywaj膮 r贸wnie偶 abstrakcyjnego poj臋cia gniazda. Gniazdo to kombinacja adresu IP i numeru portu. W zwi膮zku z tym gniazdo jednoznacznie okre艣la proces w Internecie. Gniazd to r贸wnie偶 zako艅czenie logicznego 艂膮cza komunikacyjnego mi臋dzy dwiema aplikacjami. Je艣li aplikacje realizowane s膮 na dw贸ch r贸偶nych komputerach, to para odpowiadaj膮cych im gniazd definiuje po艂膮czenie w protokole po艂膮czeniowym TCP.
Adresy IP
W sieciach wykorzystuj膮cych protoko艂y TCP/IP aktualnie s膮 stosowane 32-bitowe adresy kt贸re jednoznacznie okre艣laj膮 sie膰 oraz komputer do艂膮czony do tej sieci. Adres IP sk艂ada si臋 z dw贸ch cz臋艣ci: cz臋艣ci sieciowej i cz臋艣ci identyfikuj膮cej komputer wewn膮trz sieci. Adresy IP mo偶na sklasyfikowa膰 wg ich format贸w. W adresie IP wzajemna relacja mi臋dzy liczb膮 bit贸w okre艣laj膮cych sie膰 i liczb膮 bit贸w okre艣laj膮cych komputer zale偶y od klasy adres贸w. Istnieje 5 klas adres贸w: A, B, C, D, E. Struktur臋 adres贸w w tych klasach, dla protoko艂u IP w wersji 4, przedstawiono na rysunku:
|
|
|
|
|
|||||
Bajty |
1 |
2 |
3 |
4 |
|||||
Klasa A |
0 |
sie膰(7) |
komputer(24) |
||||||
Klasa B |
10 |
sie膰(14) |
komputer(16) |
||||||
Klasa C |
110 |
sie膰(21) |
komputer(8) |
||||||
Klasa D |
1110 |
adres grupowy (28) |
|||||||
Klasa E |
11110 |
przysz艂e zastosowania (27) |
|||||||
|
|
|
Adresy klasy A posiadaj膮 pierwszy bit r贸wny 0. Nast臋pne 7 bit贸w okre艣la sie膰, a pozosta艂e 24 bity komputer wewn膮trz sieci. Zauwa偶my, 偶e ta klasa adres贸w obejmuje tylko 127 numer贸w sieciowych i ponad 16 mln komputer贸w w jednej sieci.
Adresy klasy B rozpoczynaj膮 si臋 od pary bit贸w o warto艣ciach 10. Kolejne 14 bit贸w okre艣la sie膰 a pozosta艂e 16 bit贸w komputer wewn膮trz sieci. W klasie B istnieje ponad 16 tys. sieci, a w ka偶dej z nich ponad 65 tys. komputer贸w.
Adresy klasy C identyfikowane s膮 nast臋puj膮c膮 sekwencj膮 trzech pierwszych bit贸w 110. Nast臋pne 21 bit贸w przeznaczone jest na wskazanie sieci, a tylko 8 na okre艣lenie komputera w ka偶dej sieci. Pozwala to obs艂u偶y膰 ponad 2 mln sieci i 254 komputery.
Adresy klasy D maj膮 na pierwszych 4 bitach sekwencj臋 1110, a na pozosta艂ych adres grupowy. Odnosz膮 si臋 one nie do sieci, a do grupy komputer贸w, kt贸re nie koniecznie musz膮 si臋 znajdowa膰 w tej samej sieci fizycznej. Taki adres IP umo偶liwia jednoczesn膮 komunikacj臋 z grup膮 komputer贸w.
Adresy klasy E rozpoczynaj膮 si臋 od sekwencji 11110 i s膮 przeznaczone do przysz艂ych zastosowa艅.
Adresy IP s膮 zapisywane jako cztery liczby dziesi臋tne oddzielone kropkami, np. 132.21.123.23. Liczby te odpowiadaj膮 liczb膮 dw贸jkowym zawartym w kolejnych czterech bajtach adresu IP, a zatem s膮 one z zakresu 0-255.
Przypisanie ustalonych warto艣ci pierwszym bitom pierwszego bajtu adresu IP powoduje, 偶e warto艣膰 pierwszej liczby dziesi臋tnej jest 艣ci艣le zwi膮zana z klas膮 adresu, a zatem:
warto艣ci mniejsze od 128 - klasa A,
warto艣ci 128 - 191 - klasa B,
warto艣ci 192 - 223 - klasa C,
warto艣ci 224 - 229 - klasa D,
powy偶ej 239 - klasa E.
Adresy IP umo偶liwiaj膮 utworzenie sieci logicznych w jednej du偶ej sieci fizycznej posiadaj膮cej jeden adres IP. Mo偶na tego dokona膰 korzystaj膮c z bit贸w cz臋艣ci identyfikuj膮cej komputer w adresie IP oraz 32-bitowej maski podsieci. Zasada u偶ycia maski jest nast臋puj膮ca: je艣li bit w masce ma warto艣膰 1, to odpowiadaj膮cy mu bit w adresie IP jest bitem cz臋艣ci sieciowej. Je艣li bit w masce jest r贸wny 0, to bit adresu nale偶y do cz臋艣ci okre艣laj膮cej komputer. Przyk艂adowo maska 255.255.255.0 zastosowana do adresu klasy B rozszerzy cz臋艣膰 sieciow膮 o jeden bajt. Pierwsze dwa bajty s膮 cz臋艣ci膮 sieciow膮 klasy B, trzeci bajt jest adresem podsieci a ostatni okre艣la komputer w podsieci.
Obecnie podstawow膮 niedogodno艣ci膮 sieci Internet jest nieustanna redukcja puli adres贸w IP - praktycznie nie ma ju偶 wi臋kszych mo偶liwo艣ci adresowania w klasach A i B. Rozwi膮zaniem mo偶e by膰 propozycja nowego protoko艂u IP v6. Proponuje si臋 aby dotychczasowe 32-bitowe adresy zast膮pi膰 128-bitowymi. Oczywi艣cie zak艂ada si臋, 偶e nowe adresy obejm膮 aktualnie u偶ywane (32-bitowe).
Wykorzystanie protoko艂贸w sieciowych w j臋zykach C/C++
Jedn膮 z mo偶liwo艣ci korzystania z zalet protoko艂u TCP/IP, je艣li korzystamy z platformy Win32, jest u偶ycie Windows Sockets 2. Biblioteki te u偶ywaj膮 metod spopularyzowanych pocz膮tkowo przez Berkeley Software Distribution UNIX (BSD), kt贸re zosta艂y p贸藕niej zaadoptowane na potrzeby 艣rodowiska Windows.
Podstawowym celem biliotek Windows Sockets 2 jest zapewnienie komunikacji niezale偶nej od u偶ywanych protoko艂贸w, wykorzystuj膮cej wszystkie mo偶liwo艣ci sieci komputerowych, takie jak komunikacje multimedialne w czasie rzeczywistym. Windows Sockets 2 nie jest wi臋c protoko艂em, lecz interfejsem, wi臋c mo偶e korzysta膰 z dowolnej liczby protoko艂贸w transportowych i nie wymaga, aby by艂 stosowany na obu ko艅cach 艂膮cza komunikacyjnego.
Nale偶y zaznaczy膰, 偶e wi臋kszo艣膰 funkcji Windows Sockets ma posta膰 zgodn膮 z rodzin膮 funkcji unixowych (BSD), co czyni programy przeno艣ne na poziomie kodu.
Wykorzystanie protoko艂贸w sieciowych w j臋zyku Java
Realizacja po艂膮cze艅 sieciowych w Javie jest mo偶liwa za pomoc膮 pakietu „java.net”. Pakiet ten udost臋pnia klasy Socket i ServerSocket, kt贸re zarz膮dzaj膮 gniazdem po艂膮czenia. Klasy te udost臋pniaj膮 wszystkie niezb臋dne funkcje umo偶liwiaj膮ce po艂膮czenie si臋 z nas艂uchuj膮cym serwerem, jak r贸wnie偶 utworzenie po艂膮czenia nas艂uchuj膮cego.
Narz臋dzia do budowy parser贸w
J臋zyki mo偶emy podzieli膰 na naturalne (j臋zyk polski, angielski itp.) oraz formalne (j臋zyki programowanie, j臋zyki polece艅 system贸w operacyjnych, j臋zyki zapyta艅 bazy danych). R贸偶ni je to, 偶e j臋zyki formalne maj膮 艣ci艣le okre艣lone regu艂y sk艂adniowe - wynika to z faktu, i偶 polecenia w tych j臋zykach s膮 zwykle przetwarzane przez automaty (cho膰 cz臋sto tworzone przez ludzi). Otrzymuj膮c zdanie w j臋zyku formalny, natychmiast mo偶na okre艣li膰, czy jest ono poprawnie zbudowane.
Je偶eli j臋zyk formalny jest j臋zykiem programowania, jego realizacja mo偶e mie膰 posta膰 translatora lub interpretera. Interpreter na podstawie programu i danych wej艣ciowych generuje wynik. Natomiast translator na podstawie programu wygeneruje jego przek艂ad i dopiero ten przek艂ad przetworzy dane wej艣ciowe na wyniki. Schemat dzia艂ania translatora i interpretera przedstawiono na rysunku poni偶ej. Przedstawiony na nim translator nazywamy kompilatorem.
Niezale偶nie od tego, czy mamy do czynienia z interpreterem, czy translatorem, istnieje problem analizy sk艂adniowej, czyli problem sprawdzenia, czy tekst na wej艣ciu jest zbudowany zgodnie z regu艂ami danego j臋zyka. Aby podnie艣膰 efektywno艣膰 analizatora sk艂adniowego i upro艣ci膰 jego budow臋, wyodr臋bnia si臋 tzw. analizator leksykalny i analizator sk艂adniowy.
Analiza leksykalna - Lex
Zadaniem analizatora leksykalnego, kt贸ry jest modu艂em podrz臋dnym analizatora sk艂adniowego, jest:
rozpoznawanie identyfikator贸w i sta艂ych numerycznych,
pomijanie komentarzy,
wyodr臋bnianie 艂a艅cuch贸w znakowych,
rozpoznawanie s艂贸w kluczowych.
Zadania te m贸g艂by rozwi膮za膰 analizator sk艂adniowy, ale spowodowa艂oby to zbyt du偶y wzrost nak艂ad贸w pami臋ciowych i czasowych.
Lex jest wyspecjalizowanym generatorem analizator贸w leksykalnych. Jest on w istocie rzeczy kompilatorem problemowo zorientowanego j臋zyka, w kt贸rym opisuje si臋 konstruowany analizator. Lex zosta艂 opracowany w po艂owie lat 70. w firmie AT&T (USA) przez J.聽Leska. Z pocz膮tku stworzony dla 艣rodowiska UNIX, dzi艣 dzia艂a tak偶e w innych 艣rodowiskach - MS-DOS, Win32, OS/2.
Podstawowe poj臋cia analizy leksykalnej
Zadanie analizy leksykalnej polega na rozpoznawaniu i wyodr臋bnianiu ci膮g贸w znak贸w o okre艣lonych cechach z podanego tekstu wej艣ciowego. Czasami jest to zadanie proste, polegaj膮ce na wyodr臋bnianiu pojedynczych znak贸w, czy s艂贸w, jednak zwykle zadanie analizy jest trudniejsze - podzia艂 tekstu programu na tzw. jednostki leksykalne. Zadanie to wchodzi w sk艂ad ka偶dego kompilatora j臋zyka programowania.
Podstawowymi poj臋ciami analizy leksykalnej s膮: leksem i jednostka leksykalna. Z ka偶dym j臋zykiem (niekoniecznie musi to by膰 j臋zyk programowania) mo偶na zwi膮za膰 zbi贸r jednostek leksykalnych (identyfikator, liczba itp.). Ci膮gi znak贸w, kt贸re z punktu widzenia sk艂adni j臋zyka pe艂ni膮 podobn膮 rol臋, wchodz膮 w sk艂ad tej samej jednostki leksykalnej. Modu艂 nadrz臋dny (analizator sk艂adniowy) otrzymuje jedynie informacje o rozpoznanej jednostce - upraszcza to jego prac臋.
Przez leksem rozumie si臋 rozumiemy wyodr臋bniony w tek艣cie ci膮g znak贸w, kt贸ry odpowiada rozpoznanej jednostce leksykalnej. Na przyk艂ad, w tek艣cie wyj艣ciowym, maj膮cym posta膰 programu paskalowego:
var liczba : integer = 12;
begin
liczba := liczba + 567
end.
mo偶emy wyr贸偶ni膰 nast臋puj膮ce leksemy i jednostki leksykalne:
|
||
Jednostki leksykalne |
Leksemy |
Atrybuty |
„var” |
var |
- |
id |
liczba |
„liczba' |
„:” |
: |
- |
id |
integer |
„integer” |
„=” |
= |
- |
numb |
12 |
„12” |
„;” |
; |
- |
„begin” |
begin |
- |
id |
liczba |
„liczba” |
asgn |
:= |
- |
id |
liczba |
„liczba” |
„+” |
+ |
- |
numb |
567 |
„567” |
„end” |
end |
- |
„.” |
. |
- |
|
Poniewa偶 w pewnym momencie translacji (interpretacji) informacja o samych jednostkach leksykalnych nie wystarcza, przypisuje si臋 im (jednostkom leksykalnym) atrybuty. Atrybut jest zwykle leksemem, ale mo偶e te偶 przyjmowa膰 inn膮 posta膰 - np. kodu binarnego liczby.
Wsp贸艂praca analizatora leksykalnego z modu艂em nadrz臋dnym (zwykle analizatorem sk艂adniowym) mo偶e odbywa膰 si臋 w dw贸ch systemach, zwanych umownie poziomym i pionowym. Poni偶szy schemat przedstawia system poziomy:
W systemie poziomym, w pierwszej fazie pracuje tylko analizator leksykalny. Na podstawie tekstu wej艣ciowego, generuje on reprezentacj臋 po艣redni膮 w postaci pliku, zawieraj膮cego ci膮g jednostek leksykalnych. W drugiej fazie pracy, modu艂 nadrz臋dny wykonuje swoj膮 cz臋艣膰 pracy (np. analiz臋 sk艂adniow膮) na podstawie otrzymanej reprezentacji po艣redniej.
Schemat dzia艂ania analizatora leksykalnego i modu艂u nadrz臋dnego w systemie pionowym przedstawia poni偶szy rysunek:
W takim systemie pracy analizator leksykalny i modu艂 nadrz臋dny pracuj膮 jednocze艣nie. Analizator leksykalny ma zwykle posta膰 podprogramu (funkcji) i jest wywo艂ywany na 偶膮danie modu艂u nadrz臋dnego, kt贸remu przekazuje informacj臋 o rozpoznanej jednostce leksykalnej. Analizator leksykalny b臋dzie wi臋c uaktywniony tyle razy, ile jest jednostek leksykalnych w tek艣cie 藕r贸d艂owym.
Wprowadzenie do generatora Lex
Lex jest narz臋dziem u艂atwiaj膮cym realizacj臋 analizator贸w leksykalnych. Na podstawie specyfikacji analizatora tworzy on funkcj臋 yylex zapisan膮 w j臋zyku C. Funkcja ta mo偶e zosta膰 wykorzystana zar贸wno w systemie poziomym (w po艂膮czeniu z funkcj膮 main w przypadku j臋zyka C), jak i pionowym (po do艂膮czeniu modu艂u nadrz臋dnego).
Og贸lny schemat specyfikacji analizatora leksykalnego w j臋zyku Lex ma nast臋puj膮c膮 posta膰:
[definicje pomocnicze]
%%
[regu艂y przetwarzania]
%%
[podprogramy pomocnicze]
Zar贸wno definicje pomocnicze, jak i podprogramy pomocnicze s膮 opcjonalne. Ka偶da regu艂a przetwarzania sk艂ada si臋 ze wzorca i akcji, zapisanych w postaci:
wzorzec akcja
Je艣li w tek艣cie zostanie rozpoznany ci膮g znak贸w opisanych przez wzorzec, w贸wczas zostanie wykonana akcja. Wszystkie nierozpoznane ci膮gi znak贸w (nie pasuj膮ce do 偶adnego wzorca) zostan膮 przepisane na standardowe wyj艣cie. Najprostszy wzorzec mo偶e po prostu poda膰, o jaki ci膮g chodzi. Najprostsza akcja ma natomiast posta膰 艣rednika, oznaczaj膮cego „nic nie r贸b”.
Wa偶n膮 cech膮 Lexa jest mo偶liwo艣膰 opisu skomplikowanych wzorc贸w. Jak ju偶 wspomniano, najprostszym wzorcem jest tekst, kt贸ry musi pojawi膰 si臋 na wej艣ciu, aby zosta艂a wykonana akcja. Ale wzorzec mo偶e zawiera膰 zbiory znak贸w. Ujmuje si臋 je w nawiasy prostok膮tne, wi臋c na przyk艂ad wzorzec [abc] oznacza zbi贸r znak贸w sk艂adaj膮cy si臋 z trzech liter: `a', `b' i `c'. Je艣li wi臋c kt贸rykolwiek z tych znak贸w pojawi si臋 na wej艣ciu zostanie dopasowany do wzorca. W sytuacjach, gdy 艂atwiej jest poda膰 znaki, kt贸re nie nale偶膮 do zbioru, mo偶na zastosowa膰 operator dope艂nienia zbioru - `^'. Umieszcza si臋 go zaraz po nawiasie `[` otwieraj膮cym zbi贸r. Mo偶na te偶 okre艣li膰 zbi贸r podaj膮c zakres znak贸w o kolejnych numerach w kodzie ASCII. Wykorzystujemy w tym celu znak `-`. Tak wi臋c do wzorca [^0-9] pasuj膮 wszystkie znaki nie b臋d膮ce cyframi.
Przedstawiane wzorce s膮 wyra偶eniami regularnymi. Lex udost臋pnia wiele operacji na tych wyra偶eniach u艂atwiaj膮cych konstruowanie skomplikowanych wzorc贸w. Jedn膮 z podstawowych operacji jest konkatenacja. Je偶eli L(r1) oznacza zbi贸r znak贸w opisanych przez wyra偶enie r1, a L(r1) - zbi贸r znak贸w odpowiadaj膮cych wyra偶eniu regularnemu r2, to konkatenacj臋 wyra偶e艅 regularnych definiujemy jako:
Przyk艂adowy wzorzec [0-9][0-9] oznacza wi臋c liczb臋 sk艂adaj膮c膮 si臋 z dw贸ch cyfr.
Wyra偶enie regularne mo偶e zosta膰 poddane operacji domkni臋cia zwrotnego oznaczanej przez znak gwiazdki. Podstawow膮 w艂asno艣ci膮 pustego ci膮gu znak贸w jest to, 偶e 蔚x聽=聽x聽=聽x蔚 dla dowolonego ci膮gu x. Przyjmijmy nast臋puj膮ce definicje:
,
.
W贸wczas operacj臋 domkni臋cia mo偶na zdefiniowa膰 nast臋puj膮co:
.
Z definicji wynika, 偶e je偶eli z wyra偶eniem w zwi膮zany jest zbi贸r znak贸w W, to w* zawiera ci膮g pusty 蔚, zbi贸r W, oraz konkatenacje WW, WWW itd. Na przyk艂ad 1* oznacza zbi贸r {蔚,聽11, 111,聽…}. Z analiz膮 takich ci膮g贸w wi膮偶e si臋 pewien problem - nie wiadomo, czy przyk艂adowy ci膮g 111 potraktowa膰 jako jeden ci膮g, jako konkatenacj臋 trzech ci膮g贸w, czy mo偶e konkatenacj臋 dw贸ch. We wszystkich analizatorach leksykalnych ten problem rozwi膮zuje si臋 tak samo - poprzez zasad臋 najd艂u偶szego dopasowania. Post臋puj膮c zgodnie z t膮 zasad膮 analizator stara si臋 rozpozna膰 i dopasowa膰 mo偶liwie najd艂u偶szy ci膮g wej艣ciowy. Zatem w podanym przyk艂adzie analizator dopasowa艂by ci膮g 111. Poniewa偶 we wzorcach podobnych do przyk艂adu, analizator ka偶dy pusty ci膮g (jest ich niesko艅czenie wiele) dopasowywa艂by do wzorca (i wykonywa艂 odpowiedni膮 akcj臋), przyj臋to zasad臋, 偶e wykorzystywane s膮 tylko te regu艂y, kt贸rym odpowiada niepusty ci膮g wej艣ciowy. Je偶eli natomiast oka偶e si臋, 偶e tekst odpowiada kilku regu艂om (i nie mo偶na zastosowa膰 zasady najd艂u偶szego dopasowania), wybrana zostanie regu艂a wyst臋puj膮ca jako pierwsza w kolejno艣ci.
Innym operatorem u艂atwiaj膮cym konstrukcj臋 wzorc贸w jest operator opcjonalno艣ci - znak `?'. Ci膮g w? oznacza ci膮g w lub ci膮g pusty. Mo偶emy r贸wnie偶 u偶ywa膰 symbolu `+', r贸偶ni膮cego si臋 od `*' tym, 偶e nie zawiera ci膮gu pustego. Wzorzec m+ mo偶emy wi臋c zapisa膰 jako m*m. Mo偶emy r贸wnie偶 okre艣li膰 wprost krotno艣膰 konkatenacji danego wyra偶enia. Krotno艣膰 t臋 zapisuje si臋 po danym wyra偶eniu, uj臋t膮 w nawiasy klamrowe. Specyfikacja generatora Lex zawiera jeszcze operator kropki (`.'), kt贸ry odpowiada dowolnemu, widzialnemu znakowi.
Generator Lex ma wbudowany mechanizm retrakcji, dzi臋ki czemu unika dopasowywania ci膮gu do wzorcu w sytuacji, w kt贸rej d艂u偶szy ci膮g (rozpoczynaj膮cy si臋 od dotychczas przeczytanego) m贸g艂by zosta膰 dopasowany. W chwili, gdy ci膮g na wej艣ciu zosta艂 kompletnie dopasowany do jakiego艣 wzorca, a zasada najd艂u偶szego dopasowania sugeruje kontynuacj臋 dopasowania do innego wzorca, Lex zapami臋tuje pozycj臋 w tek艣cie wej艣ciowym i wzorzec, do kt贸rego uda艂o mu si臋 ju偶 dopasowa膰 ci膮g wej艣ciowy, a nast臋pnie kontynuuje dopasowanie do d艂u偶szego „wzorca” (wzorca, do kt贸rego dopasowane tekst b臋dzie d艂u偶szy). W przypadku, gdyby dopasowanie nie powiod艂o si臋, Lex wraca do ostatniego dopasowanego wzorca, wykonuj臋 zwi膮zan膮 z nim akcj臋 i rozpoczyna analiz臋 od miejsca, w kt贸rym zako艅czy艂 si臋 dopasowany ci膮g.
Z zaawansowanych technik, kt贸re Lex udost臋pnia u偶ytkownikowi, nale偶y jeszcze wymieni膰 mo偶liwo艣膰 uwzgl臋dniania kontekstu - zar贸wno prawego, jak i lewego. Pozwala to rozstrzyga膰 sytuacje, w kt贸rych ten sam ci膮g znak贸w mo偶e by膰 r贸偶nie potraktowany, w zale偶no艣ci od kontekstu, w kt贸rym wyst臋puje. Uwzgl臋dnianie lewego kontekstu zrealizowano w Lexie za pomoc膮 mo偶liwo艣ci korzystania ze stan贸w pocz膮tkowych, natomiast uwzgl臋dnianie prawego kontekstu za pomoc膮 mo偶liwo艣ci konstruowania regu艂 typu w/p - regu艂a taka oznacza, 偶e ci膮g wej艣ciowy mo偶na dopasowa膰 do wzorca w tylko wtedy, gdy po tym ci膮gu wyst臋puje ci膮g pasuj膮cy do p.
Analiza sk艂adniowa - Yacc
Jak wspomniano wcze艣niej, z analizatora sk艂adniowego wyodr臋bnia si臋 osobny modu艂, analizator leksykalny, do zbudowania kt贸rego mo偶e nam pos艂u偶y膰 Lex. Analizator sk艂adniowy jest wtedy modu艂em nadrz臋dnym dla analizatora leksykalnego - wykorzystuje wyniki jego pracy. Dobrym narz臋dziem pomocniczym, s艂u偶膮cym do tworzenia analizator贸w sk艂adniowych, jest YACC - podobnie jak Lex opracowany w ameryka艅skiej firmie AT&T. YACC mo偶e wsp贸艂pracowa膰 z Lexem w systemie pionowym (patrz p.聽IV.4.1). Po艂膮czone si艂y obu narz臋dzi mog膮 pos艂u偶y膰 do tworzenia r贸偶norakich translator贸w i interpreter贸w - pocz膮wszy od prostego kalkulatora, zako艅czywszy na kompilatorach skomplikowanych j臋zyk贸w programowania.
J臋zyk i gramatyka bezkontekstowa
Pierwszym warunkiem, jaki musi spe艂nia膰 j臋zyk, aby mo偶na by艂o przetwarza膰 go za pomoc膮 YACCa jest bezkontekstowo艣膰 jego gramatyki. Oznacza to, 偶e opisuj膮c gramatyk臋 j臋zyka, specyfikujemy jedn膮, lub wi臋cej grup syntaktycznych i tworzymy (opisujemy) regu艂y konstruowania ich z cz臋艣ci. Dla przyk艂adu - w j臋zyku C tak膮 grup膮 jest wyra偶enie. Jedn膮 z regu艂 tworz膮cych wyra偶enie mo偶e by膰 zdanie: „wyra偶enie sk艂ada si臋 ze znaku minus i innego wyra偶enia”. Inn膮 mo偶e by膰 zdanie: „wyra偶enie mo偶e by膰 liczb膮 ca艂kowit膮”. Jak wida膰, w opisie regu艂 cz臋sto stosuje si臋 rekursj臋, jednak musi istnie膰 przynajmniej jedna regu艂a, kt贸ry rekursj臋 ko艅czy.
Najbardziej rozpowszechnionym, formalnym systemem zapisu takich regu艂 (czyli zapisu gramatyki), w formie czytelnej dla cz艂owieka jest posta膰 BNF (Backus-Naur Form). Posta膰 ta zosta艂a opracowana przy pisaniu specyfikacji j臋zyka Algol聽60. Podstawow膮 jej cech膮 jest to, 偶e ka偶da gramatyka wyra偶ona w notacji BNF jest gramatyk膮 bezkontekstow膮. Posta膰 wej艣ciow膮 dla YACC'a stanowi gramatyka zapisana w notacji BNF w formacie czytelnym dla maszyny.
Nale偶y zaznaczy膰, 偶e nie wszystkie gramatyki bezkontekstowe mog膮 by膰 przetworzone przez YACC'a. Podzbi贸r gramatyk, kt贸re mog膮 by膰 przetworzone nazywa si臋 LALR(1) i jest on podzbiorem zbioru gramatyk okre艣lanego jako LR(1). Definicja gramatyki LR(1) m贸wi, 偶e jest to taka gramatyka, dla kt贸rej w dowolnej chwili mo偶na okre艣li膰, jak przetworzy膰 dany fragment tekstu wej艣ciowego, odczytuj膮c tylko jeden symbol (jednostk臋 leksykaln膮) wi臋cej, ni偶 wymaga tego regu艂a. W j臋zyku angielskim t臋 jednostk臋 leksykaln膮 okre艣la si臋 jako look-ahead token. Gramatyka LALR(1) jest gramatyk膮 LR(1) z pewnymi ma艂ymi ograniczeniami, kt贸re w praktyce zdarzaj膮 si臋 bardzo rzadko, a pozwoli艂y znacznie upro艣ci膰 budow臋 generatora YACC.
W formalnym zapisie gramatyki, ka偶d膮 jednostk臋 syntaktyczn膮, lub ich grup膮 nazywa si臋 symbolem. Jednostki, kt贸re sk艂adaj膮 si臋 z grupy innych jednostek opisanych regu艂膮 gramatyczn膮, nazywamy symbolami nieterminalnymi. Natomiast jednostki niepodzielne nazywamy symbolami terminalnymi (s膮 to jednostki leksykalne).
Ka偶dy symbol nieterminalny musi by膰 opisany przez regu艂臋 gramatyczn膮 okre艣laj膮c膮, jak mo偶na roz艂o偶y膰 go na prostsze symbole. Dla przyk艂adu jedn膮 z regu艂 opisuj膮cych instrukcj臋 j臋zyka C m贸g艂by by膰 opis instrukcji „return” zapisany jako ”instrukcja mo偶e sk艂ada膰 si臋 ze s艂owa kluczowego `return', `wyra偶enia' i `艣rednika'”. Takich regu艂 opisuj膮cych instrukcj臋 j臋zyka C by艂oby znacznie wi臋cej. Symbolami terminalnymi w tej regule s膮: s艂owo kluczowe `return' i 艣rednik (`;'). Natomiast symbol nieterminalny `wyra偶enie' podlega dalszemu rozk艂adowi.
W zapisie gramatyki wyr贸偶niamy jeden symbol nieterminalny, kt贸ry okre艣la ca艂o艣膰 tekstu wej艣ciowego w opisywanym j臋zyku. Jest on nazywany symbolem pocz膮tkowym (ang. start symbol). W przypadku kompilatora ten symbol opisywa艂by ca艂y program.
Parser (analizator sk艂adniowy) wygenerowany przez YACC'a odczytuje sekwencj臋 jednostek leksykalnych i grupuje te jednostki u偶ywaj膮c do tego regu艂 gramatycznych. Je偶eli wej艣cie zawiera prawid艂owy tekst (zapisany zgodnie z gramatyk膮 danego j臋zyka), ca艂a sekwencja jednostek leksykalnych zostanie zredukowana do jednego symbolu - symbolu pocz膮tkowego. W przeciwnym razie parser zg艂osi b艂膮d sk艂adniowy.
Regu艂y formalne w zapisie dla YACC'a
Gramatyka formalna jest konstrukcj膮 matematyczn膮. Aby zdefiniowa膰 j臋zyk dla YACC'a, nale偶y stworzy膰 plik zawieraj膮cy zapis gramatyki w formacie czytelnym dla YACC'a. Nale偶y przy tym pami臋ta膰 o kilku zasadach.
Symbol nieterminalny gramatyki formalnej jest w YACC'u reprezentowany przez identyfikator (wyraz z艂o偶ony z liter, cyfr i znaku podkre艣lenia, w kr贸rym pierwszy znak nie mo偶e by膰 cyfr膮). Nieterminale przyj臋艂o si臋 zapisywa膰 ma艂ymi literami - np. expr, statement, declaration.
Symbole terminalne reprezentowane s膮 r贸wnie偶 za pomoc膮 identyfikator贸w, ale dla odr贸偶nienia od nieterminali zwyk艂o si臋 zapisywa膰 je wielkimi literami - przyk艂adami mog膮 by膰 s艂owa: IF, RETURN, INTEGER. Symbol terminalny, kt贸ry jest jednostk膮 leksykaln膮 opowiadaj膮c膮 s艂owu kluczowemu j臋zyka przyj臋to nazywa膰 tak, jak to s艂owo kluczowe, ale te偶 zapisane wielkimi literami. Symbol terminalny error jest zarezerwowany. Symbol terminalny mo偶e by膰 r贸wnie偶 reprezentowany przez sta艂膮 znakow膮, zapisywan膮 podobnie jak w j臋zyku C - za pomoc膮 znaku uj臋tego w apostrofy. Tego oznaczenia u偶ywa si臋 zawsze wtedy, gdy leksem jest pojedynczym znakiem.
Regu艂a zapisana w j臋zyku YACC'a sk艂ada si臋 z symbolu nieterminalnego, kt贸ry jest przez t臋 regu艂臋 opisywany, dwukropka, wyra偶e艅 okre艣laj膮cych mo偶liwy rozk艂ad nieterminalu (oddzielonych symbolem `|') i 艣rednika ko艅cz膮cego regu艂臋. Na przyk艂ad:
stmt : RETURN expr ';'
;
Warto艣ci semantyczne
Gramatyka formalna rozr贸偶nia jednostki leksykalne tylko wed艂ug ich rodzaju. Dla przyk艂adu je艣li w regule znajdziemy okre艣lenie `sta艂a ca艂kowita', oznacza to, 偶e w tym miejscy mo偶e si臋 znale藕膰 dowolna liczba ca艂kowita. A wi臋c wyra偶enia x+1 i x+15 s膮 gramatycznie r贸wne. Jednak przy translacji (interpretacji) tekstu wej艣ciowego potrzebne s膮 r贸wnie偶 informacji nie maj膮ce znaczenia z gramatycznego punktu widzenia. Je偶eli tworzymy translator t艂umacz膮cy tekst na inn膮 posta膰, te warto艣ci (np. konkretne liczby) zostan膮 gdzie艣 umieszczone w tek艣cie wynikowym, je偶eli tworzymy interpreter - te warto艣ci s膮 potrzebne do oblicze艅. Dlatego ka偶dy symbol w gramatyce YACC'a niesie ze sob膮 dwie warto艣ci - jednostk臋 leksykaln膮 i warto艣膰 semantyczn膮.
Jednostka leksykalna, jak ju偶 napisano wcze艣niej, jest symbolem terminalnym gramatyki - i zawiera wszystkie informacje potrzebne do zadecydowania, w kt贸rym miejscu dany symbol mo偶e si臋 pojawi膰 i jak grupowa膰 symbole z innymi symbolami wed艂ug regu艂 gramatycznych. Warto艣膰 semantyczna przechowuje natomiast reszt臋 informacji zwi膮zanej z symbole - warto艣膰 liczby ca艂kowitej, konkretn膮 nazw臋 identyfikatora itd.
Dla przyk艂adu: symbol wej艣ciowy m贸g艂by zosta膰 rozpoznany jako `liczba ca艂kowita' i mie膰 warto艣膰 semantyczn膮 r贸wn膮 4. Inny symbol m贸g艂by zosta膰 rozpoznany r贸wnie偶 jako `liczba ca艂kowita', ale mie膰 inn膮 warto艣膰 semantyczn膮, np. 534. Je偶eli regu艂a gramatyczna m贸wi, 偶e w danym miejscu mo偶e pojawi膰 si臋 `liczba ca艂kowita', oba symbole mog艂yby si臋 tam pojawi膰, gdy偶 oba s膮 identyczn膮 jednostk膮 leksykaln膮. Nale偶y zaznaczy膰, 偶e grupa symboli (opisana przez regu艂臋) r贸wnie偶 mo偶e (i zwykle powinna) mie膰 warto艣膰 semantyczn膮.
Akcje semantyczne
Aby kod wygenerowany przez YACC'a by艂 u偶yteczny, musi robi膰 on co艣 wi臋cej, ni偶 tylko stwierdzi膰 poprawno艣膰 tekstu wej艣ciowego. W przypadku kompilatora powinien on wygenerowa膰 program wynikowy, w przypadku interpretera wykona膰 jakie艣 obliczenia itp. W zapisie gramatyki dla generatora YACC, ka偶da regu艂a gramatyczna mo偶e posiada膰 akcj臋, zapisan膮 w j臋zyku C. Za ka偶dym razem, gdy parser korzysta z danej regu艂y, wykonuje zwi膮zan膮 z ni膮 akcj臋. Typowym zadaniem akcji jest obliczenie warto艣ci semantycznej grupy wyra偶e艅 na podstawie warto艣ci semantycznych jej poszczeg贸lnych wyra偶e艅. Dla przyk艂adu za艂贸偶my, 偶e regu艂a opisuj膮ca wyra偶enie opisuje je jako sum臋 dw贸ch wyra偶e艅. Gdy parser rozpozna na wej艣ciu tak膮 sum臋, ka偶de z wyra偶e艅 wchodz膮cych w jej sk艂ad ma ju偶 warto艣膰 semantyczn膮. Zadaniem akcji powinno wi臋c by膰 obliczenie warto艣ci semantycznej dla nowo rozpoznanego wyra偶enia. Regu艂臋 mo偶na by zapisa膰 w nast臋puj膮cy spos贸b:
expr : expr '+' expr { $$ = $1 + $3; }
;
Akcja (zapisana w nawiasach klamrowych) m贸wi, 偶e warto艣膰 semantyczna wyra偶enia ($$) powinna by膰 sum膮 warto艣ci dw贸ch symboli - pierwszego ($1) i trzeciego ($3). Drugim symbolem w regule jest `+' i oznaczyliby艣my go jako $2.
Wynik dzia艂ania YACC'a - parser
Plikiem wej艣ciowym dla generatora YACC jest zapis gramatyki j臋zyka. Plikiem wynikowym jest natomiast 藕r贸d艂o parsera j臋zyka wej艣ciowego zapisane w j臋zyku C. Ten parser wykorzystujemy we w艂asnym programie.
Zadaniem parsera (programu wygenerowanego przez YACC'a) jest grupowanie jednostek leksykalnych zgodnie z regu艂ami gramatyki i wykonywanie odpowiednich akcji. Jednostki leksykalne s膮 pobierane za pomoc膮 funkcji z analizatora leksykalnego, kt贸ry musi by膰 do艂膮czony do wynikowego programu. YACC wywo艂uje analizator leksykalny (dok艂adnie m贸wi膮c: funkcj臋 yylex) za ka偶dym razem, gdy musi odczyta膰 now膮 jednostk臋 leksykaln膮. Jak wspomniano na pocz膮tku opisu generatora YACC, jako analizator leksykalny 艣wietnie nadaje si臋 Lex. Oba analizatory wsp贸艂pracuj膮 wtedy w systemie pionowym.
W kodzie wygenerowanym przez YACC'a najwa偶niejsz膮 rol臋 pe艂ni funkcja yyparse, kt贸ra uruchamia w艂a艣ciwy parser. Kod nie zawiera funkcji main, kt贸ra w j臋zyka C jest obowi膮zkowa. Funkcj臋 t臋 nale偶y dopisa膰 (umieszczaj膮c gdzie艣 wywo艂anie funkcji yyparse). Do programisty nale偶y r贸wnie偶 zadanie napisania funkcji obs艂uguj膮cej b艂臋dy podczas analizy tekstu wej艣ciowego - jest to funkcja yyerror, jest ona wywo艂ywana przez parser w przypadku stwierdzenia nieprawid艂owo艣ci w tek艣cie wej艣ciowym (tzn. jego niezgodno艣ci z gramatyk膮 j臋zyka).
Etapy praca z generatorem analizatora sk艂adniowego
Podsumowuj膮c, stworzenie kompilatora lub interpretera, przy za艂o偶eniu, 偶e dysponujemy gramatyk膮 opisywanego j臋zyka, sk艂ada si臋 w og贸lno艣ci z czterech krok贸w:
Zapis gramatyki w formie rozpoznawalnej dla YACC'a, napisanie akcji dla ka偶dej regu艂y j臋zykowej.
Napisanie analizatora leksykalnego. W tym celu mo偶na wykorzysta膰 generator analizator贸w leksykalnych - Lex.
Napisanie w艂asnej cz臋艣ci programu, w kt贸rej zawrzemy wywo艂anie funkcji parsera - yyparse.
Napisanie funkcji obs艂uguj膮cej b艂臋dy.
Aby z otrzymanych plik贸w 藕r贸d艂owych otrzyma膰 dzia艂aj膮cy program, nale偶y wykona膰 trzy kroki:
Uruchomi膰 YACC'a z zapisan膮 gramatyk膮, aby otrzyma膰 parser.
Skompilowa膰 kod wygenerowany przez YACC'a, jak r贸wnie偶 pozosta艂e modu艂y programu.
Z艂膮czy膰 powsta艂e pliki aby otrzyma膰 program wykonywalny (艂膮czenie - linking).
Projekt systemu magazynu danych - architektura
Za艂o偶enia projektowanego systemu
Przyst臋puj膮c do pracy nad projektem, ustalili艣my konkretne za艂o偶enia dotycz膮ce projektu, ustalaj膮ce jego architektur臋 i opisuj膮ce jego cechy. Przyj臋li艣my, 偶e zaprojektujemy system magazynowania danych oparty na metodologii ROLAP - oznaczaj膮cy relacyjny system OLAP (patrz opis ROLAPu - s. 13).
Wymaganiem, jakie stawiamy tworzonemu jest ci膮g艂e utrzymywanie jego zawarto艣ci w stanie sp贸jno艣ci w stosunku do 藕r贸d艂owych informacji. Oznacza to utrzymywanie informacji w magazynie w stanie zgodnym ze stanem 藕r贸d艂owych baz danych. Ta cecha odr贸偶nia nasz system od typowych system贸w OLAP, a wprowadzamy tak膮 innowacj臋 ze wzgl臋du na wymagania firm korzystaj膮cych z takich system贸w informacji - zwykle decyzje podejmuje si臋 szybko i wiele zale偶y od szybkiego uzyskania aktualnych informacji.
Owa szybko艣膰 uzyskiwania informacji narzuca kolejn膮 po偶膮dan膮 cech臋 systemu - jego efektywno艣膰. Poniewa偶 jest to dosy膰 istotna sprawa, nasz system musi sk艂adowa膰 dane inkrementalnie - czyli uzupe艂nia膰 zawarto艣膰 magazynu jedynie o nowe informacje.
Kolejnym za艂o偶eniem projektowanego systemu jest komunikacja z u偶ytkownikiem za pomoc膮 j臋zyka SQL. Wynika to z faktu, i偶 j臋zyk ten jest dzi艣 standardem w dziedzinie relacyjnych bazach danych i jego wyb贸r jest w艂a艣ciwie naturalny.
W kolejnym punkcie przedstawiono architektur臋 systemu i wymagania, jakie stawiamy jego otoczeniu, a dalej opisano przeznaczenie wszystkich modu艂贸w systemu.
Architektura systemu
Architektur臋 projektowanego systemu mo偶na przedstawi膰 na rysunku:
Ca艂o艣膰 systemu sk艂ada si臋 z kilku element贸w: magazynu danych, 藕r贸d艂owych baz danych i czterech modu艂贸w projektowanego systemu „rozpi臋tych” pomi臋dzy tymi bazami, a u偶ytkownikiem. Zak艂adamy istnienie poprawnie skonstruowanych 藕r贸d艂owych baz danych - za ich utrzymywanie odpowiedzialny jest odbiorca systemu. Zak艂adamy r贸wnie偶 fizyczne istnienie bazy danych przeznaczonej na magazyn. Sam projekt sk艂ada si臋 z czterech g艂贸wnych modu艂贸w - query processora, integratora, monitora i wrappera oraz narz臋dzi konfiguracyjnych. Aby dok艂adnie om贸wi膰 zadania systemu, niezb臋dne jest przedstawienie jego wymaga艅, co do struktury 藕r贸d艂owych baz danych.
Wymagania dla 藕r贸d艂owych baz danych
Z za艂o偶e艅 systemu (jest to system ROLAP) wynikaj膮 wymagania, jakie musz膮 spe艂nia膰 藕r贸d艂owe bazy danych. Przyj臋li艣my, 偶e uk艂ad relacji w tych bazach ma uk艂ad p艂atka 艣niegu. Dok艂adne za艂o偶enia tej struktury s膮 nast臋puj膮ce:
W zbiorze relacji mo偶emy wyr贸偶ni膰 jedn膮 relacj臋 centraln膮, zwan膮 tabel膮 fakt贸w. Gromadzi ona informacje o warto艣ciach liczbowych pewnych operacji, np. o warto艣ciach sprzedanych towar贸w, ilo艣ci itd.
Pozosta艂e relacje nazywamy relacjami bocznymi - zawieraj膮 one jedynie informacje o podmiotach, na kt贸rych s膮 wykonywane operacje - np. w przypadku systemu sprzeda偶y o towarach, klientach, sprzedawcach itd.
Klucz g艂贸wny relacji bocznej sk艂ada si臋 z jednego atrybutu (jest to zwykle identyfikator numeryczny, ale nie jest to wymogiem).
Relacje mog膮 艂膮czy膰 si臋 ze sob膮 za pomoc膮 kluczy obcych, przy czym atrybutem wskazywanym przez klucz obcy musi by膰 klucz g艂贸wny relacji bocznej.
Uk艂ad relacji wraz z powi膮zaniami tworzy struktur臋 p艂atka 艣niegowego. Jego centrum stanowi relacja centralna, kt贸ra zawiera powi膮zania do relacji bocznych, te za艣 zawieraj膮 powi膮zania do kolejnych relacji bocznych itd. Wymogiem jest, aby klucz obcy tworz膮cy powi膮zanie zawsze wskazywa艂 na relacj臋 boczn膮 tworz膮c膮 now膮 ga艂膮藕, a nie do艂膮cza艂 si臋 do ga艂臋zi ju偶 istniej膮cej. Inaczej m贸wi膮c: ka偶da relacja mo偶e zawiera膰 wiele kluczy obcych, ale mo偶e by膰 wskazywany tylko przez jeden klucz obcy.
Aby zobrazowa膰 t臋 struktur臋, przedstawimy przyk艂adowy schemat prawid艂owo utworzonych relacji 藕r贸d艂owych - schemat systemu sprzeda偶y:
Klucze obce podkre艣lono na rysunku lini膮 przerywan膮, natomiast klucze g艂贸wne lini膮 ci膮g艂膮. Klucz obcy `zam贸wienie' relacji `sprzeda偶' wskazuje na klucz g艂贸wny relacji `zam贸wienia' (`id'), klucz obcy `towar' w relacji `sprzedaz' wskazuje na klucz g艂贸wny `id' w relacji `towary', itd. Podobnie z relacjami bocznymi - klucz obcy `kategoria' relacji `towary' wskazuje na klucz g艂贸wny relacji `kategorie' (`id') itd.
Relacja centralna zawiera dwa atrybuty nie b臋d膮ce kluczami - `ilo艣膰' i `warto艣膰'. Ka偶dy wpis w tabeli `sprzeda偶' opisuje wi臋c jeden fakt sprzeda偶y - podaje identyfikatory klienta, sprzedawcy, towaru, itd. oraz warto艣膰 sprzeda偶y i ilo艣膰 sprzedanych towar贸w. Korzystaj膮c z dalszych relacji bocznych mo偶emy r贸wnie偶 na podstawie tego faktu okre艣li膰 do jakiej kategorii nale偶y sprzedany towar, do jakiego wojew贸dztwa trafi艂 itd.
Jak wida膰, przyk艂ad nie wykorzystuje wszystkich mo偶liwo艣ci uk艂adu p艂atka 艣niegu - z ka偶dej relacji bocznej mo偶e przecie偶 wychodzi膰 wi臋cej ni偶 jedno powi膮zanie z kolejnymi relacjami. Jest jednak wystarczaj膮cy do zilustrowania struktury ROLAPu i b臋dzie cz臋sto wykorzystywany w dalszej cz臋艣ci pracy jako przyk艂ad.
Efektem prawid艂owo dzia艂aj膮cego systemu powinno by膰 utrzymywanie w magazynie (przez ca艂y czas pracy systemu) zagregowanych danych zawieraj膮cych warto艣ci funkcji grupuj膮cych, kt贸rych argumentem b臋d膮 wybrane atrybuty relacji centralnej (w przedstawionym przyk艂adzie by艂yby to `ilo艣膰' i `warto艣膰') pogrupowane wed艂ug r贸偶nych kombinacji kluczy g艂贸wnych relacji bocznych. Umo偶liwi to „wyci膮ganie” z magazynu informacji typu: „ile towar贸w z bran偶y kosmetycznej trafia do r贸偶nych wojew贸dztw?”, „Jak rozk艂ada si臋 sprzeda偶 dla konkretnego klienta w poszczeg贸lnych miesi膮cach?” itd. S膮 to zwykle informacje maj膮ce dla firmy znaczenie strategiczne - m贸wi膮ce gdzie inwestowa膰, dok膮d lepiej sprzedawa膰 itd. W naszym przypadku w magazynie zbieramy zagregowane warto艣ci pi臋ciu funkcji grupuj膮cych j臋zyka SQL. S膮 to:
AVG - warto艣膰 艣rednia,
SUM - suma,
MIN - warto艣膰 minimalna,
MAX - warto艣膰 maksymalna,
COUNT - liczba krotek.
Funkcje poszczeg贸lnych modu艂贸w systemu
Jak ju偶 zaznaczono, w sk艂ad projektu wchodz膮 cztery modu艂y, wsp贸艂pracuj膮ce ze sob膮 oraz modu艂 do konfiguracji systemu.
Od modu艂u konfiguracji wymaga si臋 przede wszystkim 艂atwo艣ci obs艂ugi i przejrzystego interfejsu u偶ytkownika. Program sam powinien zapyta膰 o wszystkie niezb臋dne informacje (adresy 藕r贸d艂owych baz danych, schematy relacji itd.) i poprawnie skonfigurowa膰 system magazynowania. Wymagany jest interfejs graficzny.
Modu艂 query processora jest po艣rednikiem pomi臋dzy u偶ytkownikiem, a magazynem danych. Jak wcze艣niej zaznaczono, u偶ytkownik komunikuje si臋 z tym modu艂em w j臋zyku SQL, zadaniem query processora jest natomiast zrealizowanie jego polece艅. Poniewa偶 u偶ytkownik korzysta z informacji zawartych w magazynie w trybie „tylko do odczytu”, jego polecenia s膮 zapytaniami (queries). Oczywi艣cie u偶ytkownik (w firmie korzystaj膮cej z systemu u偶ytkownik贸w jest zwykle wielu) nie chce si臋 zag艂臋bia膰 w struktur臋 magazynu, wi臋c zadaje zapytania tak, jakby pyta艂 藕r贸d艂ow膮 baz臋 danych. Zadaniem query processora jest natomiast odpowiednie przetworzenie i wykonanie tego zapytania. Podstawowym wymaganiem modu艂u jest mo偶liwo艣膰 jego wykorzystania w nowo tworzonych aplikacjach - generatorach raport贸w, wykres贸w, systemach wspomagania decyzji - zastosowa艅 jest wiele.
Modu艂 integratora jest najwa偶niejszym modu艂em w ca艂ym opracowywanym systemie. Jego funkcj臋 mo偶na por贸wna膰 do roli silnika w samochodzie. Zadaniem integratora jest inicjalizacja magazynu danych, pocz膮tkowa integracja danych ze 藕r贸d艂owych baz danych oraz przyrostowa piel臋gnacja zmaterializowanych danych w magazynie danych.
Modu艂 wrappera ma za zadanie konwertowanie danych ze 藕r贸d艂owych baz danych do wsp贸lnego formatu danych u偶ywanego w naszym projekcie. Modu艂 ten jest umiejscowiony nad ka偶d膮 藕r贸d艂ow膮 baz膮 danych, wykonuje zapytanie otrzymane od modu艂u integratora i konwertuje wyniki otrzymane z tego 藕r贸d艂a do wsp贸lnego formatu danych specyficznych dla naszego projektu.
Modu艂 monitora ma za zadanie reagowanie na zachodz膮ce w bazie 藕r贸d艂owej zmiany i przesy艂anie wiadomo艣ci o nich do integratora. Wa偶ne przy tym jest to, by wiadomo艣ci o zmianach przychodzi艂y do integratora w takiej samej kolejno艣ci co zachodzi艂y zmiany.
Podstawowym wymaganiem dotycz膮cym monitora i wrappera jest to, by dla ka偶dego rodzaju 藕r贸d艂owej bazy danych mo偶na by艂o przy mo偶liwie najni偶szym nak艂adzie si艂 stworzy膰 odpowiedni膮 wersj臋 monitora i wrappera.
Implementacja systemu
Struktura magazynu
Magazyn jest w istocie zbiorem relacji, kt贸ry mo偶na podzieli膰 na dwie cz臋艣ci. Pierwsz膮 cz臋艣膰 stanowi s艂ownik systemu. W nim zgromadzone s膮 wszystkie informacje niezb臋dne do prawid艂owego dzia艂ania ca艂ego systemu, a wi臋c:
informacje o strukturze 藕r贸d艂owych baz danych - opis wszystkich relacji, atrybut贸w, ogranicze艅 (klucze g艂贸wne, klucze obce) itd.,
informacje o po艂o偶eniu 藕r贸d艂owych baz danych - adresy komputer贸w, porty komunikacyjne itd.,
informacje o danych, kt贸re system powinien agregowa膰.
Drug膮 cz臋艣膰 magazynu stanowi膮 dane zbierane na bie偶膮co ze 藕r贸d艂owych baz. Oba podzbiory zbioru relacji magazynu s膮 przechowywane na tym samym koncie w bazie danych (w naszym przypadku opartej na systemie firmy Oracle w wersji 8).
Aby system rozpocz膮艂 prac臋, wymagane jest wcze艣niejsze utworzenie odpowiedniego wpisu w bazie u偶ytkownik贸w SZBD (konta - accout). Wymagane jest tak偶e utworzenie wszystkich relacji s艂ownika i ich prawid艂owe wype艂nienie. Do wykonania tej cz臋艣ci pracy zaleca si臋 wykorzystanie do艂膮czonego programu konfiguracyjnego, kt贸ry zapyta o odpowiednie informacje i zrobi to za nas. S艂ownik (czyli konfiguracja systemu magazynowania) jest jednak zawarty ca艂kowicie w opisanym poni偶ej zbiorze relacji, a wi臋c mo偶liwe jest jego r臋czne modyfikowanie (lub nawet utworzenie). Takie podej艣cie umo偶liwia rozszerzenie systemu w przysz艂o艣ci o system zbieraj膮cy automatycznie dane ze 藕r贸d艂owych relacji. Po utworzeniu s艂ownika systemu mo偶na rozpocz膮膰 prac臋 - relacje cz臋艣ci magazynowej s膮 tworzone i wype艂niane w trakcie pracy systemu na bie偶膮co. W nast臋pnych dw贸ch punktach przedstawiono szczeg贸艂owy opis struktury obu cz臋艣ci magazynu.
S艂ownik (metadata store)
Na s艂ownik systemu sk艂ada si臋 szereg relacji. Niekt贸re z nich maj膮 struktur臋 (zbi贸r atrybut贸w) zale偶n膮 od struktury relacji 藕r贸d艂owych, jednak wi臋kszo艣膰 ma budow臋 niezale偶n膮 od konkretnego zbioru relacji w 藕r贸d艂owych bazach danych. Poni偶ej przedstawiono przeznaczenie wszystkich relacji s艂ownika, ich struktur臋, przyk艂adowe wype艂nienie (przy wykorzystaniu przyk艂adowego zbioru relacji przedstawionego przy opisie struktury 藕r贸d艂owych baz danych) oraz polecenie j臋zyka SQL tworz膮ce relacj臋 (przydatne podczas modyfikacji lub r臋cznego tworzenia s艂ownika).
`relacje'
W tej tabeli zgromadzone s膮 informacje o relacjach istniej膮cych w 藕r贸d艂owych bazach danych. Nale偶y doda膰, 偶e je偶eli istnieje relacja 藕r贸d艂owa, kt贸ra nie jest u偶ywana przy agregowaniu danych, wpis o niej nie musi pojawi膰 si臋 w s艂owniku systemu (nie dotyczy to relacji centralnej - tabeli fakt贸w). Zwi臋kszy to wydajno艣膰 systemu. Budowa relacji jest nast臋puj膮ca:
|
|
|
nazwa atrybutu |
typ atrybutu |
ograniczenia |
id_relacji |
NUMBER(4) |
primary key |
nazwa_relacji |
VARCHAR2(100) |
not null |
|
|
|
Opis atrybut贸w:
`id_atrybutu' jest unikalnym identyfikatorem opisywanej tabeli. Jak opisano wcze艣niej, w relacjach 藕r贸d艂owych mo偶na wyr贸偶ni膰 relacj臋 g艂贸wn膮 (tabel臋 fakt贸w). Tabela ta powinna mie膰 `id_relacji' r贸wne zero. Identyfikatory pozosta艂ych relacji w ich opisie s艂ownikowym mog膮 by膰 dowolne.
`nazwa_relacji' zawiera nazw臋 relacji 藕r贸d艂owej.
Polecenie j臋zyka SQL tworz膮ce relacj臋 mo偶e wygl膮da膰 nast臋puj膮co:
CREATE TABLE relacje
(
id_relacji NUMBER(4) primary key,
nazwa_relacji VARCHAR2(100) not null
)
Wype艂nianie tabeli dla przyk艂adowego schematu magazynu danych, przedstawionego wcze艣niej, mog艂oby przebiega膰 nast臋puj膮co:
insert into relacje values ( 0, 'sprzedaz' )
insert into relacje values ( 1, 'wojewodztwa' )
insert into relacje values ( 2, 'miasta' )
insert into relacje values ( 3, 'klienci' )
...
`atrybuty'
Ta tabela gromadzi informacje o atrybutach wszystkich relacji wpisanych w tabeli `relacje'. Je偶eli jaka艣 relacja istnieje w 藕r贸d艂owej bazie danych, a nie posiada wpisu w tabeli `relacje', jej atrybuty nie powinny posiada膰 wpis贸w w tabeli `atrybuty'. Podobnie, jak w przypadku relacji, nie wszystkie atrybuty relacji 藕r贸d艂owych musz膮 mie膰 wpis w s艂owniku. Poci膮ga to jednak za sob膮 pewne konsekwencje:
je偶eli atrybut jest kluczem obcy, jego pomini臋cie spowoduje odci臋cia ca艂ej ga艂臋zi relacji odchodz膮cych od relacji, do kt贸rej ten atrybut nale偶y; Je偶eli jest to naszym zamierzeniem, powinni艣my pomin膮膰 odci臋te relacje (i ich atrybuty) w opisie s艂ownika,
nie mo偶na pomin膮膰 w opisie klucza g艂贸wnego relacji,
je偶eli atrybut nie jest kluczem g艂贸wnym, ani kluczem obcym, jego pomini臋cie spowoduje niemo偶liwo艣膰 u偶ywania tego atrybutu w zapytaniach kierowanych do magazynu.
Budowa relacji `atrybuty' jest nast臋puj膮ca:
|
|
|
nazwa atrybutu |
typ atrybutu |
ograniczenia |
id_atrybutu |
NUMBER(4) |
primary key |
nazwa_atrybutu |
VARCHAR2(100) |
not null |
id_relacji |
NUMBER(4) |
foreign key |
typ |
VARCHAR2(15) |
not null |
|
|
|
Opis atrybut贸w:
`id_atrybutu' jest unikalnym identyfikatorem danego atrybutu, numery identyfikator贸w mog膮 by膰 dowolne.
`nazwa_atrybutu' okre艣la nazw臋 atrybutu w 藕r贸d艂owej bazie danych; warto艣膰 tego pola musi by膰 dok艂adn膮 kopi膮 藕r贸d艂owego atrybutu, je偶eli wi臋c nazwa ta jest atrybutem ograniczonym powinna zosta膰 wpisana do s艂ownika 艂膮cznie ze znakami ograniczaj膮cymi i z odpowiedni膮 wielko艣ci膮 liter.
`id_relacji' okre艣la relacj臋, do kt贸rej nale偶y opisywany atrybut; w rzeczywisto艣ci jest to klucz obcy, wskazuj膮cy na atrybut `id_relacji' tabeli `relacje'.
`typ' jest ci膮giem tekstowym okre艣laj膮cym typ atrybutu (np. `NUMBER(4,5)'), informacja ta jest potrzebna podczas tworzenia relacji magazynuj膮cych dane w celu okre艣lenia dok艂adno艣ci p贸l gromadz膮cych informacje o np. 艣redniej z jakiej艣 warto艣ci.
Polecenie j臋zyka SQL, tworz膮ce tabel臋 wygl膮da nast臋puj膮co:
create table atrybuty
(
id_atrybutu NUMBER(4) primary key,
nazwa_atrybutu VARCHAR2(100) not null,
id_relacji NUMBER(4) references
relacje(id_relacji),
typ VARCHAR2(15) not null
)
Wype艂nianie tabeli dla przyk艂adowego schematu magazynu danych, przedstawionego wcze艣niej, mog艂oby przebiega膰 nast臋puj膮co:
insert into atrybuty values( 0, 'id', 1, 'NUMBER(4)' )
insert into atrybuty values( 1, 'nazwa' , 1, 'VARCHAR2(30)')
insert into atrybuty values( 2, 'id', 2, 'NUMBER(4)' )
insert into atrybuty values( 3, 'nazwa', 2, 'VARCHAR2(20)')
insert into atrybuty values( 4, 'wojewodztwo', 2, 'NUMBER(4)' )
-- pozosta艂e atrybuty relacji bocznych
...
insert into atrybuty values( 28, 'zamowienie', 0, 'NUMBER(4)' )
insert into atrybuty values( 29, 'klient', 0, 'NUMBER(4)' )
insert into atrybuty values( 30, 'sprzedawca', 0, 'NUMBER(4)' )
insert into atrybuty values( 31, 'towar', 0, 'NUMBER(4)' )
insert into atrybuty values( 32, 'miesiac', 0, 'NUMBER(4)' )
insert into atrybuty values( 33, 'ilosc', 0, 'NUMBER(6)' )
insert into atrybuty values( 34, 'wartosc', 0, 'NUMBER(8,2)' )
`klucze_glowne'
Relacja `klucze_glowne' gromadzi informacje o kluczach g艂贸wnych (primary keys) relacji bocznych. W s艂owniku nie przechowujemy informacji o kluczu g艂贸wnym relacji centralnej, nawet je艣li taki istnieje. Je偶eli jaka艣 藕r贸d艂owa relacja boczna nie jest wykorzystywana do agregowania danych (wi臋c nie ma wpisu w s艂owniku), informacja o jej kluczu g艂贸wnym zostaje pomini臋ta. Struktura relacji jest prosta:
|
|
|
nazwa atrybutu |
typ atrybutu |
ograniczenia |
id_atrybutu |
NUMBER(4) |
primary key, foreign key |
|
|
|
Klucz g艂贸wny relacji - atrybut `id_atrybutu' - jest jednocze艣nie kluczem obcym i wskazuje na pole `id_atrybutu' relacji `atrybuty'. Ka偶dy wiersz relacji okre艣la jeden klucz g艂贸wny (dla jednej z relacji bocznych). Zgodnie z wcze艣niejszym opisem struktury 藕r贸d艂owych baz danych, klucz g艂贸wny relacji bocznej sk艂ada si臋 z dok艂adnie jednego atrybutu (zwykle identyfikatora obiektu). Aby system magazynu dzia艂a艂 poprawnie, ka偶dej relacji bocznej, opisanej w tabeli `relacji' (czyli takiej, dla kt贸rej `id_relacji' ma warto艣膰 niezerow膮) musi towarzyszy膰 wpis o kluczu g艂贸wnym w tabeli `klucze_g艂贸wne'.
Polecenie j臋zyka SQL, tworz膮ce relacj臋 `klucze_g艂贸wne' wygl膮da nast臋puj膮co:
create table klucze_glowne
(
id_atrybutu NUMBER(4) primary key
references atrybuty(id_atrybutu)
)
Wype艂nianie tabeli dla przyk艂adowego schematu magazynu danych, przedstawionego wcze艣niej, mog艂oby przebiega膰 nast臋puj膮co:
insert into klucze_glowne values ( '0' )
insert into klucze_glowne values ( '2' )
...
`klucze_obce'
Relacja `klucze_obce' gromadzi informacje o powi膮zaniach mi臋dzy relacjami 藕r贸d艂owymi. Zawiera opisy powi膮za艅 kluczy obcych relacji centralnej z kluczami g艂贸wnymi relacji bocznych, jak r贸wnie偶 powi膮za艅 mi臋dzy relacjami bocznymi. Zgodnie z wymagan膮 struktur膮 relacji 藕r贸d艂owych (opisan膮 w punkcie V.3) powi膮zanie klucza obcego trafia zawsze na klucz g艂贸wny relacji bocznej. Relacja `klucze_obce' musi wi臋c zawiera膰 tyle samo wierszy, co relacje `klucze_glowne' i zawiera膰 dowi膮zania do wszystkich kluczy g艂贸wnych opisanych w s艂owniku. Struktura tabeli jest nast臋puj膮ca:
|
|
|
nazwa atrybutu |
typ atrybutu |
ograniczenia |
od |
NUMBER(4) |
foreign key |
do |
NUMBER(4) |
foreign key |
|
|
|
Opis atrybut贸w:
`od' - okre艣la identyfikator atrybutu, kt贸ry jest kluczem obcym (i jednocze艣nie pocz膮tkiem dowi膮zania). Jest to klucz obcy wskazuj膮cy na atrybut `id_atrybutu' relacji `atrybuty'.
`do' - okre艣la atrybut docelowy dowi膮zania. Poniewa偶 atrybut ten musi by膰 kluczem g艂贸wnym relacji bocznej, atrybut `do' jest kluczem obcym wskazuj膮cym na atrybut `id_atrybutu' relacji `klucze_glowne'.
Polecenie j臋zyka SQL, tworz膮ce tabel臋 wygl膮da nast臋puj膮co:
create table klucze_obce
(
od NUMBER(4) references atrybuty(id_atrybutu),
do NUMBER(4) references klucze_glowne(id_atrybutu)
)
Wype艂nianie tabeli dla przyk艂adowego schematu magazynu danych, przedstawionego wcze艣niej, mog艂oby przebiega膰 nast臋puj膮co:
insert into klucze_obce values ( '4', '0' )
insert into klucze_obce values ( '8', '2' )
`wartosci_agregowane'
W relacji `wartosci_agregowane' przechowywane s膮 identyfikatory atrybut贸w, kt贸re b臋d膮 argumentami funkcji grupuj膮cych j臋zyka SQL (SUM, MIN, MAX, COUNT, AVG). Atrybuty te musz膮 si臋 znajdowa膰 w relacji centralnej. Ka偶dy wiersz relacji `wartosci_agregowane' wskazuje na jeden atrybuty, budowa tabeli sk艂ada si臋 wi臋c z jednego atrybutu:
|
|
|
nazwa atrybutu |
typ atrybutu |
ograniczenia |
id_atrybutu |
NUMBER(4) |
primary key, foreign key |
|
|
|
Atrybut `id_atrybutu' jest identyfikatorem atrybutu 藕r贸d艂owej relacji, kt贸rego warto艣膰 chcemy agregowa膰. Jest to klucz obcy, wskazuj膮cy na atrybut `id_atrybutu' relacji `atrybuty'.
Polecenie j臋zyka SQL, tworz膮ce opisywan膮 relacj臋 wygl膮da nast臋puj膮co:
create table wartosci_agregowane
(
id_atrybutu NUMBER(4) primary key
references atrybuty(id_atrybutu)
)
Wype艂nianie tabeli dla przyk艂adowego schematu magazynu danych, przedstawionego wcze艣niej, mog艂oby przebiega膰 nast臋puj膮co:
insert into wartosci_agregowane values ( '33' )
insert into wartosci_agregowane values ( '34' )
`agregaty'
Tabela `agregaty' przechowuje informacje o kombinacjach kluczy g艂贸wnych, dla kt贸rych chcemy przechowywa膰 zagregowane warto艣ci funkcji grupuj膮cych. Jej budowa jest zale偶na od informacji zawartej w 藕r贸d艂owych bazach danych. Tabela posiada dok艂adnie tyle kolumn, ile jest kluczy g艂贸wnych w relacjach bocznych (i jednocze艣nie wierszy w relacji `klucze_glowne'). Nazwami kolumn tabeli s膮 identyfikatory tych kluczy g艂贸wnych (s膮 to wi臋c liczby). Tak wi臋c struktur臋 tabeli `agregaty' mo偶na przedstawi膰 nast臋puj膮co:
|
|
|
nazwa atrybutu |
typ atrybutu |
ograniczenia |
<id_atrybutu> |
NUMBER |
|
|
|
|
Jeden atrybut relacji odpowiada jednemu kluczowi g艂贸wnemu, wed艂ug kt贸rego mo偶emy agregowa膰 wcze艣niej zdefiniowane pola relacji centralnej. Ka偶dy wiersz opisywanej relacji opisuje jedn膮 kombinacj臋, wed艂ug kt贸rej chcemy agregowa膰. Je偶eli dany klucz g艂贸wny wchodzi w sk艂ad tej kombinacji, to na odpowiednim atrybucie relacji 'agregaty' musi pojawi膰 si臋 warto艣膰 liczbowa (dowolna), w przeciwnym wypadku atrybut przyjmuje warto艣膰 NULL.
Dla przyk艂adu, za艂贸偶my, 偶e w pokazanym wcze艣niej przyk艂adowym systemie sprzeda偶y klucze g艂贸wne relacji bocznych maj膮 nast臋puj膮ce identyfikatory:
wojewodztwa.id - 0
miasta.id - 2
klienci.id - 5
sprzedawcy.id - 9
branze.id - 12
kategorie.id - 14
towary.id - 17
lata.rok - 21
kwartaly.id - 22
miesiace.id - 24
zamowienia.id - 26
Polecenie j臋zyka SQL, tworz膮ce odpowiedni膮 relacj臋 `agregaty' wygl膮da艂oby nast臋puj膮co:
create table agregaty
(
"0" NUMBER,
"2" NUMBER,
"5" NUMBER,
"9" NUMBER,
"12" NUMBER,
"14" NUMBER,
"17" NUMBER,
"21" NUMBER,
"22" NUMBER,
"24" NUMBER,
"26" NUMBER
)
Za艂贸偶my teraz, 偶e chcemy magazynowa膰 gotowe warto艣ci agregat贸w dla dw贸ch przyk艂adowych kombinacji kluczy g艂贸wnych:
`wojewodztwa.id' - `branze.id' (czyli chcemy zbiera膰 warto艣ci zgrupowane wed艂ug bran偶 towar贸w i wed艂ug wojewodztwa, w kt贸rym mieszka kupuj膮cy), w takim wypadku musimy wstawi膰 do bazy krotk臋:
insert into agregaty values
( 1, null, null, null, 1, null, null, null, null, null, null )
`lata.rok' - `klienci.id' - `kategorie.id' czyli klienci, kategorie towar贸w i lata sprzeda偶y), musimy wstawi膰 nast臋puj膮c膮 krotk臋:
insert into agregaty values
( null, null, 1, null, null, 1, null, 1, null, null, null )
Cz臋艣膰 magazynowa
Cz臋艣膰 magazynowa jest odpowiedzielna za przechowywanie zagregowanych danych. U偶ytkownik ma dost臋p jedynie do tej cz臋艣ci magazynu (za po艣rednictwem modu艂u query processora). Relacje w cz臋艣ci magazynowej projektowanej hurtownii, podobnie jak w 藕r贸d艂owych bazach danych, mo偶emy podzieli膰 na relacje boczne i jedn膮 relacje centraln膮.
Posta膰 relacji bocznych pozostaje dok艂adnie taka sama, jak w 藕r贸d艂owych bazach danych. Relacje te powinny te偶 zawiera膰 te same krotki. System magazynowy powinien wi臋c utworzy膰 te relacje na wz贸r 藕r贸d艂owych i w czasie pracy dba膰, aby zawarto艣膰 tych relacji zgadza艂a si臋 z zawarto艣ci膮 relacji 藕r贸d艂owych.
Atrybuty relacji centralnej
Budowa relacji centralnej jest natomiast inna. Zbi贸r jej atrybut贸w mo偶emy podzieli膰 na dwie cz臋艣ci. Pierwsz膮 stanowi膮 identyfikatory kluczy g艂贸wnych relacji bocznych. S膮 to takie same atrybuty, jak w relacji `agregaty' i maj膮 takie same nazwy. S膮 one kluczami obcymi. Ka偶dy z tych atrybut贸w wskazuje na taki klucz g艂贸wny relacji bocznych, kt贸rego identyfikator jest nazw膮 tego atrybutu.
Drug膮 cz臋艣膰 zbioru atrybut贸w stanowi膮 zagregowane warto艣ci. Ka偶dej agregowanej warto艣ci odpowiada pi臋膰 atrybut贸w (suma, 艣rednia, warto艣膰 minimalna i maksymalna oraz liczba krotek). Nazwa atrybutu sk艂ada si臋 z dw贸ch cz臋艣ci po艂膮czonych znakiem `_' - pierwsz膮 stanowi pierwotna nazwa agregowanej warto艣ci, a drug膮 okre艣lenie funkcji grupuj膮cej (dla 艣redniej - `avg', sumy - `sum', warto艣ci minimalnej - `min', warto艣ci maksymalnej - `max', liczby krotek - `cnt'). Przyk艂ad - je偶eli nazw膮 agregowanej warto艣ci jest wyraz `ilosc', atrybuty zawieraj膮ce zagregowane warto艣ci b臋d膮 si臋 nazywa膰:
ilosc_avg, ilosc_cnt, ilosc_max, ilosc_min, ilosc_sum
Je偶eli natomiast nazw膮 atrybutu jest "cena netto" (atrybut ograniczony), to wygenerowane nazwy atrybut贸w b臋d膮 nast臋puj膮ce:
"cena netto_avg", "cena netto_cnt", ...
Na atrybuty okre艣laj膮ce zagregowane warto艣ci nak艂adamy dodatkowe ograniczenie - nie mog膮 one przyj膮膰 warto艣ci pustej (NULL).
Posta膰 krotki relacji centralnej
Ka偶da krotka w relacji centralnej okre艣la zbi贸r zagregowanych warto艣ci dla jednej kombinacji kluczy g艂贸wnych. Atrybuty, b臋d膮ce kluczami obcymi, okre艣laj膮 kombinacj臋 kluczy g艂贸wnych, dla kt贸rej wiersz opisuje zagregowane warto艣ci. Podobnie, jak w przypadku relacji `agregaty' warto艣膰 NULL oznacza, 偶e dany atrybuty nie wchodzi w sk艂ad kombinacji, wed艂ug kt贸rej agregujemy. Inna warto艣膰 oznacz natomiast, 偶e atrybut jest cz臋艣ci膮 tej kombinacji. Warto艣膰 ta wskazuje jednocze艣nie na konkretny obiekt - klienta, towar, sprzedawc臋 itd. - podaj膮c jego identyfikator.
Atrybuty zawieraj膮ce zagregowane warto艣ci zawieraja natomias konkretne wyniki, b臋d膮ce sum膮, 艣redni膮 itd. danej warto艣ci dla danego zestawu obiekt贸w.
Przyk艂ad relacji centralnej
Dla przyk艂adowego, opisanego wcze艣niej systemu sprzeda偶y, relacja centralna wygl膮da艂aby nast臋puj膮co (w formie polecenia j臋zyka SQL tworz膮cego relacj臋):
create table sprzedaz
(
"0" NUMBER(4) references wojewodztwa(id),
"2" NUMBER(4) references miasta(id),
"5" NUMBER(4) references klienci(id),
"9" NUMBER(4) references sprzedawcy(id),
"12" NUMBER(4) references branze(id),
"14" NUMBER(4) references kategorie(id),
"17" NUMBER(4) references towary(id),
"21" NUMBER(4) references lata(rok),
"22" NUMBER(4) references kwartaly(id),
"24" NUMBER(4) references miesiace(id),
"26" NUMBER(4) references zamowienia(id),
wartosc_max NUMBER(10,5) not null,
wartosc_min NUMBER(10,5) not null,
wartosc_sum NUMBER(10,5) not null,
wartosc_avg NUMBER(10,5) not null,
wartosc_cnt NUMBER not null,
ilosc_max NUMBER(10,5) not null,
ilosc_min NUMBER(10,5) not null,
ilosc_sum NUMBER(10,5) not null,
ilosc_avg NUMBER(10,5) not null,
ilosc_cnt NUMBER not null
)
Przy tak skonstruowanej relacji centralnej, przyk艂adowy wiersz (w formie polecenia j臋zyka SQL, tworz膮cego wiersz):
insert into sprzedaz values
( 10, null, null, null, 20, null, null, null, null, null, null,
250, 112, 1500, 150, 100,
30, 5, 1000, 10, 100 )
opisuje warto艣ci liczbowe zwiazane ze sprzeda偶膮 towar贸w z konkretnej bran偶y (o identyfikatorze r贸wnym 20) do konkretnego wojew贸dztwa (o identyfikatorze r贸wnym 10). 艁膮cznie warto艣膰 sprzedanych towar贸w wynios艂a 1500, sprzedano 1000 towar贸w itd.
Program konfiguracji s艂ownika systemu
Program ten to graficzne narz臋dzie s艂u偶膮ce do poprawnej konfiguracji s艂ownika systemu. Program oparto na pojawiaj膮cych si臋 kolejno oknach dialogowych, w kt贸rych wprowadza si臋 wszystkie niezb臋dne do skonfigurowania informacje takie jak nazwy relacji, nazwy atrybut贸w, typy atrybut贸w czy powi膮zania pomi臋dzy relacjami. Na podstawie wszystkich wprowadzonych informacji program 艂膮czy si臋 z baz膮 danych w kt贸rej ma si臋 znajdowa膰 magazyn danych, generuje tabele s艂ownika oraz odpowiednio je wype艂nia. Schemat interfejsu graficznego jest wzorowany na kreatorze tworzenia nowych relacji zawartym w systemie ORACLE. Program napisany jest w j臋zyku Java przy u偶yciu narz臋dzia programistycznego Visual Cafe 2.5 s艂u偶膮cego do projektowania aplikacji graficznych w Java. Do po艂膮czenia si臋 z baz膮 danych ORACLE i wygenerowania s艂ownika u偶yto mostu JDBC - ODBC.
Modu艂 komunikacji z u偶ytkownikiem (query processor)
Za艂o偶enia projektowe
W projektowanym systemie, query processor (procesor zapyta艅) jest ogniwem po艣rednicz膮cym mi臋dzy magazynem danych, zawieraj膮cym zagregowane dane, a aplikacjami u偶ytkownika. Pierwszym za艂o偶eniem, jakie stawiamy modu艂owi query processora, jest to, aby jego interfejs mo偶na by艂o wykorzysta膰 we w艂asnych aplikacjach. Dlatego zdecydowali艣my si臋 zaimplementowa膰 modu艂 w postaci biblioteki 艂膮czonej dynamicznie (DLL).
Komunikacja z u偶ytkownikiem mo偶e odbywa膰 si臋 na r贸偶ne sposoby. Nowoczesnym rozwi膮zaniem wydaje si臋 by膰 opracowanie graficznego sposobu generowania zapyta艅. Zadecydowali艣my jednak, 偶e zapytania kierowane do query processora maj膮 format SQL'owego polecenia SELECT. Jest to konsekwencj膮 zak艂adanej mo偶liwo艣ci wykorzystania query processora we w艂asnych aplikacjach. Takie podej艣cie umo偶liwia tworzenie dowolnych aplikacji, kt贸re pos艂uguj膮c si臋 query processorem, wydobywaj膮 informacj臋 za magazynu za pomoc膮 j臋zyka SQL.
Zadanie query processora
Zadania query processora mo偶na skr贸towo uj膮膰 w trzech punktach:
Analiza i przetworzenie zapytania u偶ytkownika na zapytanie w j臋zyku SQL, zgodne ze struktur膮 danych w magazynie.
Wykonanie zapytania i odebranie wynik贸w.
Przekazanie wynik贸w u偶ytkownikowi.
Przetworzenie zapytania u偶ytkownika
Zak艂adamy, 偶e u偶ytkownik systemu magazynowania danych zna struktur臋 藕r贸d艂owych baz danych nie zna natomiast struktury wewn臋trznej magazynu. Z tego powodu jego zapytania zak艂adaj膮 istnienie w bazie danych odpowiednich relacji (takich, jak w 藕r贸d艂owych bazach danych) i wyliczanie agregat贸w na podstawie istniej膮cych krotek. Przyk艂adowe zapytanie u偶ytkownika przy za艂o偶eniu podanego wcze艣niej, przyk艂adowego schematu magazynu mo偶e wygl膮da膰 nast臋puj膮co:
SELECT id_sprzedawcy, id_towaru, sum(wartosc)
FROM sprzedaz
GROUP BY id_sprzedawcy, id_towaru
HAVING sum(wartosc) > 250
Zapytanie powinno wi臋c poda膰 sumaryczn膮 warto艣膰 wszystkich zam贸wie艅 na danych towar z艂o偶onych u danego sprzedawcy, przy czym w wyniku wy艣wietlamy tylko te zam贸wienia, w kt贸rych ta suma jest wi臋ksza od 250聽z艂. Te dane odczytujemy z magazynu, ale musimy odpowiednio przekonwertowa膰 zapytanie. Polecenie, jakie powinni艣my skierowa膰 do magazynu, zgodne z wcze艣niejszym opisem jego budowy, mog艂oby wygl膮da膰 nast臋puj膮co:
SELECT "9", "17", -- id_sprzedawcy, id_towaru,
wartosc_sum as "sum(wartosc)"
FROM sprzedaz
WHERE wartosc_sum > 250
AND "9" is not null -- id_sprzedawcy
AND "17" is not null -- id_towaru
AND "11" is null -- id_zamowienia
AND "0" is null -- id_wojewodztwa
AND <reszta> is null -- pozostale klucze obce relacji sprzedaz
Takie zapytanie powinno zosta膰 skierowane do magazynu, przy za艂o偶eniu, 偶e magazynujemy warto艣ci zgrupowane wed艂ug sprzedawcy i towaru. Je艣li taka kombinacja nie jest sk艂adowana, natomiast istnieje kombinacja szersza (zawieraj膮ca sprzedawc臋 i towar, czyli np. sprzedawca - towar - klient - rok), zapytanie si臋 zmieni i b臋dzie zawiera艂o klauzul臋 GROUP BY. Jak 艂atwo si臋 domy艣le膰, wykonanie tego zapytania b臋dzie wymaga艂o wi臋kszego nak艂ady czasowego. Zapytanie mog艂oby wygl膮da膰 nast臋puj膮co:
SELECT "9", "17", -- id_sprzedawcy, id_towaru,
sum(wartosc_sum) as "sum(wartosc)"
FROM sprzedaz
WHERE "9" is not null -- id_sprzedawcy
"17" is not null -- id_towaru
"5" is not null -- id_klienta
"21" is not null -- rok
<reszta> is null -- pozostale klucze obce relacji sprzedaz
GROUP BY "9", "17" -- id_sprzedawcy, id_klienta
HAVING sum(wartosc_sum) > 250
Mo偶liwa jest tak偶e sytuacja, w kt贸rej nie istnieje ani wymagana, ani szersza kombinacja kluczy, wed艂ug kt贸rych agregujemy. W takim wypadku query processor powinien zasygnalizowa膰 b艂膮d.
W praktyce zapytania mog膮 by膰 bardziej skomplikowane, w szczeg贸lno艣ci mog膮 wykorzystywa膰 operatory i funkcje arytmetyczne, 艂a艅cuchowe, stosowa膰 z艂膮czenia (join) itd.
Wykonanie zapytania
Kolejnym zadaniem modu艂u jest wykonanie zbudowanego zapytania. Poniewa偶 zak艂adamy, 偶e nasz magazyn jest oparty na systemie firmy Oracle, do komunikacji mo偶emy u偶y膰 gotowego zestawu bibliotek dostarczonych razem z produktem - Oracle Call Interface.
Przekazanie wynik贸w u偶ytkownikowi
Ostatni膮 faz膮 pracy query processora (podczas wykonywania jednego zapytania) jest przekazanie otrzymanych wynik贸w u偶ytkownikowi. Poniewa偶 komunikacja z u偶ytkownikiem, jak r贸wnie偶 z magazynem odbywa si臋 za pomoc膮 j臋zyka SQL, format wynik贸w jest identyczny. Dlatego otrzymane z magazynu wyniki mo偶emy przekaza膰 u偶ytkownikowi bez konwersji. W praktyce oznacza to mo偶liwo艣膰 po艂膮czenia dw贸ch krok贸w algorytmu - odebrania wynik贸w z magazynu i przekazania ich u偶ytkownikowi - w jeden.
Wymagany format zapytania
Jako format zapyta艅 u偶ytkownika wybrali艣my j臋zyk SQL. Jest to oczywisty wyb贸r, pokierowany popularno艣ci膮 j臋zyka (jest on standardem w relacyjnych bazach danych), jak r贸wnie偶 wyborem produktu firmy Oracle, jako bazy danych magazynu. Korzystamy w艂a艣ciwie jedynie z polecenia SELECT. Modyfikacje danych w magazynie (przez u偶ytkownika) nie jest przecie偶 dozwolone. Sk艂adnia polecenia jest niemal identyczna, z pewnymi ograniczeniami i zmianami opisanymi poni偶ej.
Og贸lna sk艂ania polecenia jest nast臋puj膮ca:
SELECT [ DISTINCT | ALL ]
{ funkcja_agreguj膮ca.. | wyra偶enie [ [AS] alias_kolumny ] }.,..
FROM
nazwa_relacji.,..
GROUP BY { [ nazwa_relacji. ] nazwa_kolumny }.,..
[HAVING predykat]
[ORDER BY wyra偶enie]
Jak wida膰, nie jest dozwolone stosowanie podzapyta艅, jak r贸wnie偶 klauzul WHERE, UNION, INTERSECT, EXCEPT itd. Obowi膮zkowa jest natomiast klauzula GROUP聽BY.
Podstawowym ograniczeniem jest niemo偶liwo艣膰 odnoszenia si臋 do poszczeg贸lnych krotek tabel (藕r贸d艂owych), poniewa偶 nie s膮 one sk艂adowane w magazynie. Z magazynu pobieramy jedynie informacje o gotowych warto艣ciach funkcji agreguj膮cych (SUM, MIN, MAX, COUNT, AVG). Na miejsce wyra偶enia mo偶emy wstawi膰 dowolne wyra偶enie j臋zyka SQL, zawieraj膮ce funkcje arytmetyczne, grupuj膮ce itd. je艣li standard j臋zyka na to pozwala. Podobnie jest z predykatami. Nie mo偶emy natomiast u偶ywa膰 innych funkcji agreguj膮cych, ni偶 pi臋膰 wcze艣niej wymienionych. W funkcjach grupuj膮cych s艂owa kluczowe DISTINCT i ALL s膮 zabronione.
Klauzula SELECT nie ma wi臋kszych ogranicze艅. Nie mo偶na jedynie stosowa膰 znaku '*' wybieraj膮cego wszystkie kolumny relacji. Nale偶y pami臋ta膰, 偶e obowi膮zkowa jest klauzula GROUP聽BY i ona nak艂ada pewne warunki, jakie musz膮 spe艂ni膰 elementy listy wybieranych kolumn. Natomiast w klauzuli FROM zabronione s膮 aliasy relacji. Tam, gdzie nazwa atrybutu wymaga podania nazwy relacji, nale偶y j膮 poda膰 w pe艂nym brzmieniu. Oczywi艣cie nie mo偶na r贸wnie偶 stosowa膰 w tej klauzuli operator贸w z艂膮czeniowych (JOIN). Klauzula FROM jest obowi膮zkowa i musi zawiera膰 relacj臋 centraln膮. Nazwy relacji nie mog膮 si臋 powtarza膰.
Klauzula WHERE nie jest dozwolona. Jest to spowodowane faktem, 偶e jakiekolwiek zmniejszenie liczby wybranych do grupowania krotek (poprzez odrzucenie niekt贸rych z nich - a taki jest wynik dzia艂ania omawianej klauzuli) zmieni艂oby wyniki funkcji grupuj膮cych. Jest to niedozwolone, poniewa偶 w magazyn nie dysponuje informacj膮 o krotkach 藕r贸d艂owych relacji, a jedynie gotowymi warto艣ciami funkcji grupuj膮cych. Jedynym zastosowaniem klauzuli WHERE mog艂oby by膰 tworzenie warunk贸w 艂膮czenia relacji. Postanowili艣my, 偶e u偶ytkownik nie podaje tej informacji. Dozwolone s膮 tylko specyficzne 艂膮czenia tablic i program je zna (na podstawie informacji zgromadzonych w s艂owniku), wi臋c lepiej jest je doda膰 automatycznie ni偶 sprawdza膰, czy u偶ytkownik na pewno zrobi艂 to w艂a艣ciwie. Przy za艂o偶eniu, 偶e w podanym wcze艣niej, przyk艂adowym schemacie relacji wykorzystujemy relacje 'sprzedaz', 'kategorie', 'towary', 'klienci', warunki odpowiedniego po艂膮czenia relacji wygl膮da艂yby nast臋puj膮co:
WHERE sprzedaz.klient = klienci.id
AND sprzedaz.towar = towary.id
AND towary.kategoria = kategorie.id
Query processor zak艂ada takie w艂a艣nie powi膮zanie relacji podanych w klauzuli FROM, st膮d te偶 klauzula WHERE jest niepotrzebna. W wynikowym zapytaniu (po translacji) warunki te b臋d膮 mia艂y zupe艂nie inn膮 posta膰.
Jak wcze艣niej wspomniano, klauzula GROUP 聽BY jest obowi膮zkowa. Ze wzgl臋du na specyfik臋 magazynu - gromadzimy jedynie warto艣ci funkcji grupuj膮cych wed艂ug konkretnych atrybut贸w - w tej klauzuli podajemy jedynie nazwy tych atrybut贸w. Atrybutami, wed艂ug kt贸rych grupujemy, mog膮 by膰 wszystkie atrybuty relacji bocznych i klucze obce relacji centralnej. Klauzula HAVING nie ma natomiast 偶adnych wi臋kszych ogranicze艅. Nale偶y jedynie pami臋ta膰 o funkcjach agreguj膮cych - niedozwolone s膮 operacje zmieniaj膮ce warto艣膰 funkcji grupuj膮cej - czyli s艂owa kluczowe DISTINCT (i ALL) lub wykonywanie operacji arytmetycznych na argumencie funkcji. Klauzula ORDER聽BY powoduje posortowanie wynik贸w wed艂ug podanych wyra偶e艅, kt贸rych sk艂adnia pokrywa si臋 ze sk艂adni膮 j臋zyka SQL.
Uwagi implementacyjne
Poniewa偶 za艂o偶yli艣my mo偶liwo艣膰 wykorzystania modu艂u query processora we w艂asnych aplikacjach, program sk艂ada si臋 z dw贸ch cz臋艣ci. Pierwsz膮 (i najwa偶niejsz膮) jest biblioteka 艂膮czona dynamicznie (DLL - dynamic linked library). Udost臋pnia ona klas臋 - CWarehouseConnection - umo偶liwiaj膮c膮 nam po艂膮czenie si臋 z baz膮 danych i wykonywanie zapyta艅. Podaj膮c zapytanie w j臋zyku SQL (patrz punkt VI.3.3) otrzymujemy gotowy wynik. Bibliotek臋 t臋 mo偶na wykorzysta膰 we w艂asnych programach, a jej specyfikacj臋 i spos贸b do艂膮czenia opisano w punkcie VI.3.9.
Drug膮 cz臋艣膰 programu stanowi prosty program napisany na wz贸r SQL*Plus firmy Oracle. Program jest aplikacj膮 32-bitow膮 艣rodowiska Windows (Win32) dzia艂aj膮c膮 w trybie konsoli. Umo偶liwia interaktywne wykonywanie zapyta艅, a dzi臋ki operacjom przekierowywania strumieni tak偶e przetwarzanie wsadowe.
Cz臋艣膰 modu艂贸w biblioteki DLL napisano w j臋zyku C, cz臋艣膰 w C++. Analizatory - leksykalny i sk艂adniowy - wygenerowa艂y kod w j臋zyku C. Program wykorzystuj膮cy bibliotek臋 napisany jest w C++.
Modu艂y sk艂adowe query processora
Ten punkt zawiera opisy poszczeg贸lnych modu艂贸w sk艂adowych query processora opisanych w kolejno艣ci ich tworzenia. W praktyce prac臋 z nimi rozpocz臋to od pewnych szkieletowych rozwi膮za艅, a p贸藕niej rozwijano wszystkie modu艂y r贸wnocze艣nie.
Uwagi dotycz膮ce parsera
Napisanie parsera polecenia SELECT j臋zyka SQL jest dosy膰 trudnym zadaniem, g艂贸wnie ze wzgl臋du na konstrukcj臋 j臋zyka, sprawiaj膮c膮 czasem wra偶enie „ma艂o formalnej”. Najwi臋kszym utrudnieniem jest fakt, 偶e klauzula FROM wyst臋puje dopiero po li艣cie wyboru kolumn (select-list). Poniewa偶 w czasie przetwarzania listy wybieranych kolumn niezb臋dna jest wiedza o relacjach, z kt贸rych polecenie SELECT wybiera krotki, parser musi by膰 dwuprzebiegowy. W zaimplementowanym analizatorze przetwarzanie listy kolumn odbywa si臋 w drugim przebiegu, kt贸ry jest potem ko艅czony (艣ci艣le m贸wi膮c drugi przebieg analizy ko艅czy si臋 na s艂owie kluczowym FROM). Pierwszy przebieg analizuje wszystko pocz膮wszy od klauzuli FROM. Wykorzystano go tak偶e do zapami臋tania nazw wybieranych kolumn - poniewa偶 niekt贸re kolumny po przetworzeniu zmieni膮 si臋 nale偶y nada膰 im aliasy, b臋d膮ce ich w艂a艣ciwymi nazwami.
Analizator leksykalny
Prac臋 rozpocz臋to od napisania analizatora leksykalnego w j臋zyku generatora Lex. Analizator ma za zadanie rozdzieli膰 zapytanie u偶ytkownika, sformu艂owane w postaci polecenia SELECT j臋zyka SQL, na jednostki leksykalne. Modu艂 zawarto w pliku `scan.l'. Jego zadaniem jest r贸wnie偶 odczytywanie 艂a艅cuch贸w znakowych i odpowiednia konwersja liter do tej samej wielko艣ci (j臋zyk SQL nie rozr贸偶nia wielko艣ci liter). Oczywi艣cie konwersja wielko艣ci liter nie powinna dotyczy膰 艂a艅cuch贸w znakowych (uj臋tych w apostrofy) i identyfikator贸w ograniczonych.
Jak napisano wcze艣niej, w pierwszym przebiegu parser zbiera nazwy kolumn wybieranych poleceniem SELECT. Je偶eli kolumna nie ma aliasu, to jej nazw膮 jest opisuj膮cy j膮 tekst. Na przyk艂ad w zapytaniu
SELECT zamowienie as z, avg(wartosc)+5 FROM ...
nazw膮 pierwszej kolumny jest „z”, natomiast nazw膮 drugiej „avg(wartosc)+5”. Poniewa偶 pola opisuj膮ce wybierane kolumny zmieni膮 si臋, nale偶y doda膰 im aliasy przywracaj膮ce im poprzedni膮 nazw臋 (o ile wcze艣niej nie mia艂y alias贸w). Zbieranie tych nazw jest zadaniem analizatora leksykalnego. Mo偶na zastanawia膰 si臋 nad s艂uszno艣ci膮 takiego podej艣cia - analizator leksykalny nie zna przecie偶 gramatyki j臋zyka i trudno jest mu zorientowa膰 si臋, gdzie dana nazwa si臋 zaczyna a gdzie ko艅czy. Konieczne jest zatem wyposa偶enie go w pewien zakres wiedzy umo偶liwiaj膮cej wykonanie tego zadania. Tak te偶 uczyniono, dzi臋ki wykorzystaniu stan贸w pocz膮tkowych. Niestety, wykonanie tego zadania za pomoc膮 analizatora sk艂adniowego (YACC'a), kt贸ry zna wszystkie regu艂y gramatyczne, okaza艂o si臋 niemo偶liwe. Wynika to z faktu, i偶 analizator sk艂adniowy otrzymuje jedynie informacj臋 o jednostkach leksykalnych w 藕r贸d艂owym zapytaniu oraz o warto艣ciach semantycznych. Du偶a cz臋艣膰 znak贸w (np. odst臋py) jest tracona, poniewa偶 nie jest istotna z gramatycznego punktu widzenia.
Plik z opisem analizatora leksykalnego jest przetwarzany za pomoc膮 generatora leksykalnego Lex, czego wynikiem jest 藕r贸d艂o (w j臋zyku C) analizatora leksykalnego - jest to plik `scan.c'. Plik ten jest w艂膮czany do projektu.
Analizator sk艂adniowy
Tekst 藕r贸d艂owy analizatora sk艂adniowego zawarto w pliku `gram.y' - jest to zapis gramatyki j臋zyka (polecenia SELECT SQL'a) i akcji zgodny z formatem generatora analizator贸w sk艂adniowych YACC. Plik zawiera te偶 kilka funkcji pomocniczych wykorzystywanych w akcjach. Akcje gromadz膮 w艂a艣ciwie wszystkie operacje przekszta艂caj膮ce zapytanie, ale korzystaj膮 z funkcji zawartych w dodatkowym module (`sql.c'). Wszystkie informacje niezb臋dne do dalszego przetwarzania tekstu, znalezione w zapytaniu s膮 zapami臋tywane w odpowiednich tablicach. Te informacje to np. identyfikatory relacji wybranych klauzul膮 FROM, identyfikatory atrybut贸w, wed艂ug kt贸rych grupujemy itd. W艂a艣ciwe zapytanie (przetworzone) jest tworzone poza modu艂em parsera - przy wykorzystaniu zgromadzonych informacji i szkieletu zapytania.
Poniewa偶 program przyjmuje, jako wej艣cie zapytanie (z okre艣lonymi danymi), a efektem jego dzia艂ania s膮 gotowe wyniki (odczytane z magazynu), powinni艣my patrze膰 na niego raczej jako na rodzaj interpretera, ni偶 kompilatora. Je艣li jednak spojrzymy na jego wewn臋trzn膮 struktur臋, wyra藕nie mo偶na wydzieli膰 dwie cz臋艣ci - pierwsz膮, transformuj膮c膮 podane zapytanie do przek艂adu (a wi臋c mogliby艣my nazwa膰 j膮 kompilatorem) oraz drug膮, wykonuj膮c膮 zapytanie.
Po uruchomieniu YACC'a, otrzymujemy plik `gram.c' b臋d膮cy kodem 藕r贸d艂owym wygenerowanego parsera (w j臋zyku C). Kod ten zawiera funkcj臋 yyparse, kt贸rej wywo艂anie uruchamia w艂a艣ciwy parser. Dla ka偶dego zapytania funkcja ta jest wywo艂ywana dwukrotnie.
Zarz膮dzanie tablic膮 symboli
Modu艂 `symbol.c' (i odpowiadaj膮cy mu zbi贸r nag艂贸wkowy `symbol.h') zawiera funkcje zarz膮dzaj膮ce tablic膮 symboli. Tablica symboli gromadzi s艂owa kluczowe j臋zyka i ich warto艣ci (jednostki leksykalne), co u艂atwia napisanie analizatora leksykalnego. Modu艂 ten powsta艂 w firmie MKS, Inc. i jest do艂膮czony do przyk艂ad贸w pakietu MKS Lex & Yacc do w艂asnego wykorzystania. W parserze wykorzystano podstawow膮 funkcj臋 modu艂u - znalezienie jednostki leksykalnej na podstawie leksemu. Umo偶liwia to zgromadzenie s艂贸w kluczowych w tablicy o korzystanie z nich. Bez wykorzystania tablicy symboli, ka偶de s艂owo kluczowe musia艂oby pojawi膰 si臋 jako wzorzec w analizatorze leksykalnym.
Modu艂 `sql.c'
Nast臋pnym etapem pracy by艂o opracowanie modu艂u, kt贸ry po艂膮czy wszystkie informacje zgromadzone przez parser ze szkieletowym zapytaniem. G艂贸wna funkcja tego modu艂y, parse, inicjalizuje oba analizatory, przeprowadza (z ich wykorzystaniem) dwuprzebiegow膮 translacj臋, a nast臋pnie 艂膮czy wyniki w jedno zapytanie, gotowe do wykonania. W module tym zdefiniowano r贸wnie偶 wszystkie struktury danych potrzebne do przechowywania gromadzonych informacji. Przewa偶aj膮ca wi臋kszo艣膰 tych struktur jest tworzona dynamicznie, ze wzgl臋du na nieprzewidywalne rozmiary.
Modu艂 zawiera te偶 r贸偶norakie elementy wykorzystywane przez analizator sk艂adniowy i leksykalny. Przede wszystkim tutaj zdefiniowano wszystkie s艂owa kluczowe j臋zyka. Tutaj zawarta jest tak偶e funkcja zapewniaj膮ca obs艂ug臋 b艂臋d贸w podczas analizy sk艂adniowej - yyerror.
Wa偶niejszym sk艂adnikiem jest du偶a paleta funkcji wykorzystywanych przez parser - funkcje por贸wnuj膮ce ci膮gi, odszukuj膮ce nazwy relacji lub atrybut贸w na podstawie identyfikator贸w, odszukuj膮ce relacj臋, do jakiej nale偶y atrybut, gdy nie podano tego jawnie. Jest tu te偶 zawarta funkcja wyszukuj膮ca odpowiedni膮, agregowan膮 kombinacj臋 kluczy g艂贸wnych, kt贸r膮 mo偶na wykorzysta膰.
Funkcja parse zawarta w module, jako parametry dostaje adresy struktur danych zawieraj膮cych odczytany ju偶 z bazy s艂ownik systemu.
Modu艂 `WhConn.cpp'
Modu艂 `WhConn.cpp' (napisany w j臋zyku C++), wraz z plikiem `WhConn.h' zawiera definicj臋 klasy `CWarehouseConnection', kt贸ra obs艂uguje po艂膮czenie z magazynem. Metody tej klasy umo偶liwiaj膮 po艂膮czenie si臋 z baz膮, roz艂膮czenie, a tak偶e wykonanie kilku operacji zmierzaj膮cych do wykonania zapytania. Operacje te, to spradzenie poprawno艣ci zapytanie, zdefiniowanie miejsca w pami臋ci na wyniki, pobranie tytu艂贸w kolumn i rozmiar贸w czytanych danych, wykonanie zapytania i odczytywanie danych po jednej krotce. Funkcje te s膮 podobne do funkcji OCI, wi臋c kto艣 zaznajomiony z t膮 bibliotek膮 nie b臋dzie mia艂 problem贸w z wykorzystaniem klasy.
R贸偶nica mi臋dzy u偶yciem tej klasy, a klasycznym po艂膮czeniem si臋 z baz膮 danych tkwi w dw贸ch operacjach. Pierwsz膮 jest po艂膮czenie si臋 z baz膮. S艂u偶膮ca do tego metoda nie tylko po艂膮czy nas z baz膮 danych, ale r贸wnie偶 odczyta wszystkie relacje s艂ownika i zgromadzi je w odpowiednich strukturach danych. Dzieje si臋 to niejawnie, w przypadku stwierdzenia nieprawid艂owo艣ci w s艂owniku po艂膮czenie nie powiedzie si臋. Drug膮 funkcj膮 jest funkcja sprawdzaj膮ca poprawno艣膰 zapytania. Korzystaj膮c z OCI, zapytanie przesy艂amy do bazy tylko raz - w艂a艣nie w funkcji sprawdzaj膮cej poprawno艣膰 zapytania (osql3). Nast臋pne operacje (wykonanie zapytanie, pobieranie wynik贸w) ju偶 tego nie wymagaj膮, polecenie jest pami臋tane w obszarze kursora w serwerze bazy danych. W naszej klasie jest podobnie - z t膮 r贸偶nic膮, 偶e przed wys艂aniem do bazy zapytania zostaje ono przetworzone (za pomoc膮 wcze艣niej opisanych modu艂贸w - funkcja parse).
Plik `WhConn.h' zawiera interfejs klasy `CWarehouseConnection'. Powinien on zosta膰 do艂膮czony do aplikacji wykorzystuj膮cych t臋 klas臋 (a wi臋c wykorzystuj膮cych modu艂 query processora). Opis wykorzystania tej klasy zamieszczono w p.聽VI.3.9).
Etapy dzia艂ania programu
Aby zilustrowa膰 dzia艂anie query processora, prze艣led藕my etapy jego dzia艂ania, dla przyk艂adowego zapytanie j臋zyka SQL. Przyjmijmy, 偶e w 藕r贸d艂owych bazach danych znajduje si臋 schemat relacji przedstawiony w p.聽V.3. Niech zapytanie ma posta膰:
SELECT klienci.nazwa, kategorie.nazwa, 2+sin(avg(wartosc))
FROM sprzedaz, klienci, kategorie
GROUP BY klienci.nazwa, kategorie.nazwa
HAVING sum(ilosc) > 20
Jak wida膰, podano poprawne zapytanie SQL, zgodne z opisanym wcze艣niej formatem. Zgodnie z wymogami zapytanie nie posiada klauzuli WHERE, kt贸ra w przypadku pytania 藕r贸d艂owej bazy danych mia艂aby posta膰:
WHERE sprzedaz.klient = klienci.id
AND sprzedaz.towar = towary.id
AND towary.kategoria = kategorie.id
Oczywi艣cie w takim przypadku klauzula FROM musia艂aby zawiera膰 r贸wnie偶 relacj臋 `towary'.
Zgodnie z wcze艣niejszym opisem, parser rozpoczyna w艂a艣ciwe przetwarzanie tekstu wej艣ciowego w pierwszym przebiegu od klauzuli FROM. Natomiast analizator leksykalny ma za zadanie zebranie nazw wybieranych kolumn. W tym przypadku zbierze ci膮gi: „klienci.nazwa” dla pierwszej kolumny, „kategorie.nazwa” dla drugiej kolumny i „2+sin(avg(wartosc))” dla trzeciej kolumny. Poniewa偶 偶adna z kolumn nie posiada aliasu, wszystkim kolumnom zostan膮 przypisane aliasy zgodne z ich nazwami.
Podczas przetwarzania klauzuli FROM, parser kontroluje (na podstawie informacji ze s艂ownika), czy podane relacje rzeczywi艣cie istniej膮 i zapami臋tuje je w tablicy. Parser sprawdza te偶, czy w艣r贸d podanych relacji jest relacja centralna - je艣li nie, zg艂asza odpowiedni b艂膮d, je艣li tak, kontynuuje prac臋. Od tej chwili wszystkie atrybuty zawarte w pozosta艂ych klauzulach musz膮 nale偶e膰 do relacji wymienionych w klauzuli FROM. Je艣li przy jakim艣 atrybucie nie podano relacji, w celu jej okre艣lenia przeszukuje si臋 relacje podane w klauzuli FROM. Je艣li przy takim przeszukiwaniu atrybutowi odpowiada wi臋cej ni偶 jedna relacja, zg艂aszany jest b艂膮d.
Dalszym etapem dzia艂ania parsera jest przetworzenie klauzuli GROUP BY. Efektem tego przetworzenia powinien by膰 zbi贸r atrybut贸w, b臋d膮cych kluczami g艂贸wnymi relacji bocznych. Je偶eli podane atrybuty nie s膮 kluczami obcymi (jak w naszym przypadku), wystarczy wyznaczy膰 klucz g艂贸wny relacji w kt贸rej si臋 znajduj膮 i zapami臋ta膰 go. Tak wi臋c w podanym przyk艂adzie zostan膮 zapami臋tane dwa klucze: `klienci.id' oraz `kategorie.id'. Mo偶e si臋 jednak zdarzy膰, 偶e atrybut podany w klauzuli GROUP BY b臋dzie kluczem obcym. W贸wczas odpowiadaj膮cym mu kluczem g艂贸wnym jest atrybut wskazywany przez niego. Oczywi艣cie w omawianej klauzuli nazwy relacji nie musz膮 poprzedza膰 nazw atrybut贸w, je艣li nazwa atrybutu okre艣la go jednoznacznie. W naszym przypadku jednak tak nie jest.
Nieobowi膮zkowa klauzula HAVING zawiera warunki, jakie musz膮 spe艂nia膰 krotki po operacji grupowania, aby zosta艂y wybrane. Posta膰 tej klauzuli zostaje zapami臋tana w podobnej postaci. Nie mo偶e ona po prostu pozosta膰 w zapytania, poniewa偶 predykat podany w niej mo偶e (ale nie musi) zosta膰 przeniesiony do klauzuli WHERE docelowego zapytania (patrz ni偶ej). Jedyn膮 zmian膮 w predykacie jest zapami臋tanie wszystkich funkcji grupuj膮cych (wraz z argumentami) i wstawienie w ich miejsce specjalnych znacznik贸w, umo偶liwiaj膮cych p贸藕niejsze wklejenie tych funkcji w zmienionej postaci. W tym przypadku tekst „sum(ilosc)” zast膮pimy takim znacznikiem (z odpowiednim numerem), oraz zapami臋tamy, 偶e znacznikowi o danym numerze (tutaj 1) odpowiada funkcja sumy z atrybutu `ilosc' relacji `sprzedaz'. Poniewa偶 nie podano relacji, do kt贸rej nale偶y atrybut `ilosc', zostanie ona odnaleziona. Przetworzenie klauzuli HAVING zako艅czy w naszym przypadku pierwszy przebieg parsera.
W drugim przebiegu nast膮pi przetworzenie listy wybieranych kolumn. Do wszystkich kolumn nie zawieraj膮cych alias贸w zostan膮 one dodane, wi臋c lista b臋dzie mia艂a posta膰:
SELECT klienci.nazwa as "klienci.nazwa",
kategorie.nazwa as "kategorie.nazwa",
2+sin(avg(wartosc)) as "2+sin(avg(wartosc))"
Nast臋pnie zostanie dokonana podobna operacja, jak w przypadku klauzuli HAVING - wszystkie wyst膮pienia funkcji grupuj膮cych zostan膮 zapami臋tanie, a w ich miejsce wstawione znaczniki. W naszym przypadku znacznikiem (oznaczonym numerem 2) zast膮pimy tekst „avg(wartosc)” oraz zapami臋tamy, 偶e znacznik nr聽2 oznacza warto艣膰 艣redni膮 z atrybutu `wartosc' relacji `sprzedaz'. Relacj臋, do kt贸rej nale偶y atrybut musimy odnale藕膰. Oczywi艣cie we wn臋trzu programu te informacje s膮 pami臋tane nieco inaczej - nie zapami臋tujemy nazw atrybut贸w ani relacji, lecz ich identyfikatory zapisane w s艂owniku systemu.
Przetworzyli艣my ca艂e zapytanie. Aby skonstruowa膰 zapytanie wynikowe, musimy jeszcze zna膰 odpowied藕 na jedno pytanie - z jakiej kombinacji grupuj膮cej kluczy g艂贸wnych skorzysta膰. Mo偶liwe s膮 tu trzy sytuacje:
Najlepsza sytuacja wyst臋puje, gdy agregujemy warto艣ci funkcji grupuj膮cych wed艂ug kluczy g艂贸wnych otrzymanych na podstawie klauzuli GROUP BY. Informacja, wed艂ug jakich kluczy grupujemy jest oczywi艣cie zawarta w s艂owniku systemu (relacja `agregaty'). W takim, najlepszym przypadku wygenerujemy nast臋puj膮ce zapytanie:
SELECT klienci.nazwa AS "klienci.nazwa"
kategorie.nazwa AS "kategorie.nazwa"
2+sin(sprzedaz.wartosc_avg) AS "2+sin(avg(wartosc)"
FROM sprzedaz, klienci, kategorie
WHERE sprzedaz.ilosc_sum > 20
AND sprzedaz.k1 is not null
AND sprzedaz.k2 is not null
AND sprzedaz.k3 is null
AND sprzedaz.k4 is null
AND <reszta> is null
AND sprzedaz.k1 = klienci.id
AND sprzedaz.k2 = kategorie.id
Jak wida膰, zapytanie nie wymaga du偶ych nak艂ad贸w czasowych ze strony serwera, poniewa偶 nie wymaga grupowania krotek. Postaci funkcji grupuj膮cych zmieni艂y si臋 - zast膮pi艂y je nazwy konkretnych atrybut贸w, zawieraj膮cych zagregowane warto艣ci. Predykat zawarty w klauzuli HAVING zosta艂 przeniesiony do klauzuli WHERE, gdzie pojawi艂y si臋 dodatkowy warunki. Poniewa偶 klucze nazwy kluczy obcych w relacji centralnej zostaj膮 zmienione, nie mo偶emy przewidzie膰 jakie maj膮 nazwy w rzeczywisto艣ci (informacja ta jest zawarta w s艂owniki, ich nazwami s膮 identyfikatory atrybut贸w przez nie wskazywanych). Przyjmijmy, 偶e k1 jest kluczem obcym wskazuj膮cym na atrybut 'id' relacji 'klienci, natomiast k2 kluczem obcym wskazuj膮cym r贸wnie偶 na atrybut 'id', z;e relacji 'kategorie'. Jak wida膰, warto艣ci tych dw贸ch atrybut贸w musz膮 by膰 okre艣lone, warto艣ci pozosta艂ych kluczy obcych musz膮 za艣 bu膰 nieokre艣lone (NULL). Jak wida膰, dodano r贸wnie偶 warunki poprawnego z艂膮czenia tabel. Poniewa偶 relacje centralna w magazynie zawiera klucze obce, wskazuj膮ce wszystkie klucze g艂贸wne relacji bocznych, dodanie tych warunk贸w jest proste.
Gorsza sytuacja wyst膮pi, gdy magazyn nie zbiera warto艣ci pogrupowanych wed艂ug podanych kluczy. Ale mo偶e zbiera膰 warto艣ci grupowane wed艂ug szerszej kombinacji. Program wybierze w takim przypadku kombinacj臋 mo偶liwie kr贸tk膮. Za艂贸偶my, 偶e magazynujemy dane zgrupowane wed艂ug kombinacji: klienci, sprzedawcy, kategorie. Za艂贸偶my r贸wnie偶, 偶e klucz obcy relacji centralnej w magazynie, wskazuj膮cy na atrybut 'id' relacji 'sprzedawcy' ma nazw臋 'k6'. Zapytanie wygl膮da艂oby nast臋puj膮co:
SELECT klienci.nazwa AS "klienci.nazwa"
kategorie.nazwa AS "kategorie.nazwa"
2+sin(sum(sprzedaz.wartosc_sum)/sum(sprzedaz.wartosc_cnt))
AS "2+sin(avg(wartosc)"
FROM sprzedaz, klienci, kategorie
WHERE sprzedaz.k1 is not null
AND sprzedaz.k2 is not null
AND sprzedaz.k6 is not null
AND sprzedaz.k3 is null
AND sprzedaz.k4 is null
AND <reszta> is null
AND sprzedaz.k1 = klienci.id
AND sprzedaz.k2 = kategorie.id
GROUP BY klienci.nazwa, kategorie.nazwa
HAVING sum(sprzedaz.ilosc_sum) > 20
Jak wida膰, zapytanie jest bardziej skomplikowane i, ze wzgl臋dy na operacje grupowania, b臋dzie wymaga膰 wi臋kszych nak艂ad贸w czasowych i pami臋ciowych ze strony serwera zarz膮dzaj膮cego magazynem. Klauzula GROUP BY pozosta艂a na swoim miejscy, tak samo klauzula HAVING. Klauzula WHERE zawiera te same warunki co poprzedni, z wy艂膮czeniem predykatu zabranego wcze艣niej klauzuli WHERE, oraz z wymogiem, aby warto艣膰 klucza 'k6' by艂a okre艣lona. Zmieni艂y si臋 natomiast okre艣lenia warto艣ci funkcji grupuj膮cych. o ile w poprzednim przypadku sytuacja by艂a prosta - funkcj臋 z jej argumentem mo偶na by艂o zast膮pi膰 nazw膮 odpowiedniego atrybutu, tutaj odpowiednie warto艣ci trzeba jeszcze wyliczy膰 za pomoc膮 funkcji grupuj膮cych. Je艣li wi臋c w poprzednim przypadku zamiast „sum(sprzedaz.ilosc)” napisaliby艣my „sprzedaz.ilosc_sum”, tak w obecnym przypadku musieliby艣my napisa膰 „sum(sprzedaz.ilosc_sum)”. Odpowiednie przekszta艂cenia zebrano w tabelce:
|
|
|
Wyra偶enie 藕r贸d艂owe |
Przypadek pierwszy |
Przypadek drugi |
sum(atrybut) |
atrybut_sum |
sum(atrybut_sum) |
min(atrybut) |
atrybut_min |
min(atrybut_min) |
max(atrybut) |
atrybut_max |
max(atrybut_max) |
count(atrybut) |
atrybut_cnt |
sum(atrybut_cnt) |
avg(atrybut) |
atrybut_avg |
sum(atrybut_sum) / sum(atrybut_cnt) |
|
|
|
Jak wida膰, najwi臋kszy k艂opot sprawia w przypadku drugim warto艣膰 艣rednia - obliczenie jej, jako warto艣ci 艣redniej z agregowanych warto艣ci (czyli te偶 warto艣ci 艣rednich) da艂oby niepoprawny wynik.
Trzecim przypadek wyst臋puje, gdy w magazynie nie zbieramy zagregowanych informacji zgrupowanych ani wed艂ug podanej kombinacji atrybut贸w, ani wed艂ug kombinacji szerszej. W takiej sytuacji pozostaje jedynie poinformowa膰 u偶ytkownika o niemo偶liwo艣ci wykonania zapytania. Query processor sygnalizuje w takiej sytuacji odpowiedni b艂膮d.
Ostatnim etapem dzia艂ania programu jest oczywi艣cie wykonanie zapytania. Nie jest to trudne zadanie, dlatego zdecydowano si臋 pomin膮膰 jego szczeg贸艂owy opis. Warto jedynie zaznaczy膰, 偶e przebieg programu, z jakim mamy do czynienia podczas wykonywania polecenia j臋zyka SQL za pomoc膮 OCI, przedstawiono na schemacie w punkcie聽IV.2.3.
Wykorzystane narz臋dzia
Analizator leksykalny zosta艂 wygenerowany za pomoc膮 narz臋dzia 'flex' (wersja 2.5.2 dla win32), na podstawie zapisu regu艂 dla Lex'a.
Analizator sk艂adniowy zosta艂 wygenerowany za pomoc膮 narz臋dzia 'bison' (wersja 1.24 dla win32), na podstawie zapisu gramatyki dla Yacc'a.
Do kompilacji modu艂贸w zawieraj膮cych kod w j臋zykach C i C++ (tak偶e wygenerowany przez analizatory: sk艂adniowy i leksykalny) pos艂u偶y艂 32-bitowy kompilator j臋zyka C/C++ firmy Microsoft w wersji 11.00.7022, przeznaczony dla rodziny procesor贸w 80x86 (zawarty w pakiecie MS Visual C++ 5.0).
Jako 艣rodowisko programistyczne pos艂u偶y艂 pakiet Microsoft Developer Studio.
Program SQL*Plus firmy Oracle pos艂u偶y艂 jako 艣rodowisko testowe polece艅 i program贸w j臋zyka SQL.
Wykorzystano zestaw bibliotek OCI (Oracle Call Interface) firmy Oracle zapewniaj膮cych komunikacj臋 z baz膮 danych (w wersji 8).
Przeno艣no艣膰 kodu
W modu艂ach sk艂adaj膮cych si臋 na bibliotek臋, zawieraj膮c膮 query processor starano si臋 nie u偶ywa膰 偶adnych element贸w, kt贸re nie by艂yby przeno艣ne na inne platformy sprz臋towe. Przeno艣no艣膰 poszczeg贸lnych element贸w query processora wygl膮da nast臋puj膮co:
modu艂y sk艂adowe napisane w j臋zykach C (sql.c, symbol.c, scan.c, gram.c) oraz C++ (WhConn.cpp) s膮 przeno艣ne na poziomie kodu na platformy, na kt贸re istniej膮 kompilatory j臋zyk贸w C i C++,
Je偶eli istnieje potrzeba ponownego przetworzenia (kompilacji) modu艂贸w analizatora leksykalnego (scan.l) lub analizatora sk艂adniowego (gram.y), wymagane jest istnienie na przenoszonej platformie narz臋dzi kompatybilnych ze standardem Lex i Yacc; inn膮 metod膮 mo偶e by膰 przetworzenie tych plik贸w do modu艂贸w w j臋zyku C na platformie, dla kt贸rej te narz臋dzia stworzono,
wymogiem przeno艣no艣ci ca艂ego modu艂u query processora jest istnienie na docelowej platformie zestawu bibliotek OCI (Oracle Call Interface) rozprowadzanych z pakietem Oracle; biblioteki te nale偶y po艂膮czy膰 ze skompilowanymi modu艂ami.
Wykorzystanie modu艂u we w艂asnych aplikacjach. Sk艂adowe publiczne klasy CWarehouseConnection
Biblioteka zawieraj膮ca modu艂 query processora mo偶e by膰 wykorzystana w nowo tworzonych aplikacjach. Nale偶y przy tym pami臋ta膰 o kilku rzeczach:
do modu艂贸w wykorzystuj膮cych query processor nale偶y do艂膮czy膰 plik nag艂贸wkowy `WhConn.h' zawieraj膮cy definicj臋 klasy CWarehouseConnection,
w tych modu艂ach mo偶na korzysta膰 z query processora poprzez wywo艂anie metod klasy CWarehouseConnection opisanych poni偶ej,
program powinien by膰 rozprowadzany wraz z bibliotek膮 Warehouse.dll,
niezb臋dne pliki .dll, .h, i .lib s膮 za艂膮cznikiem do niniejszej pracy.
Aby wykorzysta膰 modu艂 we w艂asnych programach, niezb臋dna jest znajomo艣膰 klasy CWarehouseConnection. Poni偶ej opisano jej publiczne metody:
CWarehouseConnection() - bezparametrowy konstruktor klasy, zwykle wywo艂ywany automatycznie,
~CWarehouseConnection() - destruktor klasy, zwalnia zajmowan膮 pami臋膰, zwykle wywo艂ywany automatycznie,
int GetLastError() - bezparametrowa funkcja przyjmuj膮ca warto艣膰 kodu b艂臋du ostatniej operacji zako艅czonej niepowodzeniem, kod ten jest zwykle kodem funkcji OCI, kt贸rej wykonanie si臋 nie powiod艂o,
char * GetLastErrorText() - funkcja, kt贸rej warto艣ci膮 jest 艂a艅cuch tekstowy, zawieraj膮cy komunikat b艂臋du ostatnie operacji zako艅czonej niepowodzeniem,
int Connect(char *username, char *password) - funkcja tworz膮ca po艂膮czenie z baz膮 danych, wymaga podania nazwy u偶ytkownika i jego has艂a jako parametr贸w,
int Disconnect() - funkcja powoduje od艂膮czenie od bazy danych,
int CParse(char *statement, char *debug = NULL) - funkcja wysy艂a zapytanie (przekonwertowane) do bazy danych, kt贸ra sprawdza jego poprawno艣膰 i zapami臋tuje je,
odsc - funkcja ma takie same parametry i warto艣膰 zwrotn膮, jak identyczna funkcja OCI, pomini臋to wi臋c dok艂adny opcji; funkcja opisuje list臋 wybranych kolumn - nazwy kolumn, typy zwracanych danych i ich rozmiary,
odefin - funkcja s艂u偶y do zdefiniowania w pami臋ci operacyjnej miejsca, do kt贸rego trafi膮 dane pobieranych krotek; funkcja jest identyczna z funkcj膮 OCI o tej samej nazwie,
int Execute(void) - bezparametrowa funkcja powoduje wykonanie (w bazie danych) zapytania podanego wcze艣niej w funkcji osql3,
int ofetch(void) - bezparametrowa funkcja pobieraj膮ca z serwera bazy danych pojedyncz膮 krotk臋 i umieszczaj膮ca je we wcze艣niej zdefiniowanym miejscu w pami臋ci komputera (za pomoc膮 odefin).
Modu艂 integratora
Zadanie integratora
Modu艂 integratora jest najwa偶niejszym modu艂em w ca艂ym opracowywanym systemie. Jego zadaniem jest inicjalizacja magazynu danych, pocz膮tkowa integracja danych ze 藕r贸d艂owych baz danych oraz piel臋gnacja zmaterializowanych danych w magazynie danych. Zadania te samoczynnie dziel膮 czas pracy modu艂u na dwie podstawowe fazy:
Faz臋 inicjalizacji magazynu danych.
Faz臋 piel臋gnacji magazynu danych.
Za艂o偶enia implementacyjne
Aktualizowanie magazynu mo偶na zrealizowa膰 na dwa sposoby. 艁atwiejszym sposobem jest odnawianie ca艂ej zawarto艣ci magazynu za ka偶dym razem, gdy wykryto zmian臋 w 藕r贸d艂owej bazie danych. Jednak, jak zaznaczyli艣my w za艂o偶eniach systemu, jest to proces nieefektywny. D艂ugi czas takiej aktualizacji mo偶e spowodowa膰, 偶e dane po umieszczeniu w magazynie mog膮 by膰 ju偶 nieaktualne.
Innym podej艣ciem jest aktualizowanie magazynu w spos贸b przyrostowy, uwzgl臋dniaj膮c poprzedni膮 zawarto艣膰 magazynu. Jest to trudniejsze, poniewa偶 trzeba rozpatrywa膰 rodzaje zmian jakie zasz艂y w 藕r贸d艂owej bazie danych - podczas uaktualniania magazynu danych w przypadku dodania krotki w 藕r贸d艂owej bazie danych wykonywane s膮 inne czynno艣ci ni偶 w przypadku usuni臋cia lub modyfikacji krotki w 藕r贸d艂owej bazie danych. Podej艣cie takie zapewnia jednak efektywno艣膰 dzia艂ania systemu na za艂o偶onym przez nas poziomie.
Sam proces uaktualniania magazynu mo偶e by膰 inicjowany przez u偶ytkownika (administratora), wykonywany automatycznie w okre艣lonych odst臋pach czasowych, lub uaktualniany na bie偶膮co. Jak ju偶 napisano w wymaganiach tworzonego systemu, zdecydowali艣my si臋 na ostatnie rozwi膮zanie - jest to konsekwencja za艂o偶enia, 偶e dane w magazynie musz膮 by膰 aktualne.
Faza inicjalizacji magazynu danych
Faz臋 inicjalizacji magazynu danych mo偶na dodatkowo podzieli膰 na kilka etap贸w:
Po艂膮czenie z magazynem danych.
Utworzenie odpowiednich relacji w magazynie danych.
Zainicjalizowanie monitor贸w.
Wype艂nienie relacji bocznych.
Wype艂nienie relacji centralnej.
Faza piel臋gnacji magazynu danych
W fazie tej nast臋puje ci膮g艂e uaktualnianie magazynu danych. Modu艂 integratora odpytuje monitory i je艣li te zg艂osz膮 jakie艣 zmiany w 藕r贸d艂owych bazach danych nast臋puje ponowne przeliczenie odpowiednich warto艣ci. Je艣li uaktualnienie nie jest mo偶liwe na podstawie dostarczonych przez monitory danych nast臋puje po艂膮czenie z odpowiednimi wraperami z nakazem odczytania odpowiednich informacji. Kiedy aktualizowanie danych w magazynie dobiegnie ko艅ca cykl si臋 zamyka i nast臋puje ponowne odpytanie monitor贸w.
Implementacja modu艂u integratora
W fazie inicjalizacji magazynu danych nast臋puje po艂膮czenie z baz膮 danych w kt贸rej znajduje si臋 s艂ownik. Przyj臋to i偶 magazyn danych znajdowa膰 si臋 b臋dzie w bazie danych firmy ORACLE (wersja 8). Po nawi膮zaniu po艂膮czenia nast臋puje zainicjalizowanie magazynu danych. Ze s艂ownika odczytywane s膮 nazwy relacji bocznych, nazwy i typy atrybut贸w ka偶dej z tych relacji oraz nast臋puje utworzenie relacji na podstawie odczytanych danych. Kolejnym krokiem jest utworzenie relacji centralnej. Relacja centralna w magazynie odpowiada logicznie tabeli fakt贸w w 藕r贸d艂owych bazach danych, jednak posiada inn膮 struktur臋 wewn臋trzn膮. Na atrybuty relacji centralnej sk艂adaj膮 si臋 atrybuty agreguj膮ce oraz atrybuty agregowane. Atrybuty agreguj膮ce to wszystkie klucze g艂贸wne wyst臋puj膮ce w relacjach bocznych w 藕r贸d艂owych bazach danych. Atrybuty agregowane to odpowiednio przerobione atrybuty z tabeli fakt贸w o kt贸rych chcemy przechowywa膰 zagregowane dane. Ka偶dy atrybut grupuj膮cy z tabeli fakt贸w jest zamieniany na pi臋膰 odpowiadaj膮cych mu atrybut贸w np. atrybut ilo艣膰 jest zamieniany na ilo艣膰_max, ilo艣膰_min, ilo艣膰_sum, ilo艣膰_avg, ilo艣膰_cnt. Atrybuty te odpowiadaj膮 najwi臋kszej oraz najmniejszej warto艣ci atrybutu ilo艣膰, sumie warto艣ci atrybutu ilo艣膰, 艣redniej warto艣ci atrybutu ilo艣膰 i liczbie wyst膮pie艅 atrybutu ilo艣膰 dla odpowiedniej kombinacji atrybut贸w grupuj膮cych. Po utworzeniu wszystkich relacji zostaj膮 aktywowane monitory, kt贸re b臋d膮 rejestrowa艂y wszystkie zachodz膮ce zmiany w 藕r贸d艂owych bazach danych. Nast臋pnym krokiem systemu jest wype艂nienie danymi utworzonych uprzednio relacji. Najpierw wype艂niane s膮 relacje boczne, p贸藕niej relacja centralna. Dla ka偶dej relacji bocznej odpytywane s膮 wszystkie wrapery, kt贸re przesy艂aj膮 zawarto艣ci danej relacji ze wszyst-kich 藕r贸d艂owych bazach danych. Powtarzaj膮ce si臋 krotki s膮 redukowane. Wype艂nienie relacji centalnej wymaga艂o zastosowania opracowanego specjalnie do tego celu algo-rytmu. Dla ka偶dej kombinacji atrybut贸w grupuj膮cych jest budowane specjalne zapyta-nie, kt贸re jest kierowane do wszystkich wraper贸w. Odczytane warto艣ci s膮 odbierane od wraper贸w pojedynczo (po jednej krotce od ka偶dego wrapera), nast臋pnie w otrzymanym w ten spos贸b zestawieniu jest wyszukiwana krotka (lub kilka krotek maj膮cych taki sam „znacznik”) i z oddzielonych krotek wyliczane s膮 warto艣ci, kt贸re s膮 wstawiane do magazynu. Je艣li aktualnie przetwarzan膮 kombinacj膮 atrybut贸w grupuj膮cych jest klient, sprzedawca, towar a atrybutem agregowanym jest warto艣膰 to zapytanie wys艂ane do wraper贸w zwr贸ci tyle krotek ile jest kombinacji warto艣ci atrybut贸w klient, sprzedawca i towar (je艣li jest 10 klient贸w, 15 sprzedawc贸w i 5 towar贸w to otrzymamy maksymalnie 10 * 15 * 5 = 750 krotek). Mo偶liwe jest, i偶 z kilku 藕r贸d艂owych baz danych otrzymamy krotki z takimi samymi warto艣ciami numer贸w klienta, sprzedawcy i towaru - czyli ta-kim samym „znacznikiem” (np. ten sam klient kupi艂 u tego samego sprzedawcy ten sam towar, lecz raz odebra艂 go w jednym magazynie a drugi raz w drugim, za ka偶dym razem dokona艂 zakupu na inna sum臋). „Znacznikiem” s膮 po艂膮czone warto艣ci numer贸w klienta, sprzedawcy i towaru czyli atrybut贸w grupuj膮cych - na przyk艂ad „102010”. „Znacznik” jest traktowany jako 艂a艅cuch znak贸w. Odnajdowany jest zawsze jeden lub kilka jednakowych znacznik贸w o najmniejszej warto艣ci. Na wszystkich krotkach posiadaj膮cych ten sam, aktualnie najmniejszy znacznik, dokonywane s膮 obliczenia. Odnajdywana jest najwi臋ksza warto艣膰 p贸l warto艣膰_max, najmniejsza warto艣膰 p贸l warto艣膰_min, sumowana jest warto艣膰 p贸l warto艣膰_sum i warto艣膰_cnt, oraz obliczana warto艣膰 dla pola warto艣膰_avg = (suma wszystkich p贸艂 warto艣膰_sum)/(suma wszystkich p贸l warto艣膰_cnt).
Przyk艂ad:
Tabela fakt贸w w 藕r贸d艂owej bazie danych nr 1:
Klient |
Sprzedawca |
Towar |
Warto艣膰 |
10 |
10 |
10 |
5 |
10 |
20 |
10 |
15 |
Tabela fakt贸w w 藕r贸d艂owej bazie danych nr 2:
Klient |
Sprzedawca |
Towar |
Warto艣膰 |
10 |
20 |
10 |
10 |
20 |
20 |
10 |
15 |
Tabela fakt贸w w 藕r贸d艂owej bazie danych nr 3:
Klient |
Sprzedawca |
Towar |
Warto艣膰 |
10 |
20 |
10 |
15 |
30 |
10 |
10 |
15 |
30 |
20 |
10 |
15 |
Krotka odczytana od wrapera nr 1:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
10 |
10 |
5 |
5 |
5 |
5 |
1 |
Krotka odczytana od wrapera nr 2:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
20 |
10 |
10 |
10 |
10 |
10 |
1 |
Krotka odczytana od wrapera nr 3:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
Krotka 1 posiada znacznik = 101010, krotki 2 i 3 posiadaj膮 znacznik = 102010. Znacznik krotki 1 jest najmniejszy, wi臋c jest to krotka na kt贸rej zostan膮 wykonane obliczenia. Z uwagi na to i偶 przeliczana jest tylko jedna krotka wstawiane warto艣ci agregowane nie ulegn膮 zmianie.
Krotka 1 wstawiona do magazynu:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
10 |
10 |
5 |
5 |
5 |
5 |
1 |
Kolejna krotka odczytana od wrapera nr 1:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
Wszystkie trzy krotki posiadaj膮 znacznik = 102010. Zatem przeliczane s膮 wszystkie trzy krotki.
Krotka 2 wstawiona do magazynu:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
20 |
10 |
15 |
5 |
30 |
10 |
3 |
Od wrapera nr 1 odebrano ju偶 wszystkie krotki, dlatego teraz pod uwag臋 brane s膮 tylko krotki odczytane od wraper贸w nr 2 i 3.
Kolejna krotka odczytana od wrapera nr 2:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
20 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
Kolejna krotka odczytana od wrapera nr 3:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
30 |
10 |
10 |
15 |
15 |
15 |
15 |
1 |
Najmniejszy znacznik posiada krotka nr 2 (202010). Zostanie ona wstawiona do magazynu. Jest to ostatnia krotka od wrapera nr 2, wi臋c brane pod uwag臋 s膮 teraz tylko krotki od wrapera nr 3. Jako i偶 wyst臋puj膮 one pojedynczo zostaj膮 po kolei i bez zmian wstawione do magazynu.
Zawarto艣膰 relacji centralnej w magazynie danych:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
10 |
10 |
5 |
5 |
5 |
5 |
1 |
10 |
20 |
10 |
15 |
5 |
30 |
10 |
3 |
20 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
30 |
10 |
10 |
15 |
15 |
15 |
15 |
1 |
30 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
Opisane powy偶ej czynno艣ci wykonywane s膮 dla ka偶dej kombinacji atrybut贸w grupuj膮cych np. klient, sprzedawca, towar lub towar, bran偶a itp. Kiedy relacja centralna jest ju偶 wype艂niona (czyli w relacji centralnej znajduj膮 si臋 przetworzone dane ze wszystkich tabel fakt贸w ze 藕r贸d艂owych baz danych) wtedy faza inicjalizacji magazynu danych dobiega ko艅ca i zaczyna si臋 faza kolejna - faza przyrostowej piel臋gnacji zgromadzonych wcze艣niej danych.
W fazie tej nast臋puje nieustaj膮ce odpytywanie monitor贸w. Monitory mog膮 zg艂osi膰, i偶 dokonano modyfikacji danych, lub nie zg艂osi膰 偶adnych zmian je艣li takowe nie nast膮pi艂y. Mo偶liwe zmiany dokonane w 藕r贸d艂owych bazach danych to modyfikacja relacji bocznych lub relacji centralnej. W przypadku relacji centralnej mo偶liwe jest dodanie nowej krotki, zmiana oraz usuni臋cie istniej膮cej krotki (Je艣li przyjmiemy i偶 jedna krotka w tabeli fakt贸w to jeden fakt sprzeda偶y np. faktura to dost臋pne modyfikacje b臋d膮 dotyczy艂y kolejno wystawienia nowej faktury, korekty oraz uniewa偶nienia istniej膮cej faktury). W przypadku relacji bocznych mo偶liwe jest jedynie dodanie nowej krotki lub zmiana istniej膮cej, niemo偶liwe jest natomiast usuni臋cie krotki (mo偶emy to rozumie膰 jako np. dopisanie nowego klienta - dodanie nowej krotki, zmiana danych personalnych klienta - modyfikacja krotki, usuni臋cie klienta wi膮za艂oby si臋 z usuni臋ciem wszystkich faktur dotycz膮cych danego klienta - usuni臋ciem odpowiednich wpis贸w z relacji centralnej). Zachodz膮ce zmiany w 藕r贸d艂owych bazach danych s膮 oznaczane przez monitory odpowiednio:
INS - dodanie krotki,
DEL - usuni臋cie krotki,
UPD - modyfikacja krotki.
Podczas sprawdzania zmian monitory informuj膮 modu艂 integratora o rodzaju zmiany, numerze relacji w kt贸rej nast膮pi艂a zmiana (relacji centralnej odpowiada zawsze numer 0, pozosta艂e numery to relacje boczne), oraz wstawianych, usuwanych lub zmianianych warto艣ciach (przesy艂ana jest odpowiednio dodana krotka, usuni臋ta krotka, krotka przed i po dokonanej zmianie).
W przypadku jakiejkolwiek modyfikacji relacji bocznych integrator jest w stanie uaktualni膰 zawarto艣膰 magazynu na podstawie otrzymanych od monitora danych. W przypadku zmian dokonanych w tabelach fakt贸w konieczne jest uaktualnienie relacji centralnej. Uaktualnianie to jest wykonywane przyrostowo. Oznacza to, 偶e relacja centralna nie jest wype艂niana od nowa, lecz modyfikowane s膮 tylko odpowiednie krotki. Modyfikacja krotek w relacji centralnej odbywa si臋 w nast臋puj膮cy spos贸b:
Je艣li dodano jedn膮 krotk臋:
Klient |
Sprzedawca |
Towar |
Warto艣膰 |
10 |
20 |
10 |
20 |
W贸wczas przetwarzana jest krotka z relacji centralnej z magazynu danych, gdzie klient = 10, sprzedawca = 20 i towar = 10. Dodano krotk臋 gdzie atrybut warto艣膰 = 20 - czyli wi臋cej ni偶 aktualne maksimum (warto艣膰_max = 15) - nowa warto艣膰 maksymalna = 20, wi臋cej ni偶 aktualne minimum (wiec warto艣膰_min pozostaje bez zmian), suma jest powi臋kszona o dodan膮 warto艣膰 (warto艣膰_sum = 30 + 20 = 50), ilo艣膰 wyst膮pie艅 (krotek) jest zwi臋kszona o jeden (dodano jedn膮 krotk臋), a warto艣膰 艣rednia jest obliczana na podstawie nowej sumy i nowej ilo艣ci wyst膮pie艅 (warto艣膰 avg = 50/4= 12 - dok艂adnie 12,5 jednak warto艣膰 ta jest zaokr膮glana). Oto zawarto艣膰 relacji centralnej po uaktualnieniu:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
10 |
10 |
5 |
5 |
5 |
5 |
1 |
10 |
20 |
10 |
20 |
5 |
50 |
12 |
4 |
20 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
30 |
10 |
10 |
15 |
15 |
15 |
15 |
1 |
30 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
Je艣li usuni臋to krotk臋:
Klient |
Sprzedawca |
Towar |
Warto艣膰 |
10 |
20 |
10 |
20 |
W贸wczas przetwarzana jest krotka z relacji centralnej z magazynu danych, gdzie klient = 10, sprzedawca = 20 i towar = 10. Usuni臋to krotk臋 gdzie atrybut warto艣膰 = 20 - czyli aktualne maksimum (warto艣膰_max = 20) - nowa warto艣膰 maksymalna nie jest znana - konieczne jest w贸wczas odwo艂anie si臋 do wszystkich wraper贸w z pytaniem o aktualne maksimum atrybutu warto艣膰. Otrzymamy tyle krotek ile jest wraper贸w i wybierzemy z nich nowe maksimum, kt贸re zostanie wstawione do bazy danych. Podobne odwo艂anie do wraper贸w wyst臋puje jeszcze w przypadku usuni臋cia aktualnego minimum - post臋powanie jest wtedy dok艂adnie takie same. Usuni臋to krotk臋 gdzie atrybut warto艣膰 = 20 - czyli wi臋cej ni偶 aktualne minimum (wiec warto艣膰_min pozostaje bez zmian), suma jest pomniejszona o usuni臋t膮 warto艣膰 (warto艣膰_sum = 50 - 20 = 30), ilo艣膰 wyst膮pie艅 (krotek) jest pomniejszona o jeden (usuni臋to jedn膮 krotk臋), a warto艣膰 艣rednia jest obliczana na podstawie nowej sumy i nowej ilo艣ci wyst膮pie艅 (warto艣膰 avg = 30/3= 10). Oto zawarto艣膰 relacji centralnej po uaktualnieniu:
Klient |
Sprzedawca |
Towar |
Warto艣膰_max |
Warto艣膰_min |
Warto艣膰_sum |
Warto艣膰_avg |
Warto艣膰_cnt |
10 |
10 |
10 |
5 |
5 |
5 |
5 |
1 |
10 |
20 |
10 |
15 |
5 |
30 |
10 |
3 |
20 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
30 |
10 |
10 |
15 |
15 |
15 |
15 |
1 |
30 |
20 |
10 |
15 |
15 |
15 |
15 |
1 |
Jak wida膰 dodanie krotki a nast臋pnie jej usuni臋cie spowodowa艂o powr贸t do warto艣ci sprzed wprowadzenia zmian.
Je艣li zmieniono krotk臋
Klient |
Sprzedawca |
Towar |
Warto艣膰 |
10 |
20 |
10 |
15 |
na:
Klient |
Sprzedawca |
Towar |
Warto艣膰 |
10 |
20 |
10 |
20 |
System post臋puje tak jakby najpierw usuni臋to „star膮” krotk臋, a nast臋pnie dodano „now膮” krotk臋.
Rozbudowa modu艂u integratora
Podczas implementacji ujawni艂o si臋 kilka dodatkowych problem贸w, kt贸rych rozwi膮zanie skomplikowa艂oby znacznie ca艂y projekt. Najwa偶niejszym uproszczeniem by艂o za艂o偶enie, i偶 modu艂 integratora w fazie piel臋gnacji magazynu danych ci膮gle odpytuje monitory. Zmiana systemu tak, aby monitory same informowa艂y modu艂 integratora o zaistnia艂ych zmianach zredukowa艂oby ilo艣膰 przesy艂anych przez sie膰 komunikat贸w oraz wyeliminowa艂o ci膮g艂y odczyt tabel zmian przez monitory co w znaczny spos贸b wp艂yn臋艂oby na efektywno艣膰 ca艂ego systemu. Wi膮za艂o si臋 to jednak z wprowadzeniem w module integratora w膮tk贸w odpowiedzialnych za odczyt komunikat贸w od monitor贸w i w膮tk贸w odpowiedzialnych za uaktualnianie magazynu danych oraz zaimplementowania kolejek komunikat贸w. Kolejnym za艂o偶eniem upraszczaj膮cym by艂o wykluczenie usuwania krotek z relacji bocznych. Wyeliminowa艂o to konieczno艣膰 usuwania krotek z relacji centralnej powi膮zanych z usuni臋t膮 krotk膮 z relacji bocznej. Innym rozwi膮zaniem kt贸re mog艂oby by膰 zmienione spos贸b odczytu nowych ekstrem贸w w przypadku usuni臋cia warto艣ci b臋d膮cej aktualnym maksimum lub minimum. Przyj臋to, i偶 usuni臋cie warto艣ci ekstremalnych wyst臋puje na tyle rzadko, i偶 nie powoduje zauwa偶alnego spadku wydajno艣ci ca艂ego systemu. Jednak w wyj膮tkowych sytuacjach mog艂oby si臋 to okaza膰 problemem. Te i inne zmiany ulepszy艂yby system i spowodowa艂y wzrost jego warto艣ci. Jednym z za艂o偶e艅 stawianych systemowi by艂a mo偶liwo艣膰 ci膮g艂ej jego rozbudowy. Wy偶ej wymienione zmiany s膮 wi臋c pierwszymi etapami rozbudowy i ulepszania systemu.
Modu艂 monitora
Zadanie monitora
Zadaniem monitor贸w jest wykrywanie i przesy艂anie do integratora zmian w 藕r贸d艂owych bazach danych. Zmiany te powinny by膰 przedstawione w postaci jednej z trzech operacji: wstawiania, usuwania lub uaktualniania krotki. W naszym projekcie 藕r贸d艂ow膮 baz膮 danych jest baza danych firmy Oracle.
Za艂o偶enia implementacyjne
Do implementacji modu艂u monitora u偶y艂em j臋zyka Java i interfejsu JDBC. G艂贸wnymi przes艂ankami tego wyboru by艂y: przenaszalno艣膰 Javy oraz 艂atwo艣膰 u偶ycia JDBC. Komunikacj臋 z modu艂em integratora opar艂em na interfejsie gniazd (sockets).
W kr臋gu moich zainteresowa艅 znalaz艂y si臋 dwa sposoby wykrywania zmian w 藕r贸d艂owej bazie danych. Pierwszy, oparty o zdalne wywo艂ywanie procedur (RPC - remote procedure call), mimo niew膮tpliwej zalety polegaj膮cej na natychmiastowym powiadamianiu o zaistnia艂ych modyfikacjach 藕r贸d艂owej bazy danych zosta艂 przeze mnie porzucony ze wzgl臋du na ograniczone zastosowanie tego mechanizmu (jest on udost臋pniany dopiero w bazie danych Oracle8). Wybra艂em spos贸b drugi, oparty na wyzwalaczach (ang. triggers). Wymaga on okresowego przegl膮dania tabel w kt贸rych zapisywane s膮 zachodz膮ce w 藕r贸d艂owej bazie danych zmiany. Powoduje to pewne op贸藕nienie w otrzymaniu informacji o zaj艣ciu zmiany, jednak nie jest to op贸藕nienie na tyle du偶e, aby wyklucza艂o zastosowanie tego rozwi膮zania. Niew膮tpliwymi zaletami powy偶szej metody s膮: po pierwsze u艂atwione buforowanie zaistnia艂ych zmian w 藕r贸d艂owej bazie (polecenie „insert into tabela_zmian” w ciele wyzwalacza); po drugie fakt, i偶 mechanizm wyzwalaczy jest mechanizmem ju偶 wypr贸bowanym i pewnym. Dlatego wybra艂em spos贸b oparty na wyzwalaczach.
W tym momencie zaprezentuj臋 szkieletowy algorytm dzia艂ania monitora:
Implementacja
Ze wzgl臋du na szybko艣膰 dzia艂ania postanowi艂em rozbi膰 monitor na dwa niezale偶ne programy, z kt贸rych pierwszy uruchamiany jest w momencie rozpocz臋cia 艣ledzenia zmian w 藕r贸d艂owej bazie danych, natomiast drugi - w momencie rozpocz臋cia pracy przez modu艂 integratora. Zadaniem pierwszego programu jest:
pobranie ze s艂ownika schematu 藕r贸d艂owej bazy danych,
utworzenie licznik贸w pozwalaj膮cych na odczytywanie danych z tabel we w艂a艣ciwej kolejno艣ci,
CREATE SEQUENCE licznik
increment by 1
start with 1
utworzenie tabel zmian w kt贸rych b臋d膮 zapisywane modyfikacje 藕r贸d艂owej bazy danych, np. dla tabeli wojewodztwa (id NUMBER(4), nazwa VARCHAR2(30)) tworz臋 tabel臋 awojewodztwa (numer NUMBER, r VARCHAR2(5), id NUMBER(4), nazwa VARCHAR2(30))
Licznik zmian |
Rodzaj zmiany (INS, DEL, UPD) |
Zmieniona krotka... |
Podczas implementacji monitora problemem okaza艂 si臋 fakt, i偶 system Oracle odczytuje krotki z tabeli w dowolnej kolejno艣ci. Rozwi膮zaniem tego problemu okaza艂o si臋 dodanie do tabeli zmian licznika i odczytywanie danych z niej zgodnie z rosn膮c膮 warto艣ci膮 tego偶 pola.
utworzenie wyzwalaczy odpowiedzialnych za zapis tych modyfikacji do tabel zmian. Np. dla tabeli awojewodztwa tworz臋 wyzwalacz atwojewodztwa:
after insert or update or delete on wojewodztwa
for each row
begin
if inserting then
insert into awojewodztwa values(licznik.nextval,'ins',:new.id,:new.nazwa);
elsif deleting then
insert into awojewodztwa values(licznik.nextval,'del',:old.id,:old.nazwa);
elsif updating then
begin
insert into awojewodztwa values(licznik.nextval,'upd',:old.id,:old.nazwa);
insert into awojewodztwa values(licznik.nextval,'upd',:new.id,:new.nazwa);
end;
end if;
end;
Z powy偶szego opisu wida膰, 偶e pierwszy program ma funkcj臋 inicjalizuj膮c膮 - przygotowuje system do rozpocz臋cia 艣ledzenia zmian w bazie danych.
Drugi program jest monitorem w艂a艣ciwym - czeka na sygna艂 integratora i gdy go otrzyma wysy艂a informacje o zmianach zasz艂ych w bazie 藕r贸d艂owej (informacje te pobiera z tabel zmian). Format wysy艂anych informacji jest nast臋puj膮cy:
Rodzaj zmiany |
Numer monitora |
Nazwa tabeli |
Zmieniona krotka (lub 2 krotki)... |
Pole „rodzaj zmiany” mo偶e przyj膮膰 jedn膮 z trzech postaci (INS, DEL, UPD) w zale偶no艣ci od rodzaju zmiany o kt贸rej informacja jest przekazywana. Pole „numer monitora” zawiera numer jaki zosta艂 nadany danemu monitorowi przez integrator przy inicjalizacji. „Nazwa tabeli” okre艣la tabel臋, w kt贸rej zmiana zasz艂a. W przypadku zmiany typu „insert” lub „delete” do integratora wysy艂ana jest tylko jedna krotka w ramce. Natomiast w przypadku zmiany typu „update” monitor przekazuje w ramce dwie krotki: star膮 i now膮.
Modu艂 os艂ony (wrapper)
Funkcje modu艂u os艂ony
Dane gromadzone w zbiorczej bazie danych s膮 pozyskiwane ze 藕r贸d艂owych baz danych, przy czym formaty fizyczne, logiczne i poj臋ciowe poszczeg贸lnych 藕r贸de艂 danych mog膮 si臋 r贸偶ni膰 mi臋dzy sob膮. Z ka偶dym z takich 藕r贸de艂 jest zwi膮zana warstwa oprogramowania o nazwie wrapper, kt贸rego zadaniem jest pozyskiwanie danych z r贸偶nych 藕r贸d艂owych baz danych i transformowanie danych z formatu wykorzystywanego w 藕r贸dle do formatu wykorzystywanego w magazynie - dla ka偶dego modelu danych 藕r贸d艂owych konieczne jest zastosowanie specyficznego modu艂u wrappera. Wrapper mo偶emy zatem zdefiniowa膰 jako modu艂 programistyczny umo偶liwiaj膮cy przystosowanie interfejsu lokalnej bazy danych do pewnego standardu (CORBA, HTTP, COM). Funkcj膮 wrappera jest umo偶liwienie fizycznego po艂膮czenia ze 藕r贸d艂ow膮 baz膮 danych. W zasadzie wrapper nie zajmuje si臋 bardziej wyrafinowanym odwzorowaniem, chodzi g艂贸wnie o translacj臋 danych, parametr贸w i wywo艂a艅 funkcji p艂yn膮cych z zewn膮trz na analogiczne dane, parametry i funkcje wyra偶one w API konkretnego lokalnego systemu do postaci, kt贸ra jest wygodna dla systemu heterogenicznych baz danych. Wrappery s膮 podstaw膮 innych 艣rodk贸w odwzorowania schemat贸w i aplikacji, takich jak monitory i perspektywy.
Za艂o偶enia implementacyjne
Projektuj膮c system, rozwa偶ali艣my stworzenie jednego wrappera, kt贸ry obs艂ugiwa艂by wszystkie 藕r贸d艂owe bazy danych. Musia艂by on umie膰 obs艂ugiwa膰 wszystkie systemy zarz膮dzania baz膮 danych, jakie zastosowano do gromadzenia 藕r贸d艂owych informacji. Takie rozwi膮zanie wyda艂o si臋 nam jednak niew艂a艣ciwe, gdy偶 utrudnia艂oby rozszerzenie systemu, o obs艂ug臋 nowych standard贸w baz danych. Rozbudowa taka wymaga艂a by przerabiania istniej膮cego modu艂u wrappera.
Zdecydowali艣my si臋 zastosowa膰 rozwi膮zanie, kt贸re jest ju偶 wykorzystywane w dzia艂aj膮cych na rynku systemach. Z ka偶d膮 藕r贸d艂ow膮 baz膮 danych wsp贸艂pracuje jeden modu艂 wrappera i obs艂uguje on tylko t臋 jedn膮 baz臋. Umo偶liwia to 艂atwiejsz膮 rozbudow臋 systemu.
My艣leli艣my r贸wnie偶 o opracowaniu og贸lniejszego interfejsu obs艂ugi baz danych. Interfejsu, kt贸ry zawiera艂by wbudowane mechanizmy stosowane w komunikacji z wi臋kszo艣ci膮 system贸w obecnych na rynku. Uzupe艂nienie systemu o obs艂ug臋 nowych system贸w baz danych sprowadza艂oby si臋 do okre艣lenia jedynie niezb臋dnych informacji, kt贸rymi istniej膮ce systemy si臋 r贸偶ni膮. Odrzucili艣my jednak to rozwi膮zanie, jako zbyt trudne i przekraczaj膮ce zakres pracy. W zastosowanym rozwi膮zaniu wrapper jest programem wykonywalnym, obs艂uguj膮cym konkretn膮 baz臋 danych. Dla bazy danych w innym standardzie nale偶y opracowa膰 nowy modu艂 wrappera, tworz膮c go od pocz膮tku.
Zasada dzia艂ania wrappera
Modu艂 os艂ony ma za zadanie konwertowanie danych ze 藕r贸d艂owych baz danych do wsp贸lnego formatu danych u偶ywanego w naszym projekcie. Modu艂 ten jest umiejscowiony nad ka偶d膮 藕r贸d艂ow膮 baz膮 danych i konwertuje informacje z tego 藕r贸d艂a do wsp贸lnego formatu danych. W naszym modelu bazy danych wrapper komunikuje si臋 z modu艂em integratora i ze 藕r贸d艂ow膮 baz膮 Oracle. Czas pracy wrappera mo偶na podzieli膰 na trzy fazy:
Poniewa偶 wrapper dzia艂a jako serwer TCP to oczekuje (nas艂uchuje) na zg艂oszenie si臋 modu艂u integratora (klienta). Po nawi膮zaniu po艂膮czenia z integratorem otrzymuje od niego potrzebne do dalszej pracy dane o u偶ytkowniku , kt贸re zostan膮 przechowane w dwuelementowej tablicy znakowej (nazwa u偶ytkownika oraz jego has艂o). Po wys艂aniu potwierdzenia, 偶e dane te otrzyma艂 wrapper oczekuje od integratora przes艂ania zapytania, kt贸re te偶 przechowywane zostaje w odpowiednich strukturach.
Po otrzymaniu zapytania od integratora wrapper musi uzyska膰 po艂膮czenie ze 藕r贸d艂ow膮 baz膮 danych a nast臋pnie przekaza膰 wyniki zapytania z powrotem do integratora. Do komunikacji z baz膮 藕r贸d艂ow膮 wykorzystuje do艂膮czone do pakietu Oracle biblioteki j臋zyka C - Oracle Call Interface (OCI). Zatem logowanie do 藕r贸d艂owej bazy danych, otwarcie kursora, przetwarzanie zapytania, wi膮zanie adresu zmiennych z obszarem kursora, zbieranie wynik贸w do odpowiednich tablic, zamykanie kursora i wylogowanie jest realizowane za pomoc膮 OCI.
Otrzymane wyniki zapytania zostaj膮 przesy艂ane do integratora wg wcze艣niej uzgodnionego schematu. Nast臋pnie zamykane jest po艂膮czenie z integratorem i nast臋puje czas oczekiwania na kolejne zg艂oszenie si臋 integratora.
Komunikacja z modu艂em integratora
Komunikacja z modu艂em integratora odbywa si臋 zgodnie z protoko艂em TCP (architektura klient-serwer) i wed艂ug wcze艣niej uzgodnionego schematu. Wrapper dzia艂a jako serwer TCP nas艂uchuj膮c na porcie 5001. Po nawi膮zaniu po艂膮czenia musi od modu艂u integratora otrzyma膰 dane o u偶ytkowniku czyli nazwa u偶ytkownika i has艂o dost臋pu do 藕r贸d艂owej bazy danych. Po otrzymaniu pojedynczej porcji danych wrapper przesy艂a potwierdzenie do integratora w postaci liczby 1. Nast臋pnie integrator musi przes艂a膰 zapytanie, kt贸re to wrapper b臋dzie musia艂 przetworzy膰. Po zebraniu wynik贸w zapytania wrapper przesy艂a je integratorowi i czeka na potwierdzenie ich otrzymania. Po otrzymaniu potwierdzenia zamyka po艂膮czenie i czeka (nas艂uchuje) na kolejne po艂膮czenie.
Funkcje zwi膮zane z po艂膮czeniem TCP:
bind() - kojarzy adres lokalny i port z utworzonym soketem,
listen() - oczekuje na przychodz膮ce po艂膮czenie na okre艣lonym porcie,
accept() - akceptuje po艂膮czenie,
recv() - odbiera dane,
send() -wysy艂a dane,
closesocket() - zamyka po艂膮czenie.
Zaimplementowane funkcje
Oto wykaz zaimplementowanych funkcji (wraz z dost臋pnymi funkcjami OCI i funkcjami protoko艂u TCP w celu otrzymania po艂膮czenia z modu艂em integratora ):
connect_user() - po艂膮czenie z baz膮 danych Oracle, wykorzystuj膮c funkcj臋 OCI olog(),
new_cursor() - otwarcie nowego kursora (wykorzystanie funkcji oopen() - OCI),
get_sql_statement() - pobranie zapytania i zapami臋tanie go w odpowiednich strukturach,
analyze() - analiza poprawno艣ci zapytania (wykorzystanie funkcji oparse() - OCI),
do_binds() - wi膮zanie adresu dla zmiennych wej艣ciowych (zapytania), wykorzystuje funkcj臋 OCI obndrv(),
describe_define() - zdefiniowanie i opisanie kolumn lub wyra偶e艅 zapytania SQL, zwi膮zane z danymi wyj艣ciowymi; wykorzystuje funkcje OCI odescr() oraz odefin(),
execute() - wykonanie zapytania (wykorzystanie funkcji exec() - OCI),
print_rows() - zbieranie wynik贸w przetworzonego zapytania, wykorzystuje funkcje ofetch(),
do_exit() - zamyka kursor i wylogowuje u偶ytkownika przy pomocy funkcji oclose() i ologof(),
Uwagi ko艅cowe
Dosy膰 wa偶nym elementem implementowanego systemu jest modu艂 wrappera odpowiedzialny za komunikacj臋 z baz膮 danych i przetwarzanie zapyta艅. Powinien on zapewnia膰 niezale偶no艣膰 od systemu zarz膮dzania baz膮 danych. Ze wzgl臋d贸w czasowych ograniczyli艣my si臋 tylko do systemu Oracle co znacznie u艂atwi艂o g艂贸wne zadanie wrapppera, czyli konwersj臋 danych. Zastosowanie j臋zyka C oraz wykorzystanie OCI (Oracle Call Interface) upro艣ci艂o komunikacj臋 z baz膮 Oracle, ale tak偶e stanowi艂o zalet臋 w postaci przeno艣no艣ci tego modu艂u na inne platformy sprz臋towe i systemy operacyjne. Komunikacja wrappera z integratorem zosta艂a zaimplementowana zgodnie z protoko艂em TCP/IP (tryb po艂膮czeniowy) co zwi臋kszy艂o jej niezawodno艣膰.
Instrukcja u偶ytkownika
Program konfiguracyjny s艂ownika magazynu
Program s艂u偶y do automatycznego generowania s艂ownika systemu, w kt贸rym opisane s膮 relacje wyst臋puj膮ce w 藕r贸d艂owych bazach danych. U偶ytkownik systemu nie musi zna膰 schematu budowy s艂ownika, kt贸ry jest niezb臋dny do prawid艂owego dzia艂ania ca艂ego systemu, wi臋c aby dokona膰 jego konfiguracji powinien post臋powa膰 wed艂ug podanych ni偶ej krok贸w:
Uruchom program generuj膮cy s艂ownik np. poleceniem
java Slownik.class
Uwaga: spos贸b uruchomienia programu zale偶y od systemu operacyjnego, kt贸rego u偶ywasz. Mo偶e okaza膰 si臋 konieczne podanie 艣cie偶ki dost臋pu do katalogu zawieraj膮cego plik `Slownik.class'
Na ekranie monitora poka偶e si臋 okienko programu, podobne do tego:
Nast臋pnie wybieramy z menu pozycj臋 Slownik/Relacje, co spowoduje otworzenie kolejnego okna:
W polu „Nazwa relacji” nale偶y wpisa膰 po kolei nazwy wszystkich relacji, kt贸re wyst臋puj膮 w 藕r贸d艂owych bazach danych. Nale偶y pami臋ta膰 aby pierwsz膮 wprowadzon膮 relacj膮 by艂a relacja centralna, kolejno艣膰 wprowadzania reszty relacji nie ma znaczenia. Aby poda膰 nast臋pn膮 relacj臋 nale偶y u偶y膰 przycisku „Kolejna relacja”. Do ewentualnej korekty s艂u偶y przycisk „Poprzednia relacja”, kt贸ry pozwala cofn膮膰 si臋 jednorazowo do wpisanej uprzednio pozycji. Po wpisaniu nazw wszystkich relacji nale偶y przej艣膰 do poni偶szego okna przy u偶yciu przycisku „Koniec relacji”.
Po wprowadzeniu nazw wszystkich relacji nale偶y poda膰 nazwy atrybut贸w ka偶dej z wprowadzonych wcze艣cniej relacji oraz okre艣li膰 typ ka偶dego atrybutu. Nazw臋 atrybutu nale偶y wprowadza膰 w polu „Nazwa atrybutu”. Wprowadzany atrybut nale偶y do relacji, kt贸rej nazwa wy艣wietlona jest w polu „Nazwa relacji”. Typ wprowadzanego w艂a艣nie atrybutu wybieramy z listy rozwijanej, kt贸ra zawiera wszystkie dost臋pne typy atrybut贸w. Je艣li wybrany zostanie typ np. number(r),char(r),varchar(r) lub varchar2(r) w pierwszym okienku nale偶y wprowadzi膰 liczb臋 znak贸w z ilu ma sk艂ada膰 si臋 ten atrybut. Dla typu number(r,n) nale偶y w pierwszym okienku poda膰 liczb臋 znak贸w z ilu ma sk艂ada膰 si臋 ten atrybut, w drugim za艣 liczb臋 miejsc po przecinku. Aby wpisa膰 kolejny atrybut danej relacji nale偶y u偶y膰 przycisku „Kolejny atrybut”. Aby wprowadzi膰 atrybuty dla kolejnej relacji nale偶y u偶y膰 przycisku „Kolejna relacja”. W przypadku ewentualnej krekty mo偶na pos艂u偶y膰 si臋 przyciskiem „Poprzedni atrybut” lub „poprzednia relacja” -dzia艂anie tych przycisk贸w jest analogiczne do przycisk贸w z poprzedniego okna. Po wprowadzeniu wszystkich atrybutu贸w dla wszystkich relacji nale偶y u偶y膰 przycisk „Koniec atrybut贸w”. Poka偶e si臋 poni偶sze okno
Tutaj dokonujemy wyboru kt贸ry z atrybut贸w relacji ma by膰 jej kluczem g艂贸wnym. Wyboru dokonujemy wybieraj膮c odpowiedni膮 pozycj臋 z rozwijanej listy, kt贸ra zawiera nazwy wszystkich atrybut贸w aktualnie wybranej relacji. Po ustwleniu kluczy g艂贸wnych wszystkich relacji przechodzimy do nast臋pnego okna przyciskiem „Koniec kluczy g艂贸wnych”. Uka偶e si臋 poni偶sze okno
Teraz nele偶y okre艣li膰 powi膮zania pomi臋dzy relacjami. Dokonuje si臋 tego poprzez okre艣lenie par uporz膮dkowanych <klucz obcy;klucz g艂贸wny>, gdzie klucz obcy jest dowolnym atrybutem jednej relacji, a klucz g艂贸wny kluczem g艂贸wnym drugiej relacji. Jednak aby powi膮zanie tych dw贸ch relacji by艂o mo偶liwe obydwa atrybuty b臋d膮ce kluczami musz膮 mie膰 taki sam typ.
W polu „Nazwa relacji” jest wy艣wietlona nazwa relacji dla kt贸rej jest aktualnie wyznaczane powi膮zanie. W polu „Nazwa atrybutu” jest wy艣wietlaona nazwa atrybutu kt贸ry ma by膰 kluczem obcym, za艣 w polu „Klucze g艂贸wne” s膮 wy艣wietlone klucze g艂贸wne wszystkich relacji, kt贸re s膮 tego samego typu co atrybut b臋d膮cy kluczem obcym. Relacja centralna mo偶e mie膰 teoretycznie tyle powi膮za艅 ile posiada atrybut贸w. Pozosta艂e relacje powinny posiada膰 co najwy偶ej po jednym powi膮zaniu. Nale偶y tak ustali膰 powi膮zania pomi臋dzy relacjami, aby utworzy艂y one „gwiazd臋”. Powi膮zane relacje nie mog膮 tworzy膰 cyklu tzn. je艣li np. relacja A jest powi膮zana z relacj膮 B a relacja B z relacj膮 C to relacja C nie mo偶e by膰 powi膮zana z relacj膮 A. Nale偶y pami臋ta膰 tak偶e o tym aby dwie relacje r贸偶ne relacje nie by艂y powi膮zane z t膮 sam膮 relacj膮.
Przyk艂adowy schemat gwiazdy
Przyk艂adowy schemat cyklu w po艂膮czeniach relacji
Przyk艂adowy schemat po艂膮czenia dw贸ch relacji do jednej relacji
Zako艅czenie wprowadznia powi膮za艅 relacji nast臋puje po u偶yciu przycisku „Koniec kluczy g艂贸wnych”. Uka偶e si臋 w贸wczas poni偶sze okno
W polu „Wybierz agregaty” nale偶y zaznaczy膰 nazwy tych atrybut贸w, kt贸rych warto艣ci chcemy agregowa膰 (agregowane s膮 maksymalna i minimalma warot艣膰, suma, 艣rednia warto艣膰 oraz liczba wyst膮pie艅 danego atrybutu). W polu „Wybierz atrybuty grupuj膮ce” nale偶y zaznaczy膰 te atrybuty, wed艂ug kt贸rych b臋d膮 pogrupowane agregowane warto艣ci. Ko艅czymy wyb贸r naciskaj膮c przycisk „Koniec agregat贸w”. Poka偶e si臋 poni偶sze okno
Tutaj mo偶liwe jest podanie r贸偶nych kombinacji atrybut贸w wed艂ug kt贸rych b臋d膮 grupowane agregowane warto艣ci. Je艣li w poprzednim oknie wybrali艣my jako atrybuty grupuj膮ce np. klient_id, sprzedawca_id, towar_id, zam贸wienie_id to mo偶emy teraz okre艣li膰 ich kombinacje np.
klient_id; towar_id; sprzedawca_id
towar_id; klient_id
klient_id; srzedawca_id
Kolejno艣膰 atrybut贸w w jednej kombinacji nie ma znaczenia. Tworzenie kombinacji nast臋puje poprzez wybranie z rozwijanej listy nazwy atrybutuoraz naci艣ni臋cie przycisku „Dodaj”. W jednej kombinacji mo偶e by膰 tyle atrybut贸w ile jest ich na w rozwijanej li艣cie, przy czym atrybuty nie mog膮 si臋 powtarza膰. Aby utworzy膰 now膮 kombinacj臋 nale偶y nacisn膮膰 przycisk „Nowa kombinacja”. Aby usun膮膰 niepotrzebn膮 lub b艂臋dn膮 komn=binacj臋 nale偶y zaznaczy膰 j膮 w polu „Wybrane kombinacje atrybutow grupujacych” a nast臋pnie nacisn膮膰 przycisk „Usun”. Aby zako艅czy膰 wprowadzanie kombinacji atrybut贸w grupuj膮cych nale偶y u偶y膰 przycisku „Koniec”. Pojawi si臋 wtedy nast臋puj膮ce okno
Nale偶y wymieni膰 adresy wszystkich komputer贸w na kt贸rych znajduj膮 si臋 藕r贸d艂owe bazy danych, nazw臋 u偶ytkownika i has艂o na kt贸rego koncie znajduj膮 si臋 opisane wcze艣niej relacje, oraz okre艣li膰 numer portu na kt贸rym b臋d膮 dzia艂a艂y modu艂y monitora i wrapera.
Adres komputera podajemy w polu „Adres bazy danych” i w tym samym polu po dwukropku numer portu np.:
adres.komputera.pl:1234 lub 123.123.123.123:1234
Je艣li 藕r贸d艂owa baza danych znajduje si臋 na tym samym komputerze co generowany s艂ownik to mo偶na poda膰 adres tego komputera lub wpisa膰 zamiast niego localhost lub 127.0.0.1 oraz oczywi艣cie numer portu.
Nazw臋 u偶ytkownika wpisujemy w polu „Uzytkownik”, a jego has艂o w polu „Has艂o”. Zamiast wpisywanego has艂a uka偶膮 si臋 gwiazdki. Okre艣lanie adres贸w 藕r贸d艂owych baz danych mo偶na zako艅czy膰 u偶ywaj膮c przycisku „Koniec baz danych”. Pojawi si臋 poni偶sze okno
Dla ka偶dej 藕r贸d艂owej bazy danych nale偶y wybra膰 odpowiednie relacje kt贸re si臋 w niej znajduj膮. W ka偶dej bazie powinien znajdowa膰 si臋 ten sam zestaw relacji. Aby unik膮膰 przypadkowych niesp贸jno艣ci najlepiej umie艣ci膰 wszystkie relacje we wszystkich 藕r贸d艂owych bazach danych. Aby tego dokona膰 nale偶y zaznaczy膰 wszystkie pozycje w polu „Relacje znajduj膮ce si臋 w bazie danych” i nacisn膮膰 przycisk „Kolejna baza danych”. Po przypisaniu relacji do wszystkich 藕r贸d艂owych baz danych nale偶y nacisn膮膰 przycisk „Koniec”.Pojawi si臋 okno
To ju偶 koniec opisu relacji. Teraz pozostaje jedynie podanie nazwy u偶ytkownika na koncie kt贸rego b臋dzie sk艂adowany wygenerowany s艂ownik oraz magazyn danych. Nazw臋 u偶ytkownika nale偶y poda膰 w polu „Uzytkownik”, a jego has艂o w polu „Haslo”. Wprowadzane has艂o b臋dzie wy艣wietlone w postaci gwiazdek. W polu „Nazwa magazynu” nale偶y poda膰 nazw臋 sterownika obs艂uguj膮cego dan膮 baz臋 danych. Po naci艣ni臋ciu przycisku „Polacz si臋 z magazynem” nast臋puje po艂膮czenie si臋 z baz膮 danych i wygenerowanie s艂ownika.
W przypadku niewype艂nienia jakiego艣 pola lub w razie niewybrania jakiej艣 opcji pojawi si臋 okno ze stosownym komunikatem
Aby w takim przypadku zako艅czy膰 dzia艂anie programu nale偶y u偶y膰 przycisku „Tak”, w przeciwnym razie „Nie” - komunikat zniknie daj膮c mo偶liwo艣膰 ponowego wype艂nienia pola lub wybory opcji.
Query processor
Do w艂a艣ciwej biblioteki query processora do艂膮czono prosty program, umo偶liwiaj膮cy zadawanie zapyta艅 do magazynu w trybie interaktywnym. Poniewa偶 jest to 32-bitowy program dzia艂aj膮cy w trybie konsoli, jest mo偶liwe jego wykorzystanie w trybie wsadowym za pomoc膮 operator贸w przekierowywania strumieni. Program uruchamiamy z linii komend, wpisuj膮c jego nazw臋 (z ewentualn膮 艣cie偶k膮 dost臋pu)
WhConsole.exe
Podanie rozszerzenia `.exe' jest opcjonalne. Program zg艂osi si臋 znakiem zach臋ty w postaci:
Warehouse>
za kt贸rym znajduje si臋 mrugaj膮cy kursor, oznaczaj膮cy miejsce wpisywania tekstu. Od tej chwili mo偶emy zadawa膰 zapytania do magazynu, pos艂uguj膮c si臋 instrukcj膮 SELECT j臋zyka SQL.
Uwaga: w tym miejscu instrukcji powinien pojawi膰 si臋 dok艂adny opis formatu zapyta艅, jakie mo偶emy kierowa膰 do magazynu. Zdecydowano si臋 go pomin膮膰, poniewa偶 opis ten pojawi艂 si臋 ju偶 wcze艣niej w niniejszej pracy.
Po wpisaniu zapytania, kt贸re nale偶y zako艅czy膰 艣rednikiem (zapytanie mo偶e by膰 rozdzielone znakami ko艅ca linii) i naci艣ni臋ciu klawisza ENTER, na ekranie zostan膮 wy艣wietlone wyniki zapytania, lub komunikat o b艂臋dzie. Obs艂uga programu jest podobna do obs艂ugi programu SQL*Plus firmy Oracle.
Poza poleceniami j臋zyka SQL, mo偶emy u偶y膰 dw贸ch komend specjalnych, kt贸re r贸wnie偶 nale偶y zako艅czy膰 艣rednikiem. Komendy specjalne poprzedzamy znakiem uko艣nika (`/'). S膮 to:
exit - polecenie powoduje zako艅czenie pracy z magazynem i opuszczenie programu,
debug - polecenie powoduje w艂膮czenie tzw. trybu testowego - w tym trybie program przedstawia posta膰 przetworzonego zapytania j臋zyka SQL, kt贸re jest kierowane do magazynu.
Uruchomienie modu艂u wrappera
Wrapper uruchamiamy poleceniem
wrapper.exe <nr_portu>
Je艣li jest to konieczne, nale偶y poda膰 艣cie偶k臋 dost臋pu do katalogu, zawieraj膮cego modu艂 wykonywalny wrappera. Jako parametr, podajemy nr portu, na kt贸rym wrapper powinien nas艂uchiwa膰. Wrapper jest uruchamiany na komputerze zawieraj膮cym baz臋 danych z relacjami 藕r贸d艂owymi.
Na komputerach wyposa偶onych w system operacyjny Windows NT modu艂 mo偶na uruchomi膰 jako serwis (service, polskie t艂umaczenie - us艂uga), za pomoc膮 narz臋dzia SRVANY, do艂膮czone do ResourceKit'a dla WinNT.
Uruchomienie modu艂u monitora
Monitor uruchamiamy poleceniem
java monit <nr_portu> <username> <password>
Je艣li jest to konieczne, nale偶y poda膰 艣cie偶k臋 dost臋pu do katalogu, zawieraj膮cego modu艂 wykonywalny monitora. Jako parametry, podajemy nr portu, na kt贸rym monitor powinien nas艂uchiwa膰, oraz parametry konta w bazie danych, kt贸ra obs艂uguje dany monitor. Monitor jest uruchamiany na komputerze zawieraj膮cym baz臋 danych z relacjami 藕r贸d艂owymi.
Przyk艂adowa sesja z systemem
Za艂o偶yli艣my, 偶e 藕r贸d艂owe bazy danych zawieraj膮 schemat relacji zawarty w p.聽V.3. Po uruchomienia programu konfiguracyjnego s艂ownika i wpisaniu potrzebnych danych, program wygenerowa艂 i wype艂ni艂 nast臋puj膮ce relacje w magazynie:
Tabela `relacje'
ID_RELACJI NAZWA_RELACJI
---------- -------------
0 sprzedaz
1 wojewodztwa
2 miasta
3 klienci
4 sprzedawcy
5 branze
6 kategorie
7 towary
8 lata
9 kwartaly
10 miesiace
11 zamowienia
Tabela `atrybuty'
ID_ATRYBUTU NAZWA_ATRYBUTU ID_RELACJI TYP
----------- -------------- ---------- ------------
0 id 1 NUMBER(4)
1 nazwa 1 VARCHAR2(30)
2 id 2 NUMBER(4)
3 nazwa 2 VARCHAR2(20)
4 wojewodztwo 2 NUMBER(4)
5 id 3 NUMBER(4)
6 nazwa 3 VARCHAR2(25)
7 adres 3 VARCHAR2(25)
8 miasto 3 NUMBER(4)
9 id 4 NUMBER(4)
10 nazwa 4 VARCHAR2(25)
11 adres 4 VARCHAR2(25)
12 id 5 NUMBER(4)
13 nazwa 5 VARCHAR2(15)
14 id 6 NUMBER(4)
15 nazwa 6 VARCHAR2(15)
16 branza 6 NUMBER(4)
17 id 7 NUMBER(4)
18 nazwa 7 VARCHAR2(30)
19 cena 7 NUMBER(8,2)
20 kategoria 7 NUMBER(4)
21 rok 8 NUMBER(4)
22 id 9 NUMBER(4)
23 rok 9 NUMBER(4)
24 id 10 NUMBER(4)
25 kwartal 10 NUMBER(4)
26 id 11 NUMBER(4)
27 data 11 DATE
28 zamowienie 0 NUMBER(4)
29 klient 0 NUMBER(4)
30 sprzedawca 0 NUMBER(4)
31 towar 0 NUMBER(4)
32 miesiac 0 NUMBER(4)
33 ilosc 0 NUMBER(6)
34 wartosc 0 NUMBER(8,2)
Tabela `klucze_glowne'
ID_ATRYBUTU
-----------
0
2
5
9
12
14
17
21
22
24
26
Tabela `klucze_obce'
OD DO
-- --
4 0
8 2
29 5
30 9
16 12
20 14
31 17
23 21
25 22
32 24
28 26
Tabela `wartosci_agregowane'
ID_ATRYBUTU
-----------
33
34
Tabela `agregaty'
2 5 9 12 14 17 21 22 24 26
-- -- -- -- -- -- -- -- -- -- --
-- -- 1 1 -- 1 -- -- -- -- --
1 -- -- -- -- -- 1 1 -- -- --
-- -- 1 1 -- -- 1 -- -- -- --
-- 1 -- -- -- -- -- -- -- -- --
W 藕r贸d艂owych bazach danych istniej膮 ju偶 pewne krotki. Wykonano zapytanie:
SELECT sprzedawcy.nazwa, klienci.nazwa, sum(ilosc), max(wartosc)
FROM sprzedaz, sprzedawcy, klienci
GROUP BY sprzedawcy.nazwa, klienci.nazwa
HAVING max(wartosc) < 1000
Otrzymano wynik:
sprzedawcy.nazwa klienci.nazwa sum(ilosc) max(wartosc)
---------------- -------------- ---------- ------------
hurtownia nr 1 sklep Piotrowo 5 300
Teraz dodano krotk臋, kt贸ra dla otrzymanej w wyniku pary sprzedawca - klient, i o okre艣lonych pozosta艂ych warto艣ci (towar, zamowienie itd.) doda艂a ilosc r贸wn膮 1 i warto艣膰 = 200. Wykonano to samo zapytanie. Wynik:
sprzedawcy.nazwa klienci.nazwa sum(ilosc) max(wartosc)
---------------- -------------- ---------- ------------
hurtownia nr 1 sklep Piotrowo 6 300
Nast臋pnie dodano identyczn膮 krotk臋, ale ilo艣膰 = 2, a warto艣膰 400. Teraz wynik wygl膮da nast臋puj膮co:
sprzedawcy.nazwa klienci.nazwa sum(ilosc) max(wartosc)
---------------- -------------- ---------- ------------
hurtownia nr 1 sklep Piotrowo 8 400
Zako艅czenie
W pracy przedstawiono prototypowy system magazynu danych dla przetwarzania analitycznego danych w trybie on-line. Zapoznano czytelnika z celem tworzenia takiego systemu i podobnych do niego i przedstawiono og贸lny opis obecnego stanu wiedzy w zakresie projektowania hurtowni danych i system贸w OLAP (on-line analitycal processing). Przedstawiono dok艂adny opis zaprojektowanego systemu - jego za艂o偶e艅 i przebiegu implementacji - poprzedzony opisem metod i narz臋dzi zastosowanych przy jego tworzeniu.
Praca nad systemem magazynu danych generalnie zako艅czy艂a si臋 sukcesem. Opracowano system spe艂niaj膮cy oczekiwania - prawid艂owo magazynuj膮cy dane w magazynie w trybie na bie偶膮co, opracowano te偶 interfejs po艣rednicz膮cy mi臋dzy magazynem a u偶ytkownikiem.
Uda艂o si臋 opracowa膰 system otwarty. Dopisanie modu艂贸w wrappera i monitora umo偶liwia dodanie nowych standard贸w baz danych, z kt贸rych magazyn mo偶e czerpa膰 dane. Szkoda, 偶e nie starczy艂o czasu na dopisanie jeszcze jednej pary tych modu艂贸w - my艣leli艣my na pocz膮tku o obs艂udze baz MS Access. Nale偶y jednak zaznaczy膰, 偶e dopisanie modu艂贸w wrappera i monitora nie jest zadaniem trywialnym. Rozwijaj膮c system, mo偶na by pomy艣le膰 o og贸lniejszym interfejsie po艣rednicz膮cym w komunikacji ze 藕r贸d艂owymi bazami danych. Wymaga艂oby to przejrzenia istniej膮cych na rynku produkt贸w i znalezienia wsp贸lnego formatu danych. Nie chodzi tu o znaczne u艂atwienie dodawania nowych standard贸w danych, bo ze wzgl臋du na ich liczb臋 wydaje si臋 to bardzo trudne, ale by膰 mo偶e mo偶liwe by艂oby stworzenie interpretowanego j臋zyka, kt贸ry u艂atwia艂by dodawanie nowych modu艂贸w. Obecnie, do napisania wrappera u偶yto j臋zyka C, natomiast do stworzenia monitora - Javy. Wyspecjalizowany j臋zyk do tworzenia takich modu艂贸w skraca艂by czas wykonania tego zadania.
Same modu艂y systemu nie s膮 zbyt wymagaj膮ce pod wzgl臋dem pami臋ciowym. Dlatego chyba nie mo偶na uzna膰 systemu ma艂o efektywnym. Jego wymagania zale偶膮 przede wszystkim od serwer贸w baz danych (zar贸wno magazynu, jak i baz 藕r贸d艂owych) oraz od ilo艣ci przetwarzanych danych. Je偶eli zak艂adamy du偶e ilo艣ci danych (a dla takich baz projektuje si臋 przecie偶 hurtownie), to dodatkowy nak艂ad wytworzony przez dzia艂aj膮ce modu艂y systemu jest niewielki. Oczywi艣cie, zgodnie z za艂o偶eniami, dane w magazynie s膮 sk艂adowane przyrostowo.
Pomys艂em na poszerzenie mo偶liwo艣ci systemu wydaje si臋 nam zmiana wymaga艅, co do struktury 藕r贸d艂owych relacji. (Obecne wymagania, zgodne z modelem ROLAP'u opisano w p.聽V.3.) Gdy przyjrzymy si臋 przyk艂adowemu schematowi relacji - systemowi magazynowania fakt贸w sprzeda偶y w sieci hurtowni - zauwa偶ymy, 偶e przydatne by艂oby zniesienie ograniczenia polegaj膮cego na tym, 偶e ka偶da relacja mo偶e by膰 wskazywana przez klucz obcy innej relacji tylko jeden raz. Dla przyk艂adu wyobra藕my sobie, 偶e dla sprzedawcy, podobnie jak dla klienta, chcieliby艣my pami臋ta膰 informacj臋 o jego po艂o偶eniu - mie艣cie i wojew贸dztwie. Obecnie wymaga to stworzenia nowych relacji - miasta i wojew贸dztwa - i w dodatku pod zmienionymi nazwami. Nie mo偶emy relacji odpowiadaj膮cej za wojew贸dztwa nazwa膰 po prostu wojew贸dztwa, bo taka relacja istnieje. Rodzi si臋 pytanie: czy klucz obcy `miasto' relacji `sprzedawcy' nie m贸g艂by wskazywa膰 na ju偶 istniej膮c膮 relacj臋 `miasta'? Wydaje si臋, ze znacznie utrudni to zadanie. W takiej sytuacji, dla ka偶dego atrybutu musimy zna膰 nie tylko relacj臋, do kt贸rej on nale偶y, ale r贸wnie偶 艣cie偶k臋 relacji, po kt贸rej powinni艣my doj艣膰 do niego z relacji centralnej. Wymaga艂oby to r贸wnie偶 zmian w formacie zapytania, kt贸re podaje u偶ytkownik systemu. C贸偶, jest to pomys艂 na przysz艂o艣膰.
Kolejnym udoskonaleniem systemu, kt贸re wydaje si臋 nam potrzebne, gdy konfigurujemy system, jest opracowanie bardziej zaawansowanego modu艂u konfiguracji. Chodzi o opracowanie metod, kt贸re pozwala艂y by automatycznie zbiera膰 ze 藕r贸d艂owych baz danych informacje o relacjach i atrybutach, orientowa膰 si臋 w ich strukturze - kt贸ra relacja jest relacj膮 centraln膮, jakie s膮 mi臋dzy nimi powi膮zania - i zapisywa膰 te dane w s艂owniku systemu. Poniewa偶 zak艂adamy r贸偶norodno艣膰 standard贸w 藕r贸d艂owych baz danych, wymaga艂oby to opracowania interfejs贸w po艣rednicz膮cych w wymianie danych z tymi bazami. Takie interfejsy ju偶 mamy - s膮 to modu艂y wrapper贸w - nale偶a艂oby tylko rozszerzy膰 je o nowe funkcje, funkcje opisu relacji istniej膮cych w bazie.
Literatura
Z.聽Kr贸likowski, T.聽Koszlajda, M.聽Matysiak, R.聽Wrembel, Magazyny Magazyny danych i technologia OLAP - materia艂y pomocnicze do wyk艂ad贸w przedmiotu Zaawansowane Systemy Baz Danych.
J.聽Wiener, H.聽Gupta, W.聽Labio, W.聽Zhuge, H.聽Garcia-Molina, J.聽Widom, A System Prototype for Warehouse View Maintenance, , Departament of Computer Science, Stanford University.
http://www.java.sun.com
http://figaro.ae.katowice.pl/~stanek
M. Spile, The Complete Guide to Java Database Programming, McGraw-Hill.
R.聽Shukla, T.聽Smith, Programmer's Giude to the ORACLE Call Interfaces, Oracle Corporation, 1990.
M.聽Gruber, SQL - znakomity podr臋cznik opisuj膮cy najnowszy standard SQL-a, Helion, 1996.
Z.聽Kr贸likowski, M.聽Zakrzewicz, Materia艂y z wyk艂ad贸w przedmiotu Zaawansowane systemy baz danych, Politechnika Pozna艅ska, Instytut Informatyki, 1999.
Prototypowy system magazynu danych dla przetwarzania analitycznego w trybie on-line
2