RIFT OSM R1 Initial Submission
[osm/SO.git] / rwlaunchpad / plugins / rwmonparam / rift / tasklets / rwmonparam / aggregator.py
1 """
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 @file aggregator.py
19 @author Varun Prasad (varun.prasad@riftio.com)
20 @date 09-Jul-2016
21
22 """
23 import abc
24 import functools
25
26
27 class IncompatibleAggregationType(Exception):
28 pass
29
30 class InvalidAggregationType(Exception):
31 pass
32
33 class InvalidAggregationOperation(Exception):
34 pass
35
36 class InvalidAggregationValues(Exception):
37 pass
38
39
40 def make_aggregator(field_types):
41 """A factory method to create the aggregator based on the field type
42 [value_interger, value_string or value_decimal]
43
44 Args:
45 field_types (list): list of field types to aggregate
46 values (list): List of values
47 aggregation_type (str): Type of aggregation.
48
49 Returns:
50 subclass of ValueAggregator
51
52 Raises:
53 InvalidAggregationType: If Unknown aggregation type is provided
54 InvalidAggregationValues: Raised if a mix of field types are provided.
55 """
56 if len(set(field_types)) != 1:
57 raise InvalidAggregationValues(
58 "Multiple value types provided for aggrgation {}".format(field_types))
59
60 field_type = field_types[0]
61
62 if field_type == IntValueAggregator.field_name():
63 return IntValueAggregator()
64 elif field_type == DecimalValueAggregator.field_name():
65 return DecimalValueAggregator()
66 elif field_type == StringValueAggregator.field_name():
67 return StringValueAggregator()
68
69 raise InvalidAggregationType("Invalid aggregation type")
70
71
72 class ValueAggregator():
73 """Base class that defines all the basic operations.
74
75 Attributes:
76 aggregation_type (str): Aggregation type to be used to select the
77 appropriate method.
78 values (list): List of values to aggregate.
79 """
80 @classmethod
81 @abc.abstractmethod
82 def field_name(self):
83 pass
84
85 def average(self, values):
86 raise InvalidAggregationOperation(
87 "Invalid operation AVERAGE for {}".format(self.values))
88
89 def sum(self, values):
90 raise InvalidAggregationOperation(
91 "Invalid operation SUM for {}".format(self.values))
92
93 def maximum(self, values):
94 raise InvalidAggregationOperation(
95 "Invalid operation MAXIMUM for {}".format(self.values))
96
97 def minimum(self, values):
98 raise InvalidAggregationOperation(
99 "Invalid operation MINIMUM for {}".format(self.values))
100
101 def count(self, values):
102 raise InvalidAggregationOperation(
103 "Invalid operation COUNT for {}".format(self.values))
104
105 def aggregate(self, aggregation_type, values):
106 OP_MAP = {
107 "AVERAGE": self.average,
108 "SUM": self.sum,
109 "MAXIMUM": self.maximum,
110 "MINIMUM": self.minimum,
111 "COUNT": self.count
112 }
113
114 op_func = OP_MAP.get(aggregation_type, None)
115
116 if op_func is None:
117 raise InvalidAggregationType("Unknown Aggregation type provided.")
118
119 return self.field_name(), op_func(values)
120
121
122 class StringValueAggregator(ValueAggregator):
123
124 @classmethod
125 def field_name(self):
126 return "value_string"
127
128
129 class DecimalValueAggregator(ValueAggregator):
130
131 @classmethod
132 def field_name(self):
133 return "value_decimal"
134
135 def average(self, values):
136 avg = functools.reduce(lambda x, y: x + y, values) / len(values)
137 return avg
138
139 def sum(self, values):
140 return functools.reduce(lambda x, y: x + y, values)
141
142 def maximum(self, values):
143 return max(values)
144
145 def minimum(self, values):
146 return min(values)
147
148 def count(self, values):
149 return len(values)
150
151
152 class IntValueAggregator(DecimalValueAggregator):
153
154 @classmethod
155 def field_name(self):
156 return "value_integer"
157
158 def average(self, values):
159 avg = functools.reduce(lambda x, y: x + y, values) / len(values)
160 return int(avg)