Introduzione a CouchDB

CouchDB logo CouchDB e' un database documentale NoSQL disponibile con l'ampia licenza Apache.
Apache CouchDB e' un moderno documentale richiamabile semplicemente con l'HTTP e che al tempo stesso offre le piu' avanzate funzionalita' di replicazione dati e di ricerca in parallelo (Map/Reduce).

CouchDB (acronimo di Cluster Of Unreliable Commodity Hardware) e' uno dei piu' diffusi DB documentali grazie alla sua velocita', alla flessibilita, alla semplicita' di utilizzo ed al... prezzo! Questo documento presenta gli aspetti principali della versione attuale di CouchDB [NdE 1.2.0 2Q 2012]: Installazione, Utilizzo (Futon, cURL), Architettura, Viste(Map/Reduce), Storia e curiosita', ...

Installazione

Installare CouchDB e cURL (che serve per accedere) e' facile su Linux (eg. RedHat, Fedora, CentOS, Scientific Linux, ...):

yum install couchdb yum install curl
CouchDB MAC OS X toolbar Ora bisogna far partire il server CouchDB con il comando couchdb. Per verificare se funziona tutto basta un comando:
# curl http://127.0.0.1:5984 {"couchdb":"Welcome","version":"1.2.0"}

CouchDB e' disponibile per tutti i sistemi UNIX-based ed anche sulle piattaforme MS-Windows e Mac OS X. Installare le versioni precedenti di CouchDB non era cosi' semplice: bisognava partire dall'installazione del linguaggio di programmazione Erlang e ricompilare... ora su Mac OS X vi e' una semplice .app ed una simpatica toolbar.

Gia' fatto!

Utilizzo

CouchDB e' accessibile esclusivamente attraverso un HTTP-based RESTful API. Cio' significa che, anziche' collegarsi al DB server utilizzando un'applicazione client per interagire con il sistema, basta utilizzare un software in grado di interagire con un HTTP server web per fare richieste. CouchDB che a sua volta eseguira' le azioni nel database, restituendo una risposta appropriata quando finito.
Quindi e' possibile gestire il database semplicemente visitando gli URL nel browser web oppure utilizzando gli strumenti della riga di comando come curl o, cosa piu' importante, attraverso qualsiasi linguaggio di programmazione che supporta richieste HTTP.
L'implementazione dell'interfaccia REST (Representational Transfer State) su CouchDB e' molto completa poiche' non si limita al CRUD (CREATE, READ, UPDATE, DELETE) ma ogni operazione svolta su CouchDB e' richiamabile con l'HTTP.

Futon

CouchDB possiede una sua interfaccia web molto user friendly, Futon, dalla quale e' possibile eseguire qualsiasi operazione per la gestione di un database, come l'inserimento, la visualizzazione, la modifica e la cancellazione dei dati. Inoltre Futon contiene anche le principali funzionalita' di amministrazione di un database, come le impostazioni di configurazione, la replicazione dei dati, definizione dei ruoli e privilegi e uno strumento di testing.
Per accedere all'interfaccia web basta collegarsi da browser a localhost:5984/_utils

CouchDB Futon

Appare la pagina iniziale da cui e' possibile navigare per creare nuovi database, visualizzare i documenti di un database, inserire documenti, ...

cURL

Per i piu' affezionati alla linea di comando, si puo' usare curl, un tool per trasferire dati da/a un server utilizzando vari protocolli, tra cui HTTP, HTTPS, FTP. Il modo per farlo e' digitando:
curl <opzioni> <ip_host>:5984/<database>/<record>.
Da notare che nel URL viene specificata la porta 5984, e' quella usata dal processo di couchdb.
Tra le opzioni piu' importanti: -X per specificare il tipo di richiesta http: GET per richiedere dati, PUT e POST per modificare dati o DELETE per cancellare. Inoltre -d permette di specificare i dati da includere nella richiesta, ad esempio per modificare documenti nel database.
Esempi:

# Crea il database "libri"
curl -X PUT http://127.0.0.1:5984/libri

# Visualizza il contenuto di "libri" (all'inizio e' vuoto)
curl -X GET http://127.0.0.1:5984/libri

# Crea il documento con _id "lafineeilmioinizio" dentro il database "libri"
curl -X PUT http://127.0.0.1:5984/libri/lafineeilmioinizio \
 -d '{"titolo":"La fine e il mio inizio", "autore":"Tiziano Terzani", 
      "casa_editrice":"Longanesi", "prezzo":"18.60"}'

# NB: Tutte le volte che un documento viene modificato riceve un revision number
# Modifica un documento aggiungendo come allegato un'immagine
curl -X PUT http://127.0.0.1:5984/libri/lafineeilmioinizio/cover.jpg?rev=1-XXX \
 --data-binary @images/budda.jpg -H "Content-Type: image/jpg"

# Crea un documento hungergames copiando il contenuto da un altro documento
curl -X COPY http://127.0.0.1:5984/libri/lafineeilmioinizio -H "Destination: hungergames"

# Cancella il documento con _id "hungergames"
curl -X DELETE http://127.0.0.1:5984/libri/hungergames?rev=1-YYY 

# Effettua un caricamento massivo di documenti da file
curl -X POST http://127.0.0.1:5984/libri/_bulk_docs -H "Content-type: application/json" -d @biblio.json

# Visualizza tutto il contenuto del database "libri" e il dettaglio dei documenti presenti
curl -X GET http://127.0.0.1:5984/libri/_all_docs?include_docs=true

Quanto visto fino ad adesso consente di iniziare a lavorare con CouchDB. Se non vi siete ancora stancati... i prossimi argomenti sono un poco piu' avanzati!

Architettura

CouchDB e' un database document-oriented. Cio' significa che a differenza dei piu' tradizionali DBMS (Database Management System) relazionali come Oracle e PostgreSQL, i dati non vengono memorizzati in tabelle (o se volete, relazioni), ma in "documenti".

Su un database relazionale le tabelle hanno una struttura rigida, sono composte da campi definiti prima della effettiva memorizzazione dei dati. Le tabelle vanno dichiarate con gli opportuni statement DDL, prima di essere utilizzate. Ogni tabella e' composta da tuple (ovvero le righe della tabella o i record) che contengono i dati. La gestione dei dati si effettua con statement DML. I comandi DDL e DML della stragrande maggioranza dei DB relazionali sono in SQL. Ora dimentichiamoci tutto questo...

