Basi di dati ad oggetti
L'avanzare della tecnologia ha portato a nuove esigenze applicative, per cui il modello relazione è diventato obsoleto, se pur largamente utilizzato nella maggioranza delle applicazioni. Per citarne alcune:
- Progettazione di componenti elettronici/meccanici
- Applicazioni che utilizzano dati multimediali
- Varie applicazioni scientifiche[1]
- Intelligenza Artificiale (in particolare i sistemi esperti)
Le basi di dati ad oggetti
[modifica]I primi prototipi di ODBMS nascono verso la metà degli anni '80, utilizzando linguaggi di programmazione per l'interazione e non attraverso interrogazioni in uno specifico linguaggio. Successivamente nasce la seconda generazione di OBDMS che fornisce una divisione delle tipologie della base di dati:
- OODBMS: una tecnologia completamente rivoluzionaria rispetto alle basi di dati relazionali;
- ORDBMS: una tecnologia con un approccio più simile ai database relazionali.
Le basi di dati ad oggetti devono avere le stesse garanzie che le basi di dati relazionali garantiscono tramite le proprietà ACID.
Funzionalità
[modifica]Gli ODBMS risolvono il problema del cosiddetto mismatch di impedenza cioè quel problema che affligge i database management system relazionali dovuto alla differenza di gestione dei dati con le applicazioni: le applicazioni, spesso ad oggetti, devono utilizzare un macchinoso sistema a cursori per ottenere la rappresentazione degli oggetti presenti nei database relazionali. I database ad oggetti risolvono questo problema.
Il manifesto delle basi di dati ad oggetti (leggibile qui) è un documento prodotto da alcuni studiosi per cercare di dare una prima standardizzazione alle basi di dati ad oggetti. In particolare fornisce una lista di funzionalità che un OODBMS deve avere. Si dividono in obbligatorie (dette anche golden rules):
- Oggetti complessi: la possibilità di costruire appunto, tipi complessi;
- Identità di oggetti: la possibilità di identificare in modo univoco un oggetto (tramite OID);
- Incapsulamento: come programmazione ad oggetti
- Tipi e/o classi: il supporto di tipi e/o classi
- Ereditarietà
- Overriding, overloading, late binding
- Completezza computazionale
- Estensibilità: la possibilità di creare nuovi tipi non presenti nel dbms
- Persistenza
E opzionali:
- Gestione della memoria secondaria: la possibilità di gestire il database in maniera efficiente tramite indici, ecc.
- Concorrenza: accessi multipli contemporanei
- Robustezza: la capacità di resistere e reagire ai guasti
- Linguaggio ad-hoc di query
Alcune di queste funzionalità verranno introdotte più avanti in questa lezione.
Componenti
[modifica]Per definire le componenti successive, partiamo dicendo che un database ad oggetti è una collezione di oggetti. Un oggetto deve possedere tre attributi:
- Un identificatore, che lo identifichi univocamente all'interno della base di dati (chiameremo questo identificatore OID)
- Lo stato dell'oggetto stesso (equivalente all'insieme di tutti gli attributi nei linguaggi di programmazione)
- Il comportamento dell'oggetto (l'insieme dei metodi dello stesso)
Tipi
[modifica]Ogni proprietà o attributo dell'oggetto ha un tipo che rappresenta il tipo di dato contenutovi. Inoltre anche i metodi possiedono i tipi di attributi e il tipo ritornato.
Come in programmazione distinguiamo:
- Tipi semplici (o atomici): interi, stringhe, OID, bool, enumerazioni, ecc.
- Tutti i tipi semplici accettano un particolare valore polimorfo detto nil.
- Tipi composti (o complessi): vettori, liste, ecc.
I tipi composti generalmente usati sono:
- Record: tuple di valori differenti (eventualmente complessi) che possiedono un etichetta associativa;
- Set: insieme di elementi dello stesso tipo senza duplicati;
- Bag: insieme di elementi dello stesso tipo che accetta duplicati;
- List: collezione ordinata di elementi dello stesso tipo che accetta duplicati.
Esempio di record
[modifica]Studente: record-of(
Matricola: integer,
Nome : string,
Cognome : string,
VotiEsami : set-of( 18,25,30,19,22 )
)
Classi e Oggetti
[modifica]Possiamo definire un oggetto come una coppia <OID, Valore>, dove OID è un identificatore univoco dell'oggetto e Valore è un dato di tipo complesso.
Una classe è la struttura di un insieme di oggetti omogenei. Per meglio chiarire, una classe definisce il tipo complesso dell'oggetto (interfaccia) e la sua implementazione. I tipi sono quindi sono astrazioni che descrivono il comportamento di uno o più oggetti, mentre le classi definiscono inoltre il funzionamento di essi.
Definiamo inoltre estensione un insieme di oggetti dello stesso tipo. Si noti che questa inclusione non è esclusiva: un oggetto può appartenere a più estensioni.
Operatori
[modifica]Oltre a normali operatori per i tipi atomici, i database ad oggetti presentano una differenza per quanto riguarda il concetto di uguale. Similmente ad altri linguaggi[2] possiamo distinguere:
- Identità (indicata dal simbolo =): restituisce vero se e solo se entrambi gli oggetti hanno lo stesso identificatore (cioè sono la stessa locazione di memoria);
- Uguaglianza superficiale (indicata dal simbolo ==): restituisce vero se e solo se gli oggetti hanno lo stesso stato, cioè proprietà uguali;
- Uguaglianza profonda (indicata dal simbolo ===): restituisce vero se e solo se gli oggetti hanno lo stesso stato seguendo i riferimenti, cioè proprietà uguali e gli oggetti rappresentati come riferimenti nelle proprietà sono a loro volta profondamente uguali.
Metodi
[modifica]Ugualmente ai linguaggi di programmazione ad oggetti, i metodi sono funzioni o procedure che agiscono su un oggetto e più precisamente sul suo stato. I metodi che modificnao lo stato sono detti trasformatori, altrimenti sono detti accessori. Solitamente nei OODBMS i metodi sono implementati con codice di un altro linguaggio (ad oggetti ovviamente) come il C++ o Java.
Esistono due categorie speciali di metodi (come i linguaggi di programmazione):
- Costruttori
- Distruttori
Ogni metodo può assumere inoltre la proprietà di pubblico o privato. Un metodo può essere override di un altro metodo o overload di un altro metodo.
Si rimanda allo studio della programmazione ad oggetti per tutti i dettagli relativi a queste definizioni.
Esempio di dichiarazione dell'interfaccia
[modifica]add method AggiungiVoto(voto : integer)
in class Studente is public;
Ereditarietà
[modifica]L'ereditarietà si comporta allo stesso modo dei linguaggi di programmazione ad oggetti. Si ricordi però che gli oggetti qui considerati non sono volatili, hanno durata persistente. L'ereditarietà multipla non è possibile in tutti i sistemi.
Anche qui si rimanda allo studio della programmazione ad oggetti per approfondire.
Persistenza
[modifica]Ogni sistema possiede un metodo differente per gestire la persistenza o meno degli oggetti. Un oggetto persistente è un oggetto che non viene eliminato al termine dell'esecuzione di un programma. Indichiamo qui alcuni metodi per la gestione, non sempre disponibili in tutti i sistemi:
- Dichiarando una classe come persistente;
- Attraverso un garbage collector, se un oggetto è referenziato da un altro oggetto non viene eliminato, in caso contrario viene eliminato;
- Denominando l'oggetto, cioè assegnando a un oggetto un nome (come avviene in C++ per esempio). Quando la denominazione non è più presente, l'oggetto può essere eliminato automaticamente (anche qui tramine un garbage collector) oppure deve essere eliminato esplicitamente (come in C++).
Object Database Management Group
[modifica]Il consorzio Object Database Management Group è stato creato alla fine degli anni '80 per definire un modello standard per i database ad oggetti ed è composto dai principali produttori di ODBMS e ricercatori in questo ambito.[3]
Il consorzio ha definito due linguaggi, uno di definizione e uno di query, dualmente a quelli relazionali: ODL e OQL.
Il linguaggio OQL
[modifica]OQL è considerato uno standard nei linguaggi di interrogazione delle basi ad oggetti. Come per SQL, non ha la stessa espressività di un linguaggio di programmazione, ma può invocare dei metodi sugli oggetti.
Presentiamo OQL per esempi, considerando il seguente schema ad oggetti:
Classe(Codice, Anno, Sezione, numeroStudenti(), Studenti) Studente(Matricola, Nome, Cognome, Classe, Nascita(Data, Luogo), CalcolaMedia(), CalcolaEta())
e le loro relative estensioni Classi e Studenti.
Per estrarre tutte le matricole degli studenti che hanno media maggiore di 25, dobbiamo eseguire (questa query ritornerà un tipo set):
SELECT s.Matricola FROM s IN Studenti
WHERE s.CalcolaMedia() > 25
Estrarre tutti i nomi degli studenti:
SELECT DISTINCT s.Nome FROM s IN Studenti
Se invece vogliamo estrarre una coppia di valori, dobbiamo utilizzare:
SELECT DISTINCT STRUCT (N: s.Nome, C: s.Cognome)
FROM s IN Studenti
WHERE s.Classe.Anno = 1 AND s.Classe.Sezione = "B"
Così quelle che prima erano le join, ora è molto più semplice:
SELECT STRUCT (IDStudente: s.Matricola, IDClasse: s.Classe.Codice)
FROM s IN Studenti
È possibile creare anche query annidiate:
SELECT STRUCT (Anno: x.Anno, Sezione: x.Sezione,
StudentiMinorenni: (SELECT y FROM y IN x.Studenti WHERE y.CalcolaEta() < 18)
)
FROM x IN Classi
Per restituire dati ordinati:
SORT s IN Studenti BY s.Matricola
Le viste vengono create anteponendo define e il nome della vista alla query cercata.
Altri due utili costrutti sono for all e exists utilizzabili come quantificatori universali. Ad esempio:
SELECT DISTINCT c.Codice FROM c IN Classi
WHERE FOR ALL x IN c.Studenti : x.CalcolaMedia() < 25
Basi di dati ad oggetti relazionali
[modifica]Le basi ad oggetti relazionali (ORDBMS) sono state concepite con lo scopo di fornire una transazione più semplice dalle basi di dati puramente relazionali a quelle puramente ad oggetti. Per fare ciò il modello di dati è compatibile con il modello relazionale.
SQL-3
[modifica]Lo standard SQL-3 (nome non ufficiale di SQL:1999) introduce il concetto di ORDBMS. L'uso delle caratteristiche object-oriented è opzionale: difatti è possibile creare tabelle con la normale sintassi delle tabelle relazionali.
SQL-3 distingue due tipi di dati:
- Tipi predefiniti e distinti (come nel modello relazionale)
- Tipi definiti dall'utente (UDT)
- Typed-table
- Sotto-tabelle
Tipi distinti
[modifica]Similmente a SQL-2 possono essere creati tipi distinti e tabelle generiche:
CREATE TYPE years AS INTEGER FINAL;
CREATE TYPE codice AS INTEGER FINAL;
CREATE TABLE Studente (
Matricola codice PRIMARY KEY,
Nome VARCHAR(50) NOT NULL,
Cognome VARCHAR(50) NOT NULL,
Eta years NOT NULL
)
Si noti che years e codice sono due tipi completamente distinti, anche se dichiarati in equal modo. Non si possono effettuare operazioni tra essi, senza un cast esplicito.
UDT - User Defined Type
[modifica]Gli UDT sono tipi complessi dotati di attributi e metodi. Permettono di definire quellI che negli OODBMS sono i tipi dei parametri delle funzioni, i ritorni dei metodi, ecc. NB: non sono una classe! Non possono creare oggetti (vedi le typed-table per questo).
Per capire la sintassi degli UDT vediamo subito un esempio:
CREATE TYPE Automobile (
Targa CHAR(7),
Marca REF(CaseProduttrici),
Modello CHAR VARYING(100),
Ruote wheel ARRAY[4]
REFERENCES ARE CHECKED -- L'integrità viene verificata
ON DELETE CASCADE -- Politica on delete come in SQL-2
) NOT FINAL
-- Definiamo qualche metodo (solo segnatura!):
METHOD getKm() RETURNS INTEGER
METHOD getTarga() RETURNS CHAR(6)
;
In questo esempio abbiamo introdotto il concetto di ARRAY, di riferimento a tipo esterno e di definizione di metodi. I metodi sono poi successivamente implementabili in linguaggio di programmazione (java, c++, ecc.) oppure tramite l'estensione SQL/PSM.
Essendo gli attributi liberamente scrivibili e leggibili, per poter creare un buon incapsulamento si può chiamare i getter e i setter con gli stessi nomi dei campi su cui agire, in modo da garantire l'accesso tramite i metodi stessi.
Per ereditare da un altro tipo:
CREATE TYPE AutomobileSportiva UNDER Automobile AS (
VelocitaMassima INTEGER
) NOT INSTANTIABLE NOT FINAL;
Si noti le parole chiave NOT INSTANTIABLE indica che il tipo appena definito è astratto e non può essere instanziato.
Typed Table
[modifica]Modifichiamo l'esempio precedente in modo da poter creare un oggetto a partire da questo tipo (che ora diventa effettivamente una typed-table, cioè corrispondente a una classe nel modello puramente ad oggetti):
CREATE TYPE TipoAutomobile (
Targa CHAR(7),
Marca CHAR VARYING(50),
Modello CHAR VARYING(100),
Ruote wheel ARRAY[4],
NumeroTelaio INTEGER,
) NOT FINAL
REF FROM (NumeroTelaio)
;
La sintassi REF specifica che NumeroTelaio sarà utilizzato come identificatore del record per le istanze di quel tipo. La colonna di riferimento può essere anche generata automaticamente dal sistema con il comando REF IS SYSTEM GENERATED.
Ora è possibile creare una tabella del tipo appena creato:
CREATE TABLE Automobile OF TipoAutomobile(REF IS NumeroTelaio DERIVED);
Basi di dati multimediali
[modifica]Negli ultimi anni le basi di dati necessitano sempre più di contenere non solo dati in formato testuale, ma anche altri dati cosiddetti multimedidali, tra i quali possiamo riconoscere:
- Immagini
- Video
- Audio
- Documenti di vario tipo (pdf, word, ecc.)
Questi tipi di dati possono essere codificati e facilmente salvati in una base di dati (ad esempio in una base di dati con linguaggio SQL può venirci in aiuto il campo BLOB).
Interrogazioni multimediali
[modifica]Il problema nasce quando viene richiesto di interrogare la base di dati su aspetti che riguardano i dati multimediali codificati. Ad esempio non solo potremmo voler cercare una particolare immagine nel database (cosa alquanto banale, si pensi di codificare l'immagine da cercare e verificare se esiste il campo blob corrispondente), ma anche poter estrarre tutte le immagini che ci somigliano.
In questi casi si utilizzano tecniche ad-hoc adattive.
Un altro esempio è la ricerca nei testi effettuata dai motori di ricerca.
Architettura interna ed esterna delle ODB
[modifica]Come per le basi di dati relazionali si pone il problema di come rappresentare fisicamente i dati. Possiamo identificare due principali tipologie di approcci:
- Approccio orizzontale: i dati vicini appartengono allo stesso oggetto;
- Approccio verticale: i dati vicini appartengono alla medesima proprietà di una classe.
Il secondo, meno intuitivo, favorisce le operazioni di ricerca e ordinamento per una proprietà.
Un altro problema è la distribuzione della base di dati. Nei database ad oggetti è necessario distribuire le classi, ma bisogna anche capire come farle interagire se si trovano su server differenti. Inoltre è necessario definire chi effettuerà una determinata azione, eventualmente potrebbe farlo anche il client. Ancora più complesso il modello a transazioni distribuito, per la corretta implementazione delle garanzie che esse impongono.
Note
[modifica]- ↑ Ad esempio è utilizzato dallo Stanford Linear Accelerator Center
- ↑ Come in Java il metodo predefinito equals e l'operatore =
- ↑ Contributori al consorzio ODMG