web-dev-qa-db-fra.com

MAX (), DISTINCT et regrouper par Cassandra

J'essaie de remodeler une base de données SQL Cassandra de telle sorte que je puisse trouver l'équivalent Cassandra pour les requêtes SQL. J'utilise CQL 3 et Cassandra v1.2. J'ai modélisé la conception de la base de données dans cassandra afin qu'il prenne en charge les clauses order by et les tables dénormalisées pour prendre en charge l'opération de jointure. Cependant, je suis en mer quand il vient aux équivalents DISTINCT, SUM () et GROUPBY

SELECT a1,MAX(b1) FROM demo1 group by a1.
SELECT DISTINCT (a2) FROM demo2 where b2='sea'
SELECT sum(a3), sum(b3) from demo3 where c3='water' and d3='ocean'

Cela ressemble à un étalage de mon travail depuis quelques jours. Existe-t-il un moyen dans Cassandra, que je puisse modéliser le schéma db pour prendre en charge des requêtes de ce type? Je ne peux pas penser à quoi que ce soit dans Cassandra. Comment ces requêtes peuvent-elles être implémentées en utilisant Cassandra?

J'ai lu qu'une couche Hive sur Cassandra peut éventuellement faire fonctionner ces requêtes. Je me demande simplement si c'est la seule façon de prendre en charge de telles requêtes dans Cassandra ..? Veuillez conseiller sur tout autre méthodes possibles ..

17
eldho

Cassandra ne prend pas en charge des opérations comme celle-ci. Vous pouvez utiliser quelque chose comme Hive ou un produit (non gratuit) d'Acunu qui peut faire ce dont vous avez besoin.

L'autre solution est de faire le travail vous-même. Par exemple, vous pouvez additionner des choses en lisant toutes les données de certaines lignes et en les additionnant. Ou maintenez un compteur Cassandra pour incrémenter à la volée.

11
Richard

Avec Cassandra vous résolvez ces types de problèmes en faisant plus de travail lorsque vous insérez vos données - ce qui semble être lent, mais Cassandra est conçu pour écrit rapidement, et vous allez probablement lire les données beaucoup plus de fois que vous ne les écrivez, il est donc logique de considérer l'ensemble du système.

Je ne peux pas vous dire exactement comment créer vos tables pour modéliser votre problème car cela dépendra beaucoup des détails. Vous devez comprendre un schéma qui vous permet d'obtenir les données sans effectuer d'agrégation à la volée. Réfléchissez à la façon dont vous créeriez des vues pour les requêtes dans un SGBDR, puis essayez de penser à la façon dont vous inséreriez des données directement dans ces vues, pas dans les tables sous-jacentes. Voilà comment vous modélisez les choses à Cassandra.

26
Theo

Bien que ce soit une vieille question, elle apparaît assez élevée dans les résultats de recherche Google. Je voulais donc faire une mise à jour.

Cassandra 2.2+ prend en charge la fonction définie par l'utilisateur et les agrégats définis par l'utilisateur. [~ # ~] avertissement [~ # ~] : cela ne signifie pas que vous n'avez plus à faire de modélisation de données (comme cela a été souligné par @Theo), il vous permet plutôt de prétraiter légèrement vos données lors de leur récupération.

SELECT DISTINCT (a2) FROM demo2 where b2 = 'sea'

Pour implémenter DISTINCT, vous devez définir une fonction et un agreggate. J'appellerai à la fois la fonction et l'agrégat uniq plutôt que distinct pour souligner le fait qu'elle est définie par l'utilisateur.

CREATE OR REPLACE FUNCTION uniq(state set<text>, val text)
  CALLED ON NULL INPUT RETURNS set<text> LANGUAGE Java
  AS 'state.add(val); return state;';
CREATE OR REPLACE AGGREGATE uniq(text)
  SFUNC uniq STYPE set<text> INITCOND {};

Ensuite, vous l'utilisez comme suit:

SELECT uniq(a2) FROM demo2 where b2='sea';

SELECT somme (a3), somme (b3) de demo3 où c3 = 'eau' et d3 = 'océan'

SUM est fourni hors de la boîte et fonctionne comme vous vous en doutez. Voir system.sum.

SELECT a1, MAX (b1) FROM demo1 group by a1

GROUP BY est délicat. En fait, il n'y a aucun moyen de regrouper les lignes de résultats par une colonne. Mais ce que vous pouvez faire, c'est créer un map<text, int> et pour les regrouper manuellement dans la carte. Basé sur un exemple du blog de Christopher Batey, group-by et max:

CREATE OR REPLACE FUNCTION state_group_and_max(state map<text, int>, type text, amount int)
  CALLED ON NULL INPUT
  RETURNS map<text, int>
  LANGUAGE Java AS '
    Integer val = (Integer) state.get(type);
    if (val == null) val = amount; else val = Math.max(val, amount);
    state.put(type, val);
    return state;
  ' ;

CREATE OR REPLACE AGGREGATE state_group_and_max(text, int) 
  SFUNC state_group_and_max
  STYPE map<text, int> 
  INITCOND {};

Ensuite, vous l'utilisez comme suit:

SELECT state_group_and_max(a1, b1) FROM demo1;

Remarques

  • Comme cela a été mentionné ci-dessus, vous devez encore investir un peu de temps dans la modélisation des données, ne pas abuser de ces fonctionnalités
  • Vous devez définir enable_user_defined_functions=true dans ton cassandra.yaml pour activer les fonctionnalités
  • Vous pouvez surcharger les fonctions pour prendre en charge le regroupement par colonnes de différents types.

Les références:

21
korya

Cassandra 3.10 prend désormais en charge le regroupement par clé de partition et clé de clustering. Vous pouvez vous référer à ce lien pour plus de détails.

12
NangSaigon