cubicle 0.1.29 → 0.1.30
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.
- 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
|