summaryrefslogtreecommitdiff
path: root/src/couch/src/couch_query_servers.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couch/src/couch_query_servers.erl')
-rw-r--r--src/couch/src/couch_query_servers.erl34
1 files changed, 29 insertions, 5 deletions
diff --git a/src/couch/src/couch_query_servers.erl b/src/couch/src/couch_query_servers.erl
index f31d24c6c..de8ef1e15 100644
--- a/src/couch/src/couch_query_servers.erl
+++ b/src/couch/src/couch_query_servers.erl
@@ -17,6 +17,7 @@
-export([reduce/3, rereduce/3,validate_doc_update/5]).
-export([filter_docs/5]).
-export([filter_view/3]).
+-export([finalize/2]).
-export([rewrite/3]).
-export([with_ddoc_proc/2, proc_prompt/2, ddoc_prompt/3, ddoc_proc_prompt/3, json_doc/1]).
@@ -86,6 +87,17 @@ group_reductions_results(List) ->
[Heads | group_reductions_results(Tails)]
end.
+finalize(<<"_approx_count_distinct",_/binary>>, Reduction) ->
+ true = hyper:is_hyper(Reduction),
+ {ok, round(hyper:card(Reduction))};
+finalize(<<"_stats",_/binary>>, {_, _, _, _, _} = Unpacked) ->
+ {ok, pack_stats(Unpacked)};
+finalize(<<"_stats",_/binary>>, {Packed}) ->
+ % Legacy code path before we had the finalize operation
+ {ok, {Packed}};
+finalize(_RedSrc, Reduction) ->
+ {ok, Reduction}.
+
rereduce(_Lang, [], _ReducedValues) ->
{ok, []};
rereduce(Lang, RedSrcs, ReducedValues) ->
@@ -171,7 +183,10 @@ builtin_reduce(rereduce, [<<"_count",_/binary>>|BuiltinReds], KVs, Acc) ->
builtin_reduce(rereduce, BuiltinReds, KVs, [Count|Acc]);
builtin_reduce(Re, [<<"_stats",_/binary>>|BuiltinReds], KVs, Acc) ->
Stats = builtin_stats(Re, KVs),
- builtin_reduce(Re, BuiltinReds, KVs, [Stats|Acc]).
+ builtin_reduce(Re, BuiltinReds, KVs, [Stats|Acc]);
+builtin_reduce(Re, [<<"_approx_count_distinct",_/binary>>|BuiltinReds], KVs, Acc) ->
+ Distinct = approx_count_distinct(Re, KVs),
+ builtin_reduce(Re, BuiltinReds, KVs, [Distinct|Acc]).
builtin_sum_rows([], Acc) ->
@@ -236,11 +251,11 @@ sum_arrays(Else, _) ->
throw_sum_error(Else).
builtin_stats(_, []) ->
- {[{sum,0}, {count,0}, {min,0}, {max,0}, {sumsqr,0}]};
+ {0, 0, 0, 0, 0};
builtin_stats(_, [[_,First]|Rest]) ->
- Unpacked = lists:foldl(fun([_Key, Value], Acc) -> stat_values(Value, Acc) end,
- build_initial_accumulator(First), Rest),
- pack_stats(Unpacked).
+ lists:foldl(fun([_Key, Value], Acc) ->
+ stat_values(Value, Acc)
+ end, build_initial_accumulator(First), Rest).
stat_values(Value, Acc) when is_list(Value), is_list(Acc) ->
lists:zipwith(fun stat_values/2, Value, Acc);
@@ -267,6 +282,8 @@ build_initial_accumulator(L) when is_list(L) ->
[build_initial_accumulator(X) || X <- L];
build_initial_accumulator(X) when is_number(X) ->
{X, 1, X, X, X*X};
+build_initial_accumulator({_, _, _, _, _} = AlreadyUnpacked) ->
+ AlreadyUnpacked;
build_initial_accumulator({Props}) ->
unpack_stats({Props});
build_initial_accumulator(Else) ->
@@ -303,6 +320,13 @@ get_number(Key, Props) ->
throw({invalid_value, iolist_to_binary(Msg)})
end.
+% TODO allow customization of precision in the ddoc.
+approx_count_distinct(reduce, KVs) ->
+ lists:foldl(fun([[Key, _Id], _Value], Filter) ->
+ hyper:insert(term_to_binary(Key), Filter)
+ end, hyper:new(11), KVs);
+approx_count_distinct(rereduce, Reds) ->
+ hyper:union([Filter || [_, Filter] <- Reds]).
% use the function stored in ddoc.validate_doc_update to test an update.
-spec validate_doc_update(DDoc, EditDoc, DiskDoc, Ctx, SecObj) -> ok when