Modélisation des données à Cassandra

1. Vue d'ensemble

Cassandra est une base de données NoSQL qui offre une haute disponibilité et une évolutivité horizontale sans compromettre les performances.

Pour obtenir les meilleures performances de Cassandra, nous devons concevoir soigneusement le schéma autour de modèles de requête spécifiques au problème commercial en question.

Dans cet article, nous passerons en revue certains des concepts clés sur la façon d'aborder la modélisation des données dans Cassandra .

Avant de continuer, vous pouvez parcourir notre article Cassandra avec Java pour comprendre les bases et comment se connecter à Cassandra en utilisant Java.

2. Clé de partition

Cassandra est une base de données distribuée dans laquelle les données sont partitionnées et stockées sur plusieurs nœuds au sein d'un cluster.

La clé de partition est composée d'un ou plusieurs champs de données et est utilisée par le partitionneur pour générer un jeton via le hachage afin de distribuer les données uniformément sur un cluster .

3. Clustering

Une clé de clustering est composée d'un ou plusieurs champs et permet de regrouper ou de regrouper des lignes avec la même clé de partition et de les stocker dans un ordre trié.

Disons que nous stockons des données de séries chronologiques dans Cassandra et que nous voulons récupérer les données dans l'ordre chronologique. Une clé de clustering qui comprend des champs de données de séries chronologiques sera très utile pour une récupération efficace des données pour ce cas d'utilisation.

Remarque: la combinaison de la clé de partition et de la clé de clustering constitue la clé primaire et identifie de manière unique tout enregistrement dans le cluster Cassandra.

4. Directives concernant les modèles de requête

Avant de commencer la modélisation des données dans Cassandra, nous devons identifier les modèles de requête et nous assurer qu'ils respectent les directives suivantes:

  1. Chaque requête doit récupérer les données d'une seule partition
  2. Nous devons garder une trace de la quantité de données stockées dans une partition, car Cassandra a des limites autour du nombre de colonnes pouvant être stockées dans une seule partition
  3. Il est normal de dénormaliser et de dupliquer les données pour prendre en charge différents types de modèles de requête sur les mêmes données

Sur la base des directives ci-dessus, examinons quelques cas d'utilisation réels et comment nous modéliserions les modèles de données Cassandra pour eux.

5. Exemples de modélisation de données du monde réel

5.1. Messages Facebook

Supposons que nous stockions les publications Facebook de différents utilisateurs dans Cassandra. L'un des modèles de requête courants sera de récupérer les « N » premiers messages publiés par un utilisateur donné.

Ainsi, nous devons stocker toutes les données d'un utilisateur particulier sur une seule partition conformément aux instructions ci-dessus.

De plus, en utilisant l'horodatage après comme la clé de clustering sera utile pour récupérer le top « N posts » plus efficacement.

Définissons le schéma de table Cassandra pour ce cas d'utilisation:

CREATE TABLE posts_facebook ( user_id uuid, post_id timeuuid, content text, PRIMARY KEY (user_id, post_id) ) WITH CLUSTERING ORDER BY (post_id DESC);

Maintenant, écrivons une requête pour trouver les 20 meilleurs articles de l'utilisateur Anna :

SELECT content FROM posts_facebook WHERE user_id = "Anna_id" LIMIT 20

5.2. Gymnases à travers le pays

Supposons que nous stockions les détails des différents gymnases partenaires dans les différentes villes et états de nombreux pays et que nous aimerions aller chercher les gymnases d'une ville donnée.

En outre, disons que nous devons renvoyer les résultats en triant les gymnases en fonction de leur date d'ouverture.

Based on the above guidelines, we should store the gyms located in a given city of a specific state and country on a single partition and use the opening date and gym name as a clustering key.

Let's define the Cassandra table schema for this example:

CREATE TABLE gyms_by_city ( country_code text, state text, city text, gym_name text, opening_date timestamp, PRIMARY KEY ( (country_code, state_province, city), (opening_date, gym_name)) WITH CLUSTERING ORDER BY (opening_date ASC, gym_name ASC);

Now, let's look at a query that fetches the first ten gyms by their opening date for the city of Phoenix within the U.S. state of Arizona:

SELECT * FROM gyms_by_city WHERE country_code = "us" AND state = "Arizona" AND city = "Phoenix" LIMIT 10

Next, let’s see a query that fetches the ten most recently-opened gyms in the city of Phoenix within the U.S. state of Arizona:

SELECT * FROM gyms_by_city WHERE country_code = "us" and state = "Arizona" and city = "Phoenix" ORDER BY opening_date DESC LIMIT 10

Note: As the last query's sort order is opposite of the sort order defined during the table creation, the query will run slower as Cassandra will first fetch the data and then sort it in memory.

5.3. E-commerce Customers and Products

Let's say we are running an e-commerce store and that we are storing the Customer and Product information within Cassandra. Let's look at some of the common query patterns around this use case:

  1. Get Customer info
  2. Get Product info
  3. Get all Customers who like a given Product
  4. Get all Products a given Customer likes

We will start by using separate tables for storing the Customer and Product information. However, we need to introduce a fair amount of denormalization to support the 3rd and 4th queries shown above.

We will create two more tables to achieve this – “Customer_by_Product” and “Product_by_Customer“.

Let's look at the Cassandra table schema for this example:

CREATE TABLE Customer ( cust_id text, first_name text, last_name text, registered_on timestamp, PRIMARY KEY (cust_id)); CREATE TABLE Product ( prdt_id text, title text, PRIMARY KEY (prdt_id)); CREATE TABLE Customer_By_Liked_Product ( liked_prdt_id text, liked_on timestamp, title text, cust_id text, first_name text, last_name text, PRIMARY KEY (prdt_id, liked_on)); CREATE TABLE Product_Liked_By_Customer ( cust_id text, first_name text, last_name text, liked_prdt_id text, liked_on timestamp, title text, PRIMARY KEY (cust_id, liked_on));

Note: To support both the queries, recently-liked products by a given customer and customers who recently liked a given product, we have used the “liked_on” column as a clustering key.

Let's look at the query to find the ten Customers who most recently liked the product “Pepsi“:

SELECT * FROM Customer_By_Liked_Product WHERE title = "Pepsi" LIMIT 10

And let's see the query that finds the recently-liked products (up to ten) by a customer named “Anna“:

SELECT * FROM Product_Liked_By_Customer WHERE first_name = "Anna" LIMIT 10

6. Inefficient Query Patterns

Due to the way that Cassandra stores data, some query patterns are not at all efficient, including the following:

  • Récupérer des données à partir de plusieurs partitions - cela nécessitera un coordinateur pour récupérer les données de plusieurs nœuds, les stocker temporairement dans le tas, puis agréger les données avant de renvoyer les résultats à l'utilisateur
  • Requêtes basées sur les jointures - en raison de sa nature distribuée, Cassandra ne prend pas en charge les jointures de table dans les requêtes de la même manière qu'une base de données relationnelle, et par conséquent, les requêtes avec jointures seront plus lentes et peuvent également entraîner des problèmes d'incohérence et de disponibilité

7. Conclusion

Dans ce didacticiel, nous avons couvert plusieurs bonnes pratiques pour aborder la modélisation des données dans Cassandra.

Comprendre les concepts de base et identifier les modèles de requête à l'avance est nécessaire pour concevoir un modèle de données correct qui obtient les meilleures performances d'un cluster Cassandra.