Class: ActiveWarehouse::Dimension
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- ActiveWarehouse::Dimension
- Includes:
- HierarchicalDimension, SlowlyChangingDimension
- Defined in:
- lib/active_warehouse/dimension.rb
Overview
Dimension tables contain the textual descriptors of the business. Dimensions provide the filters which are applied to facts. Dimensions are the primary source of query constraints, groupings and report labels.
Defined Under Namespace
Classes: Node
Class Attribute Summary collapse
-
.level_orders ⇒ Object
readonly
Get the level orders map.
-
.order ⇒ Object
Alternate order by, to be used rather than the current level being queried.
Class Method Summary collapse
-
.available_child_values(hierarchy_name, parent_values) ⇒ Object
(also: available_children_values)
Get an array of child values for a particular parent in the hierachy For example, given a DateDimension with data from 2002 to 2004:.
-
.available_values(level) ⇒ Object
Get an array of the available values for a particular hierarchy level For example, given a DateDimension with data from 2002 to 2004:.
-
.available_values_tree(hierarchy_name) ⇒ Object
Get a tree of Node objects for all of the values in the specified hierarchy.
-
.class_for_name(name) ⇒ Object
Get a class for the specified named dimension.
-
.class_name(name) ⇒ Object
Convert the given name into a dimension class name.
-
.define_hierarchy(name, levels) ⇒ Object
Define a named attribute hierarchy in the dimension.
-
.denominator_count(hierarchy_name, level, denominator_level = nil) ⇒ Object
Returns a hash of all of the values at the specified hierarchy level mapped to the count at that level.
-
.expire_value_tree_cache ⇒ Object
Expire the value tree cache.
-
.foreign_key ⇒ Object
Get the foreign key for this dimension which is used in Fact tables.
-
.hierarchies ⇒ Object
Get the ordered hierarchy names.
-
.hierarchy(name) ⇒ Object
Get the named attribute hierarchy.
-
.hierarchy_levels ⇒ Object
Get the hierarchy levels hash.
-
.last_modified ⇒ Object
Return the time when the underlying dimension source file was last modified.
-
.set_level_order(level, name) ⇒ Object
Define a column to order by for a specific level.
-
.set_order(name) ⇒ Object
Define a column to order by.
-
.sym ⇒ Object
Return a symbol used when referring to this dimension.
-
.table_name ⇒ Object
Get the table name.
-
.to_dimension(dimension) ⇒ Object
Get the dimension class for the specified dimension parameter.
Instance Method Summary collapse
Methods included from SlowlyChangingDimension
Methods included from HierarchicalDimension
Class Attribute Details
.level_orders ⇒ Object (readonly)
Get the level orders map
21 22 23 |
# File 'lib/active_warehouse/dimension.rb', line 21 def level_orders @level_orders end |
.order ⇒ Object
Alternate order by, to be used rather than the current level being queried
18 19 20 |
# File 'lib/active_warehouse/dimension.rb', line 18 def order @order end |
Class Method Details
.available_child_values(hierarchy_name, parent_values) ⇒ Object Also known as: available_children_values
Get an array of child values for a particular parent in the hierachy For example, given a DateDimension with data from 2002 to 2004:
available_child_values(:cy, [2002, ‘Q1’]) returns [‘January’, ‘Feburary’, ‘March’, ‘April’]
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/active_warehouse/dimension.rb', line 188 def available_child_values(hierarchy_name, parent_values) if hierarchy_levels[hierarchy_name].nil? raise ArgumentError, "The hierarchy '#{hierarchy_name}' does not exist in your dimension #{name}" end levels = hierarchy_levels[hierarchy_name] if levels.length <= parent_values.length raise ArgumentError, "The parent_values '#{parent_values.to_yaml}' exceeds the hierarchy depth #{levels.to_yaml}" end child_level = levels[parent_values.length].to_s # Create the conditions array. Will work with 1.1.6. conditions_parts = [] conditions_values = [] parent_values.each_with_index do |value, index| conditions_parts << "#{levels[index]} = ?" conditions_values << value end conditions = [conditions_parts.join(' AND ')] + conditions_values unless conditions_parts.empty? child_level_method = child_level.to_sym child_level = connection.quote_column_name(child_level) order = level_orders[child_level] || self.order || child_level = {:select => child_level, :group => child_level, :order => order} [:conditions] = conditions unless conditions.nil? find(:all, ).collect {|dim| dim.send(child_level_method)} end |
.available_values(level) ⇒ Object
Get an array of the available values for a particular hierarchy level For example, given a DateDimension with data from 2002 to 2004:
available_values('calendar_year') returns ['2002','2003','2004']
177 178 179 180 181 182 |
# File 'lib/active_warehouse/dimension.rb', line 177 def available_values(level) level_method = level.to_sym level = connection.quote_column_name(level.to_s) order = level_orders[level] || self.order || level find(:all, :select => level, :group => level, :order => order).collect {|dim| dim.send(level_method)} end |
.available_values_tree(hierarchy_name) ⇒ Object
Get a tree of Node objects for all of the values in the specified hierarchy.
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/active_warehouse/dimension.rb', line 220 def available_values_tree(hierarchy_name) root = value_tree_cache[hierarchy_name] if root.nil? root = Node.new('All', '__ROOT__') levels = hierarchy(hierarchy_name) nodes = {nil => root} level_list = levels.collect{|level| connection.quote_column_name(level) }.join(',') order = self.order || level_list find(:all, :select => level_list, :group => level_list, :order => order).each do |dim| parent_node = root levels.each do |level| node_value = dim.send(level) child_node = parent_node.optionally_add_child(node_value, level) parent_node = child_node end end value_tree_cache[hierarchy_name] = root end root end |
.class_for_name(name) ⇒ Object
Get a class for the specified named dimension
98 99 100 |
# File 'lib/active_warehouse/dimension.rb', line 98 def class_for_name(name) class_name(name).constantize end |
.class_name(name) ⇒ Object
Convert the given name into a dimension class name
91 92 93 94 95 |
# File 'lib/active_warehouse/dimension.rb', line 91 def class_name(name) dimension_name = name.to_s dimension_name = "#{dimension_name}_dimension" unless dimension_name =~ /_dimension$/ dimension_name.classify end |
.define_hierarchy(name, levels) ⇒ Object
Define a named attribute hierarchy in the dimension.
Example: define_hierarchy(:fiscal_calendar, [:fiscal_year, :fiscal_quarter, :fiscal_month])
This would indicate that one of the drill down paths for this dimension is: Fiscal Year -> Fiscal Quarter -> Fiscal Month
Internally the hierarchies are stored in order. The first hierarchy defined will be used as the default if no hierarchy is specified when rendering a cube.
51 52 53 54 |
# File 'lib/active_warehouse/dimension.rb', line 51 def define_hierarchy(name, levels) hierarchies << name hierarchy_levels[name] = levels end |
.denominator_count(hierarchy_name, level, denominator_level = nil) ⇒ Object
Returns a hash of all of the values at the specified hierarchy level mapped to the count at that level. For example, given a date dimension with years from 2002 to 2004 and a hierarchy defined with:
hierarchy :cy, [:calendar_year, :calendar_quarter, :calendar_month_name]
…then…
DateDimension.denominator_count(:cy, :calendar_year, :calendar_quarter) returns {'2002' => 4, '2003' => 4, '2004' => 4}
If the denominator_level parameter is omitted or nil then:
DateDimension.denominator_count(:cy, :calendar_year) returns {'2003' => 365, '2003' => 365, '2004' => 366}
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/active_warehouse/dimension.rb', line 128 def denominator_count(hierarchy_name, level, denominator_level=nil) if hierarchy_levels[hierarchy_name].nil? raise ArgumentError, "The hierarchy '#{hierarchy_name}' does not exist in your dimension #{name}" end q = nil # If the denominator_level is specified and it is not the last element in the hierarchy then do a distinct count. If # the denominator level is less than the current level then raise an ArgumentError. In other words, if the current level is # calendar month then passing in calendar year as the denominator level would raise an ArgumentErro. # # If the denominator_level is not specified then assume the finest grain possible (in the context of a date dimension # this would be each day) and use the id to count. if denominator_level && hierarchy_levels[hierarchy_name].last != denominator_level level_index = hierarchy_levels[hierarchy_name].index(level) denominator_index = hierarchy_levels[hierarchy_name].index(denominator_level) if level_index.nil? raise ArgumentError, "The level '#{level}' does not appear to exist" end if denominator_index.nil? raise ArgumentError, "The denominator level '#{denominator_level}' does not appear to exist" end if hierarchy_levels[hierarchy_name].index(denominator_level) < hierarchy_levels[hierarchy_name].index(level) raise ArgumentError, "The index of the denominator level '#{denominator_level}' in the hierarchy '#{hierarchy_name}' must be greater than or equal to the level '#{level}'" end q = "select #{level} as level, count(distinct(#{denominator_level})) as level_count from #{table_name} group by #{level}" else q = "select #{level} as level, count(id) as level_count from #{table_name} group by #{level}" end denominators = {} # TODO: fix to use select_all instead of execute connection.select_all(q).each do |row| denominators[row['level']] = row['level_count'].to_i end denominators end |
.expire_value_tree_cache ⇒ Object
Expire the value tree cache. This should be called if the dimension
283 284 285 |
# File 'lib/active_warehouse/dimension.rb', line 283 def expire_value_tree_cache @value_tree_cache = nil end |
.foreign_key ⇒ Object
Get the foreign key for this dimension which is used in Fact tables.
Example: DateDimension would have a foreign key of date_id
169 170 171 |
# File 'lib/active_warehouse/dimension.rb', line 169 def foreign_key table_name.sub(/_dimension/,'') + '_id' end |
.hierarchies ⇒ Object
Get the ordered hierarchy names
64 65 66 |
# File 'lib/active_warehouse/dimension.rb', line 64 def hierarchies @hierarchies ||= [] end |
.hierarchy(name) ⇒ Object
Get the named attribute hierarchy. Returns an array of column names.
Example: hierarchy(:fiscal_calendar) might return [:fiscal_year, :fiscal_quarter, :fiscal_month]
59 60 61 |
# File 'lib/active_warehouse/dimension.rb', line 59 def hierarchy(name) hierarchy_levels[name] end |
.hierarchy_levels ⇒ Object
Get the hierarchy levels hash
69 70 71 |
# File 'lib/active_warehouse/dimension.rb', line 69 def hierarchy_levels @hierarchy_levels ||= {} end |
.last_modified ⇒ Object
Return the time when the underlying dimension source file was last modified. This is used to determine if a cube structure rebuild is required
104 105 106 |
# File 'lib/active_warehouse/dimension.rb', line 104 def last_modified File.new(__FILE__).mtime end |
.set_level_order(level, name) ⇒ Object
Define a column to order by for a specific level.
33 34 35 |
# File 'lib/active_warehouse/dimension.rb', line 33 def set_level_order(level, name) level_orders[level] = name end |
.set_order(name) ⇒ Object
Define a column to order by. If this value is specified then it will be used rather than the actual level being queried in the following method calls:
-
available_values
-
available_child_values
-
available_values_tree
28 29 30 |
# File 'lib/active_warehouse/dimension.rb', line 28 def set_order(name) @order = name end |
.sym ⇒ Object
Return a symbol used when referring to this dimension. The symbol is calculated by demodulizing and underscoring the dimension’s class name and then removing the trailing _dimension.
Example: DateDimension will return a symbol :date
77 78 79 |
# File 'lib/active_warehouse/dimension.rb', line 77 def sym self.name.demodulize.underscore.gsub(/_dimension/, '').to_sym end |
.table_name ⇒ Object
Get the table name. By default the table name will be the name of the dimension in singular form.
Example: DateDimension will have a table called date_dimension
84 85 86 87 88 |
# File 'lib/active_warehouse/dimension.rb', line 84 def table_name name = self.name.demodulize.underscore set_table_name(name) name end |
.to_dimension(dimension) ⇒ Object
Get the dimension class for the specified dimension parameter. The dimension parameter may be a class, String or Symbol.
110 111 112 113 |
# File 'lib/active_warehouse/dimension.rb', line 110 def to_dimension(dimension) return dimension if dimension.is_a?(Class) and dimension.superclass == Dimension return class_for_name(dimension) end |
Instance Method Details
#expire_value_tree_cache ⇒ Object
289 290 291 |
# File 'lib/active_warehouse/dimension.rb', line 289 def expire_value_tree_cache self.class.expire_value_tree_cache end |