Voici une façon de le faire. Votre groupe en fonction de l'état pourrait ressembler à ceci:
CREATE FUNCTION state_group_and_total(state map<text, double>, type text, amount double)
CALLED ON NULL INPUT
RETURNS map<text, double>
LANGUAGE java AS '
Double count = (Double) state.get(type);
if (count == null)
count = amount;
else
count = count + amount;
state.put(type, count);
return state;
';
Cela va construire une carte de toutes les lignes de quantité sélectionnée par votre requête clause WHERE. Maintenant, la partie difficile est de savoir comment garder juste le top N. Une façon de le faire est d'utiliser un FINALFUNC qui est exécuté après que toutes les lignes ont été mises dans la carte. Donc, voici une fonction pour faire cela en utilisant une boucle pour trouver la valeur maximale dans la carte et le déplacer vers une carte de résultats. Donc, pour trouver le N supérieur, il parcourrait la carte N fois (il y a des algorithmes plus efficaces que cela, mais c'est juste un exemple rapide et sale).
Voici donc un exemple pour trouver les deux premiers:
CREATE FUNCTION topFinal (state map<text, double>)
CALLED ON NULL INPUT
RETURNS map<text, double>
LANGUAGE java AS '
java.util.Map<String, Double> inMap = new java.util.HashMap<String, Double>(),
outMap = new java.util.HashMap<String, Double>();
inMap.putAll(state);
int topN = 2;
for (int i = 1; i <= topN; i++) {
double maxVal = -1;
String moveKey = null;
for (java.util.Map.Entry<String, Double> entry : inMap.entrySet()) {
if (entry.getValue() > maxVal) {
maxVal = entry.getValue();
moveKey = entry.getKey();
}
}
if (moveKey != null) {
outMap.put(moveKey, maxVal);
inMap.remove(moveKey);
}
}
return outMap;
';
Vous devez ensuite enfin de définir l'ensemble d'appeler les deux fonctions que vous avez définies
CREATE OR REPLACE AGGREGATE group_and_total(text, double)
SFUNC state_group_and_total
STYPE map<text, double>
FINALFUNC topFinal
INITCOND {};
Voyons voir si cela fonctionne .
CREATE table test (partition int, clustering text, amount double, PRIMARY KEY (partition, clustering));
INSERT INTO test (partition , clustering, amount) VALUES (1, '2015', 99.1);
INSERT INTO test (partition , clustering, amount) VALUES (1, '2016', 18.12);
INSERT INTO test (partition , clustering, amount) VALUES (1, '2017', 44.889);
SELECT * from test;
partition | clustering | amount
-----------+------------+--------
1 | 2015 | 99.1
1 | 2016 | 18.12
1 | 2017 | 44.889
Maintenant, roulement de tambour ...
SELECT group_and_total(clustering, amount) from test where partition=1;
agg.group_and_total(clustering, amount)
-------------------------------------------
{'2015': 99.1, '2017': 44.889}
Donc, vous voyez, il a gardé les 2 premières lignes en fonction du montant. Notez que les clés ne seront pas triées car c'est une carte, et je ne pense pas que nous puissions contrôler l'ordre des clés dans la carte, donc trier dans FINALFUNC serait une perte de ressources. Si vous avez besoin de la carte triée, vous pouvez le faire dans le client.
Je pense que vous pourriez faire plus de travail dans la fonction state_group_and_total pour supprimer des éléments de la carte au fur et à mesure. Cela pourrait être mieux pour éviter que la carte ne devienne trop grande.
Excellente réponse! Je vais devoir donner un coup de feu. – Aaron
J'ai essayé celui-ci mais il montre l'erreur "cqlsh: chris> sélectionnez group_and_total (timestamp, value) de l'entrepôt; InvalidRequest: code = 2200 [Invalid query] message =" Erreur de type: la valeur ne peut pas être p assed comme argument 1 de la fonction chris.group_and_total de type double " –
Peut-être que vous avez copié quelque chose de mal Le premier argument de la fonction group_and_total dans mon exemple est de type texte, pas double Faire un describe décrire et décrire AGGREGATE sur les fonctions et s'assurer qu'ils sont corrects . –