Changes

Cassandra -NoSQL database

20,647 bytes added, 21:51, 16 February 2019
Partíció mérete
* '''Keyspace''': ez felel meg egy adatbázisnak az RDBMS-ben, vagy egy Index-nek az Elasticsearch-ben
* '''Column families''': egy tábla az adatbázisban, amihez sorok tartoznak. Azonban az oszlopok fajtája soronként eltérhet.
* '''Partition''': Egy sor egy táblában Azon sorok (illetve cellák) összessége, amiknek a particionáló kulcsuk értéke egyenlő (tehát ugyan azon a node-on lesznek). Ezt előre ki kell számolni, lásd lentebb.
* '''Clustering''': sorok sorba rendezése egy táblán belül (Semmi köze a Cassandra cluster-hez)
===Táblák felépítése (Column families)===
Cassandra-ban nem úgy kell elképzelni a táblaszerkezetet mint az RDBMS világban, mint egy AxB nagyságú táblázat, ahol egy entitást egy sor reprezentál. Cassandra-ban egy sort úgy kell elképzelni, mint a listája az adott sorban szereplő Oszlopnév->érték (név->érték ) pároknak. Cassandra-ban azok az oszlopok egy sorban, ahol nincs érték, nincsenek definiálva az adott sorra, az az oszlop, aminek nem adtunk értéket egyszerűen nem szerepel az Oszlopnév->érték felsorolásban.
Tételezzük fel, hogy van egy táblánk, aminek 11 oszlopa van, ahol az oszlop nevek Column1-től mennek Column11-ig. Minden sorba csak azok az oszlopok fognak bekerülni, ahol tényleg van érték:
* Egyértelműen azonosítani akarunk egy sort a kulccsal egy táblában (ez eddig triviális, RDBMS-ben is így van ('''primary vagy compound primary key''')
* A Cassandra-nak be kell tudni azonosítani hogy az adott sor melyik node-on van eltárolva. Az adott kulcs alapján a Cassandra muszáj hogy mindig ugyan azt a node-ot találja meg ahova elsőre beszúrta az adatot. ('''Partition key''')
* Sorrendezése a soroknak a táblán egy partíción belül (vagyis azonos particionáló kulccsal rendelkezező sorokon belül. ): Cassandra-ban a sorok sorrendezését már a tábla létrehozásakor definiálni kell ('''Clustering key'''= csoportosító kulcs)
<br>
Ugyan úgy Ugyanúgy mint az RDBMS világban, a Cassandra táblákon belül is egyértelműen, egyedi módon azonosítani kell tudni minden egyes sort egy egyedi azonosító alapján. Ez az elsődleges kulcs, ez eddig triviális. Az azonban, hogy hogyan épül fel az elsődleges kulcs, már kicsit bonyolultabb. A '''Primary key''' (elsődleges kulcs) a két már említett kulcsfajtából épülhet fel. Tartalmaznia kell legalább egy '''partition key'''-t és 0 vagy több '''clustering key'''-t. Amennyiben több mint egy kulcsból épül fel (tehát legalább egy p'''artition partition key'''-ből és vagy még több valamennyi '''clustering key'''-ből vagy több mint egy további partition kulcsokból) akkor '''Compound primary key'''-nek hívjuk.
:[[File:ClipCapIt-181007-185315.PNG]]
===Partition key===
A Cassandra tipikusan egy sok node-on futó elosztott alkalmazás, a benne tárolt adatok egyenletesen szét vannak szórva a cluster-ben. A szétszórás értelem szerűen értelemszerűen nem táblák mentén történik, hanem tábla soronként. Tehát elképzelhető egy egy táblából minden egyes sor más és más node-ra kerül.
Cassandra-ban a node-ok egy gyűrűbe vannak szervezve. Minden egyes node-nak van egy egyedi azonosítója, egy 64 bites token. (from -2<sup>23</sup> to 2<sup>63</sup>-1)
Azt hogy egy partíció (sorazonos particionáló kulccsal rendelkező sorok összessége) melyik node-on éli az életet (hova kell kiírni ill. honnan kell beolvasni) a particionáló dönti el a partion kulcsok alapján. Az alapértelmezett particionáló a '''Murmur3Partitioner''', ami mindig ugyan arra ugyanarra a 64 bites tokenre képzi le ugyan azt ugyanazt a '''partion kekey'''y-t.
-4069959284402364209
</pre>
 
 
===Compound primary key===
);
</pre>
{{note|A kulcsok sorrendje a PRIMARY KEY megadásánál kritikus. Ez határozza majd meg, hogy milyen 'sorrendben' kell majd őket szerepeltetni a lekérdezések WHERE szekciójában (lásd [[Cassandra_-NoSQL_database#Kulcsok_.C3.A9s_indexek_kezel.C3.A9se|Kulcsok és indexek kezelése]] című fejezetet)
===Clustering key===
A Clustering key (csoportosító kulcs) kizárólag egy táblán partíción belül határozza meg a sorok sorrendjét. Ha a compound primary kulcsunk több clustering kulcsot is tartalmaz, akkor először a listában az leső alapján fog sorrendezni, aztán a második alapján, és így tovább. Megadhatjuk a rendezés irányát is. Fontos ezt már a tábla tervezésekor kitalálni, mert később ezt már nem tudjuk megváltoztatni.  
A rendezés irányát a WITH CLUSTERING ORDER BY kulcsszóval adhatjuk meg:
<pre>
CREATE TABLE store_by_location (
country col1 text, state col2 text, city col3 text, store_name text, description col4 text, PRIMARY KEY (countrycol1, statecol2, city, store_namecol3)) WITH CLUSTERING ORDER BY (state col2 DESC, city ASC, store_name col3 ASC);
</pre>
A fenti példában a particionáló kulcs a col1 és a két Clustering (csoportosító) kulcs a col2 és col3. A col2 szerint visszafele, a col3 szerint előre rendezünk. Ha nem adjuk meg, akkor az előre rendezés az alapértelmezett.
 
 
{{note|A rendezés csak akkor értelmezett egy Clustering key alapján, ha a partitioning kulcsok megegyeznek két sorban, ahol a Clustering kulcsok különböznek (ezért mondtuk, hogy csak egy partíción belül értelmezett). Tehát egy olyan adathalmazban, ahol a particionáló kulcsok értékkészlete unique, ott a Clustering kulcsoknak a sorok sorrendjére nincs hatása. Úgy is mondhatjuk, hogy csak egy node-on belül rendezik a sorokat}}
 
A fenti példában, azokban a sorokban, ahol a '''col1''' megegyezik, a '''col2''' szerint lesznek visszafelé rendezve a sorok. És azokban a sorokban, ahol a '''col1''' és a '''col2''' is megegyezik, a '''col3''' szerint előre lesznek rendezve a sorok.
 
Pl. beszúrjuk ezeket az alábbi sorrendben:
col1=k1, col2=B, col3=B
col1=k1, col2=A, col3=Z
col1=k1, col2=C, col3=X
col1=k1, col2=B, col3=A
 
 
Akkor a végeredmény a következő lesz, ha lekérdezzük (így is van tárolva). A particionáló kulcsok minden sorban azonosak (tehát ugyan azon a node-on vannak), és a col2 szerint visszafele, a col3 szerint előre rendez:
col1=k1, col2=C, col3=X
col1=k1, col2=B, col3=A
col1=k1, col2=B, col3=B
col1=k1, col2=A, col3=Z
 
<br>
A sorrendezésen felül a clustering kulcsoknak a lekérdezés WHERE szekciójában van szerepe, mert felírhatunk rájuk '''>, >=, <, <=''' operációkat, amiket a particionáló kulcsokra nem írhatunk fel. (lást részletesen a [[Cassandra_-NoSQL_database#Lek.C3.A9rdez.C3.A9s_megk.C3.B6t.C3.A9sek|Lekérdezés megkötések]] című fejezetben.
 
 
 
===Partíció példa===
A fenti tábla definíció mellett adott a következő adathalmaz:
col1=k1, col2=B, col3=B
col1=k1, col2=A, col3=Z
col1=k1, col2=C, col3=X
col1=k2, col2=B, col3=A
 
 
Két partícióra oszlanak, mivel a col1 a particionáló kulcs:<br>
1. partíció:
col1=k1, col2=B, col3=B
col1=k1, col2=A, col3=Z
col1=k1, col2=C, col3=X
2. partíció:
col1=k2, col2=B, col3=A
 
<br>
==Időbélyegek és Time to Live==
Mary | Rodriguez | 3588
</pre>
 
 
 
<br>
==Másodlagos indexek==
* Gyakran átírt mezőknél: Ha gyorsabban gyűlnek fel a tombstones-ok mint ahogy azokat a Cassandra fel tudná dolgozni, hibára fog futni az update egy idő után
Példa: a user nevű táblában a last_name-re hozunk létre másodlagos indexet.
<pre>
CREATE INDEX ON user ( last_name );
{{note|Másodlagos indexeket a set, list, map elemeire is létrehozhatunk, akár még a user-defined-type belsejében lévő elemekre is, még akkor is ha egy map belsejében annak}}
 
 
CREATE INDEX ON user ( emails );
<br>
Cassandara 3.4-től használhatjuk az Apple által kifejlesztet SASI másodlagos index implementációt, ami több funkcionalitást tesz lehetővé mint a beépített változat:
* Kisebb, nagyobb -ra keresés
</pre>
=='''INDEX vs Filter==:'''<br>Hatékonysági okokból alap esetben a Cassandra csak arra az oszlopra enged lekérdezni, amire van index.Csak akkor lehet index nélküli oszlopra hivatkozni a WHERE kifejezésben ha ezt implicit engedélyezzük az '''ALLOW FILTERING''' kulcsszóval a lezáró ; előtt. Ugyanis ha egy oszlopon nincs index, akkor a Cassandra az összes sort be fogja olvasni, és filterrel fogja kiválasztani WHERE-ben definiált mezőket. Milliós sorszám esetén ez már problémás lehet.
https://www.datastax.com/2012/01/getting-started-with-cassandra
 
<br>
==Materialized Views==
http://cassandra.apache.org/doc/4.0/cql/mvs.html<br>
https://opencredo.com/everything-need-know-cassandra-materialized-views/<br>
A Materialized view az eredeti tálba egy részhalmazának, vagy az egész tálba egy olyan másolata, ahol más kulcsok alapján tesszük kereshetővé ugyan azt az adathalmazt. Ez akkor jó, ha van egy táblánk amit A és B oszlop szerint is keresni akarunk, ilyenkor csinálunk egy táblát, ahol A a kulcs, és egy Materialized view-t, ahol a B a kulcs. Ennek az a nagy előnye azzal szemben, mint ha erre két valódi táblát definiálnánk, hogy mikor az igazi táblába szúrunk be, akkor a materialized view-t is frissíteni fogja a Cassandra, nem nekünk kell manuálisan megcsinálni.
 
 
Az MW-ban a kulcsokra nagyon komoly megkötés van:
* az alap tábla összes kulcsát tartalmaznia kell
* csak egy olyan plusz kulcsot tartalmazhat, ami nem volt kulcs az alaptáblában.
 
{{note|Az MW-ben az alaptábla partícionáló kulcsából általában Clustering kulcsot csinálunk, és az egyik korábban nem kulcs mezőt használjuk föl mint particionáló kulcs, amire a lekérdezéseket akarjuk írni. Tehát a megkötés csak annyi, hogy minden alaptáblabeli kulcs maradjon kulcs, de a típusukat meg szabad változtatni.}}
 
 
Ezzel biztosítjuk azt, hogy az MW minden egyes sora pontosan egy sornak felel meg az alaptáblában. Pl adott a következő alaptáblánk:
<pre>
CREATE TABLE t (
k int,
c1 int,
c2 int,
v1 int,
v2 int,
PRIMARY KEY (k, c1, c2)
)
</pre>
 
 
Akkor a következő MW-k valid kulccsal rendelkeznek:
<pre>
CREATE MATERIALIZED VIEW mv1 AS
SELECT * FROM t WHERE k IS NOT NULL AND c1 IS NOT NULL AND c2 IS NOT NULL
PRIMARY KEY (c1, k, c2)
</pre>
Itt a c1 lépett elő partitioning kulccsá és a korábbi partitioning kulcsból (k) Clustering kulcs lett.
 
A '''not null''' a lekérdezésben kötelező elem minden olyan oszlopon, amiből kulcs lesz az MW-ben, hogy elkerüljük a null kulcsok beszúrást.
 
<pre>
CREATE MATERIALIZED VIEW mv1 AS
SELECT * FROM t WHERE k IS NOT NULL AND c1 IS NOT NULL AND c2 IS NOT NULL
PRIMARY KEY (v1, k, c1, c2)
</pre>
Mire kell figyelni: <br>
* Avoid too large partitions
* Choose your partition key in a way that distributes the data correctly, avoiding cluster hotspots (the partition key like days of the week is not a good one as it leads to temporal hotspots)
 
<br>
<br>
=Architektúra=
 
==Alapfogalmak==
 
===Gossip (pletykák)===
 
 
 
===Snitches===
A snitch protokoll segítségével térképezi föl egy node, hogy milyen messze vannak tőle az általa ismert node-ok, hogy ha egy műveletben koordinátor node-ként vesz részt, meg tudja határozni hogy melyik node-okról olvasson (a legközelebbi) és melyik node-okra írjon.
 
 
 
 
===Lightweight Transactions (check-and-set)===
Cassandra-ban nem létezik a hagyományos értelembe vett tranzakció kezelés, csak az úgynevezett pehelysúlyú tranzakció (LWT) ami azt biztosítja, hogy egy olvasás és az azt követő írás egy tranzakcióban lesz ('''linearizable consistency'''). Az olvasással ellenőrizzük, hogy az adott adat szerepel e már az adatbázisban, és ha nem, akkor bírjuk. Ez LWT csak egy partíción belül működik és elég költséges művelet, mivel a végrehajtásához a Cassandra a Paxos nevű konszenzus algoritmust futtatja. A konszenzus kialakításához a partíciót tároló replikák többségének konszenzusra kell jutnia az adott tranzakciót illetően.
 
 
 
 
==Node-ok csoportosítása==
Cassandrában a node-okat két szinten csoportosíthatjuk: Rack és Data Cener.
 
* '''Rack''': A rack-ben olyan nodo-kat csoportosítunk, amik tényleg egy fizikai rack-ben vannak, tehát ezek vannak a "legközelebb" egymáshoz.
* '''Data Center''': Egy datacenter-ben azokat Rack-eket csoportosítjuk, amik fizikailag egy szerverfarmon vannak.
:[[File:ClipCapIt-181106-205504.PNG]]
Alapértelmezetten minden node-unk a '''RACK1'''-be fog tartozni, és a '''DC1''' datacenterbe.
 
===Seed Nodes===
Minden egyes node-nak amit hozzáadnunk a cluster-hez szüksége van egy referencia node-ra, amitől le tudja kérdezni a cluster topológiáját (élő és halott node-ok, távolság..). Ezeket hívják seed-node-nak.
 
Minden egyes data-center-ben legalább két seed-node-ot kell létrehozni. A nem seed-node -knak a seed-nodeokat a cassandra.yaml fájlban kell statikusan beállítani. Alapértelmezetten csak a localhost van hozzáadva a listához:
<pre>
- seeds: "127.0.0.1"
</pre>
 
=Telepítés=
...
=CQL (Cassandra Query Language)alapok=
https://www.datastax.com/2012/01/getting-started-with-cassandra
2 | eng | fred | smith
</pre>
 
 
==Listák és Map-ek==
{'home': {street: '7712 E. Broadway', city: 'Tucson', state: 'AZ', zip_code: 85715}}
</pre>
 
 
 
<br>
 
=Kulcsok és indexek lekérdezésekben=
==Kulcs használati alapelvek==
* Ugyan azzal a primary kulccsal (partition és clustering kulcs együttvéve) egy INSERT-et többször is ki lehet adni, elsőre beszúrja, másodikra frissíti a sort, tehát átírja a nem kulcs mezőket a sorban az új értékre.
 
 
* A kulcsok nem kell hogy egyediek legyenek. Simán beszúrhatunk olyan sorokat, amikben a particionáló kulcsok azonosak, csak a clustering kulcsban különböznek. (Ha a clustering kulcs is egyezik, akkor nem új sort fog beszúrni, hanem a régit felülírja, ugyanis a particionáló kulcsok kijelölik a node-ot, és a node-on a particionáló + a clustering kulcsok jelölik ki a sort). Ha sok az olyan sor, ahol megegyezik a particionáló kulcsok értéke azzal az a baj, hogy úgynevezett 'hotspot'-okat hozunk létre, ami azt jelenti, hogy egy node-on őszpontosul az összes partíció (sor) mivel a partition key határozza meg a node-ot. Tehát olyan particionáló kulcsokat érdemes választani, amikben kevés az egyezés. <br>
Példa: Adott a következő tábla:
<pre>
CREATE TABLE users (
col1 int, col2 int, col3 int, col4 int,
PRIMARY KEY ((col1, col2), col3) );
</pre>
Itt particionáló kulcsok a col1 és col2, és clustering kulcs a col3.
 
 
Ekkor az alábbi két beszúrás két külön sort fog eredményezni, de ugyanarra a node-ra fognak kerülni:
<pre>
INSERT INTO users (col1, col2, col3, col4) VALUES ('col1', 'col2', 'col3', 'col4');
INSERT INTO users (col1, col2, col3, col4) VALUES ('col1', 'col2', 'col3mod', 'col4mod');
</pre>
A fenti példa azért eredményez két sort, mert a Clustering kulcs értékében elérnek (col2mod). Ha a Clustering kulcs is azonos lenne, és csak col4-ben térnének el, akkor nem eredményezne új sor.
 
 
* Lekérdezésnél az összes particionáló kulcsot meg kell adni, mivel annak segítségével találja meg a node-ot. Tehát a fenti táblára a minimum lekérdezés ez:
<pre>
SELECT * FROM user WHERE col1='aaa' AND col2='ddd'
</pre>
 
 
Ehhez ha akarjuk hozzáadhatjuk még a Clustering kulcsokat szűrési feltételnek, de nem kulcs mezőt nem adhatunk hozzá. <br>
Tehát ez helyes:
SELECT * FROM user WHERE col1='aaa' AND col2='ddd' AND col3='ccc'
De ez helytelen, mivel col4 nem kulcs mező.
SELECT * FROM user WHERE col1='aaa' AND col2='ddd' AND '''col4='ccc''''
 
 
* A Materialized view-ban az összes eredetileg particionáló kulcsot átmozgathatjuk Clustering kulccsá, és egy addig nem kucsmezöből készíthetünk particionáló kulcsot. Viszont fontos, hogy az összes korábbi kulcs mező kulcs maradjon. Az új particionáló kulcs, ami korábban nem volt kulcs mező nem kell hogy egyedi értékeket tartalmazzon. Viszont ha nem elég nagy a kardinalitása, akkor a materializált view-ból is 'hotspot' fog kialakulni mivel a materializált view is egy Cassandra tábla, így fontos, hogy az új particionáló kulcs is jól szétossza a node-ok között a tárolást. Mivel ha akarjuk, az összes base tábla particionáló kulcsából Clustering kulcsot csinálhatunk, a materializált view-ban tetszőleges korábban nem kulcs szerint tudunk keresni. <br>
Fontos, hogy az összes kulcs elemre az MW select-ben NOT NULL kikötést kell tenni, hogy biztosítsuk a sorok egyediségét. <br>
Tehát ez helyes:
<pre>
CREATE MATERIALIZED VIEW huser_mw AS
SELECT *
FROM user
WHERE col1 IS NOT NULL AND col2 IS NOT NULL AND col3 IS NOT NULL
PRIMARY KEY ((col4), col1, co2, col3);
</pre>
A korábbi col1 és col2 particionáló kulcsból Clustering kulcsot csináltunk, és az új view-ban tudunk col4 szerint keresni.
 
 
==Lekérdezés megkötések (Restriction)==
https://www.datastax.com/dev/blog/a-deep-look-to-the-cql-where-clause<br>
Itt a megkötés (restriction) szó azt jelenit, hogy egy kulcs szerepel e a WHERE ágban vagy sem. Ha igen, akkor az egy 'restricted' kulcs, ha nem szerepel, akkor az egy 'unrestricted' kulcs.
 
Példa tábla:
<pre>
CREATE TABLE adam.test1 (
col1 text,
col2 text,
col3 text,
col4 text,
PRIMARY KEY ((col1), col2, col3)
);
 
CREATE INDEX indexOnCol4 ON adam.test1 (col4);
</pre>
 
 
===Particionáló kulcsok + indexek===
Egy lekérdezésben vagy az összes particionáló kulcsot szerepeltetjük, vagy csak indexelt oszlopokat. Tehát két lehetőségünk van:<br>
1. csak a paritcionáló kulcs(ok):
SELECT * FROM adam.test1 WHERE col1 = 'k1'
(Persze ezt kiegészíthettük volna Clustering kulcsokkal)
 
2. csak az index:
SELECT * FROM adam.test1 WHERE col4 = 'C'
 
 
Alap esetben sem a particionáló kulcsokra, sem az indexekre nem használhatjuk a <, <=, >, >= operációkat, csak az =, IN ('k1', 'k2',..).
{{warning|Az IN használata erősen ellenjavallott performancia okokból, de ha már használjuk, akkor az IN értékkészletét alacsonyan kell tartani.}}
 
(A másodlagos indexre megengedett a <,> operáció, ha a SASI implementációt használjuk)
 
 
 
===Clustering kulcsok===
A Clustering kulcsokra már nagyon sok operáció engedélyezett:
* Ha csak egy oszlopot vonunk be az operációba: >, >=, =, <,<=, IN, CONTAINS
* Ha több clustering kulcsot is bevonunk: >, >=, =, <,<=, IN
 
 
A Clustering kulcsoknak az a sorrendje, ahogy a PRIMARY KEY kifejezésben megadtuk. Ha egy Clustering kulcsot szerepeltetünk a WHERE -ben, akkor az összes azt megelőző kulcsot is be kell rakni (pl. nem lehet benne csak a col3, ha a col2-öt nem szerepeltetjük)
 
 
Fontos, hogy ha a Clustering kulcsra írunk bármilyen megkötést (restriction-t) ami nem a '=', vagyis egyike a >,>=,<, <=, IN, CONTAINS megkötéseknek, akkor az összes sorban korábbi Clustering kulcsot is szerepeltetni kell, és azokban csak a '=' megkötés használható, vagy a <,>.. megkötése csak a sor legvégén használhatóak, a legutolsó clustering kulcsban, amit még beteszünk a WHERE -be (mert hogy a Clustering kulcsok megadása nem kötelező)
 
 
Ha tartományra kérdezünk le, akkor a kisebb mint és nagyobb mint (vagy fordítva) mindig ugyan arra a Clustering kulcsra kell legyen felírva és csak az utolsó kulcsra.
 
 
:[[File:ClipCapIt-181015-221508.PNG]]
Helyes, mert az egyetlen egy particionáló kulcs szerepel, és az első Clustering kulcsra írtunk fel '<' feltétel.
SELECT * FROM adam.test1 WHERE col1 = 'k1' AND col2 < 'Z'
 
:[[File:ClipCapIt-181015-221508.PNG]]
Helyes, pert benne van a particionáló kulcs, és mivel a col3 szerepel a WHERE-ben, a col2 is ott van, ahol csak az '=' restriction-t használtuk. Mivel a col3 az utolsó olyan Clustering kulcs, amit szerepel a WEHRE-ben, ezért ott használhattuk a '>' megkötést.
SELECT * FROM adam.test1 WHERE col1 = 'k1' AND col2 = 'Z' AND col3 > 'A'
 
:[[File:ClipCapIt-181015-221508.PNG]]
Helyes, mert a tartományra lekérdezés a végén van, és a nagyobb mint-kisebb mint operációkban ugyan az az oszlop (Clustering kulcs) szerepel, ráadásul a legvégén, különben nem lenne helyes.
SELECT * FROM adam.test1 WHERE col1 = 'k1' AND col2 = 'Z' AND col3 > 'A' AND col3 < 'Z'
A tartomány több Clustering kulcsra is vonatkozhat, még akkor is ha aszimmetrikus, tehát ez is helyes:
SELECT * FROM adam.test1 WHERE col1 = 'k1' AND (col2 , col3) > ('A','A') AND col2 < 'Z'
 
 
 
:[[File:ClipCapIt-181015-221536.PNG]]
Helytelen, mert a col3 Clustering kulcs szerepel, de a col2 nem, pedig a kulcsok definiálásakor a col2 előbb volt mint a col3.
SELECT * FROM adam.test1 WHERE col1 = 'k1' AND col3 > 'A'
 
:[[File:ClipCapIt-181015-221536.PNG]]
Helytelen, mert a col2-re nem az '=' operátort használjuk, pedig megadtuk a col2 utáni soron következő kulcsot is a col3-at. Mindig csak a legutolsó kulcs-ra használhatunk az '='-től eltérő operációt.
SELECT * FROM adam.test1 WHERE col1 = 'k1' AND col2 > 'Z' AND col3 > 'A'
 
 
 
===IN megkötés===
Az IN megkötést mind Particionáló kulcsra mind Clustering kulcsra lehet alkalmazni a sorrendre való tekintet nélkül (ezt a 2.2-ben vezették be, azelőtt ezt is csak az utolsó kulcs-ra lehetett rárakni).
 
 
IN az utolsó előtti Clustering kulcsra:
SELECT * FROM adam.test1 WHERE col1 = 'k1' AND col2 IN ('A', 'B') AND col3 = 'Z'
 
 
IN a particionáló kulcson:
SELECT * FROM adam.test1 WHERE col1 IN ('k1', 'k2') AND col2='A' AND col3 < 'Z';
 
 
Több oszlopos IN lekérdezés :
SELECT * FROM adam.test1 WHERE col1 = 'k1' AND (col2 , col3) IN (('A','A'), ('B','Z'));
 
===CONTAINS és CONTAINS KEY megkötések===
 
 
 
<br>
=Adatbázis GUI=
 
===DevCenter===
A datastax (a Cassandra gyártója) biztosít egy ingyenes GUI-t ami remek segítség az adatbázis karbantartásában:
Install: https://docs.datastax.com/en/developer/devcenter/doc/devcenter/dcInstallation.html
:[[File:ClipCapIt-181013-142901.PNG]]
 
 
<br>
===RazorSQL===
Sokféle grafikus eszközzel csatlakozhatunk a Cassandra adatbázishoz. A legtöbben a RazorSQL-t ajánlották, ami fizetős: https://razorsql.com/
:[[File:ClipCapIt-180930-154548.PNG]]
 
=Adat model=
:[[File:ClipCapIt-181010-232613.PNG]]
==Logical Data ModelingLogikai adatmodell==
Most hogy beazonosítottuk a szükséges lekérdezéseket, megtervezhetjük a táblákat. A táblák nem mások, mint a fenti flow diagramban a dobozok, vagyis a keresés eredmények, amik a denormalizált adatstruktúra miatt megfelel a táblának. A tábla neve mindig a fő entitással kezdődik, amit a lekérdezés visszaad, és _by_ szó használatával hozzá kell kapcsolni azokat másodlagos entitásokat, amik mentén lekérdezzük a fő entitást. Pl a Q1-re egy lehetséges elnevezés: '''tours_by_city'''
Ha a lekérdezés neve több szóból áll, akkor azokat is "_" al kell elválasztani, pl: '''available_dates_by_tour'''
===Chebotko logical diagram===
A legelterjedtebb diagram a táblák modellezésére az úgynevezett Choebotka diagram, ami ugyan dobozokból fog állni, mint a query flow diagramunk, de a dobozok belsejében ki lesznek fejtve az adott tábla oszlopai is. Jelmagyarázat:
* '''K''': partitioning key az adott oszlop
Íme az utazási iroda teljes adatbázis modellje, azaz Chebotka diagramja:
:[[File:ClipCapIt-181010181011-234005220118.PNG]] 
Ami még fontos, hogy a Q1-hez és a Q2 lekérdezésekhez tartozó táblákban a particionáló kulcs szöveges, ez az amit a felhasználó megad a felületen. A többi lekérdezésnek már van upstream lekérdezése, ahonnan kipottyannak számára a megfelelő ID-k.
{{note|A Chebotka logikai diagramon még nincsenek adattípusok meghatározva, az ábrán egy adott mező (pl customerName) lehet hogy később egy user defined adat típussal lesz megvalósítva (pl. First Name, Last Name) }}
 
==Fizikai adatmodell==
A Fizikai Chebotka diagramon már pontosan meghatározzuk az egyes mező típusokat, akár összetett, user defined típusokat is létrehozhatunk. Jelölése az alábbi:
:[[File:ClipCapIt-181011-215422.PNG|500px]]
 
 
A fenti felsorolásban láthatjuk hogy '''*név*''' formátumban kell a User Defined Type -ra hivatkozni. A UDT fizikai modelljében is két csillag közé kell rakni a nevet:
:[[File:ClipCapIt-181011-221836.PNG]]
A UDT-nak nincsenek kulcsai, mert nem önálló táblák.
 
 
 
Ezen a diagramon már nem szerepelnek a lekérdezések, pusztán a tábla szerkezetek. A tábla model tetején be kell jelölni, hogy az adott tábla melyik keyspace-be fog kerülni. Mi két keyspace-t hoztunk létre, egyet az utazásoknak, egyet pedig a foglalásoknak:
:[[File:ClipCapIt-181011-221228.PNG]]
 
 
 
===Materialized views===
A fizikai modellben az MW neveit dőlt betűkkel jelöljük, és egy szaggatott vonalú nyíllal kötjük össze a base táblával a Chebotka modellben:
:[[File:ClipCapIt-181011-230249.PNG]]
 
Láthatjuk, hogy az alaptáblában a TourId particionáló kulcs volt, az MW-ben viszont már csak Clustering key, ezzel teljesítettük a megkötést, hogy az alap tábla összes kulcsának szerepelnie kell az MW kulcsai között.
 
 
=Tervezés=
 
==Partíció mérete==
Egy partíció, vagyis azon cellák összessége, aminek ugyan az a particionáló kulcs csoportja, nem lehet nagyobb mint '''2 milliárd cella / partíció'''. Az egy partícióba eső cellák számát így lehet kiszámolni:
 
N<sub>v</sub> = N<sub>r</sub>*( N<sub>c</sub> − N<sub>pk</sub> − N<sub>s</sub>) + N<sub>s</sub>
 
* N<sub>v</sub> = össz cella szám, ezt akarjuk kiszámolni, ez nem lehet több mint 2 milliárd.
* N<sub>r</sub> = az összes sorok száma a partícióban
* N<sub>pk</sub> = primary kulcs oszlopok száma
* N<sub>c</sub> = az oszlopok száma a partícióban
* N<sub>s</sub> = statikus oszlopok
 
 
Mikor a tábla szerkezetet kitaláljuk, fontos, hogy előre megbecsüljük, hogy mi lesz az '''N<sub>v</sub>'''. Fontos hogy a legrosszabb esetet számoljuk ki beleszámolva a jövőbeli elképzelt növekedést is. Ha ez átlépné az 1 milliárdot, akkor be kell vezessünk újabb particionáló kulcsokat is.
 
Minél szélesebb egy tábla annál egyszerűbb ezt a korlátot elérni még relatíve kevés adattal is.
 
 
=Java kliens=
 
 
 
<source lang="java">
public class CassandraConnector {
 
private static CassandraConnector instance;
 
private Cluster cluster = null;
 
private Session session = null;
 
private MappingManager manager = null;
 
private CassandraConnector() {
initConnection();
}
 
public static CassandraConnector getInstance() {
 
if (instance == null) {
 
synchronized (CassandraConnector.class) {
if (instance == null) {
// if instance is null, initialize
instance = new CassandraConnector();
}
}
}
 
return instance;
}
 
private void initConnection() {
 
String host = System.getProperty("cassandra.default.host", "localhost");
String port = System.getProperty("cassandra.default.port", "9042");
String keyspace = System.getProperty("cassandra.default.keyspace");
String username = System.getProperty("cassandra.user", "user");
String password = System.getProperty("cassandra.pwd", "pass");
boolean withSSL = Boolean.parseBoolean(System.getProperty("cassandra.needSSL", "false"));
 
connect(nodes, withSSL, username, password, keyspace);
}
 
private void connect(String host, String port, boolean withSSL, String username, String password, String keyspace) {
 
try {
 
Cluster.Builder b = Cluster.builder().withSocketOptions((new SocketOptions()).setReadTimeoutMillis(1800000))
.withQueryOptions((new QueryOptions()).setFetchSize(100000));
 
 
builder.addContactPoint(host).withPort(port);
 
if (withSSL) {
b.withSSL();
}
 
if (username != null && username.trim().length() > 0 && withSSL) {
b.withCredentials(username, password);
}
 
session = cluster.connect();
 
manager = new MappingManager(session);
 
} catch (Exception e) {
System.out.println(e);
throw e;
}
}
 
 
public Session getSession() {
 
return session;
}
 
public MappingManager getManager() {
 
return manager;
}
 
 
===Mező típusok a Chebotka fizikai model-ben=== @Override:[[File:ClipCapIt-181011-215422 public void finalize() { try { session.close(); cluster.PNG|300px]]close(); } catch (Exception e) { // ... } }}</source>