Přechod z MySQL na CouchDB: Druhý díl

V předcházejícím článku jsme si ukázali základy toho, jak pracuje MySQL a CouchDB, porovnali jsme postupy jak modelovat data, a také jsme si ukázali, jak fungují základní dotazy a seznamy záznamů, a to jak pomocí SQL dotazů v MySQL, tak i s použitím pohledů (view) v CouchDB.

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

Disclaimer: Článek je překladem článku How to move from MySQL to CouchDB, part II z blogu CouchOne. Překlad i s originálními ilustracemi vychází s laskavým svolením společnosti CouchOne. Autor článku pracuje v CouchOne jako člen výboru a viceprezident pro dokumentaci, v minulosti psal dokumentaci k MySQL. Minulý týden vyšel překlad první části.

Tentokrát začneme tím, že si ukážeme, jak zadávat tyto pohledy a určité další prvky SQL dotazů, jako jsou klauzule WHERE a GROUP BY, a podíváme se na vlastní postup přenosu dat a aplikační logiky na CouchDB.

Zamyslete se nad dotazy, které budete provádět

Jak jsme už viděli, tvorba dotazů na CouchDB se ve skutečnosti skládá ze dvou kroků. Prvním z nich je vytvoření pohledu, který umožní vyhledávání a vybírání dokumentů v databázi. Druhou částí je URL a hodnoty klíče, které chceme z pohledu vybrat. To znamená, že při plánování, jak získat data z CouchDB databáze, je potřeba si promyslet, podle čeho budete data vyhledávat, a to vám pomůže určit strukturu pohledu, který bude potřeba vytvořit.

CouchDB používá pohledy k vytvoření seznamů dokumentů z databáze, a výstupem pohledu je klíč a k němu příslušná hodnota. Jak klíče, tak i tyto hodnoty mohou mít formu jakékoliv JSON hodnoty. Klíč je ve výstupu podstatný proto, že je základem pro mechanismy vyhledávání, třídění a stránkování.

Například funkce vytvářející pohled, který vrátí všechny dokumenty receptů z databáze, jejichž klíčem bude název receptu, by mohla vypadat takto:

function(doc) {
    if (doc.type == 'recipe' &&
        doc.title !== null) {
        emit(doc.title, doc);
    }
}

Takovéto funkci se říká mapovací funkce – mapuje údaje z dokumentů na formát, který má být použit. Nepovinný druhý krok se nazývá reduce, a je obdobou agregačních funkcí a klauzule GROUP BY v MySQL. (Jde o známý algoritmus map/reduce – pozn.překl.)

Při přechodu z MySQL bude mít vliv na to, jak budete data ukládat, i samotný návrh pohledů. Ty navrhujeme tak, aby odpovídaly datům, která chcete vypisovat nebo se na ně dotazovat. Vraťme se k našemu příkladu s recepty: na MySQL byste sestavili dotaz, který hledá mrkev v tabulce přísad, a získali byste tak seznam nalezených receptů. Ve formě SQL by vypadal takto:

SELECT recipe.id, recipe.title FROM ingredients join (recipe) on
    (ingredients.recipeid = recipe.id) where ingredient = 'carrot'

V CouchDB lze stejného výsledku dosáhnout vytvořením pohledu, který vrátí jeden řádek pro každou přísadu z našeho dokumentu s recepty takto:

function(doc) {
    if (doc.type == 'recipe' &&
        doc.title !== null) {
        for id in doc.ingredients {
              emit(doc.ingredients[id].ingredient, doc);
         }
    }
}

V dotazovém URL, které slouží pro zpřístupnění pohledu, byste pak zadali požadovanou hodnotu klíče, v našem případě mrkev. Například:

http://couchdb:5984/recipes/_design/recipes/_view/by_ingredient?key=%22carrot%22

Nezapomínejte, že klíčem může být jakákoliv hodnota JSON, a hodnoty klíče, které do dotazu zadáváte, musí být tedy správně enkódované. Jak je vidět z tohoto příkladu, pohled tvoří základ dotazu a samotný přístup k vyhledávání je v režii databáze.

