Вот один из способов сделать это. Ваша группа по функции состояния может быть такой:
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;
';
Это создаст карту всех строк сумм, выбранных вашим запросом WHERE. Теперь сложная часть заключается в том, как сохранить только верхние N. Один из способов сделать это — использовать FINALFUNC, который выполняется после того, как все строки будут помещены в карту. Итак, вот функция, которая использует цикл, чтобы найти максимальное значение на карте и переместить его на карту результатов. Таким образом, чтобы найти верхнее N, он будет перебирать карту N раз (есть более эффективные алгоритмы, чем этот, но это просто быстрый и грязный пример).
Итак, вот пример, чтобы найти два верхних:
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;
';
Затем, наконец, вам нужно определить AGGREGATE для вызова двух определенных вами функций:
CREATE OR REPLACE AGGREGATE group_and_total(text, double)
SFUNC state_group_and_total
STYPE map<text, double>
FINALFUNC topFinal
INITCOND {};
Итак, давайте посмотрим, работает ли это.
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
Теперь барабанная дробь...
SELECT group_and_total(clustering, amount) from test where partition=1;
agg.group_and_total(clustering, amount)
-------------------------------------------
{'2015': 99.1, '2017': 44.889}
Итак, вы видите, что он сохранил две верхние строки в зависимости от суммы.
Обратите внимание, что ключи не будут отсортированы, так как это карта, и я не думаю, что мы можем контролировать порядок ключей на карте, поэтому сортировка в FINALFUNC будет пустой тратой ресурсов. Если вам нужна сортировка карты, вы можете сделать это в клиенте.
Я думаю, вы могли бы сделать больше работы в функции state_group_and_total, чтобы удалять элементы с карты по мере продвижения. Это может быть лучше, чтобы карта не стала слишком большой.
05.08.2015