Sorolja fel az összes rendelkezésre álló Redis billentyűt

Java Top

Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:

>> ELLENŐRIZZE A FOLYAMATOT

1. Áttekintés

A gyűjtemények alapvető építőelemek, amelyek jellemzően szinte az összes modern alkalmazásban láthatók. Szóval, ez nem meglepő A Redis számos népszerű adatstruktúrát kínál mint például listák, halmazok, hashek és rendezett halmazok, amelyeket használhatunk.

Ebben az oktatóanyagban megtudhatjuk, hogyan lehet hatékonyan elolvasni az összes rendelkezésre álló Redis billentyűt, amely megfelel egy adott mintának.

2. Fedezze fel a gyűjteményeket

Képzeljük el, hogy a mi alkalmazás a Redis segítségével tárolja a labdákkal kapcsolatos információkat különböző sportokban használják. Látnunk kell a Redis gyűjteményből elérhető információkat az egyes labdákról. Az egyszerűség kedvéért az adatkészletünket csak három golyóra korlátozzuk:

  • Tücsökgömb 160 g tömegű
  • 450 g súlyú labdarúgás
  • Röplabda, súlya 270 g

Szokás szerint először tisztázzuk alapjainkat a Redis-gyűjtemények feltárásának naiv megközelítésével.

3. Naiv megközelítés redis-cli használatával

Mielőtt elkezdenénk írni a Java kódot a gyűjtemények felfedezéséhez, tisztességes elképzelésekkel kell rendelkeznünk arról, hogyan fogjuk ezt megtenni a redis-cli felület. Tegyük fel, hogy a Redis példányunk elérhető a következő címen: 127.0.0.1 a kikötőn 6379, hogy felfedezhessük az egyes gyűjteménytípusokat a parancssori felület segítségével.

3.1. Összekapcsolt lista

Először tároljuk adathalmazunkat egy Redis linkelt listában golyókat formátumában sport-név_golyósúly segítségével rpush parancs:

% redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> RPUSH labdák "krikett_160" (egész szám) 1 127.0.0.1:6379> RPUSH labdák "football_450" (egész szám) 2 127.0.0.1:6379> RPUSH labdák "röplabda_270" (egész szám) 3

Ezt észrevehetjük a listába történő sikeres beillesztés a lista új hosszát eredményezi. Az esetek többségében azonban vakok vagyunk az adatbeillesztési tevékenységre. Ennek eredményeként megtudhatjuk a linkelt lista hosszát a llen parancs:

127.0.0.1:6379> llen golyók (egész szám)

Amikor már tudjuk a lista hosszát, akkor kényelmes használja a lrange parancs a teljes adatkészlet egyszerű lekérése:

127.0.0.1:6379> Különböző labdák 0 2 1) "tücsök_160" 2) "foci_450" 3) "röplabda_270"

3.2. Készlet

Ezután nézzük meg, hogyan fedezhetjük fel az adatsort, amikor úgy döntünk, hogy egy Redis készletben tároljuk. Ehhez először fel kell töltenünk adatsorunkat egy gömbök nevű Redis készletben a szomorú parancs:

127.0.0.1:6379> nyereg golyók "krikett_160" "foci_450" "röplabda_270" "tücsök_160" (egész szám) 3

Hoppá! A parancsunkban kettős érték volt. De mivel értékeket adtunk hozzá egy készlethez, nem kell aggódnunk a másolatok miatt. Természetesen láthatjuk a kimeneti válaszértékből hozzáadott elemek számát.

Most megtehetjük tőkeáttétel a - emlékszik parancsot az összes beállított tag megtekintéséhez:

127.0.0.1:6379> golyókat néz ki 1) "röplabda_270" 2) "tücsök_160" 3) "foci_450"

3.3. Hash

Most használjuk Redis hash adatszerkezetét az adatkészlet gömbök nevű hash kulcsban történő tárolására, így a hash mezője a sport neve, a mező értéke pedig a labda súlya. Megtehetjük ezt a segítségével hmset parancs:

127.0.0.1:6379> hmset labdák krikett 160 foci 450 röplabda 270 OK

A hash-ban tárolt információk megtekintéséhez megtehetjük használja a hgetall parancs:

