Collections et UDT¶
Objectifs
- Manipuler les Collections
- Manipuler les UDT
- Utiliser une modélisation spécifique NOSQL (dénormalisé)
Les collections¶
Les collections permettent une représentation dénormalisée des données. C'est une solution pour contourner l'absence d'opération de jointure.
Cassandra définit 3 types de collections :
- MAP : représentant un dictionnaire
- SET : représentant un ensemble non ordonnées
- LIST : représentant un liste ordonnée de valeurs
Syntaxe¶
- Déclaration :
MAP '<' cql_type',' cql_type'>' SET '<' cql_type '>' LIST '<' cql_type'>'
- Litéraux :
map_literal::= '\{' [ term ':' term (',' term : term)* ] '}' set_literal::= '\{' [ term (',' term)* ] '}' list_literal::= '[' [ term (',' term)* ] ']'
- Accès :
- MAP : map_name['key']
- LIST : list_name[index]
- SET : pas d'accès aux éléments
- Opérations :
+
: Ajout d'éléments-
: Supression d'éléments=
: AffectationCONTAINS
: tester l'appartenance d'un élément à une collectionNécessite un index sur la colonne
CONTAINS KEY
: tester la présence d'une clé pour le type MAPNécessite un index sur la colonne
- Index
- LIST et SET :
CREATE INDEX index_name ON table_name(column);
- MAP :
CREATE INDEX index_name ON table_name(KEYS (column)); CREATE INDEX index_name ON table_name( VALUES (column));
- LIST et SET :
Exemples¶
Créer une table contenant des collections
CREATE TABLE personne (
id INT,
nom VARCHAR,
prenom VARCHAR,
evenements MAP <text, date>,
emails SET <text>,
enfants LIST <text>,
PRIMARY KEY (id)
);
Création d'index
CREATE INDEX idx_emails ON personne(emails);
CREATE INDEX idx_enfants ON personne(enfants);
CREATE INDEX idx_k_evenement ON personne(KEYS(evenements));
CREATE INDEX idx_v_evenement ON personne(VALUES(evenements));
INSERT INTO personne(id, nom, prenom, evenements, emails, enfants)
VALUES (1, 'DELON','Alain',
{'naissance': '1935-11-08'},
{'alain@laposte.fr','alain.delon@laposte.fr'},
['Anthony','Anouchka','Alain']);
-- Ajouter la date du mariage dans les événements et supprimer un email et modifier le prénom d'un enfant
UPDATE personne SET evenements = evenements + {'mariage':'1964-08-13'},
emails = emails - {'alain@laposte.fr'}, enfants[2] = 'Alain-Fabien'
WHERE id = 1;
-- Supprimer le premier enfant
DELETE enfants[0] FROM personne WHERE id = 1;
-- Chercher la date de naissance des personnes ayant un email alain.delon@laposte.fr
SELECT evenements['naissance'] FROM personne WHERE emails CONTAINS 'alain.delon@laposte.fr';
-- Chercher les noms et prénoms des personnes ayant un événement mariage
SELECT nom, prenom FROM personne WHERE evenements CONTAINS KEY 'mariage';
Les types utilisateurs (UDT)¶
Les types définis par l'utilisateur sont semblables aux enregistrements dans les langages de programmation. Il se composnt de champs.
Syntaxe¶
La manipulation des UDT dans CQL est similaire à celle des tables.
- Définition
CREATE TYPE [ IF NOT EXISTS ] <udt_name>(<champ> <cql_type>, ...);
- Modification
ALTER TYPE <udt_name> ADD <champ> <cql_type>; ALTER TYPE <udt_name> RENAME <ancien_nom> TO <nouveau_nom>;
- Suppression
DROP TYPE <udt_name>;
- Litéraux
{champ1:valeur, ...}
- UDT et Collections
CREATE TABLE T(collection MAP<text frozen<udt>>...);
Exemple¶
Exemple 1
CREATE TYPE address (
street text,
city text,
zip text
);
CREATE TABLE user (
name text PRIMARY KEY,
home address
);
INSERT INTO user (name, home)
VALUES (
'z3 Pr3z1den7',
{
street: '1600 Pennsylvania Ave NW',
city: 'Washington',
zip: '20500'
}
);
Exemple 2
CREATE TYPE phone (
country_code int,
number text,
);
CREATE TYPE address (
street text,
city text,
zip text,
phones map<text, phone>
);
CREATE TABLE user (
name text PRIMARY KEY,
addresses map<text, frozen<address>>
);
INSERT INTO user (name, addresses)
VALUES (
'z3 Pr3z1den7',
{
'home' : {
street: '1600 Pennsylvania Ave NW',
city: 'Washington',
zip: '20500',
phones: {
'cell' : { country_code: 1, number: '202 456‐1111' },
'landline' : { country_code: 1, number: '...' }
}
},
'work' : {
street: '1600 Pennsylvania Ave NW',
city: 'Washington',
zip: '20500',
phones: { 'fax' : { country_code: 1, number: '...' } }
}
}
);
Exercice¶
Dans l’archive fournie avec la section interrogation, nous allons utiliser le fichier InspectionsRestaurant.json
dont la structure JSON est comme suit :
{
"idRestaurant": 40373938,
"restaurant": {
"name": "IHOP",
"borough": "BRONX",
"buildingnum": "5655",
"street": "BROADWAY",
"zipcode": "10463",
"phone": "7185494565",
"cuisineType": "American"
},
"inspectionDate": "2016-08-16",
"violationCode": "04L",
"violationDescription": "Evidence of mice or live mice present in facility's food and/or non-food areas.",
"criticalFlag": "Critical",
"score": 15,
"grade": ""
}
Partie 1¶
- Définir le modèle de document associant les restaurants et leurs inspections, en utilisant les types imbriqués, et créer la table InspectionRestaurant selon le format JSON précédent. Dans cette modélisation, qui est une solution au problème de manque de jointure, les informations du restaurant sont imbriquées dans chacune de ses inspections.
- Insérer un document dans la table.
-
Faire l’import avec l’utilitaire d’insertion de documents JSON.
- copier le fichier JSON et JAR dans le container
- importer avec l'utilitaire selon la syntaxe suivante
4. Créer un index sur le Grade de la table InspectionRestaurant, puis trouver les restaurants ayant reçu le grade “A” au moins une fois.java -jar JSonFile2Cassandra [-host <host>] [-port <port>] [-keyspace <keyspace>] [-columnFamily <columnFamily>] [file]
Partie 2¶
Maintenant, on veut pouvoir rechercher les restaurants par leur quartier (borough).
- Est-ce possible sur le schéma précédent ?
- Proposer une modélisation adaptée, et créer la table. La solution consiste à ajouter une collection de type map, avec la date d’insertion comme clé, dans chaque restaurant représentant la relation un-à-plusieurs qui lie un restaurant à ses inspections.
- Insérer des données dans la nouvelle table, soit directement, soit avec l’utilitaire d’import.
- Trouver tous les restaurants du Bronx.
- Maintenant, on veut, sur cette seconde table, trouver tous les restaurants ayant reçu une note "A". Est-ce possible ? Chercher une solution permise par le fait que nous avons utilisé le type map.