Masarykova univerzita Fakulta}w¡¢£¤¥¦§¨  informatiky !"#$%&'()+,-./012345

Serverová aplikace pro mobilní katalog SmartLib

diplomová práce

Bc. Tomáš Hrabal

Brno, Jaro 2013 Prohlášení

Prohlašuji, že tato diplomová práce je mým původním autorským dílem, které jsem vypracoval samostatně. Všechny zdroje, prameny a literaturu, které jsem při vypracování používal nebo z nich čerpal, v práci řádně cituji s uvedením úplného odkazu na příslušný zdroj.

Bc. Tomáš Hrabal

Vedoucí práce: prof. RNDr. Jiří Hřebíček, CSc.

ii Poděkování

Na tomto místě bych rád poděkoval Jonáši Ševčíkovi za vedení projektu SmartLib. Jaromíru Dvořáčkovi a Marku Jelenovi za rady při vývoji a po- mocnou ruku s nasazením projektu.

iii Shrnutí

Diplomová práce se zabývá návrhem, popisem implementace a produkčního nasazení serverové aplikace SmartLib, sloužící uživatelům mobilních klientů a knihovníkům Masarykovy univerzity. V práci jsou diskutována a porovnána řešení datové struktury, včetně výběru toho nejvhodnějšího. Práce ve všech částech poukazuje na spolupráci se studenty vyvíjejícími její mobilní část.

iv Klíčová slova

SmartLib, Knihovna, Mobilní aplikace, NoSQL, Serverová aplikace, Datová struktura, API

v Obsah

1 Popis systému ...... 3 1.1 Knihovnický systém na Masarykově univerzitě ...... 3 1.1.1 Aleph ...... 3 Parametry Alephu ...... 3 Nedostatky Alephu ...... 4 1.1.2 SmartLib ...... 4 Mobilní aplikace ...... 5 1.1.3 Vlastní aplikace ...... 5 2 SmartLib ...... 7 2.1 Implementace ...... 7 2.1.1 Ruby ...... 7 vs ...... 8 Rozšíření Sinatry: Git. Bundler a Gemy ...... 9 2.1.2 OpenShift ...... 9 2.1.3 SQL/NoSQL ...... 10 Sequel a instalace databáze ...... 10 MongoDB ...... 11 ElasticSearch ...... 12 2.1.4 Služby třetí strany ...... 13 MailGun ...... 13 Veřejný repozitář ...... 13 Externí služby pro detaily knih ...... 14 3 Návrh systému ...... 16 3.1 Případy užití ...... 16 3.1.1 Parser knih z Alephu ...... 16 3.1.2 Mobilní API ...... 18 3.1.3 Webové rozhraní ...... 20 3.2 Diagram aktivit ...... 20 3.2.1 Parsování záloh databáze Alephu ...... 20 3.2.2 Hledání knihy ...... 22 3.2.3 Hodnocení knihy ...... 22 3.3 Sekvenční diagramy ...... 22 3.3.1 Aktivita m14_check_availability ...... 22 3.3.2 Aktivita P7_parse_book ...... 24 3.4 Databáze ...... 25 3.4.1 MongoDB ...... 26 3.4.2 MySQL ...... 28

1 3.4.3 ElasticSearch ...... 30 3.4.4 MySQL + ElasticSearch ...... 31 3.5 Porovnání databázových řešení ...... 32 3.5.1 Plnění databáze porovnávanými zálohami ...... 33 3.5.2 Porovnání času vyhledávání ...... 33 3.5.3 Porovnání relevance vyhledávání MySQL a ElasticSearch 35 3.5.4 Porovnání relevance vyhledávání ElasticSearch a Aleph 36 3.5.5 Shrnutí ...... 38 4 Implementace obsluhy knih pro koncová zařízení ...... 40 4.0.6 REST ...... 40 4.0.7 JSON API, HTTP Hlavičky ...... 41 4.0.8 API ...... 42 API pro MySQL ...... 43 API pro ElasticSearch ...... 45 4.0.9 Parser ...... 48 4.0.10 Registrace uživatelů ...... 51 5 Implementace webového rozhraní pro knihovníky ...... 53 5.1 Popis ...... 53 5.2 Implementace ...... 54 5.2.1 Implementace správy knihoven ...... 54 6 Aplikace jako celek ...... 58 6.1 Použité gemy ...... 58 6.2 Struktura aplikace a zásady psaní kódu ...... 59 6.2.1 Zásady psaní kódu ...... 62 7 OpenShift ...... 63 7.1 Speciální implementace pro OpenShift ...... 63 7.1.1 Umístění konfiguračního souboru ...... 63 7.1.2 Cron ...... 63 7.1.3 Kontrola dostupnosti služeb ...... 64 7.1.4 Post-deploy ...... 64 7.2 Konfigurace a instalace ...... 64 8 Umístění projektu ...... 66 8.0.1 Veřejný repozitář ...... 66 8.0.2 Produkční aplikace ...... 66 9 Závěr ...... 67

2 1 Popis systému

1.1 Knihovnický systém na Masarykově univerzitě

Mezi jednu ze základních služeb nabízející studentům většina univerzit je síť knihoven. Ne jinak je tomu i u Masarykovy univerzity, dále MU. Narozdíl od jiných univerzit MU nemá jednu ústřední knihovnu, ale 9 fakultních ústředních knihoven a několika dalších specializovaných knihoven [1]. O správu a rozvoj knihovního systému se stará Knihovnicko-informační centrum MU. V současné době je v knihovnách MU deponováno přes 1.4 miliónu jednotek [1] a využívat je mohou jak studenti/učitelé, tak bývalí absolventi univerzity.

1.1.1 Aleph Od roku 2002 využívá MU jako svůj jednotný systém pro správu knih Aleph. Před nasazením byl využíván systém TINLIB, usňadňující knihovnám au- tomatizaci a nástup informačních technologií do knihoven. Systém Aleph vyvíjí izraelská firma ExLibris a v současné době patří mezi přední kni- hovnické systémy na světě [2]. Krom MU se na zavedení a zakoupení systému podílely i univerzity VUT a VŠE. Základními rysy Alephu jsou škálovatelnost, flexibita, systém lze sestavit na míru konkrétním požadavkům, teoreticky neomezená velikost databáze, spolehlivost, jednoduchost a otevřenost, za- ložená na výměně informací skrze XML. Na MU se začal využívat také díky tomu, že jej v současné době využívají knihovny několika partnerů MU, mimo jiné např. Moravská zemská knihovna v Brně a již v roce 2002 existovala česká lokalizace.

Parametry Alephu Aleph využívá třívrstvou architekturu. Tou je myšleno rozdělení na vrstvu ap- likační, prezentační a databázovou. Databázová vrstva využívá pro ukládání dat databázový systém Oracle. Aplikační logika je určena primárně pro linux- ové distribuce. Prezentační logika využívá 2 způsobů přístupu. Kromě Win- dows klienta pro správu aplikace se běžný uživatel/čtenář dostane s Alephem do styku především za pomoci webového prohlížeče. Webová aplikace, pro MU je umístěna na webu http://aleph.muni.cz, nabízí uživateli vyhledávání v rejstřících všech knihoven a detaily o knihách samotných. Aleph na MU umožňuje vyhledávát závěrečné práce. Přihlášeným uživatelům, rozumíme-li tím osoby s identifikačním číslem na MU, nabízí přehled výpůjček.

3 1. Popis systému

Pokud budeme mluvit o detailech knih, omezuje se Aleph pouze na výpis údajů s knihou přímo souvisejících. Nalezneme zde ISBN, autory, rok vydání, popis. Mimo toho můžeme sledovat konkrétní fyzické kopie knihy. A to jejich umístění v jednotlivých knihovnách univerzity, dostupnost i způsob výpujčky. Protože Aleph nenabízí žádnou interakci vůči uživatelům, doplňuje ho nádstavba využívaná pouze na MU, jménem Beth. Tento alternativní katalog je využíván u knihoven na fakultách FF, FSS, PedF a ESF. Umožňuje přidávat k dokumentům texty, tagy, recenze, případně knihy hodnotit, pořádat aukce aj.

Nedostatky Alephu

Pokud vezmeme v potaz existenci alternativního katalogu Beth, máme zde pokus o socializaci a větší interaktivnost Alephu. Online aktivity, jakými jsou výměna názorů a vlastních poznatků jsou dnes trendem nahrazujícím předávání informací, v tomto případě o knihách, ústně. Krom zaměření na konkrétní fakulty však opomíjí další důležitý aspekt dnešní digitální doby a to přenosná mobilní zařízení. Webová prezentace omezuje uživatele pouze na monitor jeho počítače. Webové stránky Alephu, potažmo Bethu, nejsou v tuto chvíli připraveny na nástup mobilních zařízení s malým displejem a ovládají se primárně dotekem po obrazovce. Uživatel s takovým zařízením navíc často přistupuje k internetu skrze datový tarif mobilního operátora, je tedy krom pohodlnosti dané šířkou obrazovky omezen i rychlostí připojení a potřebou o co nejmenší množství přenesených dat. Pokud se pokusíme praco- vat jako čtenář s Alephem v chytrém telefonu, pravděpodobně neshledáme způsob ovládání jako příjemný a raději se posadíme za počítač. Při každém požadavku navíc dostaneme opět a znovu kompletní webovou stránku. Z pohledu mobilnosti si můžeme vymyslet spousty dalších důvodů, proč není pouze webová prezentace zcela vyhovující.

1.1.2 SmartLib

S řešením daného stavu se na MU pokusil přijít projekt SmartLib. Základní myšlenka vzešla z možnosti navigovat pomoci mobilní aplikace čtenáře po knihovně přímo k regálu s knihou. K tomuto nápadu se přidala další dodatečná funkcionalita, která se mírně překrývá s funkcionalitou Bethu a měla přidat socializační vrstvu k Alephu. Prototyp mobilní aplikace pro operační systém Android zpracoval jako svou diplomovou práci v roce 2011 Mgr. Jonáš Ševčík[5] a v roce 2012 ji začal rozšiřovat v rámci doktorského studia. Na jeho práci navázali studenti Michal Halaj[7] s mobilní aplikací pro Windows

4 1. Popis systému phone a Hoa Quoc Tran s rozšířením klienta pro Android [6]. Na backendové aplikaci pracoval Mgr. Marek Jelen, během projektu v předmětu vyučovaném na MU PV226, z kterého je tato diplomová práce. Výstupem práce všech těchto lidí se stala externí nádstavba Alephu pro mobilní zařízení, poskytující čtenářům nejen chybějící funkčnost, nastíněnou v předchozí kapitole 1.1.1, ale i další funkcionalitu. Nasazení mobilních aplikací v MU začalo v průběhu prosince roku 2012 a jejich vývoj stále pokračuje.

Mobilní aplikace

Současný stav k březnu 2012 je aplikace pro zařízení s operačním systémem Android a Windows Phone, přičemž se pracuje na verzi pro produkty od firmy Apple. Jak bude v práci nastíněno dále, aplikace využívají pro načítání dat pouze backendovou část popisovanou v této diplomové práci, která není součástí Alephu, pouze od něj odebírá některá data. Z toho vyplývá např. nutnost registrace uživatelů v případě hodnocení knih. Základními možnostmi jsou vyhledávání titulů nejen podle jejich jména či jména autorů ale také vyhledávání podle čárového kódu titulu, charakterizujícím unikátní kód ISBN. Čárový kód se načítá přímo přes fotoaparát mobilního zařízení. Detail knihy nabízí kromě obecných informací o knize dostupných z databáze Alephu i některá další vylepšení. Může to být obálka knihy, PDF náhled, či dokonce celé knihy pomocí služby Google Books a aktuální dostupnost fyzických jednotek v konkrétních knihovnách. Aplikace umožňuje knížky hodnotit nebo si je ukládat do oblíbených položek. Budoucnost aplikací směřuje k zpřesnění místa, kde se nachází konkrétní jednotka titulu, která by tak umožnila navést uživatele přímo k regálu s knihou.

1.1.3 Vlastní aplikace

Specifikem této diplomové práce je fakt, že serverová část byla vyvíjenav předmětu pojednávajícím o jazyce Ruby a přerodila se v diplomovou práci v průběhu práce na ní. Implementace některých částí se tak již několikrát během svého vývoje měnila v závislosti na tom, jakými prioritami byla právě zatížena a kde se uvažovalo o reálném nasazení. Z důvodu nemožnosti zasahovat do zdrojových kódu Alephu navíc stojí zcela vně tohoto systému, což sebou nese výhody i nepříjemnosti. Mezi výhody patří budoucí nezávislost na typu kni- hovnického systému, který bude SmartLibu dodávat data o knihách (potažmo uživatelích) a umožňuje vybírat jen taková data, která jsou pro aplikaci právě potřebná. Nevýhodou je fakt, že data jsou v takovém případě duplikována a to vede k nutnosti druhotné registrace uživatele univerzity, navyklého využívat

5 1. Popis systému pro přístup do většiny systému MU své Univerzální číslo osoby, dále UČO, a primární/sekundární heslo. Navíc chybí přímé spojení do databáze Alephu, který neposkytuje ani základní API , kterým by bylo možné dotazovat se např. na výpujčky uživatele, či aktuální dostupnost knihy. Z pohledu způsobu vývoje to však nabízí potenciální otevřenost SmartLibu a jeho využitelnost i na jiných knihovnických systémech/univerzitách. Specifikem samo o sobě je i vývoj ostré aplikace v akademickém prostředí a pro uživatele univerzity. Pokud tvůrce práce ukončí závěrečnou práci obhajobou, často již nemá důvod se dále věnovat jejímu vývoji, ladění a hrozí tak zamrznutí projektu. Ve firem- ním prostředí se kontinuita zajišťuje mnohem jednodušeji a vývojáři mají více motivací pro další práci na projektu (mimojiné je to finanční ohodnocení) než je získání titulu a ukončení studia. Vývoj cílený na lidi pohybující se na univerzitě má také svá specifika, kterým je na MU dříve zmiňováná velká provázanost osobního čísla studenta a tím, jak skrze něj vnímá přístup ke službám školy.

6 2 SmartLib

V následující kapitole se budeme zabývat přímo systémem SmartLib. Snahou této diplomové práce není popisovat funkcionalitu celého systému, do něhož z pohledu uživatelů, kteří s ním primárně přicházejí do styku, mohou patřit pouze mobilní klienti. V tomto směru se práce pouze pokusí nastínit vzájemné vztahy a způsoby komunikace, včetně jejich vývoje v čase jako bakalářských prací vypsaných pro studenty Fakulty informatiky, dále FI. Hlavním zájmem bude ukázat technologie využité pro práci na backendové části a to opět včetně vývoje, kterým si prošla nejen přerodem semestrálního projektu k této diplomové práci, ale i specifickým požadavkům, pramenícím k závazkům všech vývojářů, kteří do projektu zasáhli. Bude-li se v dalších částech práce mluvit o SmartLibu, chápejme jej jako backendovou službu, poskytující data koncovým zařízením.

2.1 Implementace

Jazyk, v němž je SmartLib implementován byl vybrán již Mgr. Markem Jelenem, který [4] jako první pracoval na prototypu jednoduché aplikace, který by poskytovala data mobilním klientům. A právě v jeho předmětu Vývoj aplikací v jazyce Ruby, vyučovaným na FI byl projekt předán studentům k realizovaní jako semestrálního projektu a získání zápočtu. Použité technologie tedy můžeme popsat následovně:

∙ Ruby 1.9.x

∙ XHTML + CSS, JavaScript, jQuery

∙ SQLite/MySQL/MongoDB/ElasticSearch

2.1.1 Ruby

Ruby je zcela objektově orientovaný skriptovací jazyk, napsaný v jazyce C [8], který se majoritně využivá na UNIXových strojích pro vývoj backendových, či webových aplikací skrze frameworkové systémy. Jeho výhodou je fakt, že vše v tomto jazyce je objektem, je relativně jednoduchý na základní naučení, ačkoliv má komunitou velice přísná pravidla proto jak psát a formátovat svůj kód a snaží se brát si to nejlepší od jazyka C, přes vývojáři oblíbený Python, Perl až po Haskell.

7 2. SmartLib

Sinatra vs Ruby on Rails

