[Groonga-commit] ranguba/rroonga at 16833f3 [master] Support calculation for drilldown

Back to archive index

Masafumi Yokoyama null+****@clear*****
Sat Feb 14 01:18:52 JST 2015


Masafumi Yokoyama	2015-02-14 01:18:52 +0900 (Sat, 14 Feb 2015)

  New Revision: 16833f3f42c9d970dc4a9fbceeb10f34761cfac6
  https://github.com/ranguba/rroonga/commit/16833f3f42c9d970dc4a9fbceeb10f34761cfac6

  Message:
    Support calculation for drilldown
    
    calc_target and calc_types are supported since Groonga 4.1.1.
    
    GitHub: fix #43

  Modified files:
    ext/groonga/rb-grn-table.c
    lib/groonga/record.rb
    test/test-table-group.rb

  Modified: ext/groonga/rb-grn-table.c (+43 -0)
===================================================================
--- ext/groonga/rb-grn-table.c    2015-02-13 21:19:38 +0900 (f3b3fd8)
+++ ext/groonga/rb-grn-table.c    2015-02-14 01:18:52 +0900 (2bb34bb)
@@ -1338,6 +1338,16 @@ rb_grn_table_sort (int argc, VALUE *argv, VALUE self)
  *     @option options :max_n_sub_records
  *       グループ化した後のレコードのそれぞれについて最大 _:max_n_sub_records_ 件まで
  *       そのグループに含まれる _table_ のレコードをサブレコードとして格納する。
+ *     @option options [String or Symbol] :calc_target
+ *       The target column name for _:calc_types_.
+ *     @option options [::Array] :calc_types
+ *       It specifies how to calculate (aggregate) values in grouped records by
+ *       a drilldown. You can specify multiple calculation types.
+ *
+ *       - +:max+ := Finding the maximum integer value from integer values in grouped records.
+ *       - +:min+ := Finding the minimum integer value from integer values in grouped records.
+ *       - +:sum+ := Summing integer values in grouped records.
+ *       - +:average+ := Averaging integer/float values in grouped records.
  *
  *   @!macro table.group.options
  *
@@ -1357,6 +1367,7 @@ rb_grn_table_group (int argc, VALUE *argv, VALUE self)
     unsigned int max_n_sub_records = 0;
     grn_rc rc;
     VALUE rb_keys, rb_options, rb_max_n_sub_records;
+    VALUE rb_calc_target, rb_calc_types;
     VALUE *rb_group_keys;
 
     rb_grn_table_deconstruct(SELF(self), &table, &context,
@@ -1376,6 +1387,8 @@ rb_grn_table_group (int argc, VALUE *argv, VALUE self)
 
     rb_grn_scan_options(rb_options,
                         "max_n_sub_records", &rb_max_n_sub_records,
+                        "calc_target", &rb_calc_target,
+                        "calc_types", &rb_calc_types,
                         NULL);
 
     if (NIL_P(rb_max_n_sub_records)) {
@@ -1427,6 +1440,36 @@ rb_grn_table_group (int argc, VALUE *argv, VALUE self)
     result.max_n_subrecs = max_n_sub_records;
     result.calc_target = NULL;
 
+    if (!NIL_P(rb_calc_target)) {
+        const char *name = NULL;
+        unsigned name_size = 0;
+        ruby_object_to_column_name(rb_calc_target, &name, &name_size);
+        result.calc_target = grn_obj_column(context, table, name, name_size);
+    }
+    if (result.calc_target) {
+        int i, n_calc_types;
+        VALUE *raw_calc_types;
+        raw_calc_types = RARRAY_PTR(rb_calc_types);
+        n_calc_types = RARRAY_LEN(rb_calc_types);
+        for (i = 0; i < n_calc_types; i++) {
+            VALUE rb_calc_type = raw_calc_types[i];
+            if (rb_grn_equal_option(rb_calc_type, "max")) {
+                result.flags |= GRN_TABLE_GROUP_CALC_MAX;
+            } else if (rb_grn_equal_option(rb_calc_type, "min")) {
+                result.flags |= GRN_TABLE_GROUP_CALC_MIN;
+            } else if (rb_grn_equal_option(rb_calc_type, "sum")) {
+                result.flags |= GRN_TABLE_GROUP_CALC_SUM;
+            } else if (rb_grn_equal_option(rb_calc_type, "average")) {
+                result.flags |= GRN_TABLE_GROUP_CALC_AVG;
+            } else {
+                rb_raise(rb_eArgError,
+                         "invalid calculation type: %s: "
+                         "available types: [:max, :min, :sum, :average]",
+                         rb_grn_inspect(rb_calc_type));
+            }
+        }
+    }
+
     rc = grn_table_group(context, table, keys, n_keys, &result, 1);
     rb_grn_context_check(context, self);
     rb_grn_rc_check(rc, self);

  Modified: lib/groonga/record.rb (+45 -1)
===================================================================
--- lib/groonga/record.rb    2015-02-13 21:19:38 +0900 (631d4df)
+++ lib/groonga/record.rb    2015-02-14 01:18:52 +0900 (f14402b)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2014  Masafumi Yokoyama <myokoym �� gmail.com>
+# Copyright (C) 2014-2015  Masafumi Yokoyama <yokoyama �� clear-code.com>
 # Copyright (C) 2009-2014  Kouhei Sutou <kou �� clear-code.com>
 #
 # This library is free software; you can redistribute it and/or
@@ -226,6 +226,50 @@ module Groonga
       @table.support_sub_records?
     end
 
+    # The maximum integer value from integer values in grouped records.
+    # It can be used when specifying _:calc_target_ and _:calc_types_
+    # to {Groonga::Table#group}.
+    #
+    # @return [Integer] The maximum integer value from integer values in grouped records.
+    #
+    # @since 5.0.0
+    def max
+      self["_max"]
+    end
+
+    # The minimum integer value from integer values in grouped records.
+    # It can be used when specifying _:calc_target_ and _:calc_types_
+    # to {Groonga::Table#group}.
+    #
+    # @return [Integer] The minimum integer value from integer values in grouped records.
+    #
+    # @since 5.0.0
+    def min
+      self["_min"]
+    end
+
+    # The sum of integer values in grouped records.
+    # It can be used when specifying _:calc_target_ and _:calc_types_
+    # to {Groonga::Table#group}.
+    #
+    # @return [Integer] The sum of integer values in grouped records.
+    #
+    # @since 5.0.0
+    def sum
+      self["_sum"]
+    end
+
+    # The average of integer/float values in grouped records.
+    # It can be used when specifying _:calc_target_ and _:calc_types_
+    # to {Groonga::Table#group}.
+    #
+    # @return [Float] The average of integer/float values in grouped records.
+    #
+    # @since 5.0.0
+    def average
+      self["_avg"]
+    end
+
     # レコードの値を返す。
     def value
       @table.value(@id, :id => true)

  Modified: test/test-table-group.rb (+99 -0)
===================================================================
--- test/test-table-group.rb    2015-02-13 21:19:38 +0900 (bf09ace)
+++ test/test-table-group.rb    2015-02-14 01:18:52 +0900 (cd58a22)
@@ -250,4 +250,103 @@ class TableGroupTest < Test::Unit::TestCase
                    grouped_records)
     end
   end
+
+  class CalculationTest < self
+    setup
+    def setup_schema
+      Groonga::Schema.define do |schema|
+        schema.create_table("Tags", :type => :hash)
+
+        schema.create_table("Memos", :type => :hash) do |table|
+          table.reference("tag")
+          table.int64("priority")
+        end
+      end
+    end
+
+    setup
+    def setup_data
+      setup_tags
+      setup_memos
+    end
+
+    def setup_tags
+      @tags = Groonga["Tags"]
+      @groonga =****@tags*****("Groonga")
+      @mroonga =****@tags*****("Mroonga")
+      @rroonga =****@tags*****("Rroonga")
+    end
+
+    def setup_memos
+      @memos = Groonga["Memos"]
+      @memos.add("Groonga1",
+                 :tag => @groonga,
+                 :priority => 10)
+      @memos.add("Groonga2",
+                 :tag => @groonga,
+                 :priority => 20)
+      @memos.add("Groonga3",
+                 :tag => @groonga,
+                 :priority => 40)
+      @memos.add("Mroonga1",
+                 :tag => @mroonga,
+                 :priority => 50)
+      @memos.add("Mroonga2",
+                 :tag => @mroonga,
+                 :priority => 25)
+      @memos.add("Mroonga3",
+                 :tag => @mroonga,
+                 :priority => 10)
+      @memos.add("Rroonga1",
+                 :tag => @rroonga,
+                 :priority => 25)
+      @memos.add("Rroonga2",
+                 :tag => @rroonga,
+                 :priority => -25)
+      @memos.add("Rroonga3",
+                 :tag => @rroonga,
+                 :priority => 0)
+    end
+
+    def test_max
+      grouped_records =****@memos*****("tag",
+                                     :calc_target => "priority",
+                                     :calc_types => [:max]).collect do |group|
+        tag = group.key
+        [
+          tag.key,
+          group.max,
+        ]
+      end
+
+      assert_equal([
+                     ["Groonga", 40],
+                     ["Mroonga", 50],
+                     ["Rroonga", 25],
+                   ],
+                   grouped_records)
+    end
+
+    def test_all_types
+      grouped_records =****@memos*****("tag",
+                                     :calc_target => "priority",
+                                     :calc_types => [:max, :min, :sum, :average]).collect do |group|
+        tag = group.key
+        [
+          tag.key,
+          group.max,
+          group.min,
+          group.sum,
+          group.average.round(3),
+        ]
+      end
+
+      assert_equal([
+                     ["Groonga", 40, 10, 70, 23.333],
+                     ["Mroonga", 50, 10, 85, 28.333],
+                     ["Rroonga", 25, -25, 0, 0.0],
+                   ],
+                   grouped_records)
+    end
+  end
 end
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index