{{predmet|Organizace a zpracování dat I|Michal Žemlička|DBI007}}
= Přednáška – stručný přehled =
== Schémata organizace souborů ==
* '''hromada''' – nehomogenní soubor (nemá pevný typ záznamu s primitivními typy)
** pravěk
* '''sekvenční soubor''' – homogenní soubor uspořádaný dle nějakého klíče
** + sekvenčí přístup; - ''(minus)'' přístup k záznamům
* '''index-sekvenční soubor''' – sekvenční soubor + (víceúrovňový) index na blocích, příp. oblast přetečení
** + přístup k záznamům i sekvenční přístup
* '''indexovaný soubor''' ''(také invertovaný soubor)'' – primární soubor + více indexů na záznamech (klasický index, bitmapy, ..)
** + přístup k záznamům, k množině záznamů; - sekvenční přístup
* '''soubor s přímým přístupem''' – typicky ''hašování''
** + přístup k záznamům; - přístup k množině i sekvenční přístup
** perfektní (prosté) hašování
*** Cormack – 2-stupňové hašování přes pomocný adresář
*** Larson & Kalja – 2-stupňové hašování + signatury a separátory stránek
** dynamické hašování
*** s pomocným adresářem (Fagin)
*** bez adresáře – skupinové štěpení
** výcerozměrná mřížka (pro OLAP?)
== Popis jednotlivých algoritmov ==
=== Perfektní hešovaní (Cormack) ===
Cormakovo hašování je založeno na existenci primární hašovací funkce <math>h(k)</math>, a celé třídy sekundárních hašovacích funkcí <math>h_{i}(k,r)</math>. funkce <math>h(k)</math> musí mít [[obor hodnot]] roven velikosti adresáře.
Položky jsou ukládány do primárního souboru (pevné velikosti), způsobem, který bude popsán za pomoci adresáře (pevné velikosti). Protože je i primární soubor i adresář pevné velikosti, řadí se Cormacovo hašování do tzv [[statické metody hasšování|statických metod hašování]].
Primární soubor si jde představit jako pole pevné velikosti. Adresář vypadá následujícím způsobem:
{| border="1" cellpadding="2" cellspacing="2"
|+Adresár
! pozice !! p !! i !! r
|-
! 1
| || ||
|-
! 2
| || ||
|-
! ...
| || ||
|-
! j
| || ||
|-
! ...
| || ||
|}
'''Význam položek''' <br>
'''p''' je odkaz do primárního souboru <br>
'''i''' značí kolikátá hašovací funkce byla použita a <br>
'''r''' označje počet položek v primárním souboru, na které se odkazuje '''p''' <br>
'''pozice''' je index položky v adresáři.
===Příklad 1.===
<table border="0" cellpadding="20">
<tr><td>
{| border="1" cellpadding="2" cellspacing="2"
|+Adresár
! pozice !! p !! i !! r
|-
! 1
| 1||2 ||3
|-
! 2
| || ||
|-
! ...
| || ||
|-
! j
| || ||
|-
! ...
| || ||
|}
</td><td>
{| border="1" cellpadding="2" cellspacing="2"
|+Primární soubor
! pozice !! hodnota
|-
! 0
| 4
|-
! 1
| 5
|-
! 2
| 6
|-
! 3
|
|-
! 4
|
|-
! 5
|
|}
</tr>
</table>
Tato situace nám popisuje, že v primárním souboru jsou uloženy 3 položky, všechny v jednom bloku(vede na ně jen jeden pointer '''p'''), které jdou od sebe rozlišit hašovací funkcí číslo 2 ('''i''' == 2) a první z těchto položek je v primárním souboru na pozici 1 ('''p''' == 1).
=== Jak funguje vkládání ===
Pokud přidáváme položku s klíčem '''k''', nejprve spočteme <math>h(k)</math>. Pokud je Adresář[<math>h(k)</math>].r == 0, provedeme následující akce
* Adresář[<math>h(k)</math>].r = 1
* Adresář[<math>h(k)</math>].i = <math>\heartsuit</math> (Pozor, ne 0)!
* V primárním souboru na první volnou pozici s adresou p<sub>new</sub> umístíme ukládanou položku
* Adresář[<math>h(k)</math>].p = p<sub>new</sub>
Pokud je Adresář[<math>h(k)</math>].r != 0, provedeme následující akce
* Adresář[<math>h(k)</math>].r = Adresář[<math>h(k)</math>].r +1
* Najdeme nejmenší i takové, že <math>h_{i}(k,r)</math> je růzdné pro nově vkládanou položku a pro všechny položky v datovém bloku příslušném pointeru Adresář[<math>h(k)</math>].p
* Adresář[<math>h(k)</math>].i = i
* V primárním souboru na první volnou a dostatečně velkou pozici s adresou p<sub>new</sub> umístíme ukládanou položku a všechny položky z bloku Adresář[<math>h(k)</math>].p v pořadí, které určí klíč sekundární hašovací funce
<math>h_{i}(k, r)</math>
* Adresář[<math>h(k)</math>].p = p<sub>new</sub>
===Příklad 2.===
Zvolne velikost adresáře M=7.
Potom <math>h(k)</math> navrhneme ve tvaru <br>
<math>h(k)</math> <math>h(k)= k \quad mod \quad M</math>;<br>
<math>h_{i}(k, r) = (k << i) \quad mod \quad r </math>, pro r případ '''r''' jemocninou 2; <br>
<math>h_{i}(k, r) = (k \quad xor i) \quad mod \quad r </math>, jinak.<br>
(<math> << i</math> značí [[bitový posun]] vlevo o i bitů)
Postupně budeme přidávat do prázného souboru položky 6, 3, 13.
<math>h(6) = 6, h(3) = 3</math>, přidání je tedy triviální a struktury mají po přidání prvních dvou tento tvar.
<table border="0" cellpadding="20">
<tr><td>
{| border="1" cellpadding="2" cellspacing="2"
|+Adresár
! pozice !! p !! i !! r
|-
! 0
| || ||
|-
! 1
| || ||
|-
! 2
| || ||
|-
! 3
| 1 ||<math>\heartsuit</math> || 1
|-
! 4
| || ||
|-
! 5
| || ||
|-
! 6
| 0 ||<math>\heartsuit</math> || 1
|}
</td><td>
{| border="1" cellpadding="2" cellspacing="2"
|+Primární soubor
! pozice !! hodnota
|-
! 0
| 6
|-
! 1
| 3
|-
! 2
|
|-
! 3
|
|-
! 4
|
|-
! 5
|
|}
</tr>
</table>
Potom se pokusíme přidat 13. <math>h(13) = 6</math>, což už je obsazeno.
Updatneme Adresář[6].r na 2, a najdeme čím je to obsazeno (položkou s klíčem 6), a hledáme první sekundární funkci, která tyto klíče rozliší. To je <math>h_{0}</math>, protože <math>h_{0}(6,2) = 0</math>, a <math>h_{0}(13,2) = 1</math>.
Takže po vložení 13 budou struktuy vypadat následujícím způsobem
<table border="0" cellpadding="20">
<tr><td>
{| border="1" cellpadding="2" cellspacing="2"
|+Adresár
! pozice !! p !! i !! r
|-
! 0
| || ||
|-
! 1
| || ||
|-
! 2
| || ||
|-
! 3
| 1 ||<math>\heartsuit</math> || 1
|-
! 4
| || ||
|-
! 5
| || ||
|-
! 6
| 2 ||0 || 2
|}
</td><td>
{| border="1" cellpadding="2" cellspacing="2"
|+Primární soubor
! pozice !! hodnota
|-
! 0
|
|-
! 1
| 3
|-
! 2
| 6
|-
! 3
| 13
|-
! 4
|
|-
! 5
|
|}
</tr>
</table>
=== Jak funguje vyhledávání ===
* spočteme <math>h(k)</math>.
* podle Adresář[<math>h(k)</math>].r se buď podíváme na přímo příslušné místo do primárního souboru, nebo spočteme příslušnou (Adresář[<math>h(k)</math>].i) sekundární hašovací funkci, najdeme příslušný blok a v něm příslušnou položku.
Další často používanou sekundární funkcí je funkce
<math>h_{i}(k,r)=(k \quad mod \quad (2i + 100r +1))\quad mod \quad r</math>
Predpokladá se, že <math> k << 2i + 100r +1</math>.
=== Pseudokód ===
Zadefinujeme si ješte nějaké datové položky:
<code>
typedef head_1 {int p; int i; int r;}
typedef body_1 {int k; int v;}
head_1 *head=new head_1[s];
body_1 *body=new body_1[];
</code>
==== Vyhledávání ====
<code>
int h(int k, int s) {}
int hi(int i, int k, int r) {}
bool find(int k, int *v) {
j=h(k, s);
if (head[j].r==0) return false;
else {
body *p=body[head[j].p+hi(head[j].i, k, head[j].r)];
if (p->k!=k) return false;
else {*v=p->v; return true;}
}
}
</code>
==== Vkládání ====
...je trošku zložitejšie, c-like algoritmus není kompletní, ale je názorný...
<code>
int free(int size) {/*nájde voľné miesto v primárnom súbore s veľkosťou size*/}
bool insert(body_1 d) {
j=h(d.k, s);
if (head[j].r==0) { //pre daný kľúč ešte nemáme alokovaný blok
int p=free(1);
body[p].k=d;
head[j].p=&body[p]; head[j].i=0; head[j].r=1;
} else {
Ak už je hodnota d.k v množine head[j].p - head[j].p+head[j].r, vráť false
Nájdi voľné miesto pre (head[j].r+1) prvkov
Nájdi i také, aby hashovacia funkcia hi vrátila pre každý z prvkov (pôvodný blok+d) rôznu adresu
Premiestni prvky zo starého umiestnenia na nové, zapíš nový prvok
Oprav adresár
}
}
</code>
=== Perfektné hashovanie - Larson & Kalja (beta) ===
* otvorené adresovanie s dvojitým hašhovaním a jedným prístupom
* používa tabuľku pomocných informácií, nazvime ju sep (povolenie), ktorá je podstatne menšia ako u Cormacka. Vyžaduje M*d bitov, kde M je počet stránok adresového priestoru, a d je veľkost pomocnej dátovej štruktúry (reťazec 0 a 1) - separátor/povolenie. Ďalej sa používa M hashovacích funkcií h<sub>i</sub>, ktoré pre každý kľúč vracajú postupne postupnosť adries tých stránok, kde je možné hľadať (vložiť) daný záznam; dalších M hashovacích funkcií s<sub>i</sub> generuje signatúry kľúča k .
Predstava:
Stránka:
+------+
| sep |
+------+-----+
| data sig | (PS: sig-signatúry záznamov si ukladať nemusíme, pomocou s<sub>i</sub> si ich dopočítame...)
| ... |
+------------+
Na začiatku sú všetky stránky prázdne...
1 2 3 M
+------+ +------+ +------+ +------+
| 1111 | | 1111 | | 1111 | | 1111 |
+------+-----+ +------+-----+ +------+-----+ +------+-----+
| | | | | | ... | |
| | | | | | | |
+------------+ +------------+ +------------+ +------------+
==== Vkladanie ====
# i=1
# Keď chceme pridať záznam (k), pomocou h<sub>i</sub>(k) zistíme umiestnenie stránky. Potom záznam zahashujeme pomocou s<sub>i</sub>, čím získame jeho signatúru.
# Porovnáme povolenie/separátor stránky so signatúrou záznamu - ak je sep<=sig, i=i+1 a opakujeme od predchadzajuceho bodu.
# Inak sme našli správnu stránku - pokúsime sa pridať do nej náš záznam. Záznamy v stránke usporiadame podľa signatúry (od zostupne - od najvačšej).
# V prípade, že je záznamov v stránke priveľa (viac ako je veľkosť stránky): vyberieme (vymažeme zo stránky) záznamy s najvačšou signatúrou (teda všetky s rovnakou signatúrou z "vrchu" stránky), túto signatúru nastavíme ako separátor stránky, a vybrané záznamy znovu zahashujeme...
Pridanie jedného prvku (33, h<sub>1</sub>=4, s<sub>1</sub>=(001)b)...
4
+------+
| 111 |
+------+-----+
| data sig |
| 33 001 |
| |
+------------+
Pridanie ďalších dvoch (11, h<sub>1</sub>=4, s<sub>1</sub>=(101)b; 15, h<sub>1</sub>=4, s<sub>1</sub>=(001)b)...
4
+------+
| 111 |
+------+-----+
| data sig |
| 11 101 | <= stránka je plná, toto budeme musieť "vyhodiť"
| 33 001 |
| 15 001 |
+------------+
|
V
4
+------+
| 101 |
+------+-----+
| data sig |
| 33 001 |
| 15 001 |
+------------+
Hodnotu 11 budeme musieť zahashovat znovu, ale tentokrát už nie "pomocou" h<sub>1</sub>/s<sub>1</sub>, ale niektorých ďalších funkcií...
==== Vyhľadávanie ====
Viď bod 0-2 z pridávania :-)
== Stromy ==
* [[wikipedia:B-Tree|B-stromy]]
= Cvičení =
Triedenie veľkých objemov dát - [http://en.wikipedia.org/wiki/Heapsort heapsort] (vytváranie v lineárnom čase), ďalej optimalizácia jeho práce s pamäťou, a nakoniec [http://en.wikipedia.org/wiki/Mergesort zlievanie] (=mergesort)
= Zkoušky =
== 30.1.2007 ==
*1. Vymazat prvek z poloprazdneho B stromu (2b)
*2. Pridat prvek do skoro plneho B* stromu (2b)
*3. Grayovy kody - k cemu jsou a jak moc nam pomuzou (2b)
*4. Rozsiritelne hashovani - pridat prvek do plneho bucketu (asi se (doufam) musel rozsirit index) (2b?)
*5. Cormack - (a) pridat prvek, (b) jak dlouho (vzhledem k disku) bude trvat nalezeni zadaneho konkretniho prvku (+zduvodnit) (2b+2b)
*6. Jake jsou pouzitelne struktury indexu (staci nejcastejsi), proc bychom je kdy pouzili (5b)
*7. Co je to striping a jak ho prakticky vyuzit v implementaci databaze (4b?)
*8. Podrobny popis, jak najit prvek ve skupinove stepenem hashi (4b?)
Cas necele dve hodiny. Hodnoceni klasicke 25..21: 1,20..19: 2,18..16: 3.
== 16.1.2007 ==
*n cestne trideni - Kolko cestne triedenie treba na vyrobenie jedneho finalneho behu ak ho chcem dosiahnut na 2 priechody a na zaciatku mam 625 behov.
*neredundantni B-strom delete
*kde sa nachadzaju medziblokove medzery, uvedte 2 priklady
*hledani ve vicerozmerne mrizce
*Larson & Kalja
*skupinove stepeni
*Fagin
*zakladni pocitani READ a REWRITE z disku
*spocti r z otacek disku.
= Odkazy =
* [http://kocour.ms.mff.cuni.cz/~zemlicka/vyuka/DBI007/ Žemličkove stránky k predmetu]
* [http://kocour.ms.mff.cuni.cz/~zemlicka/cz.html Žemličkove stránky]