U jazyka Ruby je nejmasivněji využíván jeho webový framework Ruby on Rails [9], navržený pro rychlou a jednoduchou implementaci webových aplikací, využitím návrhového vzoru MVC [28]. Tento framework je však poměrně ofenzivní ve způsobu, jakým nutí vývojáře psát kód dle představ autorů frameworku. Svou masivností může být zbytečně přebobtnalý (např. má před- implementované webové administrační či logovací rozhraní) a tím nevyhovuje aplikacím jak menším, tak tolik nekomunikujícím s uživatelem skrze webové rozhraní. Pro potřeby relativně malých backendových aplikací, API rozhraní, či zkušenějšími uživateli, majícími v oblibě vlastní řešení aplikační/prezen- tační logiky, je v současnosti oblíbeným frameworkem Sinatra [10][36]. Ten vývojáři, který se pro něj rozhodne, nenabízí takový komfort a přenechává většinu práce na něm. Odvděčí se mu ale menšími nároky na paměť, přehled- ností kódu a volností v tom, jak aplikaci strukturovat. Pokud budeme považo- vat SmartLib za API, zjistíme, že se Sinatrou máme nepřeberné možnosti jak svou aplikaci postavit, jakou používat stukturu složek, jak se připo- jit k databázi a zda-li vůbec využívat Controleru v MVC návrhu. Sinatra ponechává všechny tyto otázky, v Ruby on Rails dopředu daných, na vývojáři samotném. Klade to mnohem vyšší nároky na vývojářovu zručnost, zkušenosti a vyplatí se mít již dopředu dobře rozmyšlené, co budeme od budoucího systému požadovat a na jaké otázky se plánujeme tázat. Vezmeme-li v úvahu čistou, nerozšířenou instalaci Sinatra frameworku, máme k dispozici nástroj, který po spuštění pracuje jako server, naslouchající na námi defivonaném portu. Umí za nás vyřizovat HTTP požadavky a vracet odpovědi, využívající při tom metodiku (get, post, put, delete) a routovat je do námi zvolené třídy. Obsahuje podporu základního prezentačních jazyků využívanými v Sinatře. Nabízí automatickou podporu relací, cookies, logování, statických složek pro obrázky/CSS/javascripty, podporu chybových reportů a adekvátních odpovědí na ně (404/400/200 atd.) a podporu verzování. Poně- vadž je Sinatra sama napsána v Ruby, umožňuje automatizované testování aplikace. Pokud bychom měli shrnout důvody využití Sinatry navzdory Ruby on Rails, je to především potřeba malé, ale rychlé aplikace, která bude primárně vyřizovat požadavky a vracet pouze jednoduché odpovědi. Mezi další možná oblíbená řešení patří v současné době framework [11], snažící se zachovávat minimalismus Sinatry a zároveň nabízet předim- plementovanou základní obsluhu webové aplikace.

8 2. SmartLib

Rozšíření Sinatry: Git. Bundler a Gemy

Specifikem jak Sinatry, tak Ruby on Rails, je přítomnost zakomponovaného webového rozhraní a jednotný způsob rozšiřitelnosti základní instalace o volitelné doplňky skrze gemy [29]. Ruby využívá pro správu zdrojového kódu především verzovací systém Git. Největší světový opensource server s repozitáři GitHub je napsán v Ruby on Rails [12]. Nutností vývojaře, který se chce v Ruby naučit programovat je tak i nutná znalost Gitu. Pokud si přejeme využívat Sinatru, našim dalším krokem, pokud jako první budeme považovat nainstalovaný Git, je pochopit způsob instalace doplňků do programů v Ruby napsaných. Jednotlivým doplňkům se říka gemy a i Sinatra jedním takovým gemem je. Gemy se shraňují ve složce nazvané gemfile a pro správu jejich instalací je ve Smartlibu využíván systém Bundler [13]. Ten se nám aumaticky stará o instalaci gemů a správu závislostí každého jednotlivého gemu, případně pomahá s řešením konfliktů a s automatickým stahováním nových verzí. Pokud si přejeme spustit jednoduchou webovou prezentaci v Sinatře, po její instalaci bundlerem mám dopředu nainstalovaný i velice jednoduchý webový server Rack [14] a můžeme spustit jednoduchý webserver, naslouchající na námi zvoleném portu. Smartlibu rozlišuje webový server, který je využíván pro vývoj a v produkci. sám o sobě není tak rychlý aby bylo výhodné využít ho v produkci.

2.1.2 OpenShift

Pro potřebu využívání Smartlibu uživateli se řešilo i místo, na kterém bude Smartlib produkčně v provozu. Díky dobrým vztahům FI s firmou RedHat, která má pobočku v Brně, bylo jako umístění vybráno jejich vznikající cloudové uložitě OpenShift. Důležitými faktory byla podpora jazyka Ruby, možnost instalovat produkt na serveru za pomocí gitu včetně jeho verzování a rake instalátoru [17]. Po nahrání aplikace na server tento nástroj umožňuje nainstalovat námi definované návaznosti, jako vytvoření a prvotní naplnění databáze, spuštění testů aj. a možná správa pomocí bundleru, ssh přístup i velká škála databází k hostingu. V době prvního nasazení byl OpenShift v betaverzi a nasazení ve verzi zdarma se neobešlo zcela bez problémů kvůli neúplně dokumentaci a dostupnému místu, které bylo ze začátku v dispozici v malém množství. V době psaní diplomové práci byly všechny problémy vyřešeny a aplikace běží na OpenShiftu v ostré verzi.

9 2. SmartLib

2.1.3 SQL/NoSQL

Na výběru databázove se poměrně dost podepsalo střídání vývojářů a priorit v daném okamžiku vývoje projektu. Ruby, stejně jako ostatní programovací jazyky, nabízí svým vývojářům univerzální objektově-relační modely, podobné jako známe např. u Javy JPA, stačí si vybrat databázový adaptér. Oblíbeným nástrojem v Ruby on Rails je Active Support [15]. Jak bylo řečeno v kapitole 2.1.1, Sinatra si zakládá na tom, že vývojář si sám vybere způsob, na který je zvyklý. Základní verze SmartLibu, napsaná ještě Mgr. Markem Jelenem, proto využívala databázový toolkit Sequel [16]. V průběhu vývoje se rozhodlo o využívání NoSQL konceptu MongoDB [19] podporovaným na OpenShiftu, který však bohužel nedokázal pokrýt fulltextovou potřebu po vyhledávání v miliónu záznamech o knihách. Protože je MongoDB nerelační koncept, bylo ji potřeba napsat pro tento databázový nástroj a pak opět zpět do Sequelu s využitím SQL databáze MySQL. Jako ukázky použití alternativních databázových technologií pro porovnání jejich výkonosti bylo pro vyhledávání knih využito i hledání pomocí fulltextové NoSQL databáze ElasticSearch [18] [35].

Sequel a instalace databáze

Sequel se v ničem podstatném neliší např. od známého JPA pro Javu. V dokumentaci je popsán jako jednoduchý, ale zároveň mocný databázový SQL nástroj pro Ruby. Obsahuje ORM mapování databáze, umožňuje transakční zpracování v případě podpory ze strany databázového adaptéru a podporuje většinu nejpoužívanějších databází. Dotazy se skládají voláním metod ze základního objektu DB, dodržující názvosvosloví z SQL (select, where, limit). Specifikem používaným v Sequelu ale např. i v Active Supportu je způsob, jakým je vytvářena databáze. Tento způsob souvisí s metodikou instalace pomocí instalátoru pro Ruby aplikace Rake [17], umožňujucí pustit pomoci jednoduchého příkazu právě kód pro instalaci databáze. Instalaci databáze si můžeme představit jako sled očíslovaných kroků vzestupně od 1 do x. Pokud začínáme aplikaci psát, první kroky nám budou popisovat instalaci jednotlivých databázových tabulek s konkrétními parametry a zavedení in- dexů. V průběhu vývoje můžeme zjistit, že nám chybí některé atributý tabulky, indexy či potřebujeme nějaké další přidat či změnit. Další kroky v takovém případě budou popisovat tyto změny a to nejen ve směru nahoru např. instaluj tabulku ’x’ ale stejně je důležité popisovat i kroky dolů např. odinstaluj tabulku ’x’. Výhody takovéhoto postupu jsou nejen v tom, že sami si můžeme puštěním instalace "nahoru"aktualizovat databázi, ale stejně to

10 2. SmartLib samé může využít kterýkoliv vývojář po nás, včetně kolegů pracujících na stejném projektu pomoci jednoho repozitáře. Kolega si stáhne aktuální verzi repozitáře a puštěním příkazu pro instalaci spustí chybějící krok pro instalaci tabulky "x".

MongoDB

MongoDB, respektive adaptér Mongoid [20] pro Ruby, je mezistupněm mezi konceptem NoSQL databází a databází relační. Ačkoliv schraňuje svá data v JSON dokumentech, přičemž každý záznam je definován unikátním hashovaným řetězcem (id), zachovává si spoustu z vlastností, známých spíše z SQL databází. Mezi ně patří především možnost tvořit relace velmi podobné těm z SQL databází. Blíže NoSQL databázím jsou "embedded"relace [21]. Oba modely, mezi nimiž si přejeme navázat relaci, např. kniha a její autoři, sice programově definujeme každý ve své vlastní třídě, ale podřízený dokument, v našem případě autoři knihy, je fyzicky uložen v dokumentu společně s knihou. Co může člověku, zvyklému na SQL databáze, činit potíže, je zřejmá renundance dat. Pro každou kopii knihy bychom si tak ukládali seznam autorů a neřešili fakt, že by se v databázi nacházeli vícekrát u vícero knih. Naopak blíže SQL databázím je ukládání pomocí relace "referencing"[22]. V totožném příkladě, tedy knížka a její autoři, bychom podobně, jak jsme zvyklí u relačního schématu, navázali autory knihy pomocí cizího klíče, což je unikátní hash. Fyzicky by se každá kniha odkazovala na konkrétní dokumenty s autory. Ti by byli v naší databázi unikátní. Na celou problematiku se dá dívat i opačnou optikou. Výhodou a zároveň nevýhodou NoSQL je relativní svoboda v tom, jak budeme na celou databázi nahlížet ne tím, co nám káže denormalizace v relačních schématech, ale jak budeme v budoucnu potřebovat k našim datům přistupovat a jakými operacemi tak budeme činit nejčastěji. Špatně by tedy ani nebylo, pokud bychom jako nadřazený prvek ve dvojici kniha-autor zvolili autory knih a knihy by k nim byly v podřízené relaci. Embedded relace nejsou pro MongoDB drahou operací [23], v zásadě jsou vhodné ve chvíli, kdy nepotřebujeme vyhledávat pouze v podřízeném dokumentu, nebo jsou při vyhledávání vždy potřebná i data rodiče. To znamená, že údaje jsou při prezentaci potřeba ve většině případů pohromadě a především, že v zásadě nepotřebujeme číst data samostatně z podřízené tabulky. Odměnou je lepší výkonost při vyhledávání a odpadá nám nutnost "spojování"dokumentů, podobné INNER JOIN v relačních databázích, které je náročnější operací. Oba dokumenty vnímáme atomičně a pro jejich získání potřebuje MongoDB databáze jednu cestu do databáze. Referencing relace se

11 2. SmartLib nám naopak vyplatí pokud plánujeme vyhledávat stejně tak v rodičovském dokumentu jako v jeho potomku. Případně pokud data nejsou vždy potřeba jako nedělitelný celek či pokud nám je na překážku renundance dat a tím i rychleji narůstající místo v databázi a výhoda rychlosti čtení embedded dokumentu pro nás tuto nevýhodu nevyváží. Pomocí referencing relací také můžeme modelovat komplikovanější vazby mezi vícero dokumenty. Jako výhodu získáme jednodušší dotazování, databáze ale bude muset častěji přistupovat k databázovému serveru.

ElasticSearch

Dle zadání diplomové práce je v projektu využita i databáze ElasticSearch [18]. ElasticSearch je opensource distribuovaná REST databáze, se speci- fickým zaměřením na real-time a fulltextové vyhledávání. K databázi sedá přistupovat skrze HTTP protokol ať už pomocí JSON dokumentu a využití požadavku (get, post, delete, put), tak vyhledávání pomocí get požadavku v podobě parametrů v URL. To znamená úplnou nezávislost na programovacím jazyce, v kterém poběží naše aplikace, protože formát jakékoliv žádosti na databázi bude neměnný. Protože odpovědí databáze je JSON [24], jsme ste- jně nezávislí i při čtení výstupu. Databáze může díky tomu fungovat zcela nezávisle jako webová služba, přístupná na specifickém portu. Silných stránek je hned několik. V první řadě je to koncept NoSQL databáze totožný s databází MongoDB. Data jsou fyzicky ukládána do JSON dokumentů a není žádným problémem změnit si/přidat položky pro naše schéma. Podobně jako u MongoDB obsahuje ElasticSearch relace ve tvaru parent - child a na žádném místě nevyužívá XML. ElasticSearch nabízí vývojáři rozhodovací možnosti jaké výsledky upřed- nostnit při vyhledávání. Máme možnost mapovat si náš JSON dokument, v kterém budeme následně vyhledávat. Podobně jako u MongoDB je tak více než příhodné dobře dopředu si rozmyslet, k čemu budeme databázi potřebo- vat a jaká konkrétní data a jakých polích se budeme konkrétně dotazovat. Můžeme však také mapování ignorovat a jednoduše nechat podobu doku- mentů až na datech samotných. Pokud se uchýlíme k vlastnímu mapování, máme nespočet možností jak si upravit priority vyhledávacího algoritmu. Z těch nejzajímavějších je to analýza textu, pro každou konkrétní položku dokumentu, např. název knihy, popis knihy. ElasticSearch nám nabízí analýzu pro většinu základních světových jazyků včetně češtiny. Tato funkcionalita při vložení nového záznamu zaindexuje dané pole v pozměněné formě tak, aby při vyhledávání dokázal účiněji filtrovat rozdíl mezi tím co vyhledáváme a co máme uložené v databázi. Svou roli tu samozřejmě hraje diakritika

12 2. SmartLib typická pro český jazyk, ale i délky slov. K tomu nám nabízí využití filtrů jako whitespace, lowercase, které automaticky upravují text do požadované podoby. Příkladem je text bez bílých míst, verzálky. Další silnou zbraní je možnost zadefinovat důležitost pole pro vyhledávání, tzv. boost [25]. Zna- mená to, že pokud budeme vyhledávat slovo jak v autorovi knihy, tak v názvu knihy, můžeme jako vývojáři přidat algoritmu vyhledávání vlastní váhu. ElasticSearch kombinuje tyto možnosti dohromady, umožňuje definovat rozsahy upřednosňovaných výsledků. Pro ukázku např. knihy, které mají jazyk "cze"nebo byly do knihovny přidány v určitém časovém rozmezí. Dává tím vývojaři větší moc nad tím co uživatel vyhledá. Nové/upravené záznamy se v dokumentu automaticky indexují, pokud při mapovaní nenadefinujeme něk- teré části ignorovat. Pro složitější databáze si můžeme definovat multi-indexy nad jedním dokumentem. Neopomíjitelnou zbraní databáze je její distributovatelnost. Indexy jsou rozbity do tzv. shards a v případě našeho přání mohou být replikovány. Databáze se stará o rovnoměrné rozmístění dat v jednotlivých shardech. Pokud by velikost naší databáze rostla, můžeme do existujících prvků přidá- vat další. Samozřejmostí je možnost transakčního zpracování. ElasticSearch používá Apache 2 licenci.

2.1.4 Služby třetí strany MailGun Pro zasílání emailů uživatelům SmartLibu je využíván projekt MailGun. Důvodem využívání byly problémy se zasíláním emailů pomocí OpenShiftu. Mezi výhody MailGunu patří přehledné logování zaslaných emailů po přih- lášení na stránkách projektu. Komunikace probíhá pomocí API. Ve SmartLibu je pro zasílání emailů využíván gem napsaný přímo pro zasílání emailů přes různá API. Jmenovitě jde o Faraday [28].

