Cassandra a PHP - Twissandra
V předchozím článku jsem se věnoval obecně konfiguraci a spuštění Cassandry (více uzlů na jednom stroji), tentokrát bych se rád prezentoval svoje zkušenosti s přístupem ke Cassandře z PHP. Cassandra je často demonstrována na Twissandře, schématu určeném jakoby pro Twitter, a toto schéma bude pro jednoduchost použito i v tomto článku ...
Tento článek je určitým pokračováním článku Cassandra By Example, ve kterém Eric Evans představuje základní principy Cassandry (co jsou to keyspaces, column families apod. mimo jiné v kontrastu s relačním schématem) právě na Twissandře, a ukazuje jak je Cassandře přistupovat z Pythonu (pomocí knihovny pycassa).
Nemám v úmyslu odkazovaný článek jakkoliv vykrádat nebo zbytečně duplikovat - rád bych aktualizoval některé informace (pro Cassandru 0.7.x) a doplnil informace o přístupu z PHP. Rozhodně doporučuji k přečtení první polovinu Ericova článku, tj. odstavce "Twitter" (představující relační schéma pro Twitter) a "Twissandra" (ukazující odpovídající schéma v Cassandře).
Vytvoření schématu
Jak už jsem zmínil, článek Erica Evanse byl psán pro Cassandru 0.6, což mimo jiné znamená že struktura databáze (keyspaces, column families) byla deklarována pomocí XML souboru. To se ve verzi 0.7 změnilo, protože XML bylo defacto elimimováno a schéma se definuje přímo v databázi pomocí rozhraní cassandra-cli. Spusťte tedy cassandra-cli a vytvořte strukturu pro Twissandru:
create keyspace Twissandra; use Twissandra; create column family User with comparator = UTF8Type; create column family Username with comparator = BytesType; create column family Friends with comparator = BytesType; create column family Followers with comparator = BytesType; create column family Tweet with comparator = UTF8Type; create column family Userline with comparator = LongType; create column family Timeline with comparator = LongType;
Vysvětlení obecných pojmů keyspace a column family, stejně jako významu jednotlivých column families, najdete v již dříve zmiňovaném článku.
Knihovna phpcassa
Pro Cassandru existují dvě klientské PHP knihovny - phpcassa a SimpleCassie. Zkoušel jsem obě a osobně rozhodně doporučuji první jmenovanou. SimpleCassie se sice prezentuje jako jednodušší na použití (což je zejména v začátcích lákavé), nicméně dokumentace je naprosto nedostatečná a některé věci se mi ani po dlouhém snažení nepodařilo zprovoznit. Naopak v phpcassa fungovalo vše na první pokus a dokumentace je dosti podrobná. Navíc se jedná o "PHP variantu" knihovny pycassa, takže většinu příkladů z Pythonu lze velmi jednoduše přepsat.
Instalace knihovny je dosti jednoduchá - stačí stáhnout vhodný balíček, rozbalit ho a na začátku skriptu (nebo např. v .htaccess souboru) nastavit odpovídající include_path.
Připojení ke Cassandře a inicializace
První co je třeba udělat je vytvořit spojení ke Cassandře (k jednomu z uzlů) a inicializovat objekty reprezentující jednotlivé column families.
/* nacteni phpcassa knihoven */
require_once('phpcassa/connection.php');
require_once('phpcassa/columnfamily.php');
/* pripojeni ke keyspace Twissandra na IP 10.0.0.1 */
$conn = new ConnectionPool('Twissandra', array('10.0.0.1:9160',
'10.0.0.2:9160',
'10.0.0.3:9160'));
/* inicializace column families */
$user_cf = new ColumnFamily($conn, 'User');
$username_cf = new ColumnFamily($conn, 'Username');
$friends_cf = new ColumnFamily($conn, 'Friends');
$followers_cf = new ColumnFamily($conn, 'Followers');
$tweet_cf = new ColumnFamily($conn, 'Tweet');
$userline_cf = new ColumnFamily($conn, 'Userline');
$timeline_cf = new ColumnFamily($conn, 'Timeline');
a nyní už můžeme implementovat jednodlivé funkce. Nejdříve funkce pro vytvoření uživatele
function create_user($userid, $username, $password) {
global $user_cf, $username_cf;
$user_cf->insert($userid, array('id' => $userid,
'username' => $username,
'password' => $password));
$username_cf->insert($username, array('userid' => $userid));
}
a vytvoření "followera" (uživatel sleduje tweety jiného uživatele)
function add_follower($userid, $friendid) {
global $friends_cf, $followers_cf;
$friends_cf->insert($friendid, array($userid => time()));
$followers_cf->insert($userid, array($friendid => time()));
}
Poslední funkce vytvářející objekty se týká tweetů
function create_tweet($userid, $tweetid, $body) {
global $tweet_cf, $timeline_cf, $userline_cf, $followers_cf;
$time = time();
$tweet_cf->insert($tweetid, array('id' => $tweetid,
'userid' => $userid,
'body' => $body,
'_ts' => $time));
$userline_cf->insert($userid, array($time => $tweetid));
$timeline_cf->insert($userid, array($time => $tweetid));
foreach ($followers_cf->get($userid) AS $fid => $ftime) {
$timeline_cf->insert($fid, array($time => $tweetid));
}
}
a nakonec dvě funkce pro načítání dat - vypsání tweetů vložených konkrétním uživatem a načtení tweetů z časové osy uživatele (tj. jeho tweetů a tweetů jeho přátel):
function get_tweets($userid) {
global $userline_cf, $tweet_cf;
$timeline = $userline_cf->get($userid);
return $tweet_cf->multiget($timeline);
}
function get_timeline($userid) {
global $timeline_cf, $tweet_cf;
$timeline = $timeline_cf->get($userid);
return $tweet_cf->multiget($timeline);
}
Tyto funkce pochopitelně nejsou dokonalé a je na nich co zlepšovat (např. použití přesnějšího času než poskytuje funkce time()), eliminace globálních proměnných (které jsou použity pro jednodušší formulaci příkladů), neošetření výjimek např. při nenalezení položky s daným klíčem.
Podrobnější info o použití knihovny phpcassa najdete zde, dokumentaci API zde. Skript s implementací výše uvedeného příkladu (a krátkého případu použití) můžete stáhnout zde.




