CouchDB – tak trochu jiná databáze (3. část)

Dnes nás čeká poslední část miniseriálu o CouchDB, tak trochu jiné databázi. V této části se dozvíte, jak na replikaci, co dělat, když vám databáze zabírá moc místa, a o tom, jak pomocí pohledů dát datům strukturu.

Seriál: Nerelační databáze (11 dílů)

  1. CouchDB – tak trochu jiná databáze (1. část) 24.8.2009
  2. CouchDB – tak trochu jiná databáze (2. část) 31.8.2009
  3. CouchDB – tak trochu jiná databáze (3. část) 7.9.2009
  4. MySQL v roli neschémové databáze 6.1.2010
  5. Základy Amazon SimpleDB 30.3.2010
  6. Návrh databáze – NoSQL vs SQL 31.3.2010
  7. Amazon SimpleDB prakticky v PHP 15.4.2010
  8. Vyskúšajme si Tokyo Cabinet 4.5.2010
  9. Redis: key-value databáze v paměti i na disku 7.10.2010
  10. Přechod z MySQL na CouchDB, část první 17.2.2011
  11. Přechod z MySQL na CouchDB: Druhý díl 24.2.2011

Replikace

Replikace je způsob, jak mezi dvěma databázemi (databází je v tomto případě myšlena konkrétní přihrádka, nikoli celý server) synchronizovat data. Určí se dvě databáze – zdrojová a cílová – a všechna data, co v cílové chybí, jsou do ní ze zdrojové překopírována. Je při tom využíváno ID dokumentů a jejich revizí. Zdrojová databáze může být lokální nebo vzdálená a stejně tak může být i cílová lokální nebo vzdálenou. Podmínkou je, že obě databáze musí existovat (i když nemusí obsahovat ani jeden dokument).

Řekněme, že chceme vytvořit repliku databáze s alby (a předpokládejme, že tam nějaká alba jsou). Replika bude lokální, takže pro ni vytvoříme databázi:

$ curl -X PUT http://localhost:5984/alba-replika/
{"ok":true} 

A poté spustíme samotnou replikaci (při opravdovém spuštění uvidíte místo tří teček údaje, týkající se replikace – kdy začala, skončila apod.):

$ curl -X POST -d '{"source":"alba","target":"alba-replika"}' http://localhost:5984/_replicate
{"ok":true,...} 

Replikace je jeden z důvodů, proč CouchDB nemůže sloužit jako verzovací systém – při replikacích se kopírují jen ta nejčerstvější data.

Vzdálená databáze se od lokální liší tím, že určíme, na jakém serveru se nachází –  http://jiny-server:5984/jina-databaze/.

Stlačování (compaction)

MVCC (Multiversion Concurrency Control) má výhodu v tom, že nejsou potřeba žádné zámky, takže klienti nemusí na nic čekat. Ale jelikož se pokaždé vytváří úplně nová kopie dokumentu (a dokument může být docela velký), CouchDB si ukousne hezký kousek místa na disku. Vzhledem k tomu, že místo je levné, tak to většinou není až takový problém. Ale zase není neomezené. A proto je tu stlačování, při kterém se zahodí všechny nepotřebné (staré) revize a tím se uvolní místo.

Pokud byste měli velkou databázi alb, a ta se hodně měnila, starých revizí se zbavíte pomocí:

$ curl -X POST http://localhost:5984/alba/_compact
{"ok":true} 

Pohledy (views)

Pohledy jsou asi tou nejzáludnější věcí, na kterou u CouchDB narazíte, a tohle bude jen takové lehké nakousnutí. Pohledy jsou způsobem, jak dát nestrukturovaným datům uloženým v dokumentech strukturu.

Abychom měli nějaká data, se kterými se bude dát pracovat, vytvořme si takový menší adresář osob:

