Query » Historie » Verze 11
Jakub Jirůtka, 2013-04-21 16:05
opraveny názvy paremtrů pro stránkování
1 | 1 | Jakub Jirůtka | h1. Vyhledávání |
---|---|---|---|
2 | 1 | Jakub Jirůtka | |
3 | 2 | Jakub Jirůtka | {{>toc}} |
4 | 1 | Jakub Jirůtka | |
5 | 2 | Jakub Jirůtka | Komplexní podpora dotazování tvoří jednu ze základních funkcionalit databází. Oproti tomu většina běžných RESTových služeb nenabízí moc silné prostředky pro dotazování a omezuje se pouze na triviální předdefinované dotazy, příp. fulltextové vyhledávání. Ovšem mají-li webové služby IS(informačního systému) sloužit aplikacím jako přímý ^1^ zdroj dat, tak je komplexnější podpora vyhledávání prakticky nezbytná. |
6 | 1 | Jakub Jirůtka | |
7 | 1 | Jakub Jirůtka | |
8 | 2 | Jakub Jirůtka | h2. Předdefinované dotazy |
9 | 1 | Jakub Jirůtka | |
10 | 2 | Jakub Jirůtka | Všechny zdroje s parametrem v URI(Uniform Resource Identifier) jsou v podstatě předdefinované vyhledávací dotazy. Kupříkladu "/units/18000":https://kosapi.fit.cvut.cz/api/3/units/18000/ vyhledá _organizační jednotku_ s kódem _18000_. Na pozadí dojde k vygenerování _SELECTu_ nad tabulkou nákladových středisek, kde kód střediska je rovný 18000. To je poměrně triviální dotaz. Trochu složitější se skrývá například za "/programmes/MI/courses":https://kosapi.fit.cvut.cz/api/3/programmes/MI/courses, který vyhledá všechny _předměty_ patřící pod _studijní program_ s kódem _MI_. Zde se vygeneruje polospojení nad programy, spojovou tabulkou a předměty, kde program má kód rovný MI. |
11 | 1 | Jakub Jirůtka | |
12 | 2 | Jakub Jirůtka | Omezení takovýchto dotazů jsou zjevná. Co když potřebujeme například vyhledat všechny předměty, které se vyučují v zimním semestru, zajišťuje je Katedra softwarového inženýrství FIT a jejich název obsahuje slovo „prog“? Tady už potřebujeme nějaký dotazovací jazyk, který nám umožní kombinovat podmínky. |
13 | 1 | Jakub Jirůtka | |
14 | 2 | Jakub Jirůtka | |
15 | 1 | Jakub Jirůtka | h2. RSQL |
16 | 1 | Jakub Jirůtka | |
17 | 1 | Jakub Jirůtka | *UPOZORNĚNÍ: Integrace RSQL ještě není úplně dokončená, takže pro některé zdroje a konkrétní atributy nemusí fungovat správně!* |
18 | 1 | Jakub Jirůtka | |
19 | 9 | Jakub Jirůtka | RESTful Service Query Language (RSQL) je dotazovací jazyk a knihovna, jež jsem vyvinul pro KOSapi, která umožňuje vyhledávat záznamy (Atom Entry) podle jejich strukturovaných elementů (atributů) v Atom Content. Všechny zdroje KOSapi jsou koncipované tak, že Atom elementy využívají pouze pro metadata a vlastní data z KOSu jsou obsažená v Atom Content ve strukturované podobě (závisí na _Content-Type_, výchozí je XML(Extensible Markup Language)). RSQL(RESTful Service Query Language) dotazy se v KOSapi překládají na SQL(Structured Query Language) dotazy do KOSu. |
20 | 1 | Jakub Jirůtka | |
21 | 7 | Jakub Jirůtka | Inspiroval jsem se "Feed Item Query Language":http://tools.ietf.org/html/draft-nottingham-atompub-fiql-00 (FIQL), což je IETF(Internet Engineering Task Force) návrh dotazovacího jazyka určeného (pouze) pro vyhledávání záznamů podle „metadat“ v Atom Entry. Syntaxe FIQL(Feed Item Query Language) je výhodná svým prvoplánovým určením pro zápis v URI(Uniform Resource Identifier), díky čemuž ji není potřeba zakódovávat. Na druhou stranu je tím poněkud neobvyklá a ne příliš intuitivní. Jelikož jsem si stejně musel napsat vlastní parser, rozhodl jsem se tuto syntaxi využít a rozšířit ji ještě o alternativní zápis. |
22 | 1 | Jakub Jirůtka | |
23 | 7 | Jakub Jirůtka | Proč jsem vlastně vyvíjel vlastní řešení a nevyužil nějaké standardizované? Důvod je prostý, žádné takové kupodivu zatím neexistuje nebo jsem ho nenašel. Tedy kromě standardu "Open Data Protocol":http://www.odata.org, který mimo jiné zahrnuje komplexní podporu pro dotazování. Ovšem využití OData pro KOSapi jsem z několika důvodů zavrhl a vzhledem k tomu, že podpora vyhledávání je jeho „inherentní“ součástí, tak mi její _samostatné_ využití nepřišlo přínosné. |
24 | 1 | Jakub Jirůtka | |
25 | 7 | Jakub Jirůtka | |
26 | 8 | Jakub Jirůtka | h3. Gramatika a sémantika |
27 | 1 | Jakub Jirůtka | |
28 | 9 | Jakub Jirůtka | RSQL(RESTful Service Query Language) výraz se skládá z jednoho či více _kritérií_, které se spojují logickými (Booleovskými) operátory. |
29 | 1 | Jakub Jirůtka | |
30 | 8 | Jakub Jirůtka | expression = [ "(" ], |
31 | 8 | Jakub Jirůtka | ( constraint | expression ), |
32 | 8 | Jakub Jirůtka | [ logical-operator, ( constraint | expression ) ], |
33 | 8 | Jakub Jirůtka | [ ")" ]; |
34 | 1 | Jakub Jirůtka | |
35 | 8 | Jakub Jirůtka | Logické operátory jsou: |
36 | 8 | Jakub Jirůtka | * AND : "@;@" podle FIQL, nebo alternativní "@ and @" |
37 | 8 | Jakub Jirůtka | * OR : "@,@" podle FIQL, nebo alternativní "@ or @" |
38 | 1 | Jakub Jirůtka | |
39 | 8 | Jakub Jirůtka | logical-operator = ";" | " and " | "," | " or "; |
40 | 1 | Jakub Jirůtka | |
41 | 8 | Jakub Jirůtka | Operátor AND má standardně přednost, tj. všechny operátory OR se vyhodnocují až po něm. Toto chování lze samozřejmě změnit pomocí uzávorkování výrazů. |
42 | 3 | Jakub Jirůtka | |
43 | 1 | Jakub Jirůtka | |
44 | 8 | Jakub Jirůtka | Kritérium se skládá ze selektoru, který identifikuje element v Atom Content, operátoru porovnání a argumentu. |
45 | 1 | Jakub Jirůtka | |
46 | 8 | Jakub Jirůtka | constraint = selector, comparison-operator, argument; |
47 | 1 | Jakub Jirůtka | |
48 | 8 | Jakub Jirůtka | Operátory porovnání jsou: |
49 | 8 | Jakub Jirůtka | |
50 | 1 | Jakub Jirůtka | |_. Název |_. FIQL |_. Alternativní |_. Platné datové typy | |
51 | 1 | Jakub Jirůtka | | rovná se | @==@ | @=@ | textový řetězec, číslo, datum, výčtový typ, XLink | |
52 | 1 | Jakub Jirůtka | | nerovná se | @!=@ | @!=@ | textový řetězec, číslo, datum, výčtový typ, XLink | |
53 | 1 | Jakub Jirůtka | | menší než | @=lt=@ | @<@ | číslo, datum | |
54 | 8 | Jakub Jirůtka | | menší nebo rovno | @=le=@ | @<=@ | číslo, datum | |
55 | 1 | Jakub Jirůtka | | větší než | @=gt=@ | @>@ | číslo, datum | |
56 | 1 | Jakub Jirůtka | | větší nebo rovno | @=ge=@ | @>=@ | číslo, datum | |
57 | 1 | Jakub Jirůtka | |
58 | 8 | Jakub Jirůtka | comparison-operator = "==" | "=" | "!=" | "=lt=" | "<" | "=le=" | "<=" | "=gt=" | ">" | "=ge=" | ">="; |
59 | 8 | Jakub Jirůtka | |
60 | 8 | Jakub Jirůtka | Selektor odpovídá názvu elementu v Atom Content nebo jeho relativní cestě, pakliže je zanořený. Může také obsahovat [[Query#„Dereference“-vazeb-aka-JOIN|„dereferenci“]] XLink vazby pomocí tečkové notace. |
61 | 8 | Jakub Jirůtka | |
62 | 8 | Jakub Jirůtka | selector = identifier, { ("/" | "."), identifier }; |
63 | 8 | Jakub Jirůtka | identifier = ? ["a"-"z","A"-"Z","_","0"-"9","-"]+ ? |
64 | 8 | Jakub Jirůtka | |
65 | 8 | Jakub Jirůtka | Argumenty mohou být dvojího typu. Libovolná sekvence znaků uzavřená mezi jednoduché či dvojité uvozovky, nebo sekvence znaků bez mezer, kulatých závorek, čárek a středníků. |
66 | 8 | Jakub Jirůtka | |
67 | 8 | Jakub Jirůtka | argument = arg_ws | arg_sq | arg_dq; |
68 | 8 | Jakub Jirůtka | argument-ws = ? ( ~["(", ")", ";", ",", " "] )+ ?; |
69 | 8 | Jakub Jirůtka | argument-sq = ? "'" ~["'"]+ "'" ?; |
70 | 8 | Jakub Jirůtka | argument-dq = ? "\"" ~["\""]+ "\"" ?; |
71 | 8 | Jakub Jirůtka | |
72 | 1 | Jakub Jirůtka | Porovnávání textových řetězců nezohledňuje velikost písmen (je _case insensitive_). Pokud je URL(Uniform Resource Locator) parametr [[URLParameters#multilang|multilang]] nastaven na @true@, tak zohledňuje texty v obou jazycích (neplatí pro [[Query#„Dereference“-vazeb-aka-JOIN|dereferencované]] atributy). V opačném případě vyhledává pouze ve zvoleném jazyce (podle Accept-Language, nebo [[URLParameters#lang|lang]]). |
73 | 1 | Jakub Jirůtka | |
74 | 1 | Jakub Jirůtka | Při porovnávání řetězců lze využít i _divoké karty_ a hledat pomocí nich i jen podle části řetězce. Způsob zápisu je stejný jako v SQL _LIKE_, pouze s tím rozdílem, že místo @%@ se zde používá @*@. Například podmínce @name=prog_am*@ vyhoví všechny předměty, jejichž název začíná na „prog“, následuje jeden libovolný znak, pak „am“ a cokoli (opět bez ohledu na velikost písmen). |
75 | 5 | Jakub Jirůtka | |
76 | 1 | Jakub Jirůtka | V případě elementů, které reprezentují výčtový typ, je nutné jako argument uvádět _výčtový název_ (enum), nikoli jeho lokalizovaný popis. |
77 | 1 | Jakub Jirůtka | |
78 | 1 | Jakub Jirůtka | Argumentem pro XLink je identifikátor záznamu použitý v URI(Uniform Resource Identifier), což většinou bývá kód, nebo ID. |
79 | 5 | Jakub Jirůtka | |
80 | 5 | Jakub Jirůtka | h3. „Dereference“ vazeb (aka JOIN) |
81 | 5 | Jakub Jirůtka | |
82 | 5 | Jakub Jirůtka | V dotazu je možné přistupovat i k atributům _odkazovaných_ zdrojů (na které vede XLink) pomocí tzv. „dereference“. Jinak řečeno umožňuje zápis podmínky s _implicitním_ spojením (_JOINem_) entit, mezi kterými existuje explicitní průchozí vazba (obdobně jako v HQL(Hibernate Query Language)). Vazbami se prochází pomocí tečkové notace a je možné i zanořování. Kupříkladu @unit.unitType==FACULTY@ vybere všechny záznamy, které jsou ve vztahu s organizační jednotkou _typu_ fakulta. Na pozadí dojde k vygenerování polospojení (_LEFT JOIN_) tabulky předmětů s tabulkou nákladových středisek a podmínky unitType=FACULTY. |
83 | 5 | Jakub Jirůtka | |
84 | 5 | Jakub Jirůtka | Mějte prosím na paměti, že tyto dotazy mohou generovat velkou zátěž databáze. Jakmile bude KOSapi napojené přímo na KOS, bude tento problém dost citlivý. Používejte je proto obezřetně a vyhýbejte se zbytečně neefektivním dotazům. Z těchto důvodů jsem také omezil maximální počet implicitních _JOINů_ pro dotaz na 3. |
85 | 1 | Jakub Jirůtka | |
86 | 1 | Jakub Jirůtka | |
87 | 1 | Jakub Jirůtka | h3. Parametry |
88 | 1 | Jakub Jirůtka | |
89 | 11 | Jakub Jirůtka | RSQL(RESTful Service Query Language) výraz se zapisuje do URL(Uniform Resource Locator) parametru [[URLParameters#query|query]] a je možné ho efektivně kombinovat s parametry [[URLParameters#offset|offset]], [[URLParameters#limit|limit]] a [[URLParameters#orderBy|orderBy]]. |
90 | 1 | Jakub Jirůtka | |
91 | 7 | Jakub Jirůtka | |
92 | 1 | Jakub Jirůtka | h3. Příklady |
93 | 1 | Jakub Jirůtka | |
94 | 10 | Jakub Jirůtka | * "<code>/courses?query=name==*prog*</code>":/api/3/courses?query=name=%2Aprog%2A - vrátí předměty, jejichž název obsahuje „prog“ |
95 | 10 | Jakub Jirůtka | * "<code>/courses?query=name=='programování v*'</code>":/api/3/courses?query=name==%27programov%C3%A1n%C3%AD%20v*%27 - vrátí předměty, jejichž název začíná na „programování v“ |
96 | 10 | Jakub Jirůtka | * "<code>/courses?query=credits>5</code>":/api/3/courses?query=credits%3E5 - vrátí předměty za více než 5 kreditů |
97 | 10 | Jakub Jirůtka | * "<code>/courses?query=season==WINTER;(completion==CLFD_CREDIT,completion==CREDIT)</code>":/api/3/courses?query=season==WINTER;%28completion==CLFD_CREDIT,completion==CREDIT%29 - vrátí předměty, které se vyučují v zimním semestru a jsou zakončené klasifikovaným zápočtem nebo zápočtem |
98 | 10 | Jakub Jirůtka | * "<code>/courses?query=department.unitType==FACULTY</code>":/api/3/courses?query=department.unitType==FACULTY - vrátí předměty, které zajišťuje přímo libovolná fakulta (tzn. organizační jednotka typu fakulta) |
99 | 11 | Jakub Jirůtka | * "<code>/teachers?query=extern==true&orderBy=lastName&limit=50</code>":/api/3/teachers?query=extern==true&orderBy=lastName&limit=50 - vrátí vyučující externisty, seřadí je podle příjmení a výstup omezí na max. 50 záznamů |
100 | 4 | Jakub Jirůtka | |
101 | 4 | Jakub Jirůtka | |
102 | 1 | Jakub Jirůtka | h3. Pár slov k implementaci |
103 | 6 | Jakub Jirůtka | |
104 | 8 | Jakub Jirůtka | RSQL(RESTful Service Query Language) jsem vyvinul speciálně pro KOSapi, ale jeho návrh a implementace je dostatečně obecná i pro použití v jiných RESTových službách postavených nad relační databází. Skládá se ze dvou navazujících knihoven. |
105 | 1 | Jakub Jirůtka | |
106 | 8 | Jakub Jirůtka | První je _RSQL-parser_, který provádí lexikální analýzu, parsování a sestavení objektové reprezentace zadaného RSQL(RESTful Service Query Language) výrazu. Součástí je gramatika zapsaná v "JavaCC":http://javacc.java.net/, ze které je vygenerován vlastní parser. |
107 | 6 | Jakub Jirůtka | |
108 | 7 | Jakub Jirůtka | Druhou knihovnou je _RSQL-hibernate_. Ta zajišťuje převod dotazu na "Hibernate Criteria Query":http://docs.jboss.org/hibernate/core/3.5/reference/en/html/querycriteria.html (objektová reprezentace HQL(Hibernate Query Language), resp. SQL(Structured Query Language) dotazu), z něhož se následně generuje SQL(Structured Query Language) dotaz do relační databáze. V tomto procesu hrají hlavní roli _RSQLCriteriaBuilder_, sada _CriterionBuilders_ a _Mapper_. _CriteriaBuilder_ prochází strom výrazu, generuje _Criterion_ pro logické výrazy (AND, OR) a deleguje _kritéria_ (porovnání) na odpovídající _CriterionBuilder_. Ty má připravené v kolekci, jíž iteruje dokud nenalezne takový, který umí obsloužit daný selektor a operátor. Kromě obecného _CriterionBuilder_ obsahuje například takový, který umí vytvořit _Criterion_ pro atribut vazby (i s NaturalID), multijazyčný text, selektor s implicitním JOINem, příp. speciální pro nestandardní entity. _Mapper_ zajišťuje mapování _selektorů_ (názvů v XML, příp. cest) na názvy příslušných _atributů_ v entitách. Většina odpovídá 1:1, ale v některých případech je nutné použít přemapování (např. multijazyčné texty). |
109 | 8 | Jakub Jirůtka | |
110 | 8 | Jakub Jirůtka | Obě knihovny jsem uvolnil pod licencí LGPL a umístil na GitHub - "RSQL-parser":https://github.com/jirutka/rsql-parser a "RSQL-hibernate":https://github.com/jirutka/rsql-hibernate. |
111 | 2 | Jakub Jirůtka | |
112 | 2 | Jakub Jirůtka | __ |
113 | 2 | Jakub Jirůtka | ^1^ To znamená, že aplikace si nebudou uchovávat lokální kopii celé ani části databáze IS (cache se tím nevylučuje), ale budou je přímo získávat z webové služby. |