A Couchbase lekérdezése MapReduce nézetekkel

1. Áttekintés

Ebben az oktatóanyagban bemutatunk néhány egyszerű MapReduce nézetet, és bemutatjuk, hogyan lehet lekérdezni őket a Couchbase Java SDK használatával.

2. Maven-függőség

A Couchbase programmal való együttműködéshez egy Maven projektben importálja a Couchbase SDK-t a saját könyvtárába pom.xml:

 com.couchbase.client java-client 2.4.0 

A legújabb verziót a Maven Central oldalon találja.

3. MapReduce Views

A Couchbase-ben a MapReduce nézet egy olyan indextípus, amely felhasználható egy adatcsoport lekérdezésére. JavaScript segítségével definiálható térkép funkció és opcionális csökkenteni funkció.

3.1. A térkép Funkció

A térkép funkció minden dokumentummal egyszer fut. A nézet létrehozásakor a térkép A függvény egyszerre fut le a vödör minden egyes dokumentuma ellen, és az eredményeket a vödörben tárolja.

A nézet létrehozása után a térkép funkció csak újonnan beillesztett vagy frissített dokumentumokon fut, a nézet fokozatos frissítése érdekében.

Mert a térkép A függvény eredményei az adattárban vannak tárolva, a nézettel szembeni lekérdezések alacsony késleltetéseket mutatnak.

Nézzünk meg egy példát a térkép függvény, amely indexet hoz létre a név a vödör összes dokumentumának mezője típus mező egyenlő „StudentGrade”:

függvény (doc, meta) {if (doc.type == "StudentGrade" && doc.name) {emit (doc.name, null); }}

A kibocsát A funkció megmondja a Couchbase-nek, hogy mely index mező (ket) tárolja az indexkulcsban (első paraméter) és milyen értéket (második paraméter) társítson az indexelt dokumentumhoz.

Ebben az esetben csak a dokumentumot tároljuk név tulajdonság az indexkulcsban. És mivel nem vagyunk érdekeltek abban, hogy minden egyes bejegyzéshez külön értéket társítsunk, átmegyünk nulla mint értékparaméter.

Amint a Couchbase feldolgozza a nézetet, létrehoz egy indexet a kulcs által kibocsátott kulcsokról térkép függvény, minden kulcsot társítva az összes olyan dokumentumhoz, amelyhez ezt a kulcsot kiadták.

Például, ha három dokumentumban szerepel a név tulajdonság beállítása "Gipsz Jakab", majd az indexkulcsot "Gipsz Jakab" ehhez a három dokumentumhoz társulna.

3.2. A csökkenteni Funkció

A csökkenteni függvény segítségével összesített számításokat végeznek az a eredményei felhasználásával térkép funkció. A Couchbase Admin felhasználói felület egyszerű módot kínál a beépített alkalmazásra csökkenteni funkciókat „_Count”, „_sum”, és „_Stats”, a térkép funkció.

A sajátját is megírhatja csökkenteni funkciók bonyolultabb összesítésekhez. Látni fogunk példákat a beépített használatára csökkenteni később az oktatóanyagban működik.

4. Munka nézetekkel és lekérdezésekkel

4.1. A nézetek rendezése

A nézetek csoportonként egy vagy több tervdokumentumba vannak rendezve. Elméletileg nincs korlátozás a tervdokumentumonkénti megtekintések számára. Az optimális teljesítmény érdekében azonban azt javasolták, hogy az egyes tervdokumentumokat tíznél kevesebb nézetre korlátozza.

Amikor először hoz létre nézetet egy tervdokumentumon belül, a Couchbase kijelöli azt a fejlődés Kilátás. Lekérdezéseket futtathat a fejlődés működésének tesztelésére. Ha elégedett a kilátással, akkor megtenné publikálni a tervdokumentumot, és a nézet a Termelés Kilátás.

4.2. Lekérdezések összeállítása

A Couchbase nézet lekérdezésének összeállításához meg kell adnia a tervdokumentum nevét és a nézet nevét egy ViewQuery tárgy:

ViewQuery lekérdezés = ViewQuery.from ("terv-dokumentum-név", "nézet-név");

A végrehajtás után ez a lekérdezés a nézet minden sorát visszaadja. A későbbi szakaszokban látni fogjuk, hogyan korlátozható az eredménykészlet a kulcsértékek alapján.

A lekérdezés fejlesztési nézet alapján történő összeállításához alkalmazhatja a fejlődés() módszer a lekérdezés létrehozásakor:

ViewQuery lekérdezés = ViewQuery.from ("design-doc-name", "view-name"). Fejlesztés ();

4.3. A lekérdezés végrehajtása

Miután megvan a ViewQuery objektumot, végrehajthatjuk a lekérdezést az a megszerzéséhez ViewResult:

ViewResult result = bucket.query (lekérdezés);

4.4. A lekérdezési eredmények feldolgozása

És most, hogy van egy ViewResult, iterálhatunk a sorok között, hogy megkapjuk a dokumentum azonosítóit és / vagy tartalmát:

for (ViewRow sor: eredmény.allRows ()) {JsonDocument doc = row.document (); Karakterlánc id = doc.id (); Karakterlánc json = doc.content (). ToString (); }

5. Minta alkalmazás

Az oktatóanyag hátralévő részében MapReduce nézeteket és lekérdezéseket írunk a következő formátumú tanulói osztályzatú dokumentumok halmazához:

{"type": "StudentGrade", "name": "John Doe", "course": "History", "hours": 3, "grade": 95}

Ezeket a dokumentumokat abaeldung-tutorial”Vödör és az összes nézet a„ elnevezésű tervdokumentumbanstudentGrades. ” Nézzük meg a csoport megnyitásához szükséges kódot, hogy lekérdezhessük:

Vödör vödör = CouchbaseCluster.create ("127.0.0.1") .openBucket ("baeldung-tutorial");

6. Pontos egyezési lekérdezések

Tegyük fel, hogy meg akarja találni az összes tanulói osztályzatot egy adott tanfolyamhoz vagy tanfolyamkészlethez. Írjunk egy nézetetfindByCourse”Az alábbiak használatával térkép funkció:

függvény (doc, meta) {if (doc.type == "StudentGrade" && doc.course && doc.grade) {emit (doc.course, null); }}

Vegye figyelembe, hogy ebben az egyszerű nézetben csak a tanfolyam terület.

6.1. Párosítás egyetlen kulcson

A Történelem tanfolyam összes osztályzatának megtalálásához alkalmazzuk a kulcs módszer az alap lekérdezésünkhöz:

ViewQuery lekérdezés = ViewQuery.from ("studentGrades", "findByCourse"). Kulcs ("History");

6.2. Egyezés több kulcson

Ha meg szeretné találni az összes osztályt a matematika és természettudományi tanfolyamok számára, alkalmazhatja a kulcsok metódust az alap lekérdezéshez, átadva neki a kulcsértékek tömbjét:

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "findByCourse") .key (JsonArray.from ("Math", "Science"));

7. Tartomány lekérdezések

Egy vagy több mező értéktartományát tartalmazó dokumentumok lekérdezéséhez szükségünk van egy nézetre, amely kiadja az érdeklődésre számot tartó mező (ke) t, és meg kell adnunk a lekérdezés alsó és / vagy felső határát.

Vizsgáljuk meg, hogyan lehet egy és több mezőt tartalmazó tartománykérdezéseket végrehajtani.

7.1. Egyetlen mezőt érintő lekérdezések

Az összes olyan dokumentum megkeresése, amelyek tartománya: fokozat értékek, függetlenül a tanfolyam mezőre van szükségünk olyan nézetre, amely csak a fokozat terület. Írjuk meg a térkép funkció afindByGrade" Kilátás:

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

Írjunk egy lekérdezést Java-ban e nézet segítségével, hogy megtaláljuk az összes „B” betűs osztálynak megfelelő osztályzatot (80–89) (

ViewQuery lekérdezés = ViewQuery.from ("studentGrades", "findByGrade") .startKey (80) .endKey (89) .inclusiveEnd (true);

Vegye figyelembe, hogy a tartománylekérdezésben szereplő startkulcs értékét mindig inkluzívként kezeljük.

És ha ismert, hogy az összes fokozat egész szám, akkor a következő lekérdezés ugyanazokat az eredményeket hozza:

ViewQuery lekérdezés = ViewQuery.from ("studentGrades", "findByGrade") .startKey (80) .endKey (90) .inclusiveEnd (hamis);

Az összes „A” fokozat (90 vagy annál magasabb) megtalálásához csak az alsó határt kell megadnunk:

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "findByGrade") .startKey (90);

És az összes sikertelen (60 alatti) osztályzat megtalálásához csak a felső határt kell megadnunk:

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "findByGrade") .endKey (60) .inclusiveEnd (hamis);

7.2. Több mezőt tartalmazó lekérdezések

Tegyük fel, hogy egy adott tanfolyam összes hallgatóját meg akarjuk találni, akiknek osztályzata egy bizonyos tartományba esik. Ehhez a lekérdezéshez új nézet szükséges, amely a tanfolyam és fokozat mezők.

Többmezős nézeteknél minden indexkulcs értéktömbként kerül kibocsátásra. Mivel a lekérdezésünk rögzített értéket tartalmaz a tanfolyam és egy sor fokozat értékeket, akkor megírjuk a térképfüggvényt, hogy az egyes kulcsokat a [tanfolyam, fokozat].