$ curl -X PUT http://localhost:5984/adresar/
{"ok":true}
$ curl -X PUT -d '{"jmeno":"Pavel"}' http://localhost:5984/adresar/4835de71c4900920222793a70f5ffd9f
{"ok":true,"id":"4835de71c4900920222793a70f5ffd9f","rev":"1-77c126bcd8ca8702f3f7d9aa6e9f0fae"}
$ curl -X PUT -d '{"jmeno":"Pepa"}' http://localhost:5984/adresar/f9767dc49c498129ab71b33dccee06d0
{"ok":true,"id":"f9767dc49c498129ab71b33dccee06d0","rev":"1-edd7e3f5f0e91940c7f633052170ef21"}
$ curl -X PUT -d '{"jmeno":"Vašek"}' http://localhost:5984/adresar/38d6642e9f4f80790e41351e80067285
{"ok":true,"id":"38d6642e9f4f80790e41351e80067285","rev":"1-595c448e9755c9b1183839d6a9c73d08"}
$ curl -X PUT -d '{"jmeno":"Honza"}' http://localhost:5984/adresar/7695e6a0dc219ec16c311e4eaa19483d
{"ok":true,"id":"7695e6a0dc219ec16c311e4eaa19483d","rev":"1-e98255a638f0f7874fe24e37c11e54a4"}
$ curl -X PUT -d '{"jmeno":"Marek"}' http://localhost:5984/adresar/5747a709954fe6ae95bac69ed7090af1
{"ok":true,"id":"5747a709954fe6ae95bac69ed7090af1","rev":"1-9efd5be58372c54b03eb5da604a77018"} 

Teď se už dostaneme k Futonu, tedy ke grafickému rozhraní CouchDB. Otevřte si adresu http://localhost:5984/_utils/. Měli byste vidět něco jako:

Futon

Nás zajímá databáze adresar, takže na ni klikneme:

Futon databáze

Jsou tu jednotlivé dokumenty. Pokud byste na některý z nich klikli, dostanete se na stránku, kde můžete dokument upravovat, přidávat a mazat přílohy atp. Ale nás zajímají pohledy, takže změníme zobrazení na dočasné pohledy:

Futon temp view

Jak Futon správně varuje, dočasné pohledy by se neměly používat v produkčním nasazení, jelikož se při každém zavolání pohledu musí celý přepočítat. Na chvilku si s tím však vystačíme.

Jeden pohled bychom tam měli mít připravený (jako na obrázku), takže ho spustíme pomocí tlačítka Run. Pokud znáte styl zpracování dat pomocí MapReduce, asi je vám jasné, proč to dopadlo, jak to dopadlo. Funkce map je volána pro každý dokument v databázi a emit() vypustí pod daným klíčem daná data. V tomto případě je vždy klíčem null a data jsou celý dokument. Ale pomocí různých podmínek můžete vypustit všelijaká data pod rozličnými klíči. Také se nemusíte omezovat jen na jedno volání emit() uvnitř map funkce – můžete emit() zavolat milionkrát a nemusíte ho také zavolat vůbec.

Kdybychom chtěli získat všechny dokumenty z databáze, funkce map by mohla vypadat následovně:

function(doc) {
  emit(doc._id, {"rev" : doc._rev});
} 

Jako klíč je ID dokumentu a data jsou jeho revize. Popravdě řečeno takový pohled pro vás CouchDB připravuje automaticky a máte ho k dispozici na /<databáze>/_all_docs. Pro databázi adresar by to tedy byla adresa http://localhost:5984/…ar/_all_docs. Pokud byste rovnou chtěli získat i data dokumentů, přidejte query parametr ?include_docs=true  – http://localhost:5984/…ar/_all_docs?….

Ale chtělo by to taky nějaký užitečný pohled. Jako map funkci zadejte tedy:

function(doc) {
  emit(doc.jmeno, null);
} 

Co z toho bude? Spustíte-li pohled pomocí Run, uvidíte, že jsme na místě klíčů dostali jména v adresáři a na místě hodnot null  – přesně to, co vypustí funkce emit(). Bystřejší už vidí, že řádky jsou seřazeny abecedně podle klíče.

Pohled si uložíme. Klikněte tedy na Save As…. Pokud se chcete držet článku, jako Design document zadejte adresar a jako View name podle-jmena. Máte stálý (permanentní) pohled a na ten se jednoduše můžete dotazovat pomocí HTTP metodou GET  – http://localhost:5984/…/podle-jmena:

{"total_rows":5,"offset":0,"rows":[
{"id":"7695e6a0dc219ec16c311e4eaa19483d","key":"Honza","value":null},
{"id":"5747a709954fe6ae95bac69ed7090af1","key":"Marek","value":null},
{"id":"4835de71c4900920222793a70f5ffd9f","key":"Pavel","value":null},
{"id":"f9767dc49c498129ab71b33dccee06d0","key":"Pepa","value":null},
{"id":"38d6642e9f4f80790e41351e80067285","key":"Vau0161ek","value":null}
]} 

