activecube 0.1.23 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4761a4080baea000688c32cd35753b72f0fd51d7e6a0818da31c8bd5141f966
4
- data.tar.gz: e5116aa48a23176bd91f4e90bbf6d83ac300c09aa3c04a951afbe8eeb3918133
3
+ metadata.gz: d73be89ca360efa3b43a5d7995d68f900c536d4675e0aacfaab4f6b299d77986
4
+ data.tar.gz: a6dac69d2602c165af3125b5df873e06c15deb744013dc474adcf38280d91161
5
5
  SHA512:
6
- metadata.gz: 2638118ea471ff784d1689a86dde10a535dcfd0e4eabeb93a9b6206236f116017ffe5d08de03820adb45d5e4291b42ca853c755efa5cddf37d664a09e3122ea9
7
- data.tar.gz: 6339c6bad22e0c0fbebbd2e8987ccac2085374fa31e274c902963b5de5b8f5dd6531b19dc95c79ccf9e1722ee277bb469a1bddc03d41d991d8fe64cafa61c63e
6
+ metadata.gz: e8b45d8a7be9b2f1c4902730c8687157475f211159dd79a69de4ab14d2faeed8904038a825c4ead3097b42434ed6f59423dbe2cba50a9b3e6870d343b8ac13e0
7
+ data.tar.gz: 5a51761701938e264dad5c42190ef0bf74b415dbd89b89cb5b32d68c9f3356fc4f445067168a3c2119c798cb8118b4fe31700a23c137ff37858ce83ed047aa00
@@ -9,7 +9,7 @@ GIT
9
9
  PATH
10
10
  remote: .
11
11
  specs:
12
- activecube (0.1.23)
12
+ activecube (0.1.27)
13
13
  activerecord (>= 5.2)
14
14
 
15
15
  GEM
@@ -2,7 +2,7 @@ module Activecube::Common
2
2
 
3
3
  module Metrics
4
4
 
5
- METHODS = [:count, :minimum,:maximum,:average,:sum,:uniqueExact,:unique,:median,:any,:anyLast]
5
+ METHODS = [:count, :minimum,:maximum,:average,:sum,:uniqueExact,:unique,:median,:medianExact,:any,:anyLast]
6
6
 
7
7
  METHODS.each do |fname|
8
8
 
@@ -52,7 +52,7 @@ module Activecube
52
52
 
53
53
  include DefinitionMethods
54
54
 
55
- attr_reader :modifiers
55
+ attr_reader :modifiers, :tuple
56
56
 
57
57
  private
58
58
 
@@ -60,6 +60,9 @@ module Activecube
60
60
  (@modifiers ||= {} )[args.first.to_sym] = Modifier.new( *args)
61
61
  end
62
62
 
63
+ def tuple_fields *args
64
+ @tuple = args
65
+ end
63
66
  end
64
67
 
65
68
  end
@@ -7,13 +7,13 @@ require 'activecube/query/measure_nothing'
7
7
  module Activecube::Processor
8
8
  class Composer
9
9
 
10
- attr_reader :cube_query, :models
10
+ attr_reader :cube_query, :models, :query
11
11
  def initialize cube_query
12
12
  @cube_query = cube_query
13
13
  end
14
14
 
15
15
  def build_query
16
- compose_queries optimize! ranked_tables
16
+ @query = compose_queries optimize! ranked_tables
17
17
  end
18
18
 
19
19
  def connection
@@ -41,7 +41,7 @@ module Activecube::Processor
41
41
  end
42
42
  after = total_cost measure_tables
43
43
 
44
- raise "Optimizer made it worth #{before} -> #{after} for #{cost_matrix}" unless after <= before
44
+ raise "Optimizer made it worse #{before} -> #{after} for #{cost_matrix}" unless after <= before
45
45
  measure_tables
46
46
 
47
47
  end
@@ -18,7 +18,7 @@ module Activecube::Processor
18
18
  @tables_count = cost_matrix.map(&:count).max