Používání pohledů tímto způsobem vede k tomu, že většina aplikací bude nakonec tvořena mnoha různými pohledy. Postup vytváření pohledů se přitom vlastně neliší od tvorby základních dotazů v aplikaci, a následné optimalizaci těchto dotazů a indexů pro vrácení požadovaného výstupu. Hlavní rozdíl je v tom, že definice pohledu není dotazem v aplikačním kódu, ale je uložena v databázi.

Agregace

V MySQL se agregace (seskupení) používají na mnoha různých místech. Agregace je dosaženo kombinací klauzule GROUP BY a funkcí, které shromažďují či shrnují údaje. V našem příkladu s recepty můžeme provést dotaz, který vrátí ke každé přísadě počet receptů, v kterých je obsažena. Například dotaz:

SELECT ingredient,count(recipeid) FROM ingredients GROUP BY ingredient

vrátí seznam přísad a ke každé z nich počet receptů, do kterých daná přísada patří. Ve výsledné aplikaci se takto mohou objevit „nejčastěji používané přísady do receptů“, v jiných aplikacích to zase mohou být „nejoblíbenější příspěvky na blogu“, apod.

V CouchDB se k seskupení použije reduce funkce. Navazuje na původní mapovací funkci a zúží výsledky, které mapovací funkce vrátí.

Rozšíření dotazů

Složitější dotazy, při nichž se vyhledává ve podle více datových položek, jsou jen otázkou vytvoření vhodného pohledu, a pak správného zadání hledaných údajů v parametrech dotazu jako vyhledávacího klíče. Pokud mají být vráceny jen údaje v určitém rozmezí, lze použít k zadání tohoto rozsahu počáteční a koncový klíč. Pokud si například vytvoříte pohled, jehož klíčem bude čas přípravy jednotlivých receptů, získáte z něj seznam všech receptů, jejichž příprava zabere 5 až 25 minut, takto:

http://couchdb:5984/recipes/_design/recipes/_view/by_cooktime?startkey=%225%22&endkey=%2225%22

Jedná se o obdobu dotazu:

SELECT title FROM recipe WHERE cooktime >= 5 AND cooktime <= 25

Seřazení výsledků

Řazení výsledků se provádí automaticky podle klíče generovaného každým pohledem. Pokud tedy chcete vypsat seznam receptů seřazených abecedně podle názvu, stačí si vytvořit pohled, který vrací jako klíč název receptu. To znamená, že

http://couchdb:5984/recipes/_design/recipes/_view/by_title

je obdobou

SELECT title FROM recipe ORDER BY title

Pro seřazení výsledků sestupně se v MySQL použije klíčové slovo DESC

SELECT title FROM recipe ORDER BY title DESC

V CouchDB se v URL zadá parametr descending

http://couchdb:5984/recipes/_design/recipes/_view/by_title?descending=true

Stránkování

V MySQL lze dosáhnout stránkování pomocí kombinace klauzulí LIMIT a OFFSET, například takto získáte prvních deset záznamů z našeho dotazu na názvy receptů:

SELECT title FROM recipe ORDER BY title LIMIT 10

Dalších 10 záznamů:

SELECT title FROM recipe ORDER BY title LIMIT 10 OFFSET 10

V CouchDB se používá podobný postup, kdy se limit a skip zadávají jako parametry dotazu. Prvních deset záznamů tedy získáte takto:

http://couchdb:5984/recipes/_design/recipes/_view/by_title?limit=10

A dalších 10 záznamů:

http://couchdb:5984/recipes/_design/recipes/_view/by_title?limit=10&skip=10

Načtení celého základního objektu

V ukázkové databázi receptů v MySQL je potřeba pro zobrazení jednho receptu načíst údaje z více tabulek. V CouchDB platí, že jakmile máte ID dokumentu daného receptu, tak máte přístup k celé struktuře záznamu o tomto receptu tak, jak byl do databáze uložen.