In CouchDB il concetto di relazione o di tabella non esiste, l'elemento fondamentale e' il documento che contiene al suo interno tutti i dati relativi, organizzati in modo eterogeneo. Si possono aggiungere e modificare i campi anche dopo l'effettivo inserimento dei dati. In questo modo record appartenenti alla stessa categoria di informazioni possono avere campi diversi tra di loro. La chiave primaria dei database relazionali viene tradotta nel campo univoco _id di CouchDB, creato automaticamente dall'engine del DBMS (ma che e' anche possibile indicare in modo esplicito.

Dal punto di vista del sistema operativo CouchDB si presenta come un unico processo beam.smp in ascolto sulla porta TCP 5984 (6984 se e' abilitato l'HTTPS). In realta' all'interno del processo operano diversi thread con compiti specifici.
I file utilizzati da CouchDB cambiano a seconda della piattaforma. Su Linux la configurazione si trova su /etc/couchdb, i file di database su /var/lib/couchdb, i log su /var/log/couchdb. Su MAC OS X i path dipendono dall'utente: a partire da /Users/USER_NAME/Library/Application Support/CouchDB si trovano le directory etc e var. Su Windows dipende dal path di installazione: la configurazione si trova su PATH_COUCHDB\etc\couchdb ...

Modello fisico dei dati

Ad ogni database corrisponde un file .couch che contiene i dati in formato binario.
I documenti vengono salvati in oggetti JSON (Javascript Object Notation), che e' un formato di dati molto utilizzato in Javascript. Il principale vantaggio di JSON, oltre la sua semplicita', e' l'esistenza dei parser per i piu' utilizzati linguaggi di programmazione (C, C++, Java, PHP, Python e Javascript), ovvero strumenti in grado di riconoscere e utilizzare i dati in maniera corretta. Un esempio di oggetto JSON:

{  "titolo": "Arte della guerra",
   "autore": "Sun Tzu",
   "anno_pubblicazione": "2005",
   "prezzo": "6.00",
   "casa_editrice": "Astrolabio",
   "tag":["strategia", "guerra", "cina"]
}
in cui viene definito un libro, con i nomi dei campi ed il loro valore (per i tag il valore e' un array).

Tutti i dati in CouchDB sono mantenuti su B-Tree. Ogni singolo documento e' un nodo del B-Tree ed ha una chiave. Il file che contiene il B-Tree e' ovviamente formato da un header, da blocchi, ... ma questi sono dettagli non significativi per questo documento introduttivo.

Consistenza dei dati e replicazione

CouchDB non utilizza alcun meccanismo di locking ma sfrutta l'MVCC (Multiversion Concurrency Control): ogni modifica di un oggetto ne crea una nuova versione. Le versioni precedenti non vengono cancellate. Se due modifiche vanno in conflitto poiche' accedono allo stesso documenti, la seconda riceve un errore in save. L'applicazione deve riprendere l'ultima versione del documento e rieseguire l'UPDATE.
L'isolamento e' mantenuto solo a livello di un singolo documento, questa e' una notevole semplificazione, rispetto alla complessa logica transazionale di altri database, ma consente l'ottimizzazione, la parallelizzazione e la distribuzione dei dati in modo semplice. A livello di accesso al file di dati ogni singola modifica ad un documento rispetta le proprieta ACID (Atomic Consistent Isolated Durable) con la serializzazione delle modifiche sui documenti e la scrittura sincrona sul disco.

CouchDB Replicator Piu' database CouchDB possono essere collegati tra loro in modo molto semplice. I database vengono aggiornati tra loro con una replicazione peer-to-peer incrementale implementata nativamente nell'engine. CouchDB permette una replicazione bidirezionale asincrona, utilizza un meccanismo automatico di risoluzione dei conflitti e fornisce una eventual consistency tra i database. Se i database sono ospitati su nodi differenti si ottiene con questo la distribuzione dei dati.
La replicazione di CouchDB puo' essere utilizzata sia per sincronizzare database locali che per complesse configurazioni con sharding dei dati.

Views

CouchDB Map/Reduce Per l'estrazione dei dati con CouchDB debbono essere usate le Views. Le viste sono definite in JavaScript e richiedono come obbligatorio il componente di Map del processo di Map/Reduce.
Quando una vista viene creata per la prima volta, CouchDB attraversa tutti i documenti del database ed esegue la funzione su di essa. Prende allora il risultato della vista, che e' memorizzato sotto forma di file di coppie chiave / valore, e lo archivia in un singolo B-tree file. Anche se questo puo' richiedere molto, questa operazione viene eseguita solo la prima volta che viene creata la vista. Ad ogni successivo cambiamento di un documento, la funzione di visualizzazione viene eseguita solo sul documento stesso, tutto il resto e' gia' memorizzato nel B-tree e rimane invariato. L'analogo di una vista CouchDB su un DB relazionale e' l'esecuzione di una query e la creazione di un indice... ma le differenze sono molte!

La vista seguente, ad esempio, riceve come parametro un documento e, se tale documento e' della casa editrice Mondadori, verranno visualizzati in output il titolo, rispettivamente l'autore, con la chiave _id.

function(doc) {
    if(doc.casa_editrice=="Mondadori")
        emit(doc._id, {"titolo":doc.titolo, "autore":doc.autore});
}

Map/Reduce

In una view di CouchDB e' possibile definire anche la funzione di Reduce. Le funzioni vengono entrambe applicate ad una lista in ingresso, pero' la Map produce un output per ogni elemento dell'elenco in ingresso, mentre la Reduce produce un solo output per l'intero elenco. La reduce viene usata per realizzare i raggruppamenti e le funzioni aggregate analoghe a quelle dell'SQL, come la somma, la media, il massimo/minimo.
Esempio:

Map:
function(doc) {
    if (doc.autore=="Giorgio Faletti")
        emit (doc.autore, 1);
}

Reduce:  
function(key, values, rereduce) {
    return sum(values);
}

Con la map di sopra, per ogni libro dell'autore Giorgio Faletti viene visualizzato in output il risultato "1" con la chiave "autore". Ovviamente da sola e' una query inutile, ma insieme alla reduce produce in output un solo risultato in cui vengono contati tutti i libri dell'autore. Questo perche' i risultati della map vengono tutti raggruppati per chiave (in questo caso uguale per tutti a "Giorgio Faletti") e viene eseguita la loro somma (sommando 1 per ogni elemento, si conta il numero totale di documenti).

Questa modalita' di reperimento dei dati puo' sembrare un po' troppo complessa inizialmente... In effetti in parte e' vero, ma l'aspetto piu' importante e' che la funzione di Map puo' essere eseguita in parallelo scalando su server differenti in una complessa ma efficiente configurazione per trattare i Big Data.

Storia e curiosita'

Il motto di CouchDB e': Apache CouchDB has started. Time to relax.

CouchDB e' stato inizialmente scritto in C++ da Damien Katz, successivamente e' stato migrato in Erlang che e' tuttora il suo linguaggio di programmazione. CouchDB e' ora un progetto Apache mantenuto dalla comunita'.

Per lavorare su CouchDB esiste anche la possibilita' di installare CouchApp - una serie di script che permettono di costruire completi applicazioni stand-alone per il database usando solo HTML e JavaScript. Poiche' il database stesso risponde in HTTP e' possibile concentrare su un solo nodo (eventualmente replicabile) la classica pila applicativa web a tre livelli.

CouchDB si e' rapidamente imposto sul mercato, diventando uno tra i piu' usati database non relazionali. In pratica i due piu' diffusi NoSQL documentali sono CouchDB e MongoDB: entrambi sono velocissimi (a scapito delle proprieta' ACID), memorizzano i dati in BSON/JSON, sono scalabili in modo nativo su piu' nodi e non forniscono un'interfaccia SQL.

Damien Katz, il creatore di CouchDB, ha recentemente lasciato il progetto Apache CouchDB per entrare come CTO in Couchbase: un'azienda che sviluppa un prodotto con lo stesso nome basato su CouchDB e memcache. Couchbase e CouchDB sono tuttavia ambienti molto differenti. Couchbase e' distribuito come Open Source ma dispone di un ambiente Enterprise con supporto e relativi canoni. CouchDB e' il componente di Couchbase utilizzato per la memorizzazione, gli altri servizi sono gestiti pero' in modo differente da moduli distinti. Le API HTTP di CouchDB NON sono disponibili in Couchbase che presenta invece API compatibili a memcache. Couchbase fornisce nativamente funzionalita' di auto-sharding, clustering e la possibilita' di effettuare riconfigurazioni online.
I loghi delle due basi dati sono simili perche' ricordano un rilassante sofa': CouchDB e Couchbase

Nell'agosto 2011 sono state pubblicate le specifiche dell'UnQL un linguaggio di interrogazione basato su JSON. I due autori princiapali sono Richard Hipp (creatore di SQLite) e Damien Katz (creatore di CouchDB e CTO di Couchbase).

Per una documentazione piu' dettagliata si rimanda al sito ufficiale di Apache CouchDB.


Titolo: Introduzione a CouchDB
Livello: Medio (2/5)
Data: 10 Luglio 2012
Versione: 1.0.5 - 14 Febbraio 2013
Autori: alexandrei.loghin [AT] gmail.com, mail [AT] meo.bogliolo.name