Hogyan keresünk az elsődleges kulcsban nem szereplő jellemzőre DynamoDB-ben?
|

Ez a cikk a DynamoDB-ben történő adatmodellezésről szóló cikksorozat második része (az első a kulcsválasztásról szólt) - és még ez után is lesz folytatás.

Az első részben abban maradtunk, hogy érdemes odafigyelni az elsődleges kulcs megválasztására. A kulcs nagyban meghatározza, hogy mennyire könnyen férünk hozzá az adatainkhoz, ugyanis kevés költséggel csak az elsődleges kulcsra tudunk szűrni (itt nincs olyan flexibilis eszközünk, mint az SQL-megvalósítások WHERE záradéka).

Talán még emlékszünk a múltkori, webshopos rendeléseket tartalmazó DynamoDB-táblára. Egy picit vltoztattunk rajta, mert a rendelések állapotát (nyitott vagy lezárt) jellemző status szó egy foglalt szó a DynamoDB-ben. Ha ezt szeretnénk attribútumként használni, akkor tornázni kell, és nem volna elég szép és letisztult a mintakód. Úghogy átkereszteljük stat-ra.

{
  "client": "jozsi",
  "ordertime": 20200706080245,
  "stat": "open"
}
{
  "client": "jozsi",
  "ordertime": 20200706080244,
  "stat": "closed"
}
{
  "client": "johanna",
  "ordertime": 20200706080245,
  "stat": "closed"
}

Ebben ugye összetett elsődleges kulcsunk van, azaz két "mező" együtt azonosít egy bejegyzést. A client a Partition Key, az ordertime a Sort Key, és remekül tudunk olyat kérdezni a DynamoDB-től, hogy

  • add meg jozsi rendeléseit, vagy
  • add meg jozsi 2020. júliusi rendeléseit.

A baj akkor jön, amikor azt kérjük, hogy "add meg a lezárt rendeléseket!" Na, ilyet nem tud a DynamoDB, hiszen a status nem része az elsődleges kulcsnak. Mi hát a teendő?

Index létrehozása DynamoDB-ben

Az első gondolat

A DynamoDB táblái scannelhetők - a scannelés ez esetben szakszó, nem szleng, és azt jelenti, hogy egyesével visszakérjük az összes itemet (rekordot, ha úgy tetszik). Ezzel számos baj van:

  • utólag nekünk kell kiválogatni a szükséges rekordokat;
  • egyszerre legfeljebb egyetlen megabájt adatot kapunk vissza - ha ennél több van, akkor a DynamoDB "lapokra bontja" (paginate) az adatokat - nekünk kell figyelni, hogy van-e még oldal, és mindet egyesével elkérni;
  • lassú lehet a válasz; és
  • még drága is az egész: sok művelet, sok lekért adat.

A lekérdezés - sőt, nem is lekérdezés, hanem letapogatás - szintaxisa AWS CLI-ban a következő:

aws dynamodb scan --table-name Order

A sebességen dobhat, ha párhuzamos scannelést indítunk. A "sima" scan ugyanis akkor is csak egy fizikai partícióról olvas, ha a rengeteg adatunk sok partíción kap helyet. A scan sebességét tehát korlátozza a fizikai partíció sebessége. Párhuzamos scanneléskor a táblát szegmensekre osztjuk, és a programunk egy-egy szála, vagy az operációs rendszer egy-egy folyamata scannel egy szegmenst. A módszer működik, nem számít "ugly hack"-nek, de azért a kisujjunk sajgásából arra következtetünk, hogy az alkalmazásunk komplexitását éppen nem csökkenti.

FilterExpression

A FilterExpression arra való, hogy megszűrjük az adatokat, miután a scan végbement, de még mielőtt az adatokat visszakapnánk. A felsorolt bajok közül tehát csak az elsőt szünteti meg - s bár kétségtelenül nagy hasznunkra van, azért ez még távol áll a jótól.

A "lekérdezés" a következőképp alakul:

aws dynamodb scan --table-name Order --filter-expression "stat = :allapot" --expression-attribute-values '{":allapot":{"S":"closed"}}'

Global Secondary Index

A GSI-k arra valók, hogy lekérdezhetővé tegyük a táblánkat az elsődleges kulcsnak részét nem képező attribútumokra is. Persze attól, hogy egy táblához létrehozunk egy GSI-t, a DynamoDB nem ruházódik fel szuperképességekkel, nem változik semmi. Akkor meg miért képes lefutni az alábbi lekérdezés?

aws dynamodb query --table-name Order --index-name stat-index --key-condition-expression  "stat = :allapot" --expression-attribute-values '{":allapot":{"S":"closed"}}'

(Megjegyezzük, hogy ez már tényleg lekérdezés, figyeljük meg, hogy a scan helyett query szerepel a parancsban.)

Szóval az történik, hogy a háttérben lényegében létrejön egy másik tábla, aminek az elsődleges kulcsát az eredeti tábla olyan attribútumaiból választjuk, amelyek eredetileg nem voltak kulcsok. Ez a tábla, akarom mondani, index

  • saját nevet kap;
  • az eredeti táblának nem feltétlen tartalmazza az összes mezőjét-attribútumát (spórolva a tárterületen), a képen például látjuk, hogy csak a kulcsokat másoljuk át a stat jellemzőn kívül (ja igen, nekünk a stat mezőn kívül csak kulcsjellemzőink vannak a táblában, de a példát érted);
  • az eredeti táblával szinkronban tartja az adatait (az eredetin történik minden változtatás);
  • a számára megadott írási-olvasási teljesítmény kiszolgálására képes (az eredeti táblától teljesen függetlenül);
  • és külön fizetünk érte a tárterület és teljesítmény alapján.

Az első részben megfogalmazott tanulságaink így bővülnek:

  • Nagyon gondoljuk át, hogy az elsődleges kulcson kívül még milyen attribútumoknak kell szerepelniük a lekérdezésekben
  • és azt is, hogy a kulcson kívül milyen attribútumokat akarunk még visszakapni.

Ha kezdjük erősen sejteni, hogy amit SQL-ből tanultunk, az mehet a lecsóba, akkor igazunk van. Egy RDBMS használatakor a tábláink tervezésekor elvileg nem szempont az alkalmazás, ahol használni kívánjuk az adatokat. Elvileg, mert azért a denormalizáció meg a nézettáblák ott is vannak. Nos, a DynamoDB használatakor előbb kell tudnunk, hogy mit csinál az alkalmazás, és utána állhatunk neki táblát tervezni.

Legközelebb a GSI párjáról, az LSI-ről lesz szó.

[Vissza a bejegyzésekhez]