19
19
  @metrics_count = cost_matrix.count
20
20
 
21
- tables_count==1 ? [0]*metrics_count : do_optimize
21
+ (tables_count==1 || metrics_count==0) ? [0]*metrics_count : do_optimize
22
22
 
23
23
  end
24
24
 
@@ -27,95 +27,41 @@ module Activecube::Processor
27
27
 
28
28
  private
29
29
 
30
+ def generate_variants vs, metric_i
30
31
 
31
- def do_optimize
32
- @tables_by_metrics = []
32
+ return vs if metric_i==metrics_count
33
33
 
34
- # sort metrics from low min cost to higher min costs ( by all applicable tables )
35
- sort_metrics
34
+ metric_tables = cost_matrix[metric_i].map.with_index do |c, index|
35
+ [index] if c
36
+ end.compact
36
37
 
37
- # fill initial @tables_by_metrics by selecting tables with minimum cost for metrics.
38
- # If there are more than one table with this minimum cost, then select already selected table with maximum cost
39
- select_min_cost_by_metric
38
+ vsnew = if metric_i==0
39
+ metric_tables
40
+ else
41
+ arry = []
42
+ vs.each do |v|
43
+ metric_tables.each{|newv|
44
+ arry << (v + newv)
45
+ }
46
+ end
47
+ arry
48
+ end
40
49
 
41
- # make iterations over @tables_by_metrics ( max MAX_ITERATIONS)
42
- iterates
50
+ generate_variants vsnew, metric_i+1
43
51
 
44
- @tables_by_metrics
45
52
  end
46
53
 
47
- def sort_metrics
48
- @metrics_index_sorted = (0...metrics_count).sort_by{|m_i| cost_matrix[m_i].compact.min || UNLIM_COST }
54
+ def cost_for variant
55
+ variant.each_with_index.group_by(&:first).collect do |table_index, arry|
56
+ arry.map(&:second).map{|metric_index| cost_matrix[metric_index][table_index] }.max
57
+ end.sum
49
58
  end
50
59
 
51
- def select_min_cost_by_metric
52
-
53
- @metrics_index_sorted.collect do |m_i|
54
-
55
- table_index_cost = (0...tables_count).map{|c_i| [c_i,
56
- cost_matrix[m_i][c_i] || UNLIM_COST,
57
- (@tables_by_metrics.include?(c_i) ? -cost_matrix[@tables_by_metrics.index(c_i)][c_i] : 0)
58
- ]}.sort_by(&:third).sort_by(&:second)
59
-
60
- @tables_by_metrics[m_i] = table_index_cost.first.first
61
-
62
- end
63
- end
64
-
65
- def iterates
66
-
67
- steps = [@tables_by_metrics]
68
-
69
- (1..MAX_ITERATIONS).each do |iteration|
70
-
71
- step = []
72
- prev_step = steps.last
73
-
74
- prev_step.each_with_index {|c_i, m_i|
75
-
76
- table_included_times = prev_step.select{|c| c==c_i }.count
77
- old_cost = cost_matrix[m_i][c_i]
78
- new_c_i = (0...tables_count).detect{|c_n|
79
- new_cost = cost_matrix[m_i][c_n]
80
- next if c_i==c_n || new_cost.nil?
81
- new_table_included_times = prev_step.select{|c| c==c_n }.count
82
-
83
- if old_cost.nil?
84
- # if we have non indexed table now
85
- true
86
- elsif table_included_times>1
87
- if new_table_included_times>0
88
- # table to used table if
89
- # cost now > new cost
90
- old_cost > new_cost
91
- else
92
- # table to unused table if
93
- # cost now > new cost + max other cost in table now
94
- old_cost > new_cost + ( prev_step.select.with_index{|c,i| c==c_i && i!=m_i }.max || UNLIM_COST )
95
- end
96
- else
97
- if new_table_included_times>0
98
- # unused table to table if
99
- # new cost < cost now + max other cost in new table
100
- old_cost > new_cost - ( prev_step.select{|c| c==c_n }.max || UNLIM_COST )
101
- else
102
- # unused to unused
103
- # cost now > new cost
104
- old_cost > new_cost
105
- end
106
- end
107
-
108
- }
109
-
110
- step << c_i || new_c_i
111
-
112
- }
113
-
114
- break if steps.include? step
115
- steps << step
116
- end
60
+ def do_optimize
117
61
 
