Dopyt na Couchbase so zobrazeniami MapReduce

1. Prehľad

V tomto tutoriáli predstavíme niekoľko jednoduchých zobrazení MapReduce a ukážeme, ako ich dotazovať pomocou Couchbase Java SDK.

2. Závislosť od Maven

Ak chcete pracovať s Couchbase v projekte Maven, importujte Couchbase SDK do svojho pom.xml:

 com.couchbase.client java-client 2.4.0 

Najnovšiu verziu nájdete na serveri Maven Central.

3. MapReduce Views

V Couchbase je zobrazenie MapReduce typ indexu, ktorý je možné použiť na dopytovanie dátového segmentu. Definuje sa pomocou JavaScriptu mapa funkcia a voliteľné zmenšiť funkcie.

3.1. The mapa Funkcia

The mapa funkcia je spustená proti každému dokumentu naraz. Po vytvorení zobrazenia sa zobrazí ikona mapa funkcia sa spustí jedenkrát proti každému dokumentu v segmente a výsledky sa uložia do segmentu.

Po vytvorení zobrazenia sa zobrazí ikona mapa funkcia je spustená iba proti novo vloženým alebo aktualizovaným dokumentom s cieľom postupnej aktualizácie zobrazenia.

Pretože mapa výsledky funkcie sú uložené v dátovom bloku, dotazy proti zobrazeniu vykazujú nízku latenciu.

Pozrime sa na príklad a mapa funkcia, ktorá vytvorí index na názov pole všetkých dokumentov v segmente, ktorých typu pole sa rovná „StudentGrade“:

function (doc, meta) {if (doc.type == "StudentGrade" && doc.name) {emit (doc.name, null); }}

The vydávať funkcia povie Couchbase, ktoré dátové polia sa majú uložiť do indexového kľúča (prvý parameter) a akú hodnotu (druhý parameter) priradiť k indexovanému dokumentu.

V takom prípade ukladáme iba dokument názov vlastnosť v indexovom kľúči. A keďže nemáme záujem priraďovať ku každému záznamu žiadnu konkrétnu hodnotu, sme úspešní nulový ako hodnotový parameter.

Keď Couchbase spracováva zobrazenie, vytvára index kľúčov, ktoré emituje mapa funkcia, ktorá spája každý kľúč so všetkými dokumentmi, pre ktoré bol tento kľúč emitovaný.

Napríklad ak tri dokumenty majú názov vlastnosť nastavená na "John Doe", potom indexový kľúč "John Doe" by boli spojené s týmito tromi dokumentmi.

3.2. The zmenšiť Funkcia

The zmenšiť funkcia sa používa na vykonávanie agregovaných výpočtov pomocou výsledkov a mapa funkcie. Couchbase Admin UI poskytuje jednoduchý spôsob použitia zabudovaného zmenšiť funkcie „_Count“, „_sum“, a „_Stats“, tvojmu mapa funkcie.

Môžete napísať aj svoj vlastný zmenšiť funkcie pre zložitejšie agregácie. Uvidíme príklady použitia zabudovaného zmenšiť funkcie neskôr v návode.

4. Práca so zobrazeniami a dotazmi

4.1. Organizácia pohľadov

Pohľady sú usporiadané do jedného alebo viacerých dizajnových dokumentov na segment. Teoreticky neexistuje nijaké obmedzenie počtu zobrazení na dokument návrhu. Pre optimálny výkon sa však navrhuje, aby ste každý dokument o dizajne obmedzili na menej ako desať zobrazení.

Pri prvom vytvorení pohľadu v dokumente dizajnu ho Couchbase označí ako rozvoja vyhliadka. Môžete spustiť dotazy proti a rozvoja jeho funkčnosť. Akonáhle ste spokojní s výhľadom, mali by ste zverejniť dokument o dizajne a pohľad sa stane a výroba vyhliadka.

4.2. Tvorba dotazov

