class Activecube::Processor::Composer
Attributes
cube_query[R]
models[R]
query[R]
Public Class Methods
new(cube_query)
click to toggle source
# File lib/activecube/processor/composer.rb, line 11 def initialize cube_query @cube_query = cube_query end
Public Instance Methods
build_query()
click to toggle source
# File lib/activecube/processor/composer.rb, line 15 def build_query @query = compose_queries optimize! ranked_tables end
connection()
click to toggle source
# File lib/activecube/processor/composer.rb, line 19 def connection connections = models.map(&:connection).compact.uniq raise "No connection found for query" if connections.empty? raise "Tables #{models.map(&:name).join(',')} mapped to multiple connections, can not query" if connections.count>1 connections.first end
Private Instance Methods
compose_queries(measure_tables)
click to toggle source
# File lib/activecube/processor/composer.rb, line 72 def compose_queries measure_tables composed_query = nil @models = [] measures_by_tables = measure_tables.group_by(&:table) measures_by_tables.each_pair do |table, list| @models << table.model reduce_options = measures_by_tables.count==1 ? cube_query.options : [] reduced = cube_query.reduced list.map(&:measure), reduce_options table_query = table.query reduced composed_query = composed_query ? table.join(cube_query, composed_query, table_query) : table_query end composed_query end
optimize!(measure_tables)
click to toggle source
# File lib/activecube/processor/composer.rb, line 28 def optimize! measure_tables all_tables = measure_tables.map(&:tables).map(&:keys).flatten.uniq cost_matrix = measure_tables.collect do |measure_table| all_tables.collect{|table| measure_table.tables[table].try(&:cost) } end before = total_cost measure_tables Optimizer.new(cost_matrix).optimize.each_with_index do |optimal, index| measure_tables[index].selected = measure_tables[index].entries.map(&:table).index(all_tables[optimal]) end after = total_cost measure_tables raise "Optimizer made it worse #{before} -> #{after} for #{cost_matrix}" unless after <= before measure_tables end
ranked_tables()
click to toggle source
# File lib/activecube/processor/composer.rb, line 53 def ranked_tables tables = cube_query.tables.select{|table| table.matches? cube_query, []} measures = cube_query.measures.empty? ? [Activecube::Query::MeasureNothing.new(cube_query.cube)] : cube_query.measures measures.collect do |measure| by = MeasureTables.new measure tables.each{|table| next unless table.measures? measure max_cardinality_index = table.model.activecube_indexes.select{|index| index.indexes? cube_query, [measure] }.sort_by(&:cardinality).last by.add_table table, max_cardinality_index } raise "Metric #{measure.key} #{measure.definition.try(:name) || measure.class.name} can not be measured by any of tables #{tables.map(&:name).join(',')}" if by.tables.empty? by end end
total_cost(measure_tables)
click to toggle source
# File lib/activecube/processor/composer.rb, line 49 def total_cost measure_tables measure_tables.group_by(&:table).collect{|t| t.second.map(&:entry).map(&:cost).max }.sum end