Vidíte výstup podobný tomu z _all_docs. Je zde počítadlo total_rows oznamující, kolik řádků očekávat; offset říkající, kolik jich bylo vynecháno; a pole rows, kde jsou již samotná data.

Pokud do adresy přidáte query parametr ?skip=4 , čtyři řádky budou přeskočeny a dostanete jenom:

{"total_rows":5,"offset":4,"rows":[
{"id":"38d6642e9f4f80790e41351e80067285","key":"Vau0161ek","value":null}
]} 

Pomocí parametru descending můžete určit, mají-li se řádky řadit vzestupně ( descending=false, výchozí), či sestupně ( descending=true). Parametry se samozřejmě dají různě kombinovat – ?skip=4&descending=true :

{"total_rows":5,"offset":4,"rows":[
{"id":"7695e6a0dc219ec16c311e4eaa19483d","key":"Honza","value":null}
]} 

Parametr limit zase určuje, kolik maximálně řádků se smí vrátit (ve výchozím stave bez limitu). Poté můžete ještě určit, jaký konkrétní klíč chcete pomocí key. A startkey  a endkey dávají možnost zadat rozsah klíčů. Chcete všechny kontakty od P? Máte je mít:

{"total_rows":5,"offset":2,"rows":[
{"id":"4835de71c4900920222793a70f5ffd9f","key":"Pavel","value":null},
{"id":"f9767dc49c498129ab71b33dccee06d0","key":"Pepa","value":null}
]} 

Existuje ještě více parametrů, podle kterých můžete z pohledů vybírat řádky, které chcete. A v budoucnu možná ještě další přibudou. Všechny byste je měli najít na wiki.

Mnoho lidí se bojí, že jak CouchDB nemá schéma, jak to není všechno hezky v tabulce, tak nad daty ztratí veškerou kontrolu a všechno budou muset počítat v aplikaci (což se povětšinou nevyplatí). Pohledy CouchDB jsou důkazem, že to pravda není. Tohle bylo navíc jen takové zahřívací kolo – pravá legrace přichází, když se do všeho začnou míchat reduce funkce.

Stálé pohledy jsou předpočítané, resp. se počítají při prvním zavolání, takže žádné propastné prodlevy při dotazech na pohledy nehrozí – opět se (stejně jako u MVCC) obětovává místo ve prospěch rychlosti.

Na závěr

Toto bylo takové malé představení dokumentově orientované databáze CouchDB. Osobně mě někdy relační databáze docela vytáčejí, že něco „nejde“ udělat tak, jak bych si zrovna představoval (ano, jen do mě s tím, že to je jen kvůli tomu, že to neumím), tak se porozhlížím po jiných řešeních ukládání dat. CouchDB mě zaujala.

I když se přímo v dokumentaci píše, že CouchDB není relační databáze, ani náhrada za relační databáze, v článku jsem se srovnání právě s relačními databázemi, vzhledem k rozšířenosti a známosti jejich modelu mezi programátory, nemohl vyhnout. Myslím, že pro některé aplikace je CouchDB důstojnou alternativou relačních databází. Pro některé možná i vhodnějším řešením.

Doufám, že jsem CouchDB neudělal medvědí službu a tento článek vás zaujal alespoň natolik, že se třebas podíváte na její domovské stránky. Hlavní zdrojem inspirace pro příklady použité v článku je připravovaná kniha CouchDB: The Definitive Guide.

Autor programuje v Javascriptu, PHP, Javě, Golangu… ve všem možném. Ve volném čase probádává nejrůznější zákoutí světa programovacích jazyků a databází a všeho kolem nich.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 13

Přehled komentářů

datel Inu, není nad Lotus Notes
maks Re: Inu, není nad Lotus Notes
Kvík Lotusy, hehe...
zz Re: Lotusy, hehe...
Ivan Re: Lotusy, hehe...
Datel Re: Lotusy, hehe...
Michal MongoDB
Martin Malý Re: MongoDB
karmi Re: MongoDB
t42 Re: MongoDB
Pedro Bajecne
Kibo Pochvala
Jan Semorád fakt to funguje
Zdroj: https://www.zdrojak.cz/?p=3071