Nézzük meg a térkép funkció a nézethezfindByCourseAndGrade“:

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

Amikor ezt a nézetet a Couchbase-ben töltik fel, az indexbejegyzések rendezése szerint történik tanfolyam és fokozat. Itt található a kulcsok egy része afindByCourseAndGrade”Nézet a természetes rendezési sorrendben:

["History", 80] ["History", 90] ["History", 94] ["Math", 82] ["Math", 88] ["Math", 97] ["Science", 78] [ "Tudomány", 86] ["Tudomány", 92]

Mivel ebben a nézetben a kulcsok tömbök, akkor egy ilyen formátumú tömböket is használnia kell, ha a tartomány lekérdezésének alsó és felső határait megadja ehhez a nézethez.

Ez azt jelenti, hogy annak érdekében, hogy megtalálja mindazokat a diákokat, akik „B” osztályzatot kaptak (80–89) a matematika tanfolyamon, az alsó határt a következőre kell beállítania:

["Math", 80]

és a felső határ:

["Math", 89]

Írjuk meg a tartomány lekérdezését Java-ban:

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "findByCourseAndGrade") .startKey (JsonArray.from ("Math", 80)) .endKey (JsonArray.from ("Math", 89)) .inclusiveEnd (igaz);

Ha azt szeretnénk megtalálni az összes hallgató számára, aki „A” osztályt (90 vagy annál magasabb) kapott matematikából, akkor ezt írjuk:

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "findByCourseAndGrade") .startKey (JsonArray.from ("Math", 90)) .endKey (JsonArray.from ("Math", 100));

Vegye figyelembe, hogy mivel a tanfolyam értékét a „Math„, A lehető legmagasabb felső határt kell tartalmaznunk fokozat érték. Ellenkező esetben az eredménykészletünk tartalmazna minden olyan dokumentumot is, amelynek tanfolyam lexikográfiailag nagyobb, mintMath“.

És megtalálja az összes sikertelen matematikai osztályt (60 alatt):

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "findByCourseAndGrade") .startKey (JsonArray.from ("Math", 0)) .endKey (JsonArray.from ("Math", 60)) .inclusiveEnd (hamis);

Az előző példához hasonlóan meg kell adnunk egy alsó határt a lehető legalacsonyabb fokozattal. Ellenkező esetben az eredménykészletünk minden olyan osztályt tartalmazna, ahol a tanfolyam lexikográfiailag kisebb, mintMath“.

Végül, hogy megtalálja az öt legmagasabb matematikai osztályzatot (kizárva az összes kapcsolatot), megmondhatja a Couchbase-nek, hogy végezzen csökkenő rendezést és korlátozza az eredményhalmaz méretét:

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "findByCourseAndGrade"). Csökkenő () .startKey (JsonArray.from ("Math", 100)) .endKey (JsonArray.from ("Math", 0)) .inclusiveEnd ( igaz) .korlát (5);

Vegye figyelembe, hogy csökkenő rendezés végrehajtásakor a startKey és endKey az értékek megfordulnak, mert a Couchbase a sort rendezése előtt alkalmazza a határ.

8. Összesített lekérdezések

A MapReduce nézetek egyik fő erőssége, hogy nagyon hatékonyak az összesített lekérdezések futtatásához nagy adatkészletek ellen. Például hallgatói osztályzatunk adatkészletében könnyen kiszámíthatjuk a következő összesítéseket:

  • az egyes tanfolyamok hallgatóinak száma
  • kreditórák összege minden hallgató számára
  • évfolyamos átlag minden hallgató számára az összes tanfolyamon

Készítsünk egy nézetet és lekérdezést ezekhez a számításokhoz beépített használatával csökkenteni funkciókat.

8.1. Használni a számol() Funkció

Először írjuk meg a térkép funkció az egyes kurzusok hallgatóinak számának megtekintéséhez:

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

Ezt a nézetet hívjukcountStudentsByCourse”És jelölje meg, hogy a beépítettet használja "_számol" funkció. És mivel csak egyszerű számlálást hajtunk végre, így is kibocsáthatunk nulla mint az egyes bejegyzések értékét.

Az egyes tanfolyamok hallgatóinak számának megszámolása:

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "countStudentsByCourse") .reduce () .groupLevel (1);

Az adatok kivonása összesített lekérdezésekből eltér az eddig látottaktól. Ahelyett, hogy kibontanánk egy megfelelő Couchbase dokumentumot az eredmény minden sorához, kivonjuk az összesítő kulcsokat és eredményeket.

Futtassuk a lekérdezést, és vonjuk ki a számlálásokat a-ba java.util.Térkép:

ViewResult result = bucket.query (lekérdezés); Térkép numStudentsByCourse = új HashMap (); a (ViewRow sorhoz: result.allRows ()) {JsonArray keyArray = (JsonArray) row.key (); Karaktersorozat = keyArray.getString (0); long count = Long.valueOf (sor.érték (). toString ()); numStudentsByCourse.put (tanfolyam, számolás); }

8.2. Használni a összeg() Funkció

Ezután írjunk egy nézetet, amely kiszámítja az egyes hallgatók megkísérelt óráinak összegét. Ezt a nézetet hívjuksumHoursByStudent”És jelölje meg, hogy a beépítettet használja "_összeg" funkció:

függvény (doc, meta) {if (doc.type == "StudentGrade" && doc.name && doc.course && doc.hours) {emit ([doc.name, doc.ourse], doc.hours); }}

Vegye figyelembe, hogy a "_összeg" funkciót kell tennünk kibocsát az összesítendő érték - ebben az esetben a kreditek száma - minden bejegyzésnél.

Írjunk egy lekérdezést, hogy megtaláljuk az egyes hallgatók összes kreditszámát:

ViewQuery lekérdezés = ViewQuery .from ("studentGrades", "sumCreditsByStudent") .reduce () .groupLevel (1);

Most pedig futtassuk a lekérdezést, és vonjuk ki az összesített összegeket a-ba java.util.Térkép:

ViewResult result = bucket.query (lekérdezés); Térkép óraByStudent = új HashMap (); a (ViewRow sorhoz: result.allRows ()) {String name = (String) row.key (); hosszú összeg = Long.valueOf (row.value (). toString ()); hoursByStudent.put (név, összeg); }

8.3. Grade Point átlagok kiszámítása

Tegyük fel, hogy az egyes hallgatók osztályzatátlagát (GPA) az összes tanfolyamra ki akarjuk számítani, a hagyományos érdemjegy-skála felhasználásával, a megszerzett osztályzatok és a tanfolyam értékű kreditórák száma alapján (A = 4 pont / kreditóra, B = 3 óra hitelóránként, C = 2 pont hitelóránként és D = 1 pont hitelóránként).

Nincs beépített csökkenteni függvény az átlagos értékek kiszámításához, így két nézet kimenetét egyesítjük a GPA kiszámításához.

Már megvan a „SumHoursByStudent” nézet, amely összegzi az egyes hallgatók által megkísérelt kreditórák számát. Most szükségünk van az egyes diákok által megszerzett osztályzatok pontjára.

Hozzunk létre egy nevű nézetet „SumGradePointsByStudent” amely kiszámítja az egyes tanfolyamokon megszerzett érdemjegyek számát. Mi a beépítettet fogjuk használni "_összeg" funkció a következők csökkentésére térkép funkció:

függvény (doc, meta) {if (doc.type == "StudentGrade" && doc.name && doc.hours && doc.grade) {if (doc.grade> = 90) {emit (doc.name, 4 * doc .órák); } else if (dok.fokozat> = 80) {emit (dok.név, 3 ​​* doki óra); } else if (dok.fokozat> = 70) {emit (dok.név, 2 * doki óra); } else if (dok.fokozat> = 60) {emit (dok.név, dok.órák); } else {emit (dok.név, 0); }}}

Most kérdezzük le ezt a nézetet, és vonjuk ki az összegeket a-ba java.util.Térkép:

ViewQuery lekérdezés = ViewQuery.from ("studentGrades", "sumGradePointsByStudent") .reduce () .groupLevel (1); ViewResult result = bucket.query (lekérdezés); Map gradePointsByStudent = new HashMap (); a (ViewRow sorhoz: result.allRows ()) {String course = (String) row.key (); hosszú összeg = Long.valueOf (row.value (). toString ()); gradePointsByStudent.put (tanfolyam, összeg); }

Végül egyesítsük a kettőt Térképs annak érdekében, hogy kiszámíthassuk az egyes hallgatók GPA-ját:

Térkép eredménye = új HashMap (); for (Belépési jóváírásHoursEntry: hoursByStudent.entrySet ()) {String name = creditHoursEntry.getKey (); long totalHours = creditHoursEntry.getValue (); long totalGradePoints = gradePointsByStudent.get (név); result.put (név, ((float) totalGradePoints / totalHours)); }

9. Következtetés

Bemutattuk, hogyan lehet megírni néhány alapvető MapReduce nézetet a Couchbase-ben, és hogyan lehet lekérdezéseket összeállítani és végrehajtani a nézetek alapján, és kivonni az eredményeket.

Az oktatóanyagban bemutatott kód megtalálható a GitHub projektben.

A MapReduce nézetekről és azok lekérdezéséről Java-ban többet megtudhat a Couchbase hivatalos fejlesztői dokumentációs webhelyén.