cubicle 0.1.29 → 0.1.30
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +125 -122
- data/cubicle.gemspec +2 -2
- data/lib/cubicle/duration.rb +52 -51
- data/lib/cubicle/version.rb +2 -2
- data/test/cubicle/duration_test.rb +4 -2
- data/test/cubicles/defect_cubicle.rb +57 -56
- data/test/log/test.log +6874 -0
- data/test/models/defect.rb +105 -103
- metadata +4 -4
data/CHANGELOG.rdoc
CHANGED
@@ -1,122 +1,125 @@
|
|
1
|
-
==0.1.
|
2
|
-
*
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
==0.1.
|
21
|
-
|
22
|
-
|
23
|
-
==0.1.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
==0.1.
|
38
|
-
|
39
|
-
|
40
|
-
==0.1.
|
41
|
-
|
42
|
-
|
43
|
-
==0.1.
|
44
|
-
*
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
==0.1.
|
67
|
-
*
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
==0.1.
|
74
|
-
*
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
==0.1.
|
95
|
-
*
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
== 0.1.
|
108
|
-
*
|
109
|
-
|
110
|
-
|
111
|
-
*
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
*
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
*
|
120
|
-
|
121
|
-
== 0.1.
|
122
|
-
*
|
1
|
+
==0.1.30
|
2
|
+
*Added duration in weeks.
|
3
|
+
|
4
|
+
==0.1.29
|
5
|
+
*Enabled custom configuring cubicle's mongo connection even if MongoMapper is present, to allow running map reduce jobs
|
6
|
+
on a slave while MongoMapper operates on the master.
|
7
|
+
|
8
|
+
==0.1.28
|
9
|
+
*Updated to latest versions of MongoMapper, Mongo & BSON
|
10
|
+
==0.1.26,0.1.27
|
11
|
+
*Included mustache dependency in gem (whoops) and fixed a bug where an error in cube processing would replace
|
12
|
+
useful error information with nonsensical error information.
|
13
|
+
|
14
|
+
==0.1.25
|
15
|
+
*Modified data extraction to ensure that member and query level aliases are respected in the final result. Also
|
16
|
+
stopped automatically dropping temporary map reduce tables during query execution for performance reasons. Instead,
|
17
|
+
added a static method to the Cubicle module, clear_temp_tables, which can be called at application startup or teardown:
|
18
|
+
Cubicle.clear_temp_tables()
|
19
|
+
|
20
|
+
==0.1.24
|
21
|
+
*Added more detail to the profile for the 'find' action
|
22
|
+
|
23
|
+
==0.1.23
|
24
|
+
*Fixed profiler's capped collection sizing bug (off by x1000)
|
25
|
+
|
26
|
+
==0.1.22
|
27
|
+
*Added profiler, which is off by default, that will profile every operation performed by the aggregation engine
|
28
|
+
in a collection called cubicle.profiler. It uses a capped collection size at, by default, 250mb, but this can
|
29
|
+
be configured. Also added basic metadata table for overall aggregation definitions that will record the last processing
|
30
|
+
time, along with the duration of the processing job, in the collection cubicle.metadata
|
31
|
+
|
32
|
+
==0.1.21
|
33
|
+
*Added metadata tables in the database for cubicle to manage aggregation info. This was necessary because previously
|
34
|
+
I was trying to overload the collection name with metadata, which was making the names longer than MongoDb could support
|
35
|
+
and causing errors. This change will enable richer monitoring and profiling and optimization in the near future.
|
36
|
+
|
37
|
+
==0.1.20
|
38
|
+
*Updated to work with mongo driver 1.0 (and therefore latest versions of MongoMapper)
|
39
|
+
|
40
|
+
==0.1.19
|
41
|
+
*Fixed bug that caused cubicle to hang when grouping by days
|
42
|
+
|
43
|
+
==0.1.18
|
44
|
+
*Bug fixes
|
45
|
+
|
46
|
+
==0.1.16
|
47
|
+
*Added a set of default constants for expression templates, such as date_today, date_today_iso, date_today_utc_iso, etc.
|
48
|
+
Also added the 'define' method to the query DSL (instead of simply the aggregation DSL) so that you can either define new
|
49
|
+
named expressions or override an existing named expression or date constant in a query context, instead of only at the
|
50
|
+
global level
|
51
|
+
|
52
|
+
==0.1.15
|
53
|
+
*Added 'difference' calculated measure to aggregation DSL, used in the same was as 'ratio' - so, in your aggregation
|
54
|
+
definition, you can do 'difference :big_diff, :measure_one, :measure_two'
|
55
|
+
and the value of :big_diff will be measure_one - measure_two. Also monkey patched Mustache (per suggestion in the
|
56
|
+
mailing list) to turn of HTML escaping, so that the triple-curly syntax should not be required when using operators
|
57
|
+
in templated expressions.
|
58
|
+
|
59
|
+
==0.1.14
|
60
|
+
*Incorporated the Mustache templating library into aggregation definitions allowing expression to reference previously
|
61
|
+
defined dimensions, measures, or named expressions (using the syntax: define :expression_name, 'this.my_expression != "that"')
|
62
|
+
Allows for definitions such as this: avg :average_happy_defects, :expression=>'{{defects}} && this.type=="Happy"'
|
63
|
+
Also available is 'time_now' to represent the Ruby's Time.now in the form of a javascript date, so '{{time_now}}' will
|
64
|
+
become 'new Date(2342342)' where 2342342 is Time.now.to_i
|
65
|
+
|
66
|
+
==0.1.13
|
67
|
+
*Previous feature broke ratios. Fixed now.
|
68
|
+
|
69
|
+
==0.1.12
|
70
|
+
*Added distinct' option to 'count' measure, to allow measures which represent distinct counts of given field/expression value.
|
71
|
+
ONLY works when the value being distinctly counted is a string.
|
72
|
+
|
73
|
+
==0.1.11
|
74
|
+
*Fixed a bug when filtering categorized dimensions in transient queries
|
75
|
+
|
76
|
+
==0.1.10
|
77
|
+
*enhanced cubicle aggregation manager to transparently convert several of the basic mongo operators (such as $ne,
|
78
|
+
$gt, $gte, etc) into javascript for use in the generated $where clause for transient queries. In practice, this
|
79
|
+
means that you can define a measure as an expression, say dimension :month, :expression=>"'2010-01'", and then
|
80
|
+
use that dimension name in a standard mongo driver compatible filter expression, without concern for whether
|
81
|
+
your query is a transient query or a regular query - cubicle will do the appropriate conversion to javascript
|
82
|
+
in the former case, translating :month=>{"$gte"=>"'2009-12'", "$lt"=>"'2010-02'"} into the functional equivalent of
|
83
|
+
"$where"=>"'2010-01' >= '2009-12' && '2010-01' < '2010-02'". Actually, an inline function is used to reduce IO
|
84
|
+
as repeating the expression for each comparison can get out of hand if your expression is large.
|
85
|
+
|
86
|
+
==0.1.9
|
87
|
+
* Fixed problems with missing number in bucket intervals. Moved resolution of source measure javascript to
|
88
|
+
* last moment, to ensure dynamic values don't get accidentally cached too early.
|
89
|
+
|
90
|
+
==0.1.8
|
91
|
+
* Added 'bucketize' aliased as 'categorize' to cubicle DSL to allow dimensions to be created from bucketizing
|
92
|
+
(categorizing based on name) a measure value.
|
93
|
+
|
94
|
+
==0.1.7
|
95
|
+
* Minor bug fixes
|
96
|
+
|
97
|
+
==0.1.6
|
98
|
+
*Added generic 'condition' argument to member definitions, which allows the specification of a JavaScript expression
|
99
|
+
which will determine if the measure (or dimension) expression will be evaluated. This capability was available
|
100
|
+
before via the :expression option, but using a :condition modifier allows for more straightforward (readable) measure
|
101
|
+
definitions and separates the definition of the actual value from the conditions under which the value is valid.
|
102
|
+
|
103
|
+
==0.1.5
|
104
|
+
* Added duration_since (aliased as elapsed, age_since) to calculate the time elapsed since any
|
105
|
+
given timestamp and the current execution time of the query.
|
106
|
+
|
107
|
+
== 0.1.4
|
108
|
+
* Cached aggregations were being stored on disk, but not properly utilized. This is now fixed.
|
109
|
+
|
110
|
+
== 0.1.3
|
111
|
+
* Formalized flat (Cubicle::Data::Table) and hierarchical (Cubicle::Data::Hierarchy) data results from cubicle queries,
|
112
|
+
and added client side support for rolling up measure values in hierarchical data so that no matter how a given
|
113
|
+
query is organized hierarchically, a summary of aggregated measure values for each level of data will be available.
|
114
|
+
* Re-organized codebase
|
115
|
+
* Bug fixes
|
116
|
+
|
117
|
+
== 0.1.2
|
118
|
+
* Added ability to calculate durations between two timestamps
|
119
|
+
* Bug fixes
|
120
|
+
|
121
|
+
== 0.1.1
|
122
|
+
* Fixed a bug that required a logger to be initialized for the thing to work
|
123
|
+
|
124
|
+
== 0.1.0
|
125
|
+
* Initial release
|
data/cubicle.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{cubicle}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.30"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nathan Stults"]
|
12
|
-
s.date = %q{2010-07-
|
12
|
+
s.date = %q{2010-07-07}
|
13
13
|
s.description = %q{Cubicle provides a dsl and aggregation caching framework for automating the generation, execution and caching of map reduce queries when using MongoDB in Ruby. Cubicle also includes a MongoMapper plugin for quickly performing ad-hoc, multi-level group-by queries against a MongoMapper model.}
|
14
14
|
s.email = %q{hereiam@sonic.net}
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/cubicle/duration.rb
CHANGED
@@ -1,52 +1,53 @@
|
|
1
|
-
module Cubicle
|
2
|
-
class Duration < Measure
|
3
|
-
attr_accessor :duration_unit, :begin_milestone, :end_milestone, :timestamp_prefix
|
4
|
-
|
5
|
-
def initialize(*args)
|
6
|
-
super
|
7
|
-
self.duration_unit = options(:in) || :seconds
|
8
|
-
self.timestamp_prefix = options :timestamp_prefix, :prefix
|
9
|
-
self.expression_type = :javascript
|
10
|
-
#only one item should be left in the hash, the duration map
|
11
|
-
raise "duration must be provided with a hash with a single entry, where the key represents the starting milestone of a duration and the value represents the ending milestone." if options.length != 1
|
12
|
-
|
13
|
-
self.begin_milestone, self.end_milestone = options.to_a[0]
|
14
|
-
self.name ||= "#{begin_milestone}_to_#{end_milestone}_#{aggregation_method}".to_sym
|
15
|
-
end
|
16
|
-
|
17
|
-
def default_aggregation_method
|
18
|
-
:average
|
19
|
-
end
|
20
|
-
|
21
|
-
def condition
|
22
|
-
cond = " && (#{super})" unless super.blank?
|
23
|
-
"#{milestone_js(:begin)} && #{milestone_js(:end)}#{cond}"
|
24
|
-
end
|
25
|
-
|
26
|
-
def expression
|
27
|
-
#prefix these names for the expression
|
28
|
-
# prefix = "#{self.timestamp_prefix}#{self.timestamp_prefix.blank? ? '' : '.'}"
|
29
|
-
# ms1,ms2 = [self.begin_milestone,self.end_milestone].map{|ms|ms.to_s=='now' ? "new Date(#{Time.now.to_i*1000})" : "this.#{prefix}#{ms}"}
|
30
|
-
@expression = "(#{milestone_js(:end)}-#{milestone_js(:begin)})/#{denominator}"
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def milestone_js(which)
|
36
|
-
prefix = "#{self.timestamp_prefix}#{self.timestamp_prefix.blank? ? '' : '.'}"
|
37
|
-
ms = self.send("#{which.to_s}_milestone")
|
38
|
-
ms.to_s=='now' ? "new Date(#{Time.now.to_i*1000})" : "this.#{prefix}#{ms}"
|
39
|
-
end
|
40
|
-
|
41
|
-
def denominator
|
42
|
-
#Date math results in milliseconds in javascript
|
43
|
-
case self.duration_unit || :seconds
|
44
|
-
when :
|
45
|
-
when :
|
46
|
-
when :
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
1
|
+
module Cubicle
|
2
|
+
class Duration < Measure
|
3
|
+
attr_accessor :duration_unit, :begin_milestone, :end_milestone, :timestamp_prefix
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
self.duration_unit = options(:in) || :seconds
|
8
|
+
self.timestamp_prefix = options :timestamp_prefix, :prefix
|
9
|
+
self.expression_type = :javascript
|
10
|
+
#only one item should be left in the hash, the duration map
|
11
|
+
raise "duration must be provided with a hash with a single entry, where the key represents the starting milestone of a duration and the value represents the ending milestone." if options.length != 1
|
12
|
+
|
13
|
+
self.begin_milestone, self.end_milestone = options.to_a[0]
|
14
|
+
self.name ||= "#{begin_milestone}_to_#{end_milestone}_#{aggregation_method}".to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_aggregation_method
|
18
|
+
:average
|
19
|
+
end
|
20
|
+
|
21
|
+
def condition
|
22
|
+
cond = " && (#{super})" unless super.blank?
|
23
|
+
"#{milestone_js(:begin)} && #{milestone_js(:end)}#{cond}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def expression
|
27
|
+
#prefix these names for the expression
|
28
|
+
# prefix = "#{self.timestamp_prefix}#{self.timestamp_prefix.blank? ? '' : '.'}"
|
29
|
+
# ms1,ms2 = [self.begin_milestone,self.end_milestone].map{|ms|ms.to_s=='now' ? "new Date(#{Time.now.to_i*1000})" : "this.#{prefix}#{ms}"}
|
30
|
+
@expression = "(#{milestone_js(:end)}-#{milestone_js(:begin)})/#{denominator}"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def milestone_js(which)
|
36
|
+
prefix = "#{self.timestamp_prefix}#{self.timestamp_prefix.blank? ? '' : '.'}"
|
37
|
+
ms = self.send("#{which.to_s}_milestone")
|
38
|
+
ms.to_s=='now' ? "new Date(#{Time.now.to_i*1000})" : "this.#{prefix}#{ms}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def denominator
|
42
|
+
#Date math results in milliseconds in javascript
|
43
|
+
case self.duration_unit || :seconds
|
44
|
+
when :weeks then "1000/60/60/24/7.0"
|
45
|
+
when :days then "1000/60/60/24.0"
|
46
|
+
when :hours then "1000/60/60.0"
|
47
|
+
when :minutes then "1000/60.0"
|
48
|
+
else "1000.0"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
52
53
|
end
|
data/lib/cubicle/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Cubicle
|
2
|
-
VERSION = '0.1.
|
1
|
+
module Cubicle
|
2
|
+
VERSION = '0.1.30'
|
3
3
|
end
|
@@ -3,8 +3,8 @@ require "test_helper"
|
|
3
3
|
class DurationTest < ActiveSupport::TestCase
|
4
4
|
context "Querying a cubicle with durations" do
|
5
5
|
setup do
|
6
|
-
#record 1, ms1 = 1/1/2000, ms2 = 1/2/2000, ms3=1/4/2000
|
7
|
-
#record 2, ms1 = 1/1/2000, ms2 = 1/3/2000, ms3=1/5/2000
|
6
|
+
#record 1, ms1 = 1/1/2000, ms2 = 1/2/2000, ms3=1/4/2000, ms4=1/23/2000
|
7
|
+
#record 2, ms1 = 1/1/2000, ms2 = 1/3/2000, ms3=1/5/2000, ms4=1/29/2000
|
8
8
|
Defect.create_duration_test_data
|
9
9
|
end
|
10
10
|
should "correctly calculate durations for each activity" do
|
@@ -18,10 +18,12 @@ class DurationTest < ActiveSupport::TestCase
|
|
18
18
|
assert_equal 1 * 60 * 60 * 24, a1["ms1_to_ms2_average"]
|
19
19
|
assert_equal 2 * 60 * 60 * 24, a1["ms2_to_ms3_sum"]
|
20
20
|
assert_equal 3, a1["total_duration"]
|
21
|
+
assert_equal 22/7.0, a1["total_duration_in_weeks"]
|
21
22
|
|
22
23
|
assert_equal 2 * 60 * 60 * 24, a2["ms1_to_ms2_average"]
|
23
24
|
assert_equal 2 * 60 * 60 * 24, a2["ms2_to_ms3_sum"]
|
24
25
|
assert_equal 4, a2["total_duration"]
|
26
|
+
assert_equal 28/7.0, a2["total_duration_in_weeks"]
|
25
27
|
end
|
26
28
|
should "correctly aggregate durations" do
|
27
29
|
results = DefectCubicle.query do
|
@@ -1,57 +1,58 @@
|
|
1
|
-
class DefectCubicle
|
2
|
-
extend Cubicle::Aggregation
|
3
|
-
|
4
|
-
define :preventable, "this.root_cause != 'act_of_god'"
|
5
|
-
define :product_name, "this.product.name"
|
6
|
-
define :current_year, "'{{date_today_iso}}'.substring(0,4)"
|
7
|
-
|
8
|
-
date :manufacture_date, :field_name=>'manufacture_date', :alias=>:date
|
9
|
-
dimension :month, :expression=>'this.manufacture_date.substring(0,7)'
|
10
|
-
dimension :year, :expression=>'this.manufacture_date.substring(0,4)'
|
11
|
-
|
12
|
-
dimension :manufacture_time
|
13
|
-
|
14
|
-
dimension :product, :expression=>'{{product_name}}'
|
15
|
-
dimension :region, :field_name=>'plant.address.region'
|
16
|
-
|
17
|
-
dimensions :operator, :outcome
|
18
|
-
|
19
|
-
count :total_defects, :field_name=>'defect_id'
|
20
|
-
count :distinct_products, :expression=>'{{product}}', :distinct=>true
|
21
|
-
count :preventable_defects, :expression=>'{{preventable}}'
|
22
|
-
count :conditioned_preventable,:expression=>'1.0', :condition=>'{{preventable}}'
|
23
|
-
count :defects_this_year, :expression=>'{{year}} == {{current_year}}'
|
24
|
-
sum :total_cost, :field_name=>'cost'
|
25
|
-
avg :avg_cost, :field_name=>'cost'
|
26
|
-
|
27
|
-
#calculated fields
|
28
|
-
ratio :preventable_pct, :preventable_defects, :total_defects
|
29
|
-
ratio :distinct_ratio, :distinct_products, :total_defects
|
30
|
-
difference :inevitable_defects, :total_defects, :preventable_defects
|
31
|
-
#durations
|
32
|
-
average_duration :ms1 => :ms2
|
33
|
-
total_duration :ms2 => :ms3
|
34
|
-
duration :total_duration, :ms1 => :ms3, :in=>:days
|
35
|
-
duration :
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
aggregation :month, :
|
56
|
-
|
1
|
+
class DefectCubicle
|
2
|
+
extend Cubicle::Aggregation
|
3
|
+
|
4
|
+
define :preventable, "this.root_cause != 'act_of_god'"
|
5
|
+
define :product_name, "this.product.name"
|
6
|
+
define :current_year, "'{{date_today_iso}}'.substring(0,4)"
|
7
|
+
|
8
|
+
date :manufacture_date, :field_name=>'manufacture_date', :alias=>:date
|
9
|
+
dimension :month, :expression=>'this.manufacture_date.substring(0,7)'
|
10
|
+
dimension :year, :expression=>'this.manufacture_date.substring(0,4)'
|
11
|
+
|
12
|
+
dimension :manufacture_time
|
13
|
+
|
14
|
+
dimension :product, :expression=>'{{product_name}}'
|
15
|
+
dimension :region, :field_name=>'plant.address.region'
|
16
|
+
|
17
|
+
dimensions :operator, :outcome
|
18
|
+
|
19
|
+
count :total_defects, :field_name=>'defect_id'
|
20
|
+
count :distinct_products, :expression=>'{{product}}', :distinct=>true
|
21
|
+
count :preventable_defects, :expression=>'{{preventable}}'
|
22
|
+
count :conditioned_preventable,:expression=>'1.0', :condition=>'{{preventable}}'
|
23
|
+
count :defects_this_year, :expression=>'{{year}} == {{current_year}}'
|
24
|
+
sum :total_cost, :field_name=>'cost'
|
25
|
+
avg :avg_cost, :field_name=>'cost'
|
26
|
+
|
27
|
+
#calculated fields
|
28
|
+
ratio :preventable_pct, :preventable_defects, :total_defects
|
29
|
+
ratio :distinct_ratio, :distinct_products, :total_defects
|
30
|
+
difference :inevitable_defects, :total_defects, :preventable_defects
|
31
|
+
#durations
|
32
|
+
average_duration :ms1 => :ms2
|
33
|
+
total_duration :ms2 => :ms3
|
34
|
+
duration :total_duration, :ms1 => :ms3, :in=>:days
|
35
|
+
duration :total_duration_in_weeks, :ms1 => :ms4, :in=>:weeks
|
36
|
+
duration :conditional_duration, :ms1 => :ms3, :in=>:days, :condition=>"this.defect_id != 2"
|
37
|
+
elapsed :ms3, :in=>:days
|
38
|
+
age_since :avg_time_since_ms3,:ms3, :in=>:days
|
39
|
+
|
40
|
+
#bucketized fields
|
41
|
+
categorize :avg_cost_category,
|
42
|
+
:avg_cost, 1..5, :bucket_size=>0.5, :range_start_bump=>0.01 do |bucket_start,bucket_end|
|
43
|
+
if bucket_start == :begin
|
44
|
+
'< $1'
|
45
|
+
elsif bucket_end == :end
|
46
|
+
'> $5'
|
47
|
+
else
|
48
|
+
"$#{bucket_start} - $#{bucket_end}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
#pre-cached aggregations
|
55
|
+
aggregation :month, :year, :product
|
56
|
+
aggregation :month, :region
|
57
|
+
|
57
58
|
end
|