You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2014/02/05 00:06:20 UTC
[07/50] couch commit: updated refs/heads/import to c3116d7
Make _stats accept user-generated aggregates
Sometimes the user already has aggregate data that needs to be merged.
This patch supports that use case by allowing the user to emit a JSON
Object from the map phase containing 'sum', 'count', 'min', 'max', and
'sumsqr' keys. Users can freely intermix raw values and precomputed
aggregates in a single view.
BugzID: 14286
Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/0da481a2
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/0da481a2
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/0da481a2
Branch: refs/heads/import
Commit: 0da481a29fbda5dc445873d63ee330c2999a5cc3
Parents: 9ae2380
Author: Adam Kocoloski <ad...@cloudant.com>
Authored: Mon Aug 13 15:06:44 2012 -0400
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Tue Feb 4 17:03:23 2014 -0600
----------------------------------------------------------------------
src/couch_query_servers.erl | 55 +++++++++++++++++++++++++++++++++-------
1 file changed, 46 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0da481a2/src/couch_query_servers.erl
----------------------------------------------------------------------
diff --git a/src/couch_query_servers.erl b/src/couch_query_servers.erl
index 984c029..fb7f354 100644
--- a/src/couch_query_servers.erl
+++ b/src/couch_query_servers.erl
@@ -228,15 +228,24 @@ sum_terms([X|Xs], [Y|Ys]) when is_number(X), is_number(Y) ->
sum_terms(_, _) ->
throw({invalid_value, <<"builtin _sum function requires map values to be numbers or lists of numbers">>}).
-builtin_stats(reduce, []) ->
- {[]};
-builtin_stats(reduce, [[_,First]|Rest]) when is_number(First) ->
- Stats = lists:foldl(fun([_K,V], {S,C,Mi,Ma,Sq}) when is_number(V) ->
- {S+V, C+1, lists:min([Mi, V]), lists:max([Ma, V]), Sq+(V*V)};
- (_, _) ->
- throw({invalid_value,
- <<"builtin _stats function requires map values to be numbers">>})
- end, {First,1,First,First,First*First}, Rest),
+
+builtin_stats(reduce, [[_,First]|Rest]) ->
+ Acc0 = build_initial_accumulator(First),
+ Stats = lists:foldl(fun
+ ([_K,V], {S,C,Mi,Ma,Sq}) when is_number(V) ->
+ {S+V, C+1, erlang:min(Mi,V), erlang:max(Ma,V), Sq+(V*V)};
+ ([_K,{PreRed}], {S,C,Mi,Ma,Sq}) when is_list(PreRed) ->
+ {
+ S + get_number(sum, PreRed),
+ C + get_number(count, PreRed),
+ erlang:min(get_number(min, PreRed), Mi),
+ erlang:max(get_number(max, PreRed), Ma),
+ Sq + get_number(sumsqr, PreRed)
+ };
+ ([_K,V], _) ->
+ Msg = io_lib:format("non-numeric _stats input: ~w", [V]),
+ throw({invalid_value, iolist_to_binary(Msg)})
+ end, Acc0, Rest),
{Sum, Cnt, Min, Max, Sqr} = Stats,
{[{sum,Sum}, {count,Cnt}, {min,Min}, {max,Max}, {sumsqr,Sqr}]};
@@ -249,6 +258,34 @@ builtin_stats(rereduce, [[_,First]|Rest]) ->
{Sum, Cnt, Min, Max, Sqr} = Stats,
{[{sum,Sum}, {count,Cnt}, {min,Min}, {max,Max}, {sumsqr,Sqr}]}.
+build_initial_accumulator(X) when is_number(X) ->
+ {X, 1, X, X, X*X};
+build_initial_accumulator({Props}) ->
+ {
+ get_number(sum, Props),
+ get_number(count, Props),
+ get_number(min, Props),
+ get_number(max, Props),
+ get_number(sumsqr, Props)
+ };
+build_initial_accumulator(Else) ->
+ Msg = io_lib:format("non-numeric _stats input: ~w", [Else]),
+ throw({invalid_value, iolist_to_binary(Msg)}).
+
+get_number(Key, Props) ->
+ case couch_util:get_value(Key, Props) of
+ X when is_number(X) ->
+ X;
+ undefined ->
+ Msg = io_lib:format("user _stats input missing required field ~s",
+ [Key]),
+ throw({invalid_value, iolist_to_binary(Msg)});
+ Else ->
+ Msg = io_lib:format("non-numeric _stats input received for ~s: ~w",
+ [Key, Else]),
+ throw({invalid_value, iolist_to_binary(Msg)})
+ end.
+
% use the function stored in ddoc.validate_doc_update to test an update.
validate_doc_update(DDoc, EditDoc, DiskDoc, Ctx, SecObj) ->
JsonEditDoc = couch_doc:to_json_obj(EditDoc, [revs]),