Mercurial Hosting > luan
view 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 |
line wrap: on
line source
import "luan:Math" import "luan:Table" function of(index) local ab_testing = {} ab_testing.test_map = {} ab_testing.test_list = {} function ab_testing.test(test) test.name or error "name not defined" test.values or error "values not defined" -- test.date_field is optional local field = "ab_test_" .. test.name index.fields[field] == nil or error("test "+test.name+" already defined") index.fields[field] = field .. " index" test.field = field -- pass in map of name to aggregator factory -- returns map of name to (map of value to result) and "start_date" function test.results(aggregator_factories) return index.Searcher( function(searcher) local results = {} for name in pairs(aggregator_factories) do results[name] = {} end local date_field = test.date_field local start_date = nil for _, value in ipairs(test.values) do local aggregators = {} for name, factory in pairs(aggregator_factories) do aggregators[name] = factory() end local query = { [field] = value } searcher.search(query, function(doc) for _, aggregator in pairs(aggregators) do aggregator.aggregate(doc) end if date_field ~= nil then local date = doc[date_field] if date ~= nil and (start_date==nil or start_date > date) then start_date = date end end end) for name, aggregator in pairs(aggregators) do results[name][value] = aggregator.result end end results.start_date = start_date return results end ) end ab_testing.test_map[test.name] = test ab_testing.test_list[#ab_testing.test_list + 1] = test return test end function ab_testing.value(test_name,values) return values[test_name] or ab_testing.test_map[test_name].values[1] end -- returns map from test name to value function ab_testing.from_doc(doc) local tests = ab_testing.test_list local values = {} for _, test in ipairs(tests) do values[test.name] = doc[test.field] end return values end function ab_testing.to_doc(doc,values,tests) tests = tests or ab_testing.test_list if values == nil then for _, test in ipairs(tests) do doc[test.field] = test.values[Math.random(#test.values)] end else for _, test in ipairs(tests) do doc[test.field] = values[test.name] end end end return ab_testing end -- aggregator factories -- fn(doc) should return boolean whether doc should be counted function count(fn) return function() local aggregator = {} aggregator.result = 0 function aggregator.aggregate(doc) if fn(doc) then aggregator.result = aggregator.result + 1 end end return aggregator end end count_all = count( function() return true end ) -- fn(doc) should return number to add to result, return 0 for nothing function sum(fn) return function() local aggregator = {} aggregator.result = 0 function aggregator.aggregate(doc) aggregator.result = aggregator.result + fn(doc) end return aggregator end end local function percent(x,total) if total==0 then return 0 else return 100 * x / total end end function fancy(results,names) local fancy = {} fancy.start_date = results.start_date local name = names[1] fancy[name] = {} for value, count in pairs(result[name]) do fancy[name][value] = {} fancy[name][value].count = count fancy[name][value].pct_of_total = 100 fancy[name][value].pct_of_prev = 100 end local all = result[name] local prev = all for i in range(2,#names) do name = names[i] fancy[name] = {} for value, count in pairs(result[name]) do fancy[name][value] = {} fancy[name][value].count = count fancy[name][value].pct_of_total = percent(count,all[value]) fancy[name][value].pct_of_prev = percent(count,prev[value]) end prev = result[name] end return fancy end