118
- @tables_by_metrics = steps.last
62
+ variants = generate_variants [], 0
63
+ variant_costs = variants.map{|v| cost_for v}
64
+ variants[variant_costs.each_with_index.min.second]
119
65
 
120
66
  end
121
67
 
@@ -14,7 +14,7 @@ module Activecube::Query
14
14
 
15
15
  include ChainAppender
16
16
 
17
- attr_reader :cube, :slices, :measures, :selectors, :options, :tables
17
+ attr_reader :cube, :slices, :measures, :selectors, :options, :tables, :sql
18
18
  def initialize cube, slices = [], measures = [], selectors = [], options = [], model_tables = nil
19
19
  @cube = cube
20
20
  @slices = slices
@@ -36,18 +36,22 @@ module Activecube::Query
36
36
  end
37
37
 
38
38
  def slice *args
39
+ clear_sql
39
40
  append *args, @slices, Slice, cube.dimensions
40
41
  end
41
42
 
42
43
  def measure *args
44
+ clear_sql
43
45
  append *args, @measures, Measure, cube.metrics
44
46
  end
45
47
 
46
48
  def when *args
49
+ clear_sql
47
50
  append *args, @selectors, Selector, cube.selectors
48
51
  end
49
52
 
50
53
  def desc *args
54
+ clear_sql
51
55
  args.each{|arg|
52
56
  options << Ordering.new(arg, :desc)
53
57
  }
@@ -55,6 +59,7 @@ module Activecube::Query
55
59
  end
56
60
 
57
61
  def asc *args
62
+ clear_sql
58
63
  args.each{|arg|
59
64
  options << Ordering.new( arg, :asc)
60
65
  }
@@ -62,6 +67,7 @@ module Activecube::Query
62
67
  end
63
68
 
64
69
  def offset *args
70
+ clear_sql
65
71
  args.each{|arg|
66
72
  options << Limit.new( arg, :skip)
67
73
  }
@@ -69,6 +75,7 @@ module Activecube::Query
69
75
  end
70
76
 
71
77
  def limit *args
78
+ clear_sql
72
79
  args.each{|arg|
73
80
  options << Limit.new( arg, :take)
74
81
  }
@@ -77,13 +84,12 @@ module Activecube::Query
77
84
 
78
85
 
79
86
  def query
80
- composer = Activecube::Processor::Composer.new(self)
81
- sql = composer.build_query.to_sql
82
- composer.connection.exec_query(sql)
87
+ sql = to_query.to_sql
88
+ @composed.connection.exec_query(sql)
83
89
  end
84
90
 
85
91
  def to_query
86
- Activecube::Processor::Composer.new(self).build_query
92
+ @composed.try(:query) || (@composed = Activecube::Processor::Composer.new(self)).build_query
87
93
  end
88
94
 
89
95
  def to_sql
@@ -136,5 +142,10 @@ module Activecube::Query
136
142
  options.select{|s| s.kind_of? Ordering}
137
143
  end
138
144
 
145
+ private
146
+
147
+ def clear_sql
148
+ @composed = nil
149
+ end
139
150
  end
140
151
  end
@@ -1,3 +1,3 @@
1
1
  module Activecube
2
- VERSION = "0.1.23"
2
+ VERSION = "0.1.28"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activecube
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.23
4
+ version: 0.1.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksey Studnev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-28 00:00:00.000000000 Z
11
+ date: 2020-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord