Mercurial Hosting > luan
comparison lucene/src/luan/modules/lucene/Ab_testing.luan @ 291:a35d1177bbf0
implement Ab_testing.web_page()
git-svn-id: https://luan-java.googlecode.com/svn/trunk@292 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Tue, 09 Dec 2014 23:24:07 +0000 |
parents | 8afe9f2fdfec |
children | e8a2153f6ce1 |
comparison
equal
deleted
inserted
replaced
290:9a0cc6d9b27b | 291:a35d1177bbf0 |
---|---|
1 import "luan:Math" | 1 import "luan:Math" |
2 import "luan:Table" | 2 import "luan:Table" |
3 import "luan:Io" | |
4 import "luan:web/Http" | |
3 | 5 |
4 | 6 |
5 function of(index) | 7 function of(index) |
6 | 8 |
7 local ab_testing = {} | 9 local ab_testing = {} |
10 ab_testing.test_list = {} | 12 ab_testing.test_list = {} |
11 | 13 |
12 function ab_testing.test(test) | 14 function ab_testing.test(test) |
13 test.name or error "name not defined" | 15 test.name or error "name not defined" |
14 test.values or error "values not defined" | 16 test.values or error "values not defined" |
17 | |
18 -- list of event names | |
19 test.events or error "events not defined" | |
20 | |
21 -- map of event name to aggregator factory | |
22 test.aggregator_factories or error "aggregator_factories not defined" | |
23 | |
15 -- test.date_field is optional | 24 -- test.date_field is optional |
16 | 25 |
17 local field = "ab_test_" .. test.name | 26 local field = "ab_test_" .. test.name |
18 index.fields[field] == nil or error("test "+test.name+" already defined") | 27 index.fields[field] == nil or error("test "+test.name+" already defined") |
19 index.fields[field] = field .. " index" | 28 index.fields[field] = field .. " index" |
20 test.field = field | 29 test.field = field |
21 | 30 |
22 -- pass in map of name to aggregator factory | 31 -- returns map of event name to (map of value to result) and "start_date" |
23 -- returns map of name to (map of value to result) and "start_date" | 32 function test.results() |
24 function test.results(aggregator_factories) | |
25 return index.Searcher( function(searcher) | 33 return index.Searcher( function(searcher) |
26 local results = {} | 34 local results = {} |
27 for name in pairs(aggregator_factories) do | 35 for name in pairs(test.aggregator_factories) do |
28 results[name] = {} | 36 results[name] = {} |
29 end | 37 end |
30 local date_field = test.date_field | 38 local date_field = test.date_field |
31 local start_date = nil | 39 local start_date = nil |
32 for _, value in ipairs(test.values) do | 40 for _, value in ipairs(test.values) do |
33 local aggregators = {} | 41 local aggregators = {} |
34 for name, factory in pairs(aggregator_factories) do | 42 for name, factory in pairs(test.aggregator_factories) do |
35 aggregators[name] = factory() | 43 aggregators[name] = factory() |
36 end | 44 end |
37 local query = { [field] = value } | 45 local query = index.Query.term{ [field] = value } |
38 searcher.search(query, function(doc) | 46 searcher.search(query, function(doc) |
39 for _, aggregator in pairs(aggregators) do | 47 for _, aggregator in pairs(aggregators) do |
40 aggregator.aggregate(doc) | 48 aggregator.aggregate(doc) |
41 end | 49 end |
42 if date_field ~= nil then | 50 if date_field ~= nil then |
53 results.start_date = start_date | 61 results.start_date = start_date |
54 return results | 62 return results |
55 end ) | 63 end ) |
56 end | 64 end |
57 | 65 |
66 function test.fancy_results() | |
67 local events = test.events | |
68 local results = test.results() | |
69 local fancy = {} | |
70 fancy.start_date = results.start_date | |
71 local event = events[1] | |
72 fancy[event] = {} | |
73 for value, count in pairs(results[event]) do | |
74 fancy[event][value] = {} | |
75 fancy[event][value].count = count | |
76 fancy[event][value].pct_of_total = 100 | |
77 fancy[event][value].pct_of_prev = 100 | |
78 end | |
79 local all = results[event] | |
80 local prev = all | |
81 for i in range(2,#events) do | |
82 event = events[i] | |
83 fancy[event] = {} | |
84 for value, count in pairs(results[event]) do | |
85 fancy[event][value] = {} | |
86 fancy[event][value].count = count | |
87 fancy[event][value].pct_of_total = percent(count,all[value]) | |
88 fancy[event][value].pct_of_prev = percent(count,prev[value]) | |
89 end | |
90 prev = results[event] | |
91 end | |
92 return fancy | |
93 end | |
94 | |
95 | |
58 ab_testing.test_map[test.name] = test | 96 ab_testing.test_map[test.name] = test |
59 ab_testing.test_list[#ab_testing.test_list + 1] = test | 97 ab_testing.test_list[#ab_testing.test_list + 1] = test |
60 | 98 |
61 return test | 99 return test |
62 end | 100 end |
84 else | 122 else |
85 for _, test in ipairs(tests) do | 123 for _, test in ipairs(tests) do |
86 doc[test.field] = values[test.name] | 124 doc[test.field] = values[test.name] |
87 end | 125 end |
88 end | 126 end |
127 end | |
128 | |
129 function ab_testing.web_page(test_names) | |
130 return { service = function() | |
131 local results = {} | |
132 for _, name in ipairs(test_names) do | |
133 local test = ab_testing.test_map[name] | |
134 test or error("test not found: "..name) | |
135 results[name] = test.fancy_results() | |
136 end | |
137 Io.stdout = Http.response.text_writer() | |
138 html(test_names,ab_testing.test_map,results) | |
139 end } | |
89 end | 140 end |
90 | 141 |
91 return ab_testing | 142 return ab_testing |
92 end | 143 end |
93 | 144 |
106 end | 157 end |
107 return aggregator | 158 return aggregator |
108 end | 159 end |
109 end | 160 end |
110 | 161 |
111 count_all = count( function() return true end ) | 162 count_all = count( function(doc) return true end ) |
112 | 163 |
113 -- fn(doc) should return number to add to result, return 0 for nothing | 164 -- fn(doc) should return number to add to result, return 0 for nothing |
114 function sum(fn) | 165 function sum(fn) |
115 return function() | 166 return function() |
116 local aggregator = {} | 167 local aggregator = {} |
122 end | 173 end |
123 end | 174 end |
124 | 175 |
125 | 176 |
126 | 177 |
127 local function percent(x,total) | 178 function percent(x,total) |
128 if total==0 then | 179 if total==0 then |
129 return 0 | 180 return 0 |
130 else | 181 else |
131 return 100 * x / total | 182 return 100 * x / total |
132 end | 183 end |
133 end | 184 end |
134 | 185 |
135 function fancy(results,names) | 186 |
136 local fancy = {} | 187 function html(test_names,tests,results) %> |
137 fancy.start_date = results.start_date | 188 <html> |
138 local name = names[1] | 189 <body> |
139 fancy[name] = {} | 190 <h2>A/B Tests</h2> |
140 for value, count in pairs(result[name]) do | 191 <% |
141 fancy[name][value] = {} | 192 for _, test_name in ipairs(test_names) do |
142 fancy[name][value].count = count | 193 local test = tests[test_name] |
143 fancy[name][value].pct_of_total = 100 | 194 local result = results[test_name] |
144 fancy[name][value].pct_of_prev = 100 | 195 local n = #test.values |
145 end | 196 %> |
146 local all = result[name] | 197 <h3><%=test_name%></h3> |
147 local prev = all | 198 <table> |
148 for i in range(2,#names) do | 199 <tr> |
149 name = names[i] | 200 <th>Event</th> |
150 fancy[name] = {} | 201 <th class="top" colspan="<%=n%>">Count</th> |
151 for value, count in pairs(result[name]) do | 202 <th class="top" colspan="<%=n%>">% of total</th> |
152 fancy[name][value] = {} | 203 <th class="top" colspan="<%=n%>">% of prev</th> |
153 fancy[name][value].count = count | 204 </tr> |
154 fancy[name][value].pct_of_total = percent(count,all[value]) | 205 <tr> |
155 fancy[name][value].pct_of_prev = percent(count,prev[value]) | 206 <th></th> |
156 end | 207 <% |
157 prev = result[name] | 208 for _ in range(1,3) do |
158 end | 209 for _, value in ipairs(test.values) do |
159 return fancy | 210 %> |
160 end | 211 <th class="top"><%=value%></th> |
212 <% | |
213 end | |
214 end | |
215 %> | |
216 </tr> | |
217 <% | |
218 for _, event in ipairs(test.events) do | |
219 local event_values = result[event] | |
220 %> | |
221 <tr> | |
222 <td><%=event%></td> | |
223 <% | |
224 for _, value in ipairs(test.values) do | |
225 %> | |
226 <td><%=event_values[value].count%></th> | |
227 <% | |
228 end | |
229 for _, value in ipairs(test.values) do | |
230 %> | |
231 <td><%=event_values[value].pct_of_total%></th> | |
232 <% | |
233 end | |
234 for _, value in ipairs(test.values) do | |
235 %> | |
236 <td><%=event_values[value].pct_of_prev%></th> | |
237 <% | |
238 end | |
239 %> | |
240 </tr> | |
241 <% | |
242 end | |
243 %> | |
244 </table> | |
245 <% | |
246 end | |
247 %> | |
248 </body> | |
249 </html> | |
250 <% end |