Potřeba zjednodušit mechanismus načítání takovýchto složitých objektů vedla u MySQL k mnoha různým pomocným projektům, které mohou pomoci zvýšit dostupnost dat (např. jejich cachováním v paměti). I při použití CouchDB zůstává nutnost načíst údaje z databáze, ale načtení celého záznamu receptu je možné v rámci jedné operace, namísto několika dotazů a převedení dat do struktury použité pro jejich zobrazení.

Jakmile máte ID dokumentu, stačí k získání obsahu celého dokumentu v CouchDB jediná operace. Pokud například získáte ID dokumentu Aromaticroastchic­ken z našeho pohledu podle přísad, lze pak celý dokument receptu zobrazit pomocí jediného web requestu:

GET http://couchdb:5984/recipes/Aromaticroastchicken

Výsledkem jsou data receptu jako JSON:

{
   "title" : "Aromatic roast chicken",
   "preptime" : "15",
   "servings" : "6",
   "totaltime" : "120",
   "subtitle" : "A couscous stuffing, and aromatic spices with fragrant lime and roasted garlic, turn a simple roast chicken into something special.",
   "cooktime" : "105",
   "_id" : "Aromaticroastchicken",
   "_rev" : "1-c76ba47a4848af8f965d3940efb118df"
    "keywords" : [
      "diet@dairy-free",
      "cook method.hob, oven, grill@oven",
      "diet@peanut-free",
      "special collections@cheffy recommended",
      "diet@corn-free",
      "special collections@weekend meal",
      "occasion@entertaining",
      "special collections@very easy",
      "diet@yeast-free",
      "diet@shellfish-free",
      "special collections@feeling spicy!",
      "main ingredient@poultry",
      "diet@demi-veg",
      "meal type@main",
      "diet@egg-free",
      "diet@cow dairy-free"
   ],
 "ingredients" : [
 ...
   ],
 "method" : [
 ...
   ],
}

Stačí jeden dotaz, jeden požadavek na databázi, aby vrátila vše potřebné pro zobrazení celého receptu na stránce. Samozřejmě zde může být zahrnutý i další obsah, jako komentáře uživatelů nebo další metadata, vše uložené v jednom dokumentu, dostupné pomocí jednoho dotazu.

Přesun dat

Výstupní formát dat je základem pro další závažné rozhodnutí související s přechodem. Je třeba vzít v potaz, jak se bude s údaji pracovat. Pokud jsou údaje, které pochází v MySQL z více zdrojových tabulek, zobrazovány najednou, mívá smysl sloučit tyto informace a ukládat je v CouchDB jako jeden dokument.

Jak už bylo uvedeno, mnoho urychlujících mechanismů, používaných ve spojení s MySQL, funguje na základě toho, že si cachují data z více tabulek, jakmile byly jednou načteny, a tím urychlují nahrávání komplexních datových struktur.

Stejný princip platí i v CouchDB, pokud vezmeme v potaz výše zmíněné pravidla omezující strukturu. Pokud chcete podle určitých kritérií získávat dokumenty z databáze, musíte zajistit, že  struktura dat dovoluje vytvořit pohled umožňující vyhledávání.

Například ve struktuře našeho receptu nemá smysl ukládat přísady jako jediné textové pole a tím ztratit podrobnosti o obsahu. To je obdobou uložení všeho do jediného textového sloupce v MySQL a vede ke stejným problémům: zhoršuje možnosti vyhledávání a dotazování podle těchto údajů, a omezuje možnosti zobrazení dat.

Samotný postup přesunu dat je vcelku jednoduchý – načíst data z MySQL databáze, vytvořit dokument pro každý hlavní objekt v databázi, a pak tyto dokumenty zapsat do CouchDB databáze.

Dokumenty v CouchDB jsou ukládány podle svého ID. ID může být libovolný řetězec, což znamená, že můžete použít jakýkoliv údaj jednoznačný pro vás nebo vaší aplikací bez toho, abyste ho museli tento hledat v některém pohledu. V naší všudypřítomné databázi receptů byste takto mohli použít název receptu, například „Rybí polévka“. Omezením tohoto přístupu (stejně jako unikátních indexů v MySQL) je, že nelze uložit dva dokumenty se stejným ID.

Stejně jako funguje klauzule AUTO_INCREMENT v MySQL, tak i CouchDB dokáže vygenerovat automaticky UUID pro každý nový dokument. To ale není povinné, takže můžete mít v jedné databázi jak dokumenty s konkrétním ID, tak i s automaticky vygenerovaným ID, což umožňuje přiřadit předem zvolená ID význačným instancím a dokumentům, a pro zbývající data použít automaticky generované ID.

Rozhraní k CouchDB

MySQL se nepoužívá jen ve webových aplikacích, a já zde nebudu tvrdit totéž ani o CouchDB, ale stojí za to si zapamatovat, že přístup ke CouchDB probíhá pomocí webového rozhraní, které je založené na koncepci REST. Dokumenty jsou načítány za pomocí URL, a možnosti pohledů a dotazů se zadávají jako parametry tohoto URL, stejně jako u jiné CGI nebo podobné webové aplikace.

Pro většinu programovacích jazyků a platforem jsou k dispozici rozhraní, které zjednodušují postup ukládání informace v databázi CouchDB. Existují nástroje pro Perl, Python, Javu, PHP a mnoho dalších. I pokud dojde k nepravděpodobné situaci, že pro vámi vybranou platformu nebude existovat vhodná knihovna, postačuje ke komunikaci s CouchDB pouze schopnost provádět HTTP dotazy.

U většiny webových aplikací v rámci obvyklých platforem, obzvláště pokud používáte AJAX, vypadá postup dotazování dost podobně jako na následujícím obrázku. Váš dotaz pochází z jQuery, je zpracován aplikací, která komunikuje s MySQL databází a vrátí správně údaje v požadované formě.

Při používání CouchDB můžete část aplikační logiky přesunout na samotnou CouchDB databázi, když pomocí návrhových dokumentů získáte data ve správném formátu už z CouchDB.

Když si vše shrneme

Hlavním rozdílem mezi CouchDB a MySQL je to, v jaké podobě jsou data uložené a jak se k nim přistupuje. Pro určité datové struktury poskytuje CouchDB jednodušší řešení problému načtení dat celého jednoho objektu, jak jsme to viděli v předcházejících příkladech. Recepty jsou pěkným příkladem, kde hlavním prvkem báze dat je recept jako celek (náš dokument). Potřeba vyhledávat údaje o receptu a zobrazovat seznamy je požadavkem pouze na prezentaci dat, nejde o přímý požadavek na to, jak mají být data uložená.

Snad vám tyto dva příspěvky daly určitou představu, jak lze přesunout data z MySQL na CouchDB a jak modelovat data v CouchDB a vyvíjet aplikační kód tak, aby celý systém fungoval stejně jako ve vaší existující aplikaci založené na databázi MySQL.

Komentáře: 18

Přehled komentářů

A co XML databáze A co XML databáze?
František Kučera Re: A co XML databáze?
Jerry12 Re: A co XML databáze?
Radek Re: A co XML databáze?
mizsha stromy
Jan Semorád Objektová databáze
logik Re: Objektová databáze
MarekB. Re: Objektová databáze
Jan Semorád Re: Objektová databáze
alef0 Re: Objektová databáze
Pavel Křivánek CouchDB a XULRunner
eL Strom
Stefan Re: Strom
Karel Minařík Re: Strom
Jan Semorád Zelená je Praxe
Jiří Kosek Re: Zelená je Praxe
František Kučera Re: Zelená je Praxe
gondo horizontalne skalovanie?
Zdroj: https://www.zdrojak.cz/?p=3441