Ak chcete zostaviť dopyt proti pohľadu Couchbase, musíte zadať názov jeho návrhového dokumentu a názov pohľadu, aby ste vytvorili ViewQuery objekt:

ViewQuery query = ViewQuery.from ("design-document-name", "view-name");

Po vykonaní tento dopyt vráti všetky riadky zobrazenia. V ďalších častiach si ukážeme, ako obmedziť množinu výsledkov na základe kľúčových hodnôt.

Na zostavenie dotazu proti vývojovému pohľadu môžete použiť znak vývoj () metóda pri vytváraní dotazu:

ViewQuery query = ViewQuery.from ("design-doc-name", "view-name"). Development ();

4.3. Vykonanie dotazu

Keď už máme ViewQuery objektu, môžeme vykonať dopyt a získať a ViewResult:

ViewResult result = bucket.query (dopyt);

4.4. Spracovanie výsledkov dotazu

A teraz, keď máme ViewResult, môžeme iterovať cez riadky, aby sme získali ID a / alebo obsah dokumentu:

pre (riadok ViewRow: result.allRows ()) {JsonDocument doc = row.document (); Reťazec id = doc.id (); Reťazec json = doc.content (). ToString (); }

5. Ukážka aplikácie

V zostávajúcej časti tohto tutoriálu napíšeme zobrazenia a dotazy MapReduce pre skupinu dokumentov známok študentov, ktoré majú nasledujúci formát, pričom známky sú obmedzené na rozsah 0 až 100:

{"type": "StudentGrade", "name": "John Doe", "course": "História", "hodiny": 3, "známka": 95}

Tieto dokumenty uložíme do „baeldung-tutorial„Segment a všetky zobrazenia v dokumente dizajnu s názvom“študentské triedy. “ Pozrime sa na kód potrebný na otvorenie segmentu, aby sme ho mohli dopytovať:

Vedro vedro = CouchbaseCluster.create ("127.0.0.1") .openBucket ("baeldung-tutorial");

6. Dotazy na presnú zhodu

Predpokladajme, že chcete nájsť všetky známky študentov pre konkrétny kurz alebo skupinu kurzov. Napíšme pohľad s názvom „findByCourse”Pomocou nasledujúceho mapa funkcia:

function (doc, meta) {if (doc.type == "StudentGrade" && doc.course && doc.grade) {emit (doc.course, null); }}

Upozorňujeme, že v tomto jednoduchom pohľade musíme emitovať iba znak samozrejme lúka.

6.1. Zhoda na jednom kľúči

Na nájdenie všetkých známok z kurzu História používame program kľúč metóda na náš základný dotaz:

ViewQuery query = ViewQuery.from ("studentGrades", "findByCourse"). Key ("História");

6.2. Zhoda na viacerých klávesoch

Ak chcete nájsť všetky známky pre kurzy matematiky a prírodných vied, môžete použiť kľúče metódu na základný dotaz a odovzdať mu pole kľúčových hodnôt:

ViewQuery query = ViewQuery .from ("studentGrades", "findByCourse") .keys (JsonArray.from ("Math", "Science"));

7. Rozsahové dotazy

Aby sme mohli vyhľadávať dokumenty obsahujúce rozsah hodnôt pre jedno alebo viac polí, potrebujeme pohľad, ktorý vyžaruje polia, ktoré nás zaujímajú, a musíme určiť dolnú a / alebo hornú hranicu dotazu.

Poďme sa pozrieť na to, ako vykonávať dotazy na rozsah zahŕňajúce jedno pole a viac polí.

7.1. Dotazy týkajúce sa jedného poľa

Ak chcete nájsť všetky dokumenty s rozsahom stupeň hodnoty bez ohľadu na hodnotu samozrejme pole, potrebujeme pohľad, ktorý vyžaruje iba stupeň lúka. Poďme napísať mapa funkcia pre „findByGrade" vyhliadka:

function (doc, meta) {if (doc.type == "StudentGrade" && doc.grade) {emit (doc.grade, null); }}

Poďme napísať dotaz v Jave pomocou tohto zobrazenia, aby sme našli všetky stupne ekvivalentné stupňu písmen „B“ (80 až 89 vrátane):

ViewQuery query = ViewQuery.from ("studentGrades", "findByGrade") .startKey (80) .endKey (89) .inclusiveEnd (true);

Upozorňujeme, že s hodnotou začiatočného kľúča v dotaze na rozsah sa vždy zaobchádza ako s inkluzívnym.

A ak je známe, že všetky stupne sú celé čísla, potom nasledujúci dotaz prinesie rovnaké výsledky:

ViewQuery query = ViewQuery.from ("studentGrades", "findByGrade") .startKey (80) .endKey (90) .inclusiveEnd (false);

Ak chcete nájsť všetky stupne „A“ (90 a vyššie), stačí zadať dolnú hranicu:

ViewQuery query = ViewQuery .from ("studentGrades", "findByGrade") .startKey (90);

A aby sme našli všetky zlyhávajúce stupne (pod 60), stačí zadať hornú hranicu:

ViewQuery query = ViewQuery .from ("studentGrades", "findByGrade") .endKey (60) .inclusiveEnd (false);

7.2. Dotazy týkajúce sa viacerých polí

Teraz predpokladajme, že chceme nájsť všetkých študentov v konkrétnom kurze, ktorého známka spadá do určitého rozsahu. Tento dopyt vyžaduje nové zobrazenie, ktoré vyžaruje samozrejme a stupeň polia.

Pri zobrazení viacerých polí je každý indexový kľúč emitovaný ako pole hodnôt. Pretože náš dopyt obsahuje pevnú hodnotu pre samozrejme a rad stupeň hodnoty, napíšeme funkciu mapy tak, aby vydávala každý kľúč ako pole formulára [samozrejme, stupeň].

Pozrime sa na mapa funkcia pre zobrazenie “findByCourseAndGrade“:

function (doc, meta) {if (doc.type == "StudentGrade" && doc.course && doc.grade) {emit ([doc.course, doc.grade], null); }}

Keď je toto zobrazenie vyplnené v Couchbase, položky registra sú zoradené podľa samozrejme a stupeň. Tu je podmnožina klávesov vfindByCourseAndGrade”Zobrazenie zobrazené v ich prirodzenom poradí zoradenia:

[„História“, 80] [„História“, 90] [„História“, 94] [„Matematika“, 82] [„Matematika“, 88] [„Matematika“, 97] [„Veda“, 78] [ „Science“, 86] [„Science“, 92]

Pretože kľúče v tomto zobrazení sú polia, pri určovaní dolnej a hornej hranice dotazu rozsahu proti tomuto zobrazeniu by ste tiež použili polia tohto formátu.

To znamená, že ak chcete nájsť všetkých študentov, ktorí v matematickom kurze dostali známku „B“ (80 až 89), stanovili by ste dolnú hranicu:

[„Matematika“, 80]

a horná hranica:

[„Matematika“, 89]

Poďme napísať dotaz na rozsah v Jave:

ViewQuery query = ViewQuery .from ("studentGrades", "findByCourseAndGrade") .startKey (JsonArray.from ("Math", 80)) .endKey (JsonArray.from ("Math", 89)) .inclusiveEnd (true);

Ak by sme chceli nájsť pre všetkých študentov, ktorí obdržali známku “A” (90 a viac) z matematiky, napísali by sme:

ViewQuery query = ViewQuery .from ("studentGrades", "findByCourseAndGrade") .startKey (JsonArray.from ("Math", 90)) .endKey (JsonArray.from ("Math", 100));

Upozorňujeme, že pretože fixujeme hodnotu kurzu na „Matematika“, Musíme zahrnúť hornú hranicu s najvyššou možnou hodnotou stupeň hodnotu. V opačnom prípade by naša sada výsledkov zahŕňala aj všetky dokumenty, ktorých samozrejme hodnota je lexikograficky väčšia ako „Matematika“.

A nájsť všetky zlyhávajúce matematické stupne (pod 60):

ViewQuery query = ViewQuery .from ("studentGrades", "findByCourseAndGrade") .startKey (JsonArray.from ("Math", 0)) .endKey (JsonArray.from ("Math", 60)) .inclusiveEnd (false);

Rovnako ako v predchádzajúcom príklade, musíme určiť dolnú hranicu s najnižšou možnou známkou. V opačnom prípade by naša sada výsledkov zahŕňala aj všetky stupne, kde samozrejme hodnota je lexikograficky menšia ako „Matematika“.

Nakoniec, aby ste našli päť najvyšších matematických stupňov (okrem akýchkoľvek väzieb), môžete povedať Couchbase, aby vykonal zostupné triedenie a obmedzil veľkosť výsledkovej sady:

ViewQuery query = ViewQuery .from ("studentGrades", "findByCourseAndGrade") .descending () .startKey (JsonArray.from ("Math", 100)) .endKey (JsonArray.from ("Math", 0)) .inclusiveEnd ( pravda) .limit (5);

Upozorňujeme, že pri zostupnom triedení sa startKey a endKey hodnoty sú obrátené, pretože Couchbase použije triedenie skôr, ako použije limit.

8. Súhrnné dotazy

Hlavnou výhodou zobrazení MapReduce je, že sú vysoko efektívne na vykonávanie agregovaných dotazov proti veľkým množinám údajov. Napríklad v našom súbore údajov o známkach študentov môžeme ľahko vypočítať nasledujúce agregáty:

  • počet študentov v každom kurze
  • súčet kreditných hodín pre každého študenta
  • priemer známok pre každého študenta vo všetkých kurzoch

Vytvorme zobrazenie a dopyt pre každý z týchto výpočtov pomocou vstavaného nástroja zmenšiť funkcie.

8.1. Pomocou count () Funkcia

Najprv napíšeme mapa funkcia pre zobrazenie počítať počet študentov v každom kurze:

function (doc, meta) {if (doc.type == "StudentGrade" && doc.course && doc.name) {emit ([doc.course, doc.name], null); }}

Tento pohľad nazveme „countStudentsByCourse”A určiť, že sa má používať vstavaný „_Count“ funkcie. A keďže vykonávame iba jednoduchý počet, stále môžeme emitovať nulový ako hodnota pre každú položku.

Ak chcete spočítať počet študentov v každom kurze:

ViewQuery query = ViewQuery .from ("studentGrades", "countStudentsByCourse") .reduce () .groupLevel (1);

Extrakcia údajov z agregovaných dotazov sa líši od toho, čo sme videli až do tohto okamihu. Namiesto extrakcie zodpovedajúceho dokumentu Couchbase pre každý riadok vo výsledku extrahujeme agregované kľúče a výsledky.

Spustíme dotaz a extrahujeme počty do a java.util.Map:

ViewResult result = bucket.query (dopyt); Mapa numStudentsByCourse = nový HashMap (); pre (riadok ViewRow: result.allRows ()) {JsonArray keyArray = (JsonArray) row.key (); Kurz reťazca = keyArray.getString (0); long count = Long.valueOf (row.value (). toString ()); numStudentsByCourse.put (kurz, počet); }

8.2. Pomocou suma () Funkcia

Ďalej napíšeme pohľad, ktorý počíta súčet pokusných hodín kreditu každého študenta. Tento pohľad nazveme „sumHoursByStudent”A určí, že sa má používať vstavaný modul „_Sum“ funkcia:

function (doc, meta) {if (doc.type == "StudentGrade" && doc.name && doc.course && doc.hours) {emit ([doc.name, doc.course], doc.hours); }}