Veřejný repozitář Pro správu repozitáře projektu je využíván Git. Největším světovým serverem pro správu repozitářů u opensource projektů je GitHub (http://github.com) [26]. V prvotní fázi vývoje však existoval požadavek na privátní repozitář, proto byl pro správu projektu vybrán server BitBucket (http://bitbucket. org), nabízející i privátní repozitáře. V současné době je již projekt veřejný, pro přispívání do kódu je třeba svolení vlastníka repozitáře, klonování repoz- itáře je dostupné veřejnosti. Přímo na stránce projektu je možné sledovat jednotlivé commity. BitBucket je také využíván jako issue tracker projektu.

13 2. SmartLib

Příspěvky do trackeru jsou veřejné, nové požadavky, či chyby, se přidávají pomocí API, využívající privátní klíč. Konkrétní privátní klíče nejsou součásti repozitáře a jsou uloženy pouze v živé kopii na OpenShiftu v perzistentní složce. Druhá kopie repozitáře je uložena na OpenShiftu. Aplikace hostované na OpenShiftu jsou budovány pomocí gitu, nebo jenkinsu. Kód je po nahrání commitu na server aktualizován v historii repozitáře a zpracován sadou tzv. "hooks"[27]. Ty aktualizují složky s kódem na serveru a restartují jak server, tak služby na něm běžící včetně doplňků jakými jsou např. databáze, či cron. V praxi to znamená, že při commitu/restartu služby jsou ztraceny všechny soubory ve složce aplikace na serveru. Pro konfiguraci projektu (připojení k databázi, privátní klíče k BitBucketu, či MailGunu) je využívaná persistentní složka, kterou má každý projekt na OpenShiftu k dispozici. Privátní repozitář je umístěn na adrese https://bitbucket.org/thrabal/ smartlib

Externí služby pro detaily knih

Pro kompletní obsluhu při vyhledávání knih jsou využívány 3 externí zdroje. Mezi první patří služba Google Books využívána dohromady s českou službou Obálky knih. Služby jsou využívány pro získání URL na obálku knihy. Vyhledávání je v obou službách dostupné skrze ISBN knihy. Některé knihy obsahují navíc v Google Books náhled několika stran či rovnou celou knihu, ve formátu PDF. Při vyhledávání určité knihy přes mobilní aplikaci je u všech výsledků, jež doposud nemají odkaz na svůj náhled nebo obálku, podán dotaz nejprve na službu Google Books a v případě neúspěchu pak na Obálky knih. Google Books je první v pořadí z toho důvodu, že může krom obálky obsahovat i výše zmíněný PDF náhled. V případě neúspěchu při hledání obálky je namísto URL na obrázek uložen prázdný text, hledání se tak neopakuje při příštím vyhledání. Jako druhou externí službou je možné vnímat samotný Aleph. Vstupy do SmartLibu k němu proudí ze dvou směrů. Prvním je seznam knih, který si SmartLib ukládá do vlastní databáze. Způsob jakým záloha databáze probíhá bude detailněji popsán v kapitole 3.1.1. Ve zkratce byl pracovníky Knihovnick- ého centra MU zpřístupněn textový výstup se seznamem knih a následně i každodenní porovnávaný soubor, který obsahuje změněné položky knihoven. Ten je v pravidelném intervalu stahován a aktualizuje databázi SmartLibu. Směrem druhým je kontrola dostupnosti svazků v jednotlivých knihovnách. Jak již bylo řečeno v kapitole o Alephu 1.1.3, systém neposkytuje žádné API. Získání on-line dostupnosti je třeba obcházet. Pro kontrolu dostupnosti svazků jsou využívány samotné stránky Alephu pro uživatele. SmartLib podá

14 2. SmartLib regulérní POST požadavek na adresu, jež využívá i vyhledávácí formulář Ale- phu. Vrácená HTML stránka je rozparsována dle předpřipravených cest, jsou z ní vytažena potřebná data o dostupnosti konkrétního svazku pro konkrétní knihovnu dle unikátního čísla každého svazku a uložena do databáze. Do budoucna je pracovníky Knihovnického centra příslíbené jednoduché API.

15 3 Návrh systému

Návrh jednotlivých komponent systému se zcela neřídil doporučenými pos- tupy. Ovlivněn byl hned několika faktory. Prvním byla raná implementace základního API pro mobilní aplikace jako bakalářských prací. Požadavky se tak sbíraly spíše ze strany studentů píšících tyto práce. Druhým byly rozdílné požadavky na databázi a tím i slepá vývojová větev v případě MongoDB, jež však byla požadavkem splněním projektu při vývoji v předmětu o Ruby. Dalším zádrhelem byl prvotní vlažný přístup Knihovnického centra MUNI k projektu a na to navazující problémy s implementací parseru knih. V poslední řadě to byly problémy s nasazením a efektivitou na OpenShiftu. Ty projektu pomohl řešit Mgr. Marek Jelen, pracující jako OpenShift evangelista pro firmu RedHat.

3.1 Případy užití

V této kapitole budou popsány případy užití v jejich závěrečné fázi a nastíněn budoucí vývoj spolupráce.

3.1.1 Parser knih z Alephu Jak bylo řečeno v kapilote o Alephu na straně 6, knihovnický systém neob- sahuje API pro komunikaci s ním samotným, ani žádnou možnost jak rozumně exportovat data uložená v jeho databázi. Stejně tak není možné zasahovat do zdrojového kódu Alephu a nepřichází v úvahu možnost samostatného dotazování se databáze na konkrétní knihy. Z toho důvodu vznikla vlastní databáze SmartLibu, kopírující data podstatná pro mobilní klienty a přináše- jící navíc údaje potřebné pro komunikaci s uživateli. To na systém klade požadavek rozumným způsobem zálohovat databázi a následně ji přeparsovat do databáze SmartLibu. Záloha je poskytován Alephem a každý den jsou periodicky vytvářeny seznamy všech knih konkrétních knihoven a seznam změněných záznamů pro každou knihovnu MU. Na níže zobrazeném diagramu případu užití jsou zobrazeny základní aktivity parseru. Na diagramu vidíme 3 aktéry. Aktérem Aleph je myšlen robot implemen- tovaný Knihovnickým centrem, který periodicky vytváří soubory se zálohami databáze. Na straně SmartLibu to je Web User a SmartLib. Uživatel Web user se využíval především v začátcích projektu, kdy bylo možné stahovat soubory se zálohami pouze z IP rozsahu MU. Ve webové administraci pro knihovníky je možné nahrát na server soubory s dumpy a pustit jejich parsování. V ak- tuální verzi se již tato funkčnost nevyužívá, protože databáze je již naplněna

16 3. Návrh systému

Obrázek 3.1: Diagram případu užití - Parser

17 3. Návrh systému a je pouze potřeba stahovat periodicky porovnávané zálohy. O to se stará aktér Smartlib. Tímto aktérem může býž myšlen jak uživatel, zalogovaný přes SSH na serveru a pouštící příkazy pro pouštění parseru, tak cron, který jednou za den stahuje porovnané zálohy a pouští nad nimi parser. Mezi ak- tivitami jsou přítomny 3, které odpovídají možným parametrům při pouštění parseru. Aktivita p7 provádí kompletní úpravu záznamů. Kontroluje název knihy, autory a ostatní parametry. Bez této aktivity skript pouze kontroluje přítomnost knihy a v případě, že kniha již existuje, upravuje parametr o dostupnosti knihy. Aktivita p8 značí přímé stahování souborů z Aleph serveru. Bez tohoto parametru by byl parsován soubor uložený v persistentním uložišti na serveru.

3.1.2 Mobilní API

Vývoj API pro mobilní klienty se řídil především požadavky ze strany vývojářů mobilních klientů. Od začátku vývoje sám prošel několika vývojovými cykly a mnoho funkcionality se muselo nahradit či zcela opravit. Nejvýraznějším pří- padem byla registrace uživatelů, na diagramu jde o aktivitu m12_serve_user. Protože aplikace běží na OpenShiftu na předpřipraveném prostředí, bylo zavrhnuta možnost přihlašování studentů skrze jejich UČO a sekundární heslo. Důvodem byla nemožnost nainstalovat na prostředí OpenShiftu odpovídající knihovny, umožňující připojení do databáze Informačního systému univerzity, dále IS, a stejně tak není doposud možné dotazovat se přes jakékoliv API Aleph. V první verzi byla registrace uživatelů do systému skrze jejich mo- bilního klienta zadáním jejich UČO. SmartLib zaslal na univerzitní email přihlašovací údaje a uživatel získal možnost hodnotit knihy a psát na ně recenze. Tento způsob nebyl optimální a tak v druhé verzi mohli uživatelé hodnotit knihy známkami i bez přihlášení, nutnost přihlásit se do systému zůstala pouze pro psaní recenzí na knihy. Podobně se měnily požadavky na informace požadované na výstupu. Na diagramu můžeme vidět dva aktéry. Prvním je aktér "Smartlib". Jeho aktivity znázorňující schopnost systému stahování dodatečných informací o knihách, tak jak bylo popisováno v kapitole 2.1.4. Z diagramu vyplývá, že jsou využívány při aktivitě m2_get_book, znázorňující sestavení údajů o detailu knihy. Aktivita m7 vyjadřuje zasílání chybových reportů na web BitBucketu, popsaných v kapitole 2.1.4. Aktivita je sdílená druhým aktérem v diagramu: "Mobile device". Aktéry jsou myšleny všichni mobilní klienti, využívající k přístupu k datům API. Většina aktivit tohoto uživatele souvisí s potřebami těchto klientů. Vyhledávání knih, fyzických kopií knížek a zasílání hodnocení. Většina aktivit využívá pro svou práci aktivitu m2_get_book.

18 3. Návrh systému

Obrázek 3.2: Diagram případu užití - Mobilní API

19 3. Návrh systému

Můžeme říct, že i požadavek na vyhledání konkrétní kopie ověřuje jako první existenci knihy obecně v databázi, stejně jako při přidávání hodnocení. Požadavků na detail knihy je v systému implementováno několik, záleží na tom, na jakém místě mobilní aplikace si přejí zobrazit data. Aktivita m8_get_book_detail zašťiťuje všechny její konkrétní implementace, podobně jako aktivita m12_serve_user. Pod ní si je možné představit obsluhu správy uživatele od registrace, práce s heslem do systému, po přihlášení a odhlášení z aplikace.

3.1.3 Webové rozhraní Webové rozhraní není dostupné pro uživatele SmartLibu, ale pouze pro knihovníky a administrátory systému. Primárním učením je agenda správce systému a to v první fázi odstraňování případných nevhodných recenzí, oprava údajů o knihách a především možnost nahrát do SmartLibu mapové podklady a umisťovat do polic konkrétní knihy. Dvěma základními aktéry tu jsou Admin, který může uživatelům přiřazovat administrátorská práva a pak samotný User, s možnostmi na úpravu knih. V diagramu se objevují 3 aktivity s prefixem p, jde o aktivity využitelné pro parsování záloh databáze Alephu, popsané v kapitole 3.1.1

3.2 Diagram aktivit

V této sekci ukáže práce některé aktivity z pohledu fungování systému v době psaní práce a pro ukázku pak nabídne i srovnání rozdílu chování aktivit z implementace v raném vývoji, kde byly požadavky definováný především autory bakalářských prací. Ostatní aktivitní diagramy jsou k shlédnutí v příloze.

3.2.1 Parsování záloh databáze Alephu První zobrazená aktivita představuje parsování záloh databáze Alephu. Ak- tivita v tomto směru neřeší typ databáze, do níž jsou údaje ukládány, zajímá se pouze o typ parsování. Některé z obecnějších aktivit si zaslouží další popis. Již na začátku je rozhodovací větev, naznačující zda-li vůbec pokračovat ve zpracování aktivity. Důvodem je fakt, že na OpenShiftu se pro pravidelné spouštění skriptu dá nastavit pouze určitý interval (minuta/hodina/měsíc). Pokud si tedy přejeme pustit zálohu v konkrétní dobu, dopředu musíme přímo v kódu kontrolovat hodinu spuštění. Při spouštění jednou za hodinu to znamená 23 falešných pokusů. Výjimkou je přímé spuštění přes SSH nebo

20 3. Návrh systému

Obrázek 3.3: Diagram případu užití - Webové rozhraní

21 3. Návrh systému webové rozhraní. Zajímavou aktivitou je například Set Libraries. Protože záloha databáze Alephu není dodáván v celku jako jediný soubor, ale Aleph ho SmartLib poskytuje jako soubor pro každou knihovnu, je dopředu důležíté vědět, jaké knihovny si přejeme parsovat, popřípadě stáhnout. Jejich seznam se uchovává v databázi, ale pokud bychom aktivitu rozkreslili, za předpok- ladu naší znalosti její zkratky by zobrazovala možnost zadat pro zpracování konkrétní knihovnu. Další rozkreslitelnou aktivitou je Download dump. Tato aktivita pro svou práci potřebuje znát typ zálohy. Jde-li o porovnávanou verzi souboru nebo klasickou, tak i knihovnu. K připojení k Alephu a stáhnutí používá několik pokusů. Nejrozsáhlejší aktivitou je Parse book and force update. Parsování knih jedné po druhé je samo o sobě náročnějším procesem, při němž se prochází a cachují jednotlivé řádky zálohy a pro databázi se dále upravují. Skript se snaží najít již existující autory v databázi pro ukládání data do MongoDB, či MySQL, stejně jako ověřit existenci knihy, vydavatelství a dalších jejích atributů. Při tomto typu parsování jsou upravovány i atributy jako název knihy a přeukládány jednotlivé fyzické kopie knihy.

3.2.2 Hledání knihy Tato aktivita se týká vyhledávání knihy koncovými mobilními klienty. V první části se zpracovává výsledný dotaz pro hledání knihy. Rozhodují kombinace v kterých konkrétních oblastech budeme vyhledávat. V prvotní fázi projektu se vyhledávalo pouze pomocí jména knihy a dodatečně dle jména autorů, pro doplnění výsledků. Aktuální verze klientů už nabízejí svým uživatelům vybrat si konkrétní možnosti, či jejich kombinace, včetně vyhledání knihy jen v těch případech, kdy jsou její svazky uloženy v konkrétní knihovně. Druhá část diagramu, v případě nalezení knih, vypisuje aktivity pro nalezení náhledu a obálky knihy, jak bylo popisována v kapitole 3.1.2.

3.2.3 Hodnocení knihy Aktivita je rozdělena na dvě poloviny. V levé půlce je ukázáno hodnocení knihy v původním systému. Krom ověření existence knihy se ověřovalo i zalogování uživatele do aplikace.

3.3 Sekvenční diagramy

3.3.1 Aktivita m14_check_availability Sekvenční diagram zobrazuje aktivitu m14_check_availability z diagramu případu užití na obrázku 3.2. Jde o aktivitu spouštěnou mobilním klientem,

22 3. Návrh systému

Obrázek 3.4: Diagram aktivity - Parsování knihy

Obrázek 3.5: Diagram aktivity - Hledání knihy

23 3. Návrh systému

Obrázek 3.6: Diagram aktivity - Hodnocení knihy

související s potřebou získávat aktuální data o dostupnosti svazků v konkrét- ních knihovnách. V sekvečním diagramu figuruje krom třídy Api, starající seo vracení požadavků klientům, i externí třída Alephu. V sekvenčním diagramu je Alephu předsunuto unikátní číslo knihy sysno a vrácena je HTML stránka s kopiemi dané knihy. V nich metoda find_copies hledá informace o dostup- nosti, které vrací mobilnímu klientovi a mimo jiné je ukládá do databáze. Tyto informace hypoteticky vrací databáze klientovi v alternativním scé- naří rovnou bez požadavku na Aleph pokud jsou v databázi uloženy a nový požadavek na zjištění dostupnosti byl podán do určitého časového intervalu. Diagram nepředpokládá, že by informace v Alephu nenalezl, protože klient se ptá dostupnosti již na konkrétní knihu a konkrétní fyzické kopie z databáze. V praxi jsou samozřejmě ošetřeny i výjimky, kdy data od Alephu neobdržíme. Druhou alternativní linií je vrácení prázdného seznamu v případě, kdy třída nenalezne kopie knih nebo samotnou knihu v databázi.

3.3.2 Aktivita P7_parse_book

Sekvenční diagram zobrazuje aktivitu p7_parse_book z diagramu užití 3.1. Aktivitu spouští skript shoot_parser, volající třídu Parser samotnou. Z diagramu můžeme vyčíst, že pro každý řádek voláme metodu my_parser, zpracovávající údaje ze zálohy. Třída Parser komunikuje s databázovou třídou, ta je v reálném systému realizována pomocí adaptéru Sequel a ve způsobu implementace v Ruby se připojení k databázi neřeší implicitně voláním třídy pro připojení, ale databáze se automaticky připojuje při zavolání databázové

24 3. Návrh systému

Obrázek 3.7: Sekvenční diagram - Dostupnost knihy

metody. Při konkrétní implementaci je metoda process_book rozdělena na několik dalších metod pro větší přehled a především pro její využívání jak v ostatních módech, jimiž jsou skriptu předávány při inicializaci v parametru args. Mezi ty patří metody, které z textu zálohy dostávají data a ověřují si např. existenci autora s daným jménem v databázi. Skript vrací status a počet zpracovaných knih.

3.4 Databáze

V této kapitole budou zobrazeny návrhy databází pro 3 využité technologie. U databáze využívající ElasticSearch je znázorněno propojení databáze Elas- ticSearch s MySQL a v kapitole o MySQL jsou pak barevně odlišeny tabulky, pro ukázku postupného vývoje.

25 3. Návrh systému

Obrázek 3.8: Sekvenční diagram - Hodnocení knihy

3.4.1 MongoDB

Jak již bylo řečeno v kapilote popisující databázový systém MongoDB 2.1.3, tato databáze byla využita v prvotní fázi projektu, jako součást semestrální práce v předmětu o vývoji v jazyce Ruby. V současné době již využívána není, hlavním důvodem bylo pomalé fulltextové vyhledávání, které je pro pro- jekt SmartLib důležité. Diagram není zcela kompletní, nezobrazuje atributy, indexy a představuje především použité typy vazeb mezi jednotlivými doku- menty. Ústředním dokumentem v databázi je model Book. Jak již bylo řečeno v kapitole o 2.1.3 o MongoDB, není zcela jasné, jaký návrh databáze je ten správný a způsob rozdělení dokumentů je do značné míry ovlivněn nejen potřebou vývojáře, ale i schopnostmi adaptéru Mongoid a MongoDB samotné. Book má embeddován dokument Author. Autoři jsou v dokumentu renundantně pohromadě s knihou což především usnadňuje vyhledávání a snižuje požadavky na databázi, za cenu větší velikostí databáze. Důvodem je jasný požadavek na vyhledávání buď názvem knihy, nebo jménem jejich

26 3. Návrh systému

Obrázek 3.9: Návrh databáze - MongoDB

autorů. V aplikaci nikdy nepotřebujeme vyhledávat jen jména autorů bez návaznosti na knihy jež napsali. Naopak, potřebujeme-li vyhledávat dle jména knihy, často potřebujeme stejný řetězec vyhledávat i u jména autora. A nakonec, nejčastější hledání provozované mobilním klientem je takové, v němž vyžadujeme i jména jejich autorů. Protože v době, kdy aplikace využívala MongoDB jako svou databázi, nebyl požadavek na vyhledávání knih pro konkrétní knihovnu, jsou ostatní dokumenty navázány přes vztah referencing. Pokud bychom tuto databázi využívali i v tomto případě, je pravděpodobné, že struktura modelu Copy by byla také embeddována v modelu Book. Ostatní dokumenty nejsou využívány při žádném vyhledávání a prezentují pouze dodatečné atributy databáze. V tomto případě je na prvním místě snaha o ušetření na velikosti databáze, při prvotním využívání na OpenShiftu nebyly prostředky tolik štědré, jako v současné době. V praxi to ovšem znamená více vstupů do databáze pro získání doplňujících dat. Pokud budeme blíže SQL standarům a SmartLib by využíval MongoDB i v současné době, stálo by opět za zvážení embeddování parametrů do dokumentu Book. Blíže NoSQL přístupu by bylo odstranění takového množství modelů a začlenění dokumentů: Language, Publisher, PageType pouze jako atributů modelu Book, v diagramu by tedy neměli svého zástupce. Pro srovnání je možné podívat se na ukázku databáze pro ElasticSearch 3.4.3. Mírně netradičním na tomto návrhu je i např. dokument Publisher. Směr

27 3. Návrh systému

šipky můžeme chápat tak, že Publisher je nadřazený prvek knihy. V SQL databází by měla být šipka vedena spíše opačným směrem, u MongoDB s adaptérem Mongoid je však výhodnější směr tento a v konečném důsledku to i odpovídá reálnému chápání vztahu Vydavatel - Kniha, či Knihovna - Kopie (Library - Copy).

3.4.2 MySQL

Databáze MySQL je standardní open-source, na daném diagramu je zobrazen kompletní ER diagram v 3 normální formě. Ústřední tabulkou je books, obsahující ty atributy, jež u knih bývají unikátní a zároveň doplňují požadavky na data od vývojářů mobilních klientů. Proto je např. z názvu knih parsován pouze hlavní název, využívaný ve vyhledávání a podnázev se ukládá do atributu books.full_title. Zajímavý je např. atribut books.page_desc. Data v Alephnu nemívají jednotný formát a spousta knih má v informaci o počtu stránek uveden i doplňující popis např. +3CD, i s obrázkovou přílohou. Databáze se snaží, pro snížení renundance dat, ukládat stejné názvy do dalších tabulek. Těmi jsou myšleny tabulky: languages, publishers, years, page_types (např. str., strana, pages ...), years. Tento postup je náročnější na databázi při plnění daty. Pro každnou knihu musíme u těchto parametrů ověřovat jejich přítomnost v databázi, vytvořit nový záznam při záporné odpovědi a naopak přiřadit související cizí klíč při odpovědi kladné. Vycházíme-li s předpokladu jednoho prvotního naplnění databáze kompletní zálohoud databáze, jde o jediné vážnější zatížení databáze. Porovnané zálohy už obsahují řádově desítky, max. stovky změněných knih, při jejich aktualizaci jednou denně v ranních hodinách to není na překážku. Primárním účelem databáze je tedy čtení, nikoliv zápis a takovýto postup je výhodnější. Nedostatkem se může zdát ukládání autorů s identickým jménem do tabulky authors. V požadavcích ale není specifikována potřeba výpisu knih konkrétního autora a ani záloha Alephu neposkytuje o autorovi konkrétnější informace. Největším problémem je nemožnost indexovat tabulky typu InnoDB pomocí FULLTEXT indexu a tento rys MySQL byl chybně odhalen až v pokročilejší fázi projektu. V diagramu jsou tabulky označeny červenou barvou. Do těchto tabulek, vytvořených pomocí MyISAM (tyto tabulky naopak neumí vytvářet cizí klíče), jsou ukládány názvy bez diakritiky a kratších slov, např. spojek, a jsou využívány pro vyhledávání. Seznam cizích klíčů, ať už books.id, nebo authors.id, jsou použity v druhém dotazu, žádající si konkrétní knihy od tabulky books. Zelené tabulky byly přidány v poslední fázi vývoje. Konkrétně tabulka device umožňuje hodnotit knihu bez nutnosti přihlášení, ale zachovávající

28 3. Návrh systému

Obrázek 3.10: Návrh databáze - MySQL

29 3. Návrh systému přitom požadavek unikátnosti hodnocení. V tomto případě si pod device můžeme představit unikátní číslo telefonu. Tabulka schema_info je vytvářena adaptérem Sequel pro MySQL, viz. kapitola 2.1.3 s popisem instalace databáze pomocí migrací. Tabulka dumps se využívá pro uložení seznamu sufixů souborů, dodávaných knihovnou jako obraz databáze, protože každá knihovna má svůj vlastní soubor.

3.4.3 ElasticSearch Poslední ukázkou databáze je ElasticSearch. Protože pro ukládání knihy byl zvolen jeden jediný dokument, nabízená ukázka je výňatek z JSON, který namapovává strukturu dokumentu. Není nezbytné mapovací dokument využí- vat, ale pokud potřebujeme z indexování vyřadit určité položky a definovat klíče, které mají mít při vyhledávání vyšší prioritu, je mapping vhodný. Elas- ticSearch není nutné využívat samostatně, ale je běžné využití dohromady s relační databází a toho je využito i ve SmartLibu. Údaje o uživatelích jsou tak ukládány v MySQL databázi, odpadla tím nutnost transformovat data z MySQL databáze. Na ukázce JSON dokumentu můžeme vidět klíč "copy". Jde o fyzické kopie knihy a jsou taktéž uloženy pohromadě v jednom dokumentu. U položek, o kterých víme, že nebudou při vyhledávání potřebné, zadáme "index": "not_analyzed". V případě této databáze nám pomohla předchozí zkušenost z již existujícího API pro mobily, využívající jako databázi MySQL. Klíče od "sysno"patří knize samotné. Klíč "search_title"bude při vyhledávání upřednostňován před klíčem author.search_name. Jako u "copy"jde o vnořený objekt, s kterým můžeme nakládat jako s polem údajů. V případě potřeby přidání dalšího klíče nejde o zásadní změnu, index stačí buď domapovat, nebo pouze přidat nový klíč při ukládání dokumentu do databáze. Problematičtější je změna vyhledávácích priorit, v takovém případě by bylo nutné databázi přeindexovat. Pokud bychom podobný postup srovnali s návrhem pro MongoDB, všechny model by byly vnořeny v dokumentu jako atribut modelu book. Modely: authors a copies by byly vnořeny do dokumentu pomoci relace embedded.

" c o p i e s " : { "type" : "object", "properties" : { "signature" : {"type" : "string"}, "barcode" : {"type" : "string"}, "last_check" : { "type": "date", "format": "dateOptionalTime", "index": "not_analyzed" }, }

30 3. Návrh systému

}, "sysno" : {"type" : "string"}, "isbn" : {"type" : "string"}, "title" : {"type" : "string", "index": "not_analyzed "}, "search_title" : {"type" : "string", "boost" : 99}, "average_rating" : {"type" : "float"}, "full_title" : { "type" : "string", "index": "not_analyzed" }, " page " : { "type" : "string", "index": "not_analyzed" }, " author " : { "type" : "object", "properties" : { "search_name" : { "type" : "string", "boost" : 0.1 }, " name " : { "type" : "string", "index": "not_analyzed" }, "author_type" : { "type" : "string", "index": "not_analyzed" } } }

3.4.4 MySQL + ElasticSearch

Daný ER diagram zobrazuje finální podobu MySQL databáze. Využívána je společně s ElasticSearch databází tak, jak je popsána v předchozí kapi- tole 3.4.3. Data o uživatelích a recenze jsou ukládány v MySQL, všechny údaje o knihách jsou uloženy v ElasticSearch databázi. Příslušnost hodnocení, nebo recenze ke konkrétní knize je dána parametrem sysno, který souhlasí s unikátním identifikátorem knihy v ElasticSearch databázi. Databáze zo- brazuje i tabulky pro umístění knih do knihoven a polic dle jejich signatur. Funkcionalita je popisovaná v kapitole 5.3.

31 3. Návrh systému

Obrázek 3.11: Návrh databáze - MySQL v produkci

3.5 Porovnání databázových řešení

Nejdůležitějším prvkem aplikace je právě databáze. Protože uživatelé kon- cových zařízení budou primárně vyhledávat knihy ať už dle jejich názvu, nebo podle ISBN, rychlost jakou k nim výsledky doputují a relevance mezi hledaným textem a nalezenou knihou může rozhodovat o tom, zda-li ji budou aktivně využívat. Protože první databáze - MongoDB - nevyhovuje při full- textovém vyhledávání, zaměří se porovnání výsledků a rychlosti vyhledávání na MySQL a ElasticSearch. Pro vývojáře je mimo rychlosti a relevance vyh- ledávání důležitá i rychlost naplnění databáze a její velikost. Všechny časy jsou měřeny na produkčním serveru na OpenShiftu. V tabulce 3.1 jsou uvedeny základní údaje obou databází. Pro Elas- ticSearch nemá význam řešit počet kopií, protože jsou uloženy přímo v dokumentku knihy. Počet knih je samozřejmě stejný. Větší velikost MySQL databáze je dána jak větším množstvím vazebních tabulek viz 3.10, tak využití MyISAM tabulek pro vyhledávání, využívajících fulltext index. Pokud bychom tyto dvě tabulky books_search, authors_search odečetli, dostali bychom se na zhruba stejnou velikost. ElasticSearch databáze má však narozdíl od MySQL velké množství dat uložena renundantně.

32 3. Návrh systému

3.5.1 Plnění databáze porovnávanými zálohami Tabulka 3.2 ukazuje čas, strávený parserem, při zpracovávání databázových záloh. Jde o porovnovávané zálohy, tedy změněné údaje za posledních 24 hodin. Ukázka pochází ze záloh stahovaných automaticky ze dne 25.4.2013. Všechny údaje o knize jsou u tohoto typu synchronizace s Alephem přeuloženy. Pro MySQL to znamená kontrolu existence parametrů v tabulkách navázaných na hlavní tabulku Books. Výsledky ukazují předpokládanou věc a to, že hromadná úprava knih bude rychlejší u ElasticSearch databáze. Protože zde není třeba dodržovat normální formy a kniha je jakoby jedna tabulka v databázi, jedinou zátěží je nalezení knihy, což je ale dle unikátního klíče velmi levná operace. Větší čas u zálohy pro knihovnu PEDF je dán přítomností většího počtu knih s mnoha fyzickými kopiemi v této záloze.

Knihovna Počet zpracovaných knih MySQL [sec] ES [sec] FI 13 4 0 SCI 320 221 4 FF 975 252 8 FSS 74 54 0 ESF 23 15 0 PRAF 103 31 1 PEDF 828 649 21 KUK 55 30 1 TEIR 3 7 0 TELC 11 13 1 Celkem 2405 1276 38

Tabulka 3.2: Porovnání času pro zpracování porovnávaných zálohy databázemi

3.5.2 Porovnání času vyhledávání Konkrétní způsob implementace vyhledávání je popsán v kapitole 4.0.8. Tabulka 3.2 nám ukazuje nejen čas práce databáze, ale i zpracování výsledků dalším kódem. Nejde tedy o čístý čas zpracování dotazu, ale dobu zpracování požadavku tak, jak je ve SmartLibu implementován. V časech není započítáno stahování externích informací o obálkách a náhledech. V tabulce jsou uvedeny dodatečné parametry hledání a limit výsledku byl ponechán výchozí, tedy 20. Pokud nebyl zadán žádný parametr, MySQL vyhledává pouze podle titulu knihy, ElasticSearch hledá vždy zároveň jak v titulu knihy, tak v autorech knihy, není-li použit upřesňující parametr title nebo author. ElasticSearch

33 3. Návrh systému je znevýhodněn tím, že není spuštěn ve stejné aplikaci jako API a spojení probíhá skrze tunelované SSH.

Dotaz title author library MySQL [sec] ES [sec] informatika NE NE NE 9.5 0.51 nemocnice NE NE NE 1.32 0.35 sprava NE NE NE 4.52 0.56 tom sawyer NE NE NE 7.19 0.62 ruska kultura NE NE NE 7.87 0.38 anna kareninova ANO NE NE 1.68 0.93 romeo julie ANO NE NE 0.75 0.34 bohumil hrabal NE ANO NE 3.21 0.78 jirasek NE ANO NE 8.38 0.21 puskin NE ANO FF 15.82 0.15 uvod NE NE FI 5.24 0.64 pohran NE NE NE 1.01 7.25 geografick NE NE NE 6.77 6.25

Tabulka 3.3: Porovnání času pro zpracování dotazů

Z výsledků vyplývá, že si ElasticSearch, narozdíl od MySQL, udržuje stabilní výsledky okolo 3 desetin sekundy až sekunkdy. V zásadě nezáleží, dle kterých klíčů vyhledáváme. Až v případě, kdy ElasticSearch nenalezne dostatek výsledků, využívá se úprava hledaného výrazu o znak *. Výrazně pomalejší výsledky zaznamenává ElasticSearch právě u těchto neúplných slov. V tabulce jde o výrazy pohran, geografick, kde si přejeme hledat slova podobná slovům pohraničí a geografick(ý,é,á). V dokumentaci k ElasticSearch nalezneme pro vyhledávání textu v části slova několik dalších metod jako sufix, prefix, wildcard [31], které v aktuální verzi SmartLib nevyužívá. Budoucí úprava těchto dotazů by tak mohla být přepsána do efektivnější podoby. Pro MySQL je v těchto případech také využito upravené vyhledávání s regulárním výrazem. Konkrétní implementace je popsána v kapitole 4.0.8. Výsledky jsou podobně pomalejší. Výchozí vyhledávání hledá výskyt daného slova kdekoliv v textu. Rozdíl mezi rychlosti hledání MySQL v případě, že není nuceno vyhledávat i podle jmen autorů můžeme vidět například u vyhledávání výrazu anna kareninova, romeo julie. Pro vyhledávání je využito pouze hledání v titulu knihy a čas je menší. V případě zapojení restrikce na konkrétní knihovnu se dostávají výsledky pro MySQL nad hranici 10 sekund.

34 3. Návrh systému

3.5.3 Porovnání relevance vyhledávání MySQL a ElasticSearch Hledání books/search?query=romeo+julie&type=title

MySQL

1. Romeo a Julie: Tragédie v 24 scénách, William Shakespeare

2. Romeo a Julie, William Shakespeare

ElasticSearch

1. Romeo a Julie: tragedie v 24 scénách, William Shakespeare

2. Romeo a Julie, William Shakespeare

Hledání books/search?query=geografick

Při hledání neúplného slova jsou výsledky u ubou databází velmi rozdílné

MySQL

1. Změněná cizí vlastní geografická jména, Ivo Čáslavská

2. Geografická analýza pohraničí České republiky, Milan Jeřábek

3. Československá geografická literatura 1961-1965, Střída

ElasticSearch

1. Historicko-geografický obraz Blanenska, Boskovicka a Kunštátska v letech 1781-1848, Michaela Markovová

2. Změněná cizí vlastní geografická jména, Ivo Čáslavská

3. Geodetický a kartografický podnik

Hledání books/search?query=tom+sawyer

Naopak při hledání specifického výrazu jsou výsledky velmi podobné. MySQL

1. Tom Sawyer

2. The adventures of Tom Sawyer

3. Tom Sawyer na cestách a jiné prózy

35 3. Návrh systému

ElasticSearch

1. Tom Sawyer

2. The adventures of Tom Sawyer

3. The adventures of Tom Sawyer

Hledání books/search?query=harry+rowling

Špatné výsledky pro MySQL dostaneme pokud budeme hledat část jména titulu a zároveň část jména autora. Protože výsledky pro MySQL jsou hledány v první fázi v titulu knihy (tak aby odpadlo spojování tab- ulek a opakování dotazu), vychází lépe vyhledávání pro aElasticSearch. U něho hledá aktuální implementace současně v obou klíčích. Pro tento typ dotazu by bylo třeba pro MySQL přepsat SQL dotazy do komplikovanější podoby, zatímco pro ElasticSearch je napsání takového dotazu jednoduché. Výsledky s názvem harry a autorem rowling dostaneme u MySQL až na 17. místě a dále od místa 30, kdy vyprší možnosti knih obsahující harry.

MySQL

1. Harry’s fragments

2. Harry S. Truman

3. Harry S. Truman

ElasticSearch

1. Harry Potter a Kámen mudrců, J.K. Rowling

2. Harry Potter a Tajemná komnata

3. Harry Potter a Fénixův řád

3.5.4 Porovnání relevance vyhledávání ElasticSearch a Aleph Hledání books/search?query=tolstoj

Aleph má mnohem lepší výsledky pokud dáma vyhledávát jméno autora a nespecifikujeme oblast hledání. Výsledky pro ElasticSearch korespondují s nastavením mapování databáze. Přednost při vyhledávání má jméno titulu. Aleph

36 3. Návrh systému

1. Anna Karenina, L.N. Tolstoj

2. Semejnoje sčast’je ; Krejcerova sonata ; Rasskazy, L.N. Tolstoj

3. Skazki, rasskazy, byli i basni, L.N. Tolstoj

ElasticSearch

1. L.N. Tolstoj: perepiska s russkimi pisateljami, L.N. Tolstoj

2. Tolstoj své ženě, L.N. Tolstoj

3. L.N. Tolstoj o literature, L.N. Tolstoj

Hledání books/search?query=váňa

Pokud bychom předpokládali nalezení titulu Strýček Váňa, v tomto pří- padě vychází lepší výsledky pro ElasticSearch. Naopak první nalezený titul v Alephu hledal podle příjmení autora. Mezi prvními dvaceti tituly se u Alephu tato kniha ani neobjevila. První shoda je na 4. místě u ElasticSearch u titulu Doktor Proktor a vana času. ElasticSearch zařadil první titul s příjmení autora váňa na 6 pozici. Aleph

1. Perfektnost techniky, přeložil Milan Váňa

2. Výpočet hodnoty nitrooční čočky po předchozí refrakční operaci, Vana Latinac

3. Doktor Proktor a vana čas, Jo Nesbø

ElasticSearch

1. Strýček Váňa: výjevy z vesnického života ve čtyřech dějstvích

2. Doktor Proktor a vana času, Jo Nesbø

3. Kdy a jak využít přímou reklamu, Jan Váňa

V Alephu nelze simulovat vyhledávání neúplného výrazu, protože aplikace nabídne zpřesnění vyhledávání podle příbuzných slov, nikoliv výpis knih.

37 3. Návrh systému

3.5.5 Shrnutí Z výše zmíněného porovnávání vychází jako lepší varianta ElasticSearch. Nabízí ve většině rychlejší vyhledávání se stabilními časy. Implementace je rychlá, protože není třeba řešit nejoptimálnější sestavení dotazu jako pro SQL databáze. Přidání záznamů je také rychlejší, stejně jako jejich správa během pravidelnýcch synchronizací s databází Alephu. Relevance výsledků je v porovnání s fulltext indexem MySQL velmi podobná, ElasticSearch nám však nabízí spoustu dalších možností jak výsledky upřednostnit. Mezi plánovanými úpravami je např. upředňostňování výsledku s obalem či náhledem knihy, či knihy hodnocené. MySQL však po využití jeho potenciálnu taktéž nabízí velmi slušnou výkonost, na úkor složitější samotné implementace dotazů. V produkční aplikaci byla vybrána možnost kombinace MySQL s daty o uživatelích a ElasticSearch s daty o knihách viz 3.4.4

38 3. Návrh systému

Knihovna Počet knih Počet kopií Velikost [Mb] Čas [hod] MySQL 650000 1400000 1000 40 ElasticSearch 650000 - 872.3 2.5

Tabulka 3.1: Porovnání velikostí databází a času pro zpracování hlavní zálohy databázemi

39 4 Implementace obsluhy knih pro koncová zařízení

V této kapitole se seznámíme s nejdůležitějšími aspekty implementace obsluhy knih. Text se bude týkat vývoje API pro koncová zařízení, parseru pro stahování záloh z Alephu a to včetně ukázky rozdílů mezi kódem pro databázi MySQL a pro ElasticSearch. Ve shodě s vývojáři mobilních klientů byly stanoveny 3 základní priority popisující komunikaci mezi mobilními klienty a backend aplikací na serveru.

4.0.6 REST Přístup k funkcionalitě serveru by měl být lidsky čitelný, tedy, z cílové adresy, na níž zašleme svůj požadavek na určitá data, bychom měli být schopni i bez předchozí znalosti zjistit jaká je její funkce. Jednotlivé části koncové adresy jsou za sebe logicky skládány. Práce s konkrétní entitou by měla být dostupná na jedné adrese. Typ požadavku by měl být zřejmý z přístupové metody. Návratové hodnoty, chyby, či případné chybějící parametry by měly být deklarovány pomocí známých HTTP hlaviček. Lidsky čitelná adresa využívá anglické názvosloví entit a jejich parametrů. Za názvosloví považujme slova jako book, copies, detail, sysno, barcode, books aj.. Pokud si přejeme získat data o konkrétní knize, typ atributů aplikací vrá- cených popisuje poslední parametr v adrese požadavku. Pro čtení používáme požadavek typu get, pro přidání post, pro úpravu put, pro mazání delete. Přičemž cílová adresa se nemění. Framework Sinatra, využívaný u SmartLibu, má právě jako jednu ze svých zabudovaných funkcionalit nastavení cesty, tzv. routování [30]. V konfigu- račním souboru nastavíme Sinatře, pro které prefixy (např. /api, /admin ) má používat které třídy. Konkrétní cesta ve tříde (např. /books/search/ je napro- gramována jako metoda mající ve svém názvu typ přístupové metody (get, post, put, delete) a cestu. Výhodou takovéhoto postupu je přehled nad tím co metoda dělá, nevýhodou může být nepřehlednost při nárustu používaných cest. S roustoucím kódem také bývá potřeba dekomponovat kód do menších podmetod, pokud si nepřejeme duplikovat kód se stejnou funkcionalitou.

1 GET /api/books/search?query=:query&limit=20&offset=0 2 GET /api/books/search?query=:query&type=author&limit=20&offset=0 3 GET /api/books/search?query=:query&type=title&libraries=FI ,FF&type= title&limit=20&offset=0 4

40 4. Implementace obsluhy knih pro koncová zařízení

GET /api/book/:sysno/reviews 5 GET /api/book/:sysno/details 6 GET /api/book/:sysno/copies 7 GET /api/book?sysno=:sysno| isbn=:isbn 8 GET /api/book/:sysno/check?barcodes=:barcode_1 ,: barcode_2 ... 9 GET /api/books/list ?category=top&limit=20&offset=0 10 POST /api/book/:sysno/reviews 11 POST /api/report 12 POST /api/user/authentication?user=:user&password=:password 1 Tato adresa vyhledává knihy dle query. To může obsahovat buď ISBN (čárový kód naskenovaný fotoaparátem telefonu), nebo text, vyhledávající dle jména knihy a jména autorů knihy. Zdali nejde u parametru query o ISBN kontroluje gem isbn viz 6.1. Ten v případě chybné validace vrátí výjimku. 3 Vyhledávání knih je omezeno na jméno titulu. Fyzické kopie knihy se musí nacházet alespoň v jedné z knihoven specifikovaných parametrem libraries 4-6 Požadavek na detail některých atributů knihy. Unikátním parametrem je sysno, tedy unikátní číslo knihy. 7 Adresa vrací všechny informace o knize, které se jinak dají získat jednotlivě pomocí dotazů 4-6. 8 Požadavek na ověření dostupnosti fyzických kopií knih specifikované unikátním číslem v katalogu a především unikátními čisly knih tzv. barcode. 9 Tato adresa vrací knihy nejlépe hodnocené uživateli. 10 Požadavek na přidání recenze ke konkrétní knize. 11 Adresa na kterou jsou zasílány reporty uživatelů mobilních klientů. Ty jsou dále přeposílány skrze BitBucket API do seznamu požadavků přímo na stránkách repozitáře, viz kapitola 2.1.4. 12 Adresa pro kontrolu, zda-li je uživatel přihlášen pod svými údaji a může tak přidávat textové recenze na knihy.

4.0.7 JSON API, HTTP Hlavičky Část aplikace používaná mobilními zařízeními pod prefixem /api je dos- tupná pouze jako API. Na nepovolený požadavek vrací aplikace jinou HTTP hlavičku Status než 200 - Požadavek kladně vyřízen. Pro ukázku to jsou např. 401 - Neautorizovaný přístup, nebo 400 - chybný požadavek pro chy-

41 4. Implementace obsluhy knih pro koncová zařízení bějící parametry. Zvlášností pro využívání hostingu na OpenShiftu je způsob, jakým nakládá právě s polem v HTTP hlavičce Status. Krom chybového hlášení 404 - Neexistující stránka, zabudovaným přímo v Sinatře, přepisuje toto pole vždy hodnotou 200. Proto je do každého požadavku v API pro mobily přidávána hlavička s vlastním názvem StatusCode z níž se zařízení dozví jak dopadl jeho požadavek. Pokud bychom si URL adresy využívané v API otevřeli v prohlížeči, přivítá nás pouze prázdná bílá stránka. V případě kladného vyřízení není serverem vrácena HTML stránka, ale data uložena jako JSON. Tento formát je datově mnohem méně náročnější než XML, lehce a rychle čitelný i shlédnutím okem a umožňuje nerušeně přidávat či ubírat parametry. Na straně serveru je pro zabalení dat do JSONu používán gem Oj, v době psaní práce šlo o nejrychlejší generátor a čtečku JSONu. Při vyhledávání neexistujících položek aplikace vrací prázdné pole. Klíče v JSON dokumentu využívají tzv. CamelCase, narozdíl od zvyklosti v Ruby, které využívá malá písmena a slova oddělená pomlčkou. Důvodem je požadavek vzešlý od vývojářů mobilních aplikací.

4.0.8 API

Vývoj API probíhal ve 3 fázích, přičemž první fáze byla implementována pro databázi MongoDB na jaře 2012 tak, aby API bylo schopné vracet požadavky mobilním klientům. Další verze využívala MySQL a konečně poslední kombinaci MySQL + ElasticSearch. Data o uživatelích a recenze byly uloženy v MySQL databázi a primární určení ElasticSearch databáze bylo rychlé vyhledávání knih. Všechny 3 verze jsou dohledatelné v repozitáři projektu na BitBucketu, více v kapitole 2.1.4, a liší se pouze typem, jakým jsou psány dotazy nad databázi. V rámci přepisování kódu obsahují i podobné metody, sloužící pro unikátnost kódu (neopakování již napsaného kódu). Z případu užití pro API 3.2 vidíme případ užití m2_get_book. To se promítlo i do zdrojového kódu samotného v podobě dvou metod vracejících detail knihy a detail autorů knihy. Pro každé z různých typů vyhledávání detailu knihy využíváme různé dotazy nad databází, návratové atributy jsou však vždy stejné a tyto metody je přeloží do výstupního formátu očekávaného koncovými zařízeními. Samozřejmě jsou zde změny pro různé databáze. Budeme-li mluvit o vrácení autorů knih, MySQL využívá v metodě get_author další SQL dotaz s parametrem unikátního čísla knihy. Dotaz je puštěn nad databází a výsledné položky jsou v iteraci přidány do výstupních dat. ElasticSearch naproti tomu obsahuje informace o autorech přímo v dokumentu, metoda tak pouze proiteruje skrze pole autorů a přidá je do výstupních dat.

42 4. Implementace obsluhy knih pro koncová zařízení

API pro MySQL Pro vyhledávání v MySQL databázi byl využit gem Sequel 6.1. Mezi jeho hlavní přednosti patří adaptovatelnost na vícero relačních databází, např. MySQL, PgSQL, SQLite, tedy odpadá potencionální nutnost přepisovat dotazy při změně databáze. Plusem jsou migrace pro instalaci databáze popisovanou v kapitole 2.1.3 i skládání dotazu pomocí DSL. Právě tato položka působila při implementaci nemalé potíže. Vyhledávací dotazy sklá- dané pomocí DSL a poté sestavené samotným Sequelem však nebyly zcela vyhovující a vyhledávání podle jména titulu zabíralo i několik desítek vteřin. Problém byl i s využíváním vyhledávacíh metod v MySQL přímo pro práci s fulltext indexem. V reakci na to byly dotazy přepsány do ruční podoby a využity vyhledávací metody přímo pro hledání textů, čímž ale aplikace přišla nejen o přehlednost, ale v první řadě o výhodu adaptovatelnosti na jiné databáze, protože syntaxe se často mírně liší. Došlo ale k výraznému zrychlení provádění dotazů. Protože databázové tabulky jsou relativně velké, velkou brzdou v rychlosti bylo i spojování těch největších tabulek při hledání za pomoci cizích klíčů. Velká většina dotazů byla rozdělena na více vyko- naných poddotazů. Dohromady s tím byla i přepsána logika vyhledávání. Pokud uživatel nespecifikoval oblast hledání, autor knihy versus titulek knihy, byly knihy hledány podle jejich názvu. Až v případě, že jich nebyl nalezen dostatek, doplnilo se vyhledávání o jména autorů knihy. Na škodu tu opět bylo spojování tabulek. Při vyhledávání podle titulu knihy byla informace o autorech vyžadovaná na výstup, zjištěna v dalším SQL dotazu za pomoci unikátního čísla knihy. Zcela se bohužel nepodařilo odladit vyhledávání za pomoci restrikce na fyzické kopie v určitých knihovnách. Podrobné časy vyhledávání v porovnání s databází ElasticSearch jsou k nalezení v kapitole 3.5. Do rychlosti vyhledávání zasahuje i stahování dat o náhledu knihy a obalu knihy z externích zdrojů a také zjištění dostupnosti knihy přes stránku Alephu, z části popisované v kapitole 3.3.1. Pokud nebyla kniha nikdy vyhledávána, je poslán požadavek na obálku a případný náhled knihy viz 2.1.4. U zjišťování kopií knih je stahována aktuální dostupnost knihy přímo ze stránek Alephu za předpokladu, že jsou data starší než parametricky určená doba, standardně 24 hodin. mode = "NATURAL LANGUAGE MODE" if attempt > 0 mode = "BOOLEAN MODE" query = "*#{ query }*" unless query =~ /\s+/

43 4. Implementace obsluhy knih pro koncová zařízení

query = "#{query}*" if query=~/\s+/ end attempt += 1

# params contains specific libraries if params.include?(’library ’) library = params[’library ’].gsub(/ −[a−z]+,?/i, ’,’) s e l e c t = " " j o i n = " INNER JOIN ‘copies ‘ ON (‘copies ‘. ‘book_id‘ = ‘books ‘ . ‘ id ‘ ) " + " INNER JOIN ‘libraries ‘ ON (‘copies ‘.‘library_id ‘ = ‘ libraries ‘.‘id‘)" library , where, counter = library.split(’,’), " AND (", 0 library.each do |lib| or_ = counter == 0 ? ’’ : ’OR’ counter += 1 where += " #{or_} ‘libraries ‘. ‘library ‘ LIKE ’#{lib. s t r i p } ’ " end where += " ) " end

if (!params.include?(’type’) && (output.count < limit)) || ( params.include?(’type ’) && params[’type ’] && params[’type ’]. eql?(’author ’) ) if (!params.include?(’type’) || (params.include?(’type ’) && !params[’type ’])) && o f f s e t > 20 count = DB[ " SELECT DISTINCT(COUNT( ‘ id ‘ ) ) as count FROM " + " ‘books_search ‘ WHERE MATCH ( ‘authors_search ‘ . " + " ‘search_name ‘) AGAINST (’#{query}’ IN #{mode })"] offset = offset − count. first [:count] end books = DB["SELECT DISTINCT ‘books ‘. ‘id ‘,‘books ‘. ‘ title ‘, " + "‘books‘. ‘full_title ‘, ‘books‘. ‘sysno‘, ‘books‘. ‘isbn ‘ , " + " ‘books‘. ‘average_rating ‘, ‘books‘. ‘cover_url‘, ‘ books " + " ‘. ‘preview_url ‘ #{select} FROM ‘books‘ INNER JOIN ‘ books_authors" + "‘ ON (‘books ‘. ‘id ‘ = ‘books_authors ‘. ‘book_id‘) INNER " + "JOIN ‘authors_search ‘ ON (‘books_authors ‘. ‘author_id ‘ " + "= ‘authors_search ‘. ‘ author_id ‘) #{join} WHERE MATCH ( " + " ‘authors_search ‘. ‘search_name ‘) AGAINST (’#{ query } ’ " + " IN #{mode}) #{where}" + " LIMIT #{limit − output.count} OFFSET #{offset }"] output = add_books(books , output) end

44 4. Implementace obsluhy knih pro koncová zařízení

Ukázka zdrojového kódu se týká právě vyhledávání knih v MySQL. První větvění sestavuje část dotazu pro vyhledávání s restrikcí na konkrétní knihovny. Tedy z parametru params[’library’] dostane pole knihoven a ty postupně přidá do dotazu. Jednotlivé knihovny mají mezi sebou logickou spojku OR. Tento dotaz je uložen do proměnné where, která je využívána v poslední části dotazu v druhém větvění. Toto větvení je využito pouze v případě, že vyhledáváme podle autora knihy, nebo jsme způsob vyhledávání neupřesnili, již máme uloženy nějaké výsledky z vyhledávání pomocí titulu knihy, ale není jich tolik, kolik si koncové zařízení vyžaduje v parametru params[’limit’]. Výsledků pak požadujeme jen tolik, kolik jich do tohoto limitu zbývá. Na konci vidíme metodu add_books, jež výsledky zpracuje do JSON výstupu a stáhne případné obálky a náhledy knih. Snažíme se, podobně jako následně u databáze ElasticSearch, vyhledávat v prvním kole pomocí celých slov. Jde o dotaz typu AGAINTS NATURAL LANGUAGE MODE. Pokud je počet výsledků stále nedostatečný, vyhledáváme i s pomocí hvězdiček a dotazu typu BOOLEAN MODE, umožňující používat i regulární výrazy. Úprava hledaného výrazu je stejná jako v případě ElasticSearch.

API pro ElasticSearch

API pro ElastichSearch kombinuje některou funkcionalitu z MySQL, vyh- ledávání knih je primárně napsáno pro tuto databázi. Aplikace jako taková využívá pro přístup k databázi a skládání dotazů gem Tire 6.1. Tento gem umožňuje podobně jako Sequel pro MySQL snadnější psaní dotazů, které jsou u ElasticSearch posílány jako JSON na URL adresu, na níž má Elastic- Search otevřený port pro naslouchání, nebo jako get požadavek, přejeme-li si stáhnout zcela konkrétní dokument. Protože SmartLib používá pouze je- den dokument pro knihu, viz popis mapování v kapitole 3.4.3, v němž jsou uloženy všechny potřebné údaje, je potřeba pouze jedna cesta do databáze. Tire jako takový umožňuje několik způsobu jak vrací uživateli odpovědi na jeho dotazy. Jedním z nich může být automatické namapování JSON dokumentu do objektu, přičemž atributy jsou dostupné jako metody. Ve SmartLibu je využíváno namapování do JSON, uložených jako prvky pole. Spojení MySQL a ElasticSearch je na několika místech a vyžaduje i některé ústupky. Data o uživatelích jsou uložena v MySQL databázi, stejně jako jejich recenze. Protože hodnocení a recenze musí být navázány na konkrétní knihy a uživatele, nabízí se několik možností, jak překrytí provést a není jasná odpověď na otázku, které z nich je to správné. Zvolená možnost spočívá v tom, že namísto unikátního čísla knihy v databázi, máme-li tím namysli umělý

45 4. Implementace obsluhy knih pro koncová zařízení primární klíč generovaný databází, ukládáme v MySQL databázi unikátní číslo knihy Alephu, tzv. sysno. Takový postup se jeví jako výhodný proto, že jako unikátní atribut máme v ElasticSearch sysno zvoleno taktéž. Pokud bychom nechali toto vytváření na databázi, byl by to alfanumerický řetězec. Dalším řešením by mohlo být vytvoření tabulky Books, jejiž unikátní číslo knihy by nahradilo sysno knihy a ta by byla uložena právě v tabulce Books. Dalším řešením by mohlo být ukládání recenzí a hodnocení přímo do dokumentu knihy v ElasticSearch databázi. Ty by krom samotného hodnocení obsahovaly i odkaz na uživatele v MySQL databázi. Současné řešení totiž vyžaduje ústupek v podobě předukládání počtu recenzí a průměrného hodnocení knihy do ElasticSearch dokumentu. Tyto informace se využívají jak pro získání nejnověji hodnocených knih a také nejlépe hodnocených knih, přičemž požadavek je i na informace o knize. Tak se využívají i přímo při vyhledávání knihy, kdy tyto dvě informace vracíme v API koncovým zařízením. Tyto údaje jsou tedy uloženy konkrétně v MySQL databázi, a jejich statistika proto, abychom nemuseli sahat pro počet do MySQL databáze, i v ElasticSearch databázi. Jednodušším oproti API pro MySQL je i práce s informacemi o knize. To vyplývá z nepřítomnosti vazebních tabulek a tím i spojování a ukládání doplňujících informací na více místech. ElasticSearch mi vrátí dokument jako celek. Při ověřování dostupnosti knih uložíme změněné informace zpět do dokumentu a ten nechám pod jeho unikátním ID uložit. Protože ElasticSearch najde takový záznam ve své databázi, data rychle upraví včetně automatického verzování. Pokud by k titulu např. přibyly nové fyzické kopie knihy, jsou pouze přidány do stávajícího pole kopií, uloženy a automaticky obnoveny. Jistá renundatnost dat je tu vykoupena rychlostí a velmi velkou jednoduchostí práce s daty. again = t r u e attempt = 0 while again

if attempt > 0 query = "*#{ query }*" unless query =~ /\s+/ query = "#{query}*" if query=~/\s+/ end attempt += 1

library = params.include?(’library ’) ? params[ ’library ’]. gsub(/ −[a−z]+,?/i, ’,’) : nil ES . r e f r e s h . . . elsif params.include?(’type ’) && params[’type ’]. eql?(’author ’) books = ES.search{|search|

46 4. Implementace obsluhy knih pro koncová zařízení

search.query do boolean do must { string "author. search_name:#{query}" } must { string "copy.library :#{library}"} if library end end search.size limit search.from offset } e l s e books = ES.search{|search| search.query do boolean do should { string "author. search_name:#{query}" } should { string " search_title:#{query}" } must { string "copy. library:#{library}"} if l i b r a r y end end search.size limit search.from offset } end again = false if attempt > 1 || !books.empty? end end books.each do |book| add_book(book, output) end Tato ukázka představuje totožný výňatek jako v případě API pro MySQL. Vyhledávání v databázi je rozděleno na 2 pokusy. V prvním pokusu nepřidáváme do dotazu * známý z regulárních výrazů a narozdíl od MySQL si můžeme z důvodu rychlosti rovnou dovolit hledat jak v dle jména titulu, tak dle jmen autorů. Při vyhledávání je využito klíčové slovo should, značící, že daný klíč v dokumentu by mohl obsahovat takovýto parametr. Klíčové slovo string pak značí, že slovo se může nacházet kdekoliv v textu. Pokud nenalezneme žádnou položku, přidáme k vyhledávanému textu znak *. Specifické pro ElasticSearch při takovýchto klíčových slovech při vyhledávání je, že databáze nám najde i slova podobná našemu vyhledávanému. Jak jsme popsali v části 3.4.3 o mapování, při našem vyhledávání má velkou přednost jméno titulu před jménem autora. Nalezené výsledky je možné porovnat v sekci o porovnání obou databází v tabulce 3.3. Pokud porovnáme restrikci vyhledávání na fyzické kopie v knihovnách, stačí nám pouze přidat klíčové slovo must a text konkrétních knihoven předaných jako slova s mezerou, např. FF FI PDEF. Protože ElasticSearch je dostupný jako webová služba, při konfiguraci připojení k této databázi určujeme počet pokusů o vyřízení dotazu. Využitý

47 4. Implementace obsluhy knih pro koncová zařízení gem Tire poté řeší opakování dotazů i prodlevu v případě nedostupnosti mezi jednotlivými pokusy za nás.

4.0.9 Parser Aktuální verze parseru představuje komplexní zdrojový kód, umožňující zpracovávat nové knihy jak pro MySQL, tak pro ElasticSearch. Obsahuje dva články. Tím prvním je skript, který přijímá argumenty při spuštění, kontroluje jejich správnost, načítá a stahuje zálohy dat z Alephu. Surová data poté předává článku druhému. Tím je parser samotný. Zpracovat zálohu databáze znamená procházet textovou podobu řádek po řádku kdy každý z nich obsahuje údaje ve tvaru klíč hodnota. Prvotním klíčem je unikátní číslo knihy sysno, konec knihy prezentuje řádek prázdný. Největším problém u prvních verzí parseru bylo přezpracování dat do databáze v podobě co nejbližší realitě v Alephu. Spousta knih je v něm přidána chybně. V položce rok se například kromě čísel objevuje i psaný text, nebo se liší způsob zapisování stránek knihy. Až v průběhu vývoje byly do záloh přidány informace o fyzických jednotkách v konkrétní knihovně a až v tomto roce poskytla knihovna porovnávané zálohy. Prvotní naplnění databáze SmartLibu údaji z Alephu znamená projít několika miliónový záznam databáze a vytvořit příslušné knihy. První naplnění databáze probíhá ručním stažením záloh ze serveru Alephu, nahrání skrze webový formulář a následné ruční spuštění prvního článku. Porovnávané zálohy jsou naopak stahovány automaticky každé ráno v určitou hodinu pro každou knihovnu zvlášť. Ty obsahují maximálně několik tisíc řádků a obsahují jen takové knihy, u kterých došlo k nějaké změně, nebo knihy z knihovny odebrané. To znamená, že si přejeme všechny atributy knihy upravit. V rámci MySQL to znamená kontrolu v navazujicích tabulkách a případné přidání záznamu do nich a změnu cizího klíče. Pro ElasticSearch stačí pouze změnit hodnoty a dokument uložit pod daným unikátním číslem. Prvotní naplnění zabere MySQL databázi několik hodin, opakované pak několik minut. Údaje o výsledcích jsou zapisovány do logu pro případnou kontrolu. Reads configuration from configuration file config.rb.

Usage : file #{__FILE__}| all

48 4. Implementace obsluhy knih pro koncová zařízení

− cron true : run script only at 2AM, set false to run immediately − elastic false : feed ElasticSearch? false for MySQL/true for ElasticSearch − env development : set script enviroment; production for OpenShift

Examples # for initial database feed file all direct false cron false elastic true env production # for downloading all dump files from server file all direct true cron false elastic false # for downloading FI dump files from server and force updating file fi direct true cron false elastic false force true # for downloading all dump files and force update whole book file all direct true force true cron false elastic false # for downloading diff dump and update just statuses and add new books file all direct true elastic false # for downloading diff dump and feed ElasticSearch database on production file all diff true direct true force true elastic true cron false env production V ukázce vidíme možnosti pro spuštění parseru, nápověda je součástí skriptu. Důležitým prvkem je parametr elastic a pak také force a direct. Ve zdrojovém kódu je pro obě databáze jednotně naprogramována část, parsující data ze souboru. V případě MySQL databáze se ale snažíme zjistit přítomnost unikátního klíče knihy v databázi abychom věděli, zdali jde o dotaz insert nebo update. V případě ElasticSearch nám na tom nezáleží. Data nahrajeme do proměnné v JSON formátu a pouze zadáme uložení záznamu. Oba dva příkazy pro přidání knihy můžeme vidět v druhé ukázce. U MySQL přidáváme pouze základní parametry knihy obsažené v tabule Books, přidání vydavatele - publisher představuje ukázku kontroly existence záznamu u všech navazujících tabulek. Skript pro ElasticSearch ukazuje přidání autorů a jejich následné uložení do knihy. Opět je zde pouze krátká ukázka. ElasticSearch využívá tzv. bulk_store. Jde o hromadné naplnění databáze pomocí pole položek. Počet položek po kterých jsou data ukládána je definován v konfiguraci připojení k ElasticSearch. #### E l a s t i c S e a r c h ##############

@book[’author ’].each do |author| matches = author.match(/([a−zA−Z\ −]*) \ s * (. * ) /im ) name = matches[2] =~ /(\S+),\s?(. * )/i ? "#{$2} #{$1}" : n i l next unless name name = name.gsub(’,’, ’’) this_book[:author] << { :name =>name, :author_type => matches[1] , :search_name => clean_name(name) }

49 4. Implementace obsluhy knih pro koncová zařízení

end if @book.include?(’author ’) @books.push this_book

. . .

# insert into database counter = 0 b = @books.dup while counter < $CONFIG[: es ][: attempts] do begin Tire.index $CONFIG[: es ][: books] do import b end @books = [ ] r e t u r n t r u e r e s c u e s l e e p 0 . 1 counter += 1 end end

####### MySQL ############### # publishers if @book[’publisher ’] publisher = DB[: publishers ]. select(:id). filter (:publisher => @book[’publisher ’]) . first publisher = publisher ? publisher[:id] : DB[: publishers ]. insert (:publisher => @book[ ’publisher ’]) this_book[: publisher_id] = publisher end . . # force update book when we have id if @book[’id ’] query = "UPDATE LOW_PRIORITY ‘ books ‘ SET " + "‘isbn‘ = ?, ‘title‘ = ?, ‘full_title‘ = ?, ‘pages‘ = ?, " + "‘lastmod‘ = ?, ‘page_desc‘ = ?, ‘place‘ = ?, ‘sysno‘ = ?, " + "‘language_id‘ = ?, ‘page_type_id‘ = ?, ‘year_id‘ = ?, " + "‘publisher_id ‘ = ? WHERE ‘id ‘ = #{@book[’id ’]} LIMIT 1" else # insert pure new book query = "INSERT LOW_PRIORITY INTO ‘ books ‘ ( " + "‘isbn‘, ‘title ‘, ‘full_title ‘, ‘pages‘, ‘lastmod‘, ‘page_desc ‘ , " + " ‘place‘, ‘sysno‘, ‘language_id‘, ‘page_type_id‘, " + "‘year_id ‘, ‘publisher_id ‘) VALUES ( ?,?,?,?,?,?,?,?,?,?,?,?)" end book = DB[query , this_book[:isbn] || nil, this_book[:title] || nil, this_book[:full_title] || nil, this_book[:pages] || nil, this_book[:lastmod] || nil, this_book[:page_desc] || nil,

50 4. Implementace obsluhy knih pro koncová zařízení

this_book[:place] || nil, this_book[:sysno] || nil, this_book[:language_id] || nil , this_book[:page_type_id] || nil , this_book[:year_id] || nil, this_book[:publisher_id] || nil ] book = @book[’id ’] ? book.update : book.insert

@book[’id ’] ? DB["UPDATE ‘books_search ‘ SET ‘search_title ‘ = ? WHERE ‘" + "book_id‘ = ? LIMIT 1", short, @book[’id ’]].update : DB[:books_search]. insert(:search_title => self .tr(short), : book_id => book)

4.0.10 Registrace uživatelů Protože bylo již v prvních verzích SmartLibu potřeba mít možnost hodnotit knihy a požadavek byl zároveň na hodnocení pouze od registrovaných uži- vatelů, k tomu uživatelů knihoven MU s vlastním unikátním číslem, vyvstala otázka jakým způsobem provést registraci uživatelů. Masarykova univerzita umožňuje autorizovaným aplikacím přístup ke své databázi studentů. Zdárné spuštění vyžaduje instalaci některých modulů a knihoven na server, což se v případě využivání OpenShiftu ukázalo jako časově mnohem problematičtější řešení než zprovoznit verzi vlastní registrace. Aktuální verze umožňuje uži- vatelům registraci za pomoci zadání jejich unikátního univerzitního čísla. Na univerzitní email jim následně přijdou přihlašovací údaje. Tento způsob není optimální, protože obtěžuje uživatele zbytečnou registrací a uživatelé MU jsou zvyklí používat své údaje ve velké většině univerzitních aplikací. Pro zasílání emailu je navíc využívána externí služba MailGun, viz kapitola 2.1.4. Důvo- dem použití byly problémy s časovou prodlevou pro odeslání emailu pomocí SMTP serveru OpenShiftu. Do budoucna se nabízí řešení pomocí připojení k některé sociální sítí, nebo zprovoznění API obsahující i seznam výpujček konkrétního uživatele knihovny. Aktuálně je potřeba přihlášení pouze pro napsání recenze ke knize, pro hodnocení knížky se pro jednoznačnost používá unikátní číslo telefonu viz 3.2.3. not_found unless params.include?(’firstName ’) && params. include?(’lastName ’) && params. include?(’uco ’) simple_error 409 if DB[:people]. filter (:username => params[’uco’] , :active => true ) . count > 0 password = self . class ::get_random_text 10 person = DB[:people]. insert(

51 4. Implementace obsluhy knih pro koncová zařízení

{ ’first_name ’ => params[ ’firstName ’] , ’surname’ => params[’lastName’] , ’username’ => params[’uco’] , ’email’ => "#{params[’uco’]}@mail.muni.cz", ’password’ => self .class ::md5(password), ’active’ => false, ’admin’ => false } ) person = DB[:people]. filter (:id => person). first

text = erb :registration , :locals => { :username => params[ ’uco ’] , :password => password }

self .class ::send_email person[:email], ’SmartLib − registrace ’, text ok V ukázce vidíme nastavení návratové hlavičky na hodnotu 409 - Conflict v případě, že databáze již obsahuje registrovaného a aktivního uživatele pod daným loginem. Jako aktivní je brán uživatel, který se alespoň jednou přihlásil do systému. V případě chybějícího parametru je vrácen Status 400. Po přidání do databáze je zaslán uživateli registrační email skrze službu MailGun.

52 5 Implementace webového rozhraní pro knihovníky

V této kapitole jsou popsány základní postupy implementace webového rozhraní, určeného pro knihovníky a správce SmartLibu. Požadavky pro webovou část jsou jednoduchá správa uživatelů a zařízení, recenzí, hodnocení a také kresba polic do mapových podkladů jednotlivých knihoven. Právě na tuto část se text podrobněji zaměří. V případech užití 3.1.3 najdeme tuto funkcionalitu pod případy w2_serve_library a w3_place_book_into_library.

5.1 Popis

Webová část aplikace je stejně jako API implementována ve frameworku Sinatra [10], ukryta je za URL adresou /admin. Další podobnost je v REST přístupu k jednotlivým funkcionalitám aplikace. URL adresa by měla vyjadřo- vat s jakou částí aplikace pracujeme, např. book, user, review, typ metody definujeme přístupovou metodou. Narozdíl od API ale nevrací webová část data v JSON formátu, ale buď kompletní HTML stránku, či její část v případě, že jde o AJAX požadavek. Pro usnadnění práce s HTML byl zvolen frame- work s předdefinovanými styly napsaný v HTML5 od společnosti Twitter: Bootstrap [32]. Pro usnadnění práce s kaskádovými styly byl použit frame- work SAAS, kompilující přehledně CSS. Pro snadnější práci s JavaScriptem je použit framework jQuery [34] a jQueryUI usnadňující práci s přesouváním prvků na stránce. Na obrázku 5.2 vidíme ukázku aplikace využívající jednoduché horní menu, rozdělené do 4 částí. Ty umožňují uživatelům vyhledávat knihy, uživatele a spravovat knihovny. Vyhledávání knih a uživatelů nabízí jednoduchý formulář. Výpis nalezených dat nabízí odkazy na detail knihy a uživatele, včetně odkazu na recenze uživatele nebo konkrétní knihy. Recenze a hodnocení je v případě nutnosti možné i přímo mazat. Pro snadnější pohyb v administraci je v horní části přítomné menu znázorňující aktuální polohu v aplikaci. U uživatele máme možnost smazat jeho účet, případně znemožnit mu přihlášení do SmartLibu. Jako uživatel, nebo zařízení, je chápán stejný uživatel, který se registruje do systému pomocí mobilního rozhraní. Prvotní administrátor je nastaven programově, další je možné vytvořit z již registrovaných uživatelů taktéž v administraci.

53 5. Implementace webového rozhraní pro knihovníky

Obrázek 5.1: Ukázka aplikace - Hledání knihy

Obrázek 5.2: Ukázka aplikace - Detail uživatele

5.2 Implementace

Implementace webového rozhraní je umístěna do třídy Admin. V případě, že využívá podobnou funkcionalitu jako API, používá jednotné metody pro obě části. Takovým příkladem je např. vyhledávání knih. Administrátor v aplikace tedy vyhledá totožné výsledky jak při hledání přes mobilní zařízení, tak při použítí webové aplikace.

5.2.1 Implementace správy knihoven Správa knihoven umožňuje uživateli definovat jednotlivé knihovny. Budoucí využití by mělo umožnit dovést uživatele pomocí mobilní aplikace přímo ke konkrétnímu regálu knihovny. Proto potřebujeme k jednotlivým knihovnám vytvářet poschodí včetně grafických map a na mapy umisťovat regály tak, jak

54 5. Implementace webového rozhraní pro knihovníky odpovídají realitě v budovách knihoven. Backendová část v Ruby v této části spolupracuje s JavaScriptovým kódem, který umožňuje na obrázek kreslit a přesouvat police znázorněné obdelníkem. Veškerý HTML obsah poskytuje Ruby. Jako příklad uveďmě přidání police, které vyvolá požadavek aplikaci na vrácení HTML šablony s policí pomocí AJAXu. Aplikace vrací HTML a JavaScriptový kód ho umístí na stránku a nastaví mu korektně potřebné atributy. Ruby kód v ukázce nám právě takové vrácení kódu představuje. První metoda v ukázce get ’/shelf’ do zobrazuje načtení šablony :shelf, která je využívána i při načtení detailu patra. V tomto případě vracíme pouze tuto část HTML stránky, vynecháme tedy její zbytek. Druhá metoda ukazuje detail poschodí. Šabloně načteme data breadcrumb pro drobečkovou nápovědu a načteme police v proměnné shelves do šablony floor. V poslední části ukázky je část HTML kódu této šablony, která proměnnou shelves předá stejně jako při kreslení polic šabloně shelf.

# admin . rb get ’/shelf ’ do erb :shelf , :layout => false , :locals => { :counter => params[’shelf ’], :shelf =>{}, :only =>true } end get ’/floor/:id’ do @breadcrumb << {:link => ’/admin/libraries ’, :text => ’ Knihovny ’ } floor = get_floors(nil , params[’id ’]) @breadcrumb << { :link => "/admin/library/#{floor [: library_id]}" , :text => floor [:library_name] } @breadcrumb << { :text => floor[:floor] }

erb :floor, :locals => { :floor => floor, :shelves => get_shelves(params[’id ’]) } end

## ERB Template floor ;

55 5. Implementace webového rozhraní pro knihovníky

<%= erb :shelves , :layout => false , :locals => {:shelves => s h e l v e s } %>
">

V následující ukázce si můžeme prohlédnout spolupracující kód běžící na straně webového prohlížeče. Jde o metodu add_shelf, přidávající na stránku HTML kód s policí. Ta na svém začátku pošle AJAX požadavek na adresu /admin/shelf s parametrem shelf, který můžeme chápat jako počítadlo polic na patře sloužící k nastavení jejich unikátního čísla. Metoda tedy volá Ruby kód ve tříde Admin, a metodu get ’/shelf’ do popsanou výše. Postup s využitím AJAXu se využívá např. i při vyhledávání knih a uživatelů, kdy není potřeba vracet znovu celou kompletní HTML stránku, ale postačí pouze část s výsledky. Při vyhledávání je ovšem jako typ návratových dat využíván JSON, v našem příkladě jde čistě o HTML. Pokud právě pracujeme s některou policí, má taková police nastavenou CSS třídu focus-shelf. Při přidání nové police nastavíme nově vkládanou jako upravovanou. Polici přidáme do elementu s unikátním id #canvas a nastavíme mu vypočítanou pozici na stránce. Na závěr využijeme framework jQueryUI a označíme polici jako resizable, draggable. Díky tomuto frameworku můžeme prvek posouvat v rámci elementu #canvas, nebo měnit jeho rozměry. Pokud posouváme s právě upravovanou policí, posun, či změna velikosti se promítne do hodnot ve formuláři s údaji o polici. V posledním kroku zvedneme počet polic v proměnné shelf. Náhled stránky můžeme vidět na obrázku 5.3. Data o signaturách, či unikátní číslo police v databázi se ukládáji přímo do HTML elementu pomocí atributů se prefixem data-. Ten se v HTML5 využívá právě pro ukládání dodatečných informací. Právě upravovaná položka je označena zeleným rámováním, ostatní police mají okraje v šedé barvě.

56 5. Implementace webového rozhraní pro knihovníky

Obrázek 5.3: Ukázka aplikace - Správa poschodí knihovny

57 6 Aplikace jako celek

Protože zdrojový kód je volně k prohlédnutí a stáhnutí v repozitáři na Bit- Bucketu 2.1.4, je popsán i způsob konfigurace, včetně instalace na OpenShift a požadavkům navíc s tím spojeným.

6.1 Použité gemy

Seznam popisuje využité gemy. Všechny gemy, s výjimkou gemu shotgun, jsou využívány v produkčním prostředí, shotgun navíc ve vývojovém.

sinatra-contrib Umožňuje vývojáři rozdělit HTML stránku do podšablon a ty pak do sebe vkládat. Využití je především u AJAX požadavků, kdy nevracíme celou stránku, ale pouze její část. Můžeme tak přehledně rozdělit aplikaci a předejít duplikátnímu kódu.

sequel a tire Frameworky pro jednodušší práci s databázemi. Sequel je využíván pro MySQL databázi, některého jeho vlastnosti byly popsány v kapitole 2.1.3 a . Tire slouží k pohodlnějšímu přístupu k databázi ElasticSearch.

rest-client Klient pro snadné zasílání HTTP požadavků s využitím REST. V aplikaci se používá k dotazování externích zdrojů 2.1.4 a stahování záloh z Alephu viz 3.1.1.

oj JSON parser využívaný především v API pro mobilní klienty. Implementačně je schován za metodou my_json, tedy v případě potřeby změny tohoto gemu stačí změnit aplikaci na tomto jediném místě.

nokogiri Nokogiri je XML, HTML parser, v aplikaci je využíván pro přeložení HTML stránek Alephu při zjišťování dostupnosti knih, popisovanou v kapitole 3.3.1. Umožňuje přistupovat a vyhledávat ve stromu HTML dokumentu.

rake Rake je knihovna sloužící k vytváření a spouštění vývojářem definovaných

58 6. Aplikace jako celek

úloh. V aplikace se využívá k vytvoření a prvotnímu naplnění databáze ve spolupráci s gemem sequel pro MySQL a k namapování ElasticSearch databáze. Úlohy se definují ve speciálním souboru pojmenovaném Rakefile.

∙ sinatra

∙ sinatra-contrib

∙ sinatra-content-for2

∙ mysql2

∙ sequel

∙ tire

∙ isbn

∙ faraday

∙ rest-client

∙ oj

∙ nokogiri

∙ bzip2-ruby

∙ rake

∙ sass

∙ shotgun

6.2 Struktura aplikace a zásady psaní kódu

Jak již bylo popsáno v kapitole 2.1.1, pro Sinatru neexistuje žádné pevně dané rozmístění součástí aplikace, daná struktura tak vychází ze zkušeností autora a jeho citu pro přehlednost. Složky jsou popsány velkým F, soubory malým f.

.openshift Obsahuje konfigurační soubory pro spuštění v produkci na serveru OpenShift,

59 6. Aplikace jako celek konktréní soubory budou popsány v kapitole 7.1.3.

config Složka obsahuje soubory chápané jako konfigurační. Protože aplikace je veřejně přístupná v repozitáři a umístění konfiguračního souboru s nas- tavením a klíči k externím službám není vhodné řešení, vidíme v ní soubor config.rb.example, který je v produkčním módu třeba zkopírovat do námi definované složky jako config.rb a v něm nastavit potřebné údaje. Při vývoji můžeme soubor umístit přímo do této složky. Umístění pro OpenShift je popsáno v kapitole 7.2. Složka migrations obsahuje soubory pro instalaci databáze pomocí rake, viz 6.1, soubor mapping.json obsahuje JSON data využívaná taktéž k namapování ElasticSearch databáze pomocí rake.

lib Složka se soubory napsanými v ruby a HTML šablonami. V podsložce app jsou třídy pro obsluhu API a webového rozhraní, v podsložce views pak ERB šablony s HTML kódem. Ve složce smartlib nalezneme třídy společné pro obě části SmartLibu. Je to třída s metodami pro práci s databází ElasticSearch, soubor database.rb který se k oboum databázím připojuje, v případě změny či přidání databáze tak změníme definování připojení na jednom místě. Sou- bor common.rb obsahuje společné metody, jako např. vyhledávání knih, či přihlašování uživatelů do aplikace a parser.rb je blíže popsán v kapitole 4.0.9.

public Obsahuje statické soubory veřejně přístupné, jako CSS, obrázky a JavaScript.

config.ru Soubor slouží aplikačnímu serveru pro načtení a spuštění serverové aplikace.

watch_dog.rb Krátký skript kontrolující dostupnost služeb na OpenShiftu v produkci, blíže popsaný v kapitole 7.1.3. Spolupracuje se souborem restart.

∙ F .openshift

∙ F config

⋆ F migrations ⋆ f config.rb.example

60 6. Aplikace jako celek

⋆ f mapping.json

∙ F dump

∙ F lib

⋆ F smartlib ∘ F app · f admin.rb · f api.rb · f api_elastic.rb ∘ F views ∘ f app.rb ∘ f common.rb ∘ f database.rb ∘ f elastic.rb ∘ f parser.rb

∙ F log

∙ F public

∙ F tmp

∙ f .gitignore

∙ f config.ru

∙ f Gemfile

∙ f Rakefile

∙ f README

∙ f restart

∙ f shoot_parser.rb

∙ f watch_dog.rb

61 6. Aplikace jako celek

6.2.1 Zásady psaní kódu Stejně jako neexistují pro Sinatru jasně dané pokyny pro rozložení složek a souborů, není přesně definované jakým způsobem dodržovat čistotu kódu. Dané preference opět záleží především na zkušenostech a především disciplíně vývojáře, držící se zásady, že dobře napsaný kód není třeba komentovat, protože mluví sám za sebe. Pro psaní SmartLibu jsou dány tyto zásady:

∙ Začátky řádků v Ruby jsou odsazovány tabulátorem o šířce 4 znaků. Každé další odsazení v řádku je prováděno mezerami.

∙ Délka řádku by neměla přesáhnout 82 znaků pro kód psaný v Ruby.

∙ Názvy souborů i názvy metod by se měly držet jednotného začátku a formy. Jako příklad slouží metody get_..... Všechny metody s tímto prefixem v názvu by měly tento prefix i dodržovat. Stejně je tomuu názvu souborů. Jako příklad slouží ERB šablony list_, pro vypsání seznamu výsledků.

∙ Související kusy kódu v metodách by neměli být oddělovány prázd- nými řádky. Naopak část kódu řešící další problém by mezerou oddělen být měl.

∙ Závorky začínají na stejném řádku jako výraz využívající je. Pokud je konec závorky na dalším řádku, ddsazení uzavíracích závorek od začátku řádku by mělo dodržovat velikost výrazu od začátku řádku, který závorky vyvolává.

62 7 OpenShift

SmartLib je produkčně spuštěn na platformě OpenShift, kterou provozuje společnost RedHat. Aplikace je spuštěna na webové adrese: https://web- -smartlibweb.rhcloud.com pro webovou aplikaci a API. OpenShift umožňuje spouštět aplikace, pojmenované jako gear a pro ně definovat další služby, kterým se říká cartridge. SmartLib využivá následující:

∙ web - webová aplikace

⋆ Ruby 1.9 ⋆ MySQL Database 5.1 ⋆ phpMyAdmin 3.4 ⋆ Cron 1.4

∙ elasticsearch - jde o tzv. DIY - udělej si sám. V této části je spuštěný ElasticSearch.

⋆ Do-It-Yourself

7.1 Speciální implementace pro OpenShift

Protože OpenShift nabízí specificky vytvořené služby, využívá SmartLib na několika místech speciální implementaci či nastavení přímo pro OpenShift.

7.1.1 Umístění konfiguračního souboru Takovou speciální implementací je načítání konfiguračního souboru con- fig.rb. Tento soubor obsahuje nastavení připojení k oběma databázím, klíče k využívání externích služeb a definuje zápis informací do logu. Protože klíče není možné ukládat veřejně v repozitáři, je třeba přímo na serveru vytvořit kopii ukázkového konfiguračního souboru, která není součástí repozitáře. Při každém restartování aplikace jsou ale tyto soubory smazány, proto je třeba umístit je do speciální persistentní složky, kterou pro takové případy Open- Shift nabízí. Přímo ve zdrojovém kódu pak není konfigurační soubor volán ze složky config, ale z umístění, dané proměnnou OPENSHIFT_DATA_DIR.

7.1.2 Cron Pro opakované spouštění využívá SmartLib cartridge Cron-1.4. Nastavení probíhá přidáním skriptu napsaných v bashi do složky v repozitáři /.openshift/cron/

63 7. OpenShift a dále do složky popisující pravidelnost spouštění minutely, hourly, weekly, monthly. Kromě dostupnosti služeb spouští Cron ve SmartLibu restartování služeb a také stahování záloh z Alephu.

7.1.3 Kontrola dostupnosti služeb Pro kontrolu dostupnosti služeb na serveru byl implementován skript watch_dog.rb. Pomocí služby Cron, spouštějící v pravidelném intervalu vývojářem defino- vané služby, kontroluje skript 4 základní služby. Jsou jimi připojení k MySQL databázi, připojení k ElasticSearch databázi, dostupnost API a dostupnost gearu na kterém je spuštěn ElasticSearch. V případě nedostupnosti zasílá skript na emaily definované v konfiguračním souboru. Pokud je nedostupné API, či MySQL databáze, skript uloží do složky /tmp speciální soubor, jehož přítomností avizuje skriptu restart napsaném v bashi, že má restartovat ap- likaci pomocí speciální příkazu dostupném pouze na OpenShiftu. V případě nedostupnosti ElasticSearch databáze se skript pokouší obnovit spojení s druhým gearem.

7.1.4 Post-deploy Pomocí složky .openshift můžeme při nahrávání commitu na serveru stanovit kroky, tzv. hooky, které proběhnou při spuštění aplikace, při jejím zastavení, či před a po instalaci. Pro OpenShift je využíván post-deploy, který je spouštěn po nainstalování aplikace na serveru. Má za úkol dvě věci. První je vytvoření zástupce ze složky public/img/maps do persistentí složky na OpenShiftu a složky maps. Důvodem je fakt, že potřebujeme uložit obrázky map využívané ve webové aplikaci. Při každém restartování aplikace by ale byly smazány, proto se ukládájí do této složky, které ale není přístupná přes URL adresu. Pomocí zástupce přesměrujeme složku s mapami z veřejně dostupné adresy do této složky. Druhým je vytvoření tunelovaného SSH připojení ke gearu, na kterém je spuštěn ElasticSearch za předpokladu, že takové připojení není prozatím vytvořeno.

7.2 Konfigurace a instalace

Kapitola popisuje prvotní postup při instalaci na OpenShift za předpokladu, že máme vytvořené všechny geary a přidány všechny cartridge.

∙ Instalace databáze ElasticSearch. Do persistentní složky stáhneme a nainstalujeme ElasticSearch. Něk- teré kroky pro starší verzi ElasticSearch jsou popsány v návodu na

64 7. OpenShift

adrese: https://www.openshift.com/blogs/searching-with-elasticsearch-on- -openshift. V konfiguraci databáze je třeba nastavit porty na hodnotu větší než 15000, které nejsou blokovaný OpenShiftem. ElasticSearch spustíme s parametrem nohup. Pro SmartLib je nastaven běh na portu 15000. V gearu s webovou aplikací si vytvoříme ssh klíč, postup je popsán v návodu na adrese: https://www.openshift.com/faq/how-can-i-run-ssh-port-forwarding-from-one-gear-to-another, který přidáme v administraci OpenShiftu a poté se můžeme přes SSH propojit mezi oběma geary a připojit se k ElasticSearch databázi. Samozřejmě je možné nainstalovat ElasticSearch databázi i přímo v gearu s ruby aplikací a tento krok vynechat.

∙ Vytvoření konfiguračního souboru. Do persistentí složky v gearu s ruby aplikací zkopírujeme konfigu- rační soubor uložený v repozitáři ve složce config/config.rb.example a nastavíme nevyplněné hodnoty. Tento krok je popsaný v README aplikace.

∙ Vytvoření složky maps a dumps. V persistentní složce v gearu s ruby aplikací vytvoříme složku /maps a složku /dumps

∙ Instalace. Podle návodu v README spustíme kroky potřebné k instalaci databází. Ty jsou popsány v README v repozitáři. Nakonec aplikaci na OpenShiftu restartumeme.

∙ Naplnění databáze knihami. Pokud jde o prvotní spuštění aplikace, je potřeba stáhnout zálohy databázi knih z Alephu a ty nahrát na server do libovolné složky, nejlépe však do persistentní složky na OpenShiftu a složky dumps. Prvotní naplnění databáze musíme provést ručním spuštěním skriptu shoot_parser.rb, uloženém v repozitáři. Skript můžeme spustit s parametrem -h pro vypsání nápovědy.

65 8 Umístění projektu

8.0.1 Veřejný repozitář Veřejný repozitář je umístěn na adrese https://bitbucket.org/thrabal/ smartlib

8.0.2 Produkční aplikace Produkční aplikace pro knihovníky je umístěna na adrese: https://web-smartlibweb. rhcloud.com/admin API pro mobilní zařízení se nachází na adrese https://web-smartlibweb. rhcloud.com/api

66 9 Závěr

Cílem této diplomové práce bylo navrhnout a vyvinout funkční aplikaci SmartLib ve spolupráci s vývojáři mobilních klientů a poté ji produkčně nasadit. Mobilní aplikace jsou od roku 2012 dostupné ke stažení veřejnosti a serverová část je v produkci na serveru OpenShift. Základní požadavky tedy byly úspěšně splněny. V rámci diplomové práce byly vyzkoušeny a implementovány 3 přístupy v práci s databázovými daty, 2 nejúspěšnější - ElasticSearch a MySQL, pak byly vzájemně porovnány jak v rychlosti, tak relevanci vyhledávání. Nakonec byla vybrána nejoptimálnější varianta, a to knihy uložené v ElasticSearch a ostatní data v MySQL. Pokud bychom se v této části zamysleli nad dalším směřováním, otevírá se spousta dalších možností, jak zpřesnit uživatelům vyhledávání knih a více preferovat knihy např. s existujícím PDF náhledem či kladným hodnocením od uživatelů. Další vývoj by měl směřovat k usnadnění hodnocení knih uživateli mobilních klientů skrze přístup do databáze Masarykovy univerzity a využití dalších externích funkcí, jako je např. automatické generování citací. Největším problémem při návrhu a vývoji byla počáteční nejasná koncepce a rychlé změny, které navazovaly na vývoj mobilních klientů a také problémy s nasazením na Open- Shift, jenž začal SmartLib využívat již v jeho začátcích, kdy nebyla dostupná kvalitní dokumentace k řešení některých požadavků. Všechny těžkosti se však podařilo vyřešit, a tím bylo dosaženo cílů diplomové práce. Na závěr je možné zamyslet se nad možnostmi replikace této práce. V současné implementaci by bylo pouze potřeba vyvinout parser knih pro konkrétní knihovny, a aplikace by tak byla přenositelná i mezi dalšími univerzitami a knihovnami.

67 Seznam obrázků

3.1 Diagram případu užití - Parser 17 3.2 Diagram případu užití - Mobilní API 19 3.3 Diagram případu užití - Webové rozhraní 21 3.4 Diagram aktivity - Parsování knihy 23 3.5 Diagram aktivity - Hledání knihy 23 3.6 Diagram aktivity - Hodnocení knihy 24 3.7 Sekvenční diagram - Dostupnost knihy 25 3.8 Sekvenční diagram - Hodnocení knihy 26 3.9 Návrh databáze - MongoDB 27 3.10 Návrh databáze - MySQL 29 3.11 Návrh databáze - MySQL v produkci 32 5.1 Ukázka aplikace - Hledání knihy 54 5.2 Ukázka aplikace - Detail uživatele 54 5.3 Ukázka aplikace - Správa poschodí knihovny 57

68 Seznam tabulek

3.2 Porovnání času pro zpracování porovnávaných zálohy databázemi 33 3.3 Porovnání času pro zpracování dotazů 34 3.1 Porovnání velikostí databází a času pro zpracování hlavní zálohy databázemi 39

69 Literatura

[1] BARTOŠEK, Miroslav. Bartošek. In: [online]. 2011. vyd. [cit. 2013-03-06]. Dostupné z: http://www.ics.muni.cz/bulletin/articles/337.html [2] EXLIBRIS. ExLibris: Aleph [online]. [cit. 2013-03-06]. Dostupné z: http://www.exlibris.co.il/category/Aleph [3] Architektura systému Aleph. UNIVERZITA KARLOVA, Ústav výpočetní techniky. Aleph [online]. [cit. 2013-03-06]. Dostupné z: http://aleph.cuni.cz/ALEPH-13.html [4] ŠKRABÁLEK, Josef, Marek JELEN a Jonáš ŠEVČÍK. SmartLib. [online]. [cit. 2013-03-06]. Dostupné z: https://is.muni.cz/auth/publication/949963/cs?lang=cs [5] ŠEVČÍK, Jonáš. Rozšířená realita na mobilní platformě An- droid a její aplikace v knihovnictví. Brno, 2011. Dostupné z: http://is.muni.cz/th/255493/fi_m/. Bakalářská práce. Masarykova univerzita. Vedoucí práce RNDr. Jaroslav Škrabálek. [6] TRAN, Hoa Quoc, Rozšíření Android klienta mobilního knihovního katalogu smartLib. Brno, 2012. Dostupné z: http://is.muni.cz/th/359768/fi_b/. Bakalářská práce. Masarykova univerzita. Vedoucí práce Mgr. Jonáš Ševčík. [7] HALAJ, Michal, Rozšíření mobilního knihovního katalogu smartLib o WP7 klienta. Brno, 2012. Dostupné z: http://is.muni.cz/th/359690/fi_b/. Bakalářská práce. Masarykova univerzita. Vedoucí práce Mgr. Jonáš Ševčík. [8] FLANAGAN, David a . textitThe Ruby pro- gramming language. 1st ed. Sebastopol, CA: O’Reilly, 2008, xi, 429 p. ISBN 05-965-1617-7. [9] RUBY, Sam, David THOMAS a David Heinemeier HANSSON. Ruby on Rails: průvodce agilním vývojem webových aplikací. Vyd. 1. Brno: Computer Press, 2011, 488 s. ISBN 978-80-251-3647-8. [10] Documentation. Sinatra [online]. 2013 [cit. 2013-03-15]. Dostupné z: http://www.sinatrarb.com/intro.html [11] The Elegant Ruby Web Framework. Padrino [online]. 2013 [cit. 2013-03-15]. Dostupné z: http://www.padrinorb.com/

70 9. Závěr

[12] GitHub. CrunchBase [online]. 2013 [cit. 2013-03-15]. Dostupné z: http://www.crunchbase.com/company/github

[13] Bundler. In: GemBundler [online]. 2013 [cit. 2013-03-16]. Dostupné z: http://gembundler.com/#use-bundler

[14] Rack. In: RubyDoc [online]. 2013 [cit. 2013-03-16]. Dostupné z: http://rack.github.com/

[15] RUBYDOC. Active Support – Utility classes and Ruby extensions from Rails. In: RubyDoc [online]. 2013 [cit. 2013-03-24]. Dostupné z: http://rubydoc.info/gems/activesupport/3.2.13/frames

[16] RUBYFORCE. Documencation for Sequel [online]. 2013 [cit. 2013-03-24]. Dostupné z: http://sequel.rubyforge.org/documentation.html

[17] RubyForge. RUBYFORGE. RAKE – Ruby Make [online]. 2013 [cit. 2013-03-24]. Dostupné z: http://rake.rubyforge.org/

[18] Elasticsearch. Elasticsearch [online]. 2013 [cit. 2013-03-24]. Dostupné z: http://www.elasticsearch.org/

[19] Introduction to MongoDB. MONGODB. MongoDB [online]. 2013 [cit. 2013-03-25]. Dostupné z: http://www.mongodb.org/about/introduction/

[20] Mongoid. MONGOID. Mongoid [online]. 2013 [cit. 2013-03-25]. Dostupné z: http://mongoid.org/en/mongoid/index.html

[21] Embedding. In: MongoDB [online]. 2013 [cit. 2013-03-25]. Dostupné z: http://docs.mongodb.org/manual/core/data-modeling/#data-model- ing-embedding

[22] Referencing. In: MongoDB [online]. 2013 [cit. 2013-03-25]. Dostupné z: http://docs.mongodb.org/manual/core/data-modeling/#data-model- ing-referencing

[23] MongoDB Manual: Data Modeling Considerations for MongoDB Ap- plications. In: MongoDB [online]. 2013 [cit. 2013-04-02]. Dostupné z: http://docs.mongodb.org/manual/core/data-modeling/

[24] Get. In: ElasticSearch [online]. 2013 [cit. 2013-04-03]. Dostupné z: http://www.elasticsearch.org/guide/reference/api/get/

[25] Boost. In: ElasticSearch [online]. 2013 [cit. 2013-04-03]. Dostupné z: http://www.elasticsearch.org/guide/reference/mapping/boost-field/

71 9. Závěr

[26] Github Has Surpassed Sourceforge and Google Code in Popu- larity. In: ReadWrite [online]. 2011 [cit. 2013-04-06]. Dostupné z: http://readwrite.com/2011/06/02/github-has-passed-sourceforge

[27] Deploying and Building Applications. In: Open- Shift [online]. 2012 [cit. 2013-04-06]. Dostupné z: https://www.openshift.com/developers/deploying-and-building-ap- plications

[28] Faraday. RUBYGEMS. RubyGems [online]. 2012 [cit. 2013-04-06]. Dos- tupné z: https://rubygems.org/gems/faraday

[28] Úvod do architektury MVC. In: Zdroják [online]. 2009 [cit. 2013-04-20]. Dostupné z: http://www.zdrojak.cz/clanky/uvod-do-architektury-mvc/

[29] Ruby gems — what, why and how. In: RubyLearn- ing Blog [online]. 2010 [cit. 2013-04-20]. Dostupné z: http://rubylearning.com/blog/2010/12/14/ruby-gems -%E2%80%94- -what-why-and-how/

[30] Routes. In: Sinatra [online]. 2011 [cit. 2013-04-24]. Dostupné z: http://www.sinatrarb.com/intro.html#Routes

[31] Wildcard query. In: ElasticSearch [online]. 2013 [cit. 2013-04-25]. Dos- tupné z: http://www.elasticsearch.org/guide/reference/query-dsl/wild- card-query/

[32] Bootstrap. Bootstrap [online]. 2013 [cit. 2013-05-19]. Dostupné z: https://github.com/twitter/bootstrap

[33] Saas. Saas [online]. 2013 [cit. 2013-05-19]. Dostupné z: http://sass- -lang.com/

[34] JQuery API. jQuery [online]. 2013 [cit. 2013-05-19]. Dostupné z: http://api.jquery.com/

[35] KUC, Rafal a Marek ROGOZIN’SKI. ElasticSearch Server: Create a fast, scalable, and flexible search solution with the emerging open source search server, ElasticSearch. Oxford, United Kingdom: Packt Publishing, 2013, 488 s. ISBN 1849518440.

[36] HARRIS, Alan a Konstantin HAASE. Sinatra: up and running. Se- bastopol, CA: Oreilly, 2012, xi, 103 p. ISBN 14-493-0423-0.

72