En Java la variable UDT est représenté par la classe com.datastax.driver.core. UDTValue. Cette classe a des méthodes get et set. Il existe des méthodes utilisant un index (0 ...) pour identifier les champs (dans l'ordre dans lequel ils sont définis dans l'UDT) et les méthodes qui utilisent le nom du champ.
Voir API Doc.
Voici quelques exemples, en utilisant le type défini dans la question:
TupleValue accumState = state.getTupleValue("accum");
String prevSource = accumState.getString(0);
Map<String,Double> avgMap = state.getMap("avg_map", String.class, Double.class);
La première ligne obtient le accum champ de l'état de la fonction. Au lieu du nom, l'index 0 (zéro, c'est le premier champ) pourrait être utilisé.
La deuxième ligne obtient le premier élément du tuple. Seule la version de l'index peut être utilisée, car les éléments d'un tuple ne sont pas nommés.
La troisième ligne obtient le champ avg_map.
accumState.setDouble(2, value);
state.setTupleValue("accum", accumState);
L'exemple ci-dessus définit le troisième élément du tuple, et met alors le tuple retour dans la variable d'état de la fonction. Notez que vous devez replacer le tuple dans la variable d'état. Ce qui suit ne fonctionne pas.
// does not work
state.getTupleValue("accum").setDouble(2, value);
Ci-dessous l'exemple complet UDF.
// sums up until the source changes, then adds the avg to the map
// IMPORTANT: table must be ordered by source
CREATE OR REPLACE FUNCTION average_by_source_1(state avg_type_1, source text, value double)
CALLED ON NULL INPUT
RETURNS avg_type_1
LANGUAGE java
AS $$
TupleValue accumState = state.getTupleValue("accum");
String prevSource = accumState.getString(0);
// when no source yet, save the first source, set the count to 1, and set the value
if (prevSource == null) {
accumState.setString(0, source);
accumState.setInt(1, 1);
accumState.setDouble(2, value);
state.setTupleValue("accum", accumState);
}
// when same source, increment the count and add the value
else if (prevSource.equals(source)) {
accumState.setInt(1, accumState.getInt(1) + 1);
accumState.setDouble(2, accumState.getDouble(2) + value);
state.setTupleValue("accum", accumState);
}
// when different source, calc average and copy to map, then re-init accumulation
else if (accumState.getInt(1) > 0) {
double avgVal = accumState.getDouble(2)/accumState.getInt(1);
Map<String,Double> mapState = state.getMap("avg_map", String.class, Double.class);
mapState.put(prevSource, avgVal);
state.setMap("avg_map", mapState, String.class, Double.class);
accumState.setString(0, source);
accumState.setInt(1, 1);
accumState.setDouble(2, value);
state.setTupleValue("accum", accumState);
}
// should not happen - prev case uses "if" to avoid division by zero
else {
Map<String,Double> mapState = state.getMap("avg_map", String.class, Double.class);
mapState.put("ERROR: div by zero", null);
accumState.setString(0, source);
accumState.setInt(1, 1);
accumState.setDouble(2, value);
state.setTupleValue("accum", accumState);
}
// IMPROTANT: final function must calculate the average for the last source and
// add it to the map.
return state;
$$
;
Je pense que getMap() de la classe UDTValue est la solution. Il compile. Je vais poster une réponse quand j'ai un exemple de travail complet. – rwfbc