Upozorňujeme, že pri použití „_Sum“ funkcie, musíme vydávať hodnota, ktorá sa má sčítať - v tomto prípade počet kreditov - pre každý záznam.

Poďme napísať dotaz a nájdeme celkový počet kreditov pre každého študenta:

ViewQuery query = ViewQuery .from ("studentGrades", "sumCreditsByStudent") .reduce () .groupLevel (1);

A teraz poďme spustiť dotaz a extrahovať súhrnné sumy do a java.util.Map:

ViewResult result = bucket.query (dopyt); Hodiny na mapeByStudent = nový HashMap (); pre (riadok ViewRow: result.allRows ()) {názov reťazca = (reťazec) row.key (); long sum = Long.valueOf (row.value (). toString ()); hoursByStudent.put (meno, suma); }

8.3. Výpočet priemerov bodu na konci

Predpokladajme, že chceme vypočítať priemer každého študenta (GPA) vo všetkých kurzoch pomocou konvenčnej stupnice skóre na základe získaných známok a počtu kreditných hodín, ktoré kurz stojí za to (A = 4 body za hodinu, B = 3 body za úverovú hodinu, C = 2 body za úverovú hodinu a D = 1 bod za úverovú hodinu).

Nie je vstavaný zmenšiť funkcia na výpočet priemerných hodnôt, takže na výpočet GPA spojíme výstup z dvoch zobrazení.

Už máme „SumHoursByStudent“ názor, ktorý predstavuje počet kreditných hodín, ktoré každý študent vyskúšal. Teraz potrebujeme celkový počet známok, ktoré každý študent získal.

Vytvorme pohľad s názvom „SumGradePointsByStudent“ ktorá počíta počet bodov za každý absolvovaný kurz. Použijeme zabudovaný „_Sum“ funkcie na zníženie nasledujúceho mapa funkcia:

function (doc, meta) {if (doc.type == "StudentGrade" && doc.name && doc.hours && doc.grade) {if (doc.grade> = 90) {emit (doc.name, 4 * doc .hodiny); } else if (doc.grade> = 80) {emit (doc.name, 3 * doc.hours); } else if (doc.grade> = 70) {emit (doc.name, 2 * doc.hours); } else if (doc.grade> = 60) {emit (doc.name, doc.hours); } else {emit (doc.name, 0); }}}

Teraz poďme dotazovať toto zobrazenie a extrahujme sumy do a java.util.Map:

ViewQuery query = ViewQuery.from ("studentGrades", "sumGradePointsByStudent") .reduce () .groupLevel (1); ViewResult result = bucket.query (dopyt); Mapa gradePointsByStudent = nový HashMap (); pre (riadok ViewRow: result.allRows ()) {kurz reťazca = (reťazec) row.key (); long sum = Long.valueOf (row.value (). toString ()); gradPointsByStudent.put (kurz, suma); }

Nakoniec tieto dve spojíme Mapas pre výpočet GPA pre každého študenta:

Výsledok mapy = nový HashMap (); pre (Entry creditHoursEntry: hoursByStudent.entrySet ()) {Názov reťazca = creditHoursEntry.getKey (); long totalHours = creditHoursEntry.getValue (); long totalGradePoints = gradePointsByStudent.get (name); result.put (name, ((float) totalGradePoints / totalHours)); }

9. Záver

Predviedli sme, ako napísať niekoľko základných zobrazení MapReduce v Couchbase a ako zostaviť a vykonať dotazy proti zobrazeniam a extrahovať výsledky.

Kód predstavený v tomto návode nájdete v projekte GitHub.

Ďalšie informácie o zobrazeniach MapReduce a o tom, ako ich môžete dopytovať v prostredí Java, sa dozviete na oficiálnej stránke dokumentácie pre vývojárov Couchbase.


$config[zx-auto] not found$config[zx-overlay] not found