127.0.0.1:6379> hgetall labdák 1) "tücsök" 2) "160" 3) "futball" 4) "450" ​​5) "röplabda" 6) "270"

3.4. Rendezett készlet

Az egyedi tagérték mellett a rendezett halmazok lehetővé teszik, hogy pontszámot tartsunk mellettük. Nos, felhasználási esetünkben megtarthatjuk a sport nevét, mint tagértéket, és a labda súlyát, mint pontszámot. Használjuk a zadd parancs az adatkészlet tárolására:

127.0.0.1:6379> zadd golyók 160 krikett 450 futball 270 röplabda (egész szám) 3

Most először használhatjuk a zcard parancsot a rendezett halmaz hosszának megkeresésére, majd a zrange parancsot a teljes készlet felfedezéséhez:

127.0.0.1:6379> zcard labdák (egész szám) 3 127.0.0.1:6379> zrange labdák 0 2 1) "tücsök" 2) "röplabda" 3) "futball"

3.5. Húrok

Láthatjuk a a szokásos kulcsérték-húrok felületes tárgygyűjteményként. Töltsük fel először az adatkészletünket a mset parancs:

127.0.0.1:6379> mset labdák: krikett 160 labda: foci 450 labda: röplabda 270 OK

Meg kell jegyeznünk, hogy a „balls:” előtagot adtuk hozzá.hogy ezeket a kulcsokat azonosítani tudjuk a Redis adatbázisunkban esetlegesen fekvő többi kulcsból. Sőt, ez a névstratégia lehetővé teszi számunkra a kulcsok parancs az adatkészlet felfedezéséhez az előtagmintaillesztés segítségével:

127.0.0.1:6379> gombok * 1) "labdák: tücsök" 2) "labdák: röplabda" 3) "labdák: futball"

4. Naiv Java implementáció

Most, hogy kidolgoztuk a vonatkozó Redis-parancsok alapgondolatát, amelyek segítségével különböző típusú gyűjteményeket fedezhetünk fel, itt az ideje, hogy bepiszkítsuk a kezünket a kóddal.

4.1. Maven-függőség

Ebben a részben mi leszünk használni a Jedis kliens könyvtár Redis számára a megvalósítás során:

 redis.clients jedis 3.2.0 

4.2. Redis Client

A Jedis könyvtár a Redis-CLI név-hasonló módszerekkel érkezik. Javasoljuk azonban, hogy mi hozzon létre egy burkoló Redis klienst, amely belsőleg meghívja a Jedis függvényhívásokat.

Amikor a Jedis könyvtárral dolgozunk, ezt szem előtt kell tartanunk egyetlen Jedis-példány nem biztonságos a menetben. Ezért ahhoz, hogy Jedis erőforrást kapjunk alkalmazásunkba, megtehetjük kihasználni JedisPool, ami egy szálbiztos medence hálózati kapcsolatok.

És mivel nem szeretnénk, hogy a Redis kliensek többször lebegjenek az alkalmazásunk életciklusa alatt, akkor létre kell hoznunk a RedisClient osztály a szingulett tervezési minta elvén.

Először hozzunk létre egy privát konstruktort kliensünk számára, amely inicializálja a JedisPool amikor a RedisClient osztály jön létre:

privát statikus JedisPool jedisPool; privát RedisClient (String ip, int port) {try {if (jedisPool == null) {jedisPool = new JedisPool (new URI ("//" + ip + ":" + port)); }} catch (URISyntaxException e) {log.error ("Helytelenül formázott kiszolgáló címe", e); }}

Ezután szükségünk van egy hozzáférési pontra egyszemélyes kliensünkhöz. Tehát hozzunk létre egy statikus módszert getInstance () erre a célra:

privát statikus volatilis RedisClient példány = null; public static RedisClient getInstance (String ip, final int port) {if (instance == null) {synchronized (RedisClient.class) {if (instance == null) {instance = new RedisClient (ip, port); }}} visszatérési példány; }

Végül nézzük meg, hogyan hozhatunk létre burkoló módszert a Jedis-ek tetején lrange módszer:

public List lrange (végső karakterlánc-kulcs, végső hosszú kezdet, végső hosszú megállás) {try (Jedis jedis = jedisPool.getResource ()) {return jedis.lrange (kulcs, indítás, leállítás); } catch (Exception ex) {log.error ("Kivétel lrange-ben elkapva", ex); } return new LinkedList (); }

Természetesen ugyanezt a stratégiát követhetjük a többi burkoló módszer létrehozásához, mint pl lpush, hmset, hgetall, szomorú, - emlékszik, kulcsok, zadd, és zrange.

4.3. Elemzés

Az összes Redis parancs, amelyre használhatjuk a gyűjtemény egyetlen menetben történő felfedezése a legjobb esetben természetesen O (n) időbeli összetettséggel bír.

Talán kissé liberálisak vagyunk, naivnak nevezzük ezt a megközelítést. A Redis valóságos gyártási példányaiban meglehetősen gyakori, hogy több ezer vagy millió kulcs van egyetlen gyűjteményben. Továbbá, Redis egyszálú jellege több nyomorúságot hoz, és megközelítésünk katasztrofálisan blokkolhat más magasabb prioritású műveleteket.

Tehát el kell tennünk, hogy korlátozzuk naiv megközelítésünket, hogy csak hibakeresési célokra alkalmazzuk.

5. Iterátor alapjai

A naiv megvalósításunk legfőbb hibája az, hogy arra kérjük Redist, hogy egyetlen lekérdezésünk összes eredményét adja meg egy mozdulattal. A probléma kiküszöbölése érdekében az eredeti lekérési lekérdezést több szekvenciális lekérdezésre bonthatjuk, amelyek a teljes adatkészlet kisebb darabjain működnek.

Tegyük fel, hogy van egy 1000 oldalas könyvünk, amelyet el kell olvasnunk. Ha naiv megközelítésünket követjük, ezt a nagy könyvet egyetlen szünet nélkül, szünetek nélkül el kell olvasnunk. Ez végzetes lesz közérzetünk számára, mivel kimeríti az energiánkat és megakadályozza, hogy bármilyen más, kiemelt feladatot végezzünk.

Természetesen a helyes módszer az, ha a könyvet több olvasási ülésen befejezzük. Minden munkamenetben onnan folytatjuk, ahol az előző ülésen abbahagytuk - tudunk nyomon követheti előrehaladásunkat egy könyvjelző használatával.

Bár a teljes olvasási idő mindkét esetben összehasonlítható értékű lesz, ennek ellenére a második megközelítés jobb, mivel teret enged a lélegzésnek.

Nézzük meg, hogyan használhatunk iterátor alapú megközelítést a Redis gyűjtemények feltárásához.

6. Redis Scan

A Redis számos szkennelési stratégiát kínál a kulcsok gyűjteményből történő kiolvasására kurzor alapú megközelítéssel, amely elvileg hasonló az oldal könyvjelzőjéhez.

6.1. Szkennelési stratégiák

Végigpásztázhatjuk a teljes kulcsérték-gyűjteményt a Letapogatás parancs. Ha azonban az adatkészletet gyűjteménytípusok szerint szeretnénk korlátozni, akkor használhatjuk az egyik változatot:

  • Sscan halmazokon keresztüli iterációra használható
  • Hscan segít iterálni a hash mező-érték párokon keresztül
  • Zscan válogatásban tárolt tagokon keresztüli iterációt tesz lehetővé

Meg kell jegyeznünk, hogy mi valójában nincs szükség kifejezetten a linkelt listákhoz tervezett kiszolgálóoldali vizsgálati stratégiára. Ez azért van, mert a linkelt lista tagjaihoz indexek segítségével férhetünk hozzá a lindex vagy lrange parancs. Ráadásul megtudhatjuk az elemek számát és felhasználását lrange egyszerű ciklusban a teljes lista kis darabokban történő ismétléséhez.

Használjuk a LETAPOGATÁS parancs a karakterlánc típusú kulcsok átkutatására. A beolvasás megkezdéséhez a kurzor értékét „0” -ként kell használnunk, a mintaszalag „labda *” -ként illeszkedik:

127.0.0.1:6379> mset golyók: tücsök 160 golyó: foci 450 golyó: röplabda 270 OK 127.0.0.1:6379> SCAN 0 MATCH labda * SZÁMA 1 1) "2" 2) 1) "golyó: tücsök" 127.0.0.1 : 6379> SCAN 2 MATCH labda * COUNT 1 1) "3" 2) 1) "labdák: röplabda" 127.0.0.1:6379> SCAN 3 MATCH labda * COUNT 1 1) "0" 2) 1) "labdák: foci "

Minden befejezett beolvasással megkapjuk a kurzor következő értékét, amelyet a következő iterációban használunk. Végül tudjuk, hogy átnéztük a teljes gyűjteményt, amikor a következő kurzor értéke „0”.

7. Szkennelés Java-val

Mostanra már elég megértettük a megközelítésünket, hogy elkezdhessük a Java-ban való megvalósítását.

7.1. Szkennelési stratégiák

Ha betekintünk a Jedis osztályban találunk stratégiákat a különböző gyűjteménytípusok beolvasására:

nyilvános ScanResult szkennelés (végleges karakterlánc-kurzor, utolsó ScanParams-paraméterek); nyilvános ScanResult sscan (végső karakterlánc-kulcs, végleges karakterlánc-kurzor, végső ScanParams-paraméterek); nyilvános ScanResult hscan (utolsó karakterlánc-kulcs, végleges karakterlánc-kurzor, végső ScanParams-paraméterek); nyilvános ScanResult zscan (végleges karakterlánc-kulcs, végleges karakterlánc-kurzor, végső ScanParams-paraméterek);

Jedis két opcionális paramétert igényel, keresési minta és eredményméret a szkennelés hatékony irányításához - ScanParams teszi ezt. Ebből a célból a mérkőzés() és számol() módszerek, amelyek lazán az építő tervezési mintáján alapulnak:

nyilvános ScanParams egyezés (végleges karakterlánc minta); nyilvános ScanParams számlálás (végső egész szám);

Most, hogy átitattuk az alapvető ismereteket Jedisé szkennelési megközelítés, modellezzük ezeket a stratégiákat a ScanStrategy felület:

nyilvános felület ScanStrategy {ScanResult scan (Jedis jedis, String kurzor, ScanParams scanParams); }

Először is dolgozzunk a legegyszerűbben letapogatás stratégia, amely független a gyűjtemény-típustól és olvassa a kulcsokat, de nem a kulcsok értékét:

public class Scan megvalósítja a ScanStrategy {public ScanResult scan (Jedis jedis, karakterlánc kurzor, ScanParams scanParams) {return jedis.scan (kurzor, scanParams); }}

Ezután vegyük fel a hscan stratégia, amely egy adott kivonatkulcs összes mezőkulcsának és mezőértékének beolvasására szolgál:

nyilvános osztályú Hscan valósítja meg a ScanStrategy programot {privát karakterlánc-kulcs; @Orride public ScanResult scan (Jedis jedis, karakterlánc kurzor, ScanParams scanParams) {return jedis.hscan (kulcs, kurzor, scanParams); }}

Végül készítsük el a halmazok és a rendezett halmazok stratégiáit. A sscan stratégia le tudja olvasni egy halmaz összes tagját, míg a zscan stratégia elolvashatja a tagokat a pontszámukkal együtt Tuples:

public class Sscan megvalósítja a ScanStrategy {private String kulcsot; nyilvános ScanResult keresés (Jedis jedis, karakterlánc kurzor, ScanParams scanParams) {return jedis.sscan (kulcs, kurzor, scanParams); }} public class Zscan implementálja a ScanStrategy {private String kulcsot; @Orride public ScanResult scan (Jedis jedis, String kurzor, ScanParams scanParams) {return jedis.zscan (kulcs, kurzor, scanParams); }}

7.2. Redis Iterator

Ezután vázoljuk fel az építéshez szükséges építőelemeket RedisIterator osztály:

  • Karakterlánc-alapú kurzor
  • Szkennelési stratégia, mint pl letapogatás, sscan, hscan, zscan
  • Helyőrző a paraméterek szkenneléséhez
  • Hozzáférés JedisPool hogy a Jedis forrás

Most továbbléphetünk, és meghatározhatjuk ezeket a tagokat a mi csoportunkban RedisIterator osztály:

privát döntő JedisPool jedisPool; privát ScanParams scanParams; saját karakterlánc kurzor; privát ScanStrategy stratégia;

A szakaszunk készen áll arra, hogy meghatározzuk az iterátor specifikus funkcionalitását. Erre a mi RedisIterator osztálynak végre kell hajtania a Iterátor felület:

nyilvános osztály RedisIterator valósítja meg az Iterator-ot { }

Természetes, hogy felül kell írnunk a hasNext () és következő() módszerektől örököltek Iterátor felület.

Először válasszuk ki az alacsonyan függő gyümölcsöt - a hasNext () módszer - mivel a mögöttes logika egyenes. Amint a kurzor értéke „0” lesz, tudjuk, hogy készen vagyunk a beolvasással. Tehát nézzük meg, hogyan tudjuk ezt megvalósítani egyetlen sorban:

@Orride public boolean hasNext () {return! "0" .equals (kurzor); }

Ezután dolgozzunk a következő() módszer, amely a szkennelés nehéz emelését végzi:

@ A nyilvános lista felülírása következő () {if (kurzor == null) {kurzor = "0"; } try (Jedis jedis = jedisPool.getResource ()) {ScanResult scanResult = strategy.scan (jedis, kurzor, scanParams); kurzor = scanResult.getCursor (); return scanResult.getResult (); } catch (Exception ex) {log.error ("A következőben elkapott kivétel ()", ex); } return new LinkedList (); }

Ezt meg kell jegyeznünk ScanResult nemcsak a beolvasott eredményeket adja meg, hanem a következő kurzorértéket is szükséges a későbbi átvizsgáláshoz.

Végül engedélyezhetjük a funkcionalitást a létrehozáshoz RedisIterator ban,-ben RedisClient osztály:

public RedisIterator iterátor (int initialScanCount, String minta, ScanStrategy stratégia) {return new RedisIterator (jedisPool, initialScanCount, minta, stratégia); }

7.3. Olvassa el Redis Iteratorral

Ahogy megterveztük a Redis iterátorunkat a Iterátor interfész, elég intuitív olvassa el a gyűjtemény értékeit a következő() módszer mindaddig hasNext () visszatér igaz.

A teljesség és az egyszerűség kedvéért először a sportlabdákkal kapcsolatos adatállományt tároljuk egy Redis hash-ban. Ezt követően használjuk a mi RedisClient iterátor létrehozásához a Hscan szkennelési stratégia. Teszteljük a megvalósításunkat azáltal, hogy ezt működésben látjuk:

@Test public void testHscanStrategy () {HashMap hash = new HashMap (); hash.put ("tücsök", "160"); hash.put ("foci", "450"); hash.put ("röplabda", "270"); redisClient.hmset ("golyók", hash); Hscan scanStrategy = új Hscan ("golyók"); int iterációSzám = 2; RedisIterator iterator = redisClient.iterator (iterációszám, "*", scanStrategy); Lista eredmények = új LinkedList(); while (iterator.hasNext ()) {results.addAll (iterator.next ()); } Assert.assertEquals (hash.size (), results.size ()); }

Kicsi módosítással ugyanazt a gondolkodási folyamatot követhetjük, hogy teszteljük és megvalósítsuk a fennmaradó stratégiákat a különféle típusú gyűjteményekben elérhető kulcsok beolvasására és olvasására.

8. Következtetés

Ezt az oktatóanyagot azzal a szándékkal indítottuk, hogy megtudjuk, hogyan olvashatjuk el az összes hozzáillő kulcsot a Redisben.

Megtudtuk, hogy Redis felajánl egy egyszerű módszert, amellyel egyszerre olvashatja el a kulcsokat. Bár egyszerű, megvitattuk, hogyan terheli ez az erőforrásokat, és ezért nem alkalmas a termelési rendszerek számára. A mélyebbre ásva megtudtuk, hogy van egy iterátor alapú megközelítés a szkenneléshez a Redis billentyűk illesztésével az olvasási lekérdezéshez.

Mint mindig, az ebben a cikkben használt Java-implementáció teljes forráskódja elérhető a GitHubon.

Java alsó

Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:

>> ELLENŐRIZZE A FOLYAMATOT