comparison lucene/src/luan/modules/lucene/Ab_testing.luan @ 274:8afe9f2fdfec

AB testing, not fully tested git-svn-id: https://luan-java.googlecode.com/svn/trunk@275 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Mon, 10 Nov 2014 03:28:32 +0000
parents
children a35d1177bbf0
comparison
equal deleted inserted replaced
273:073044e3ac03 274:8afe9f2fdfec
1 import "luan:Math"
2 import "luan:Table"
3
4
5 function of(index)
6
7 local ab_testing = {}
8
9 ab_testing.test_map = {}
10 ab_testing.test_list = {}
11
12 function ab_testing.test(test)
13 test.name or error "name not defined"
14 test.values or error "values not defined"
15 -- test.date_field is optional
16
17 local field = "ab_test_" .. test.name
18 index.fields[field] == nil or error("test "+test.name+" already defined")
19 index.fields[field] = field .. " index"
20 test.field = field
21
22 -- pass in map of name to aggregator factory
23 -- returns map of name to (map of value to result) and "start_date"
24 function test.results(aggregator_factories)
25 return index.Searcher( function(searcher)
26 local results = {}
27 for name in pairs(aggregator_factories) do
28 results[name] = {}
29 end
30 local date_field = test.date_field
31 local start_date = nil
32 for _, value in ipairs(test.values) do
33 local aggregators = {}
34 for name, factory in pairs(aggregator_factories) do
35 aggregators[name] = factory()
36 end
37 local query = { [field] = value }
38 searcher.search(query, function(doc)
39 for _, aggregator in pairs(aggregators) do
40 aggregator.aggregate(doc)
41 end
42 if date_field ~= nil then
43 local date = doc[date_field]
44 if date ~= nil and (start_date==nil or start_date > date) then
45 start_date = date
46 end
47 end
48 end)
49 for name, aggregator in pairs(aggregators) do
50 results[name][value] = aggregator.result
51 end
52 end
53 results.start_date = start_date
54 return results
55 end )
56 end
57
58 ab_testing.test_map[test.name] = test
59 ab_testing.test_list[#ab_testing.test_list + 1] = test
60
61 return test
62 end
63
64 function ab_testing.value(test_name,values)
65 return values[test_name] or ab_testing.test_map[test_name].values[1]
66 end
67
68 -- returns map from test name to value
69 function ab_testing.from_doc(doc)
70 local tests = ab_testing.test_list
71 local values = {}
72 for _, test in ipairs(tests) do
73 values[test.name] = doc[test.field]
74 end
75 return values
76 end
77
78 function ab_testing.to_doc(doc,values,tests)
79 tests = tests or ab_testing.test_list
80 if values == nil then
81 for _, test in ipairs(tests) do
82 doc[test.field] = test.values[Math.random(#test.values)]
83 end
84 else
85 for _, test in ipairs(tests) do
86 doc[test.field] = values[test.name]
87 end
88 end
89 end
90
91 return ab_testing
92 end
93
94
95 -- aggregator factories
96
97 -- fn(doc) should return boolean whether doc should be counted
98 function count(fn)
99 return function()
100 local aggregator = {}
101 aggregator.result = 0
102 function aggregator.aggregate(doc)
103 if fn(doc) then
104 aggregator.result = aggregator.result + 1
105 end
106 end
107 return aggregator
108 end
109 end
110
111 count_all = count( function() return true end )
112
113 -- fn(doc) should return number to add to result, return 0 for nothing
114 function sum(fn)
115 return function()
116 local aggregator = {}
117 aggregator.result = 0
118 function aggregator.aggregate(doc)
119 aggregator.result = aggregator.result + fn(doc)
120 end
121 return aggregator
122 end
123 end
124
125
126
127 local function percent(x,total)
128 if total==0 then
129 return 0
130 else
131 return 100 * x / total
132 end
133 end
134
135 function fancy(results,names)
136 local fancy = {}
137 fancy.start_date = results.start_date
138 local name = names[1]
139 fancy[name] = {}
140 for value, count in pairs(result[name]) do
141 fancy[name][value] = {}
142 fancy[name][value].count = count
143 fancy[name][value].pct_of_total = 100
144 fancy[name][value].pct_of_prev = 100
145 end
146 local all = result[name]
147 local prev = all
148 for i in range(2,#names) do
149 name = names[i]
150 fancy[name] = {}
151 for value, count in pairs(result[name]) do
152 fancy[name][value] = {}
153 fancy[name][value].count = count
154 fancy[name][value].pct_of_total = percent(count,all[value])
155 fancy[name][value].pct_of_prev = percent(count,prev[value])
156 end
157 prev = result[name]
158 end
159 return fancy
160 end