[Groonga-commit] groonga/groonga at 3caff6e [master] logical_select: start to support labeled drilldowns

Back to archive index

Kouhei Sutou null+****@clear*****
Mon Jul 6 16:47:29 JST 2015


Kouhei Sutou	2015-07-06 16:47:29 +0900 (Mon, 06 Jul 2015)

  New Revision: 3caff6e4c72956297e08b976d9c6bce37c422474
  https://github.com/groonga/groonga/commit/3caff6e4c72956297e08b976d9c6bce37c422474

  Message:
    logical_select: start to support labeled drilldowns
    
    Complex labeled drilldowns may not be worked.

  Added files:
    test/command/suite/sharding/logical_select/drilldown/labeled/keys/one.expected
    test/command/suite/sharding/logical_select/drilldown/labeled/keys/one.test
  Modified files:
    plugins/sharding/logical_select.rb

  Modified: plugins/sharding/logical_select.rb (+226 -13)
===================================================================
--- plugins/sharding/logical_select.rb    2015-07-06 16:47:13 +0900 (e0c1e5e)
+++ plugins/sharding/logical_select.rb    2015-07-06 16:47:29 +0900 (b4982de)
@@ -30,12 +30,23 @@ module Groonga
           executor.execute
 
           n_results = 1
-          drilldowns = context.drilldown.result_sets
-          n_results += drilldowns.size
+          n_plain_drilldowns = context.plain_drilldown.n_result_sets
+          n_labeled_drilldowns = context.labeled_drilldowns.n_result_sets
+          if n_plain_drilldowns > 0
+            n_results += n_plain_drilldowns
+          elsif
+            if n_labeled_drilldowns > 0
+              n_results += 1
+            end
+          end
 
           writer.array("RESULT", n_results) do
             write_records(writer, context)
-            write_drilldowns(writer, context, drilldowns)
+            if n_plain_drilldowns > 0
+              write_plain_drilldowns(writer, context)
+            elsif n_labeled_drilldowns > 0
+              write_labeled_drilldowns(writer, context)
+            end
           end
         ensure
           context.close
@@ -87,12 +98,14 @@ module Groonga
         end
       end
 
-      def write_drilldowns(writer, context, drilldowns)
-        output_columns = context.drilldown.output_columns
+      def write_plain_drilldowns(writer, context)
+        plain_drilldown = context.plain_drilldown
 
+        drilldowns = plain_drilldown.result_sets
+        output_columns = plain_drilldown.output_columns
         options = {
-          :offset => context.drilldown.output_offset,
-          :limit  => context.drilldown.limit,
+          :offset => plain_drilldown.output_offset,
+          :limit  => plain_drilldown.limit,
         }
 
         drilldowns.each do |drilldown|
@@ -109,6 +122,33 @@ module Groonga
         end
       end
 
+      def write_labeled_drilldowns(writer, context)
+        labeled_drilldowns = context.labeled_drilldowns
+
+        writer.map("DRILLDOWNS", labeled_drilldowns.n_result_sets) do
+          labeled_drilldowns.each do |drilldown|
+            writer.write(drilldown.label)
+
+            result_set = drilldown.result_set
+            n_elements = 2 # for N hits and columns
+            n_elements += result_set.size
+            output_columns = drilldown.output_columns
+            options = {
+              :offset => drilldown.output_offset,
+              :limit  => drilldown.limit,
+            }
+
+            writer.array("RESULTSET", n_elements) do
+              writer.array("NHITS", 1) do
+                writer.write(result_set.size)
+              end
+              writer.write_table_columns(result_set, output_columns)
+              writer.write_table_records(result_set, output_columns, options)
+            end
+          end
+        end
+      end
+
       module KeysParsable
         private
         def parse_keys(raw_keys)
@@ -128,7 +168,8 @@ module Groonga
         attr_reader :sort_keys
         attr_reader :output_columns
         attr_reader :result_sets
-        attr_reader :drilldown
+        attr_reader :plain_drilldown
+        attr_reader :labeled_drilldowns
         def initialize(input)
           @input = input
           @enumerator = LogicalEnumerator.new("logical_select", @input)
@@ -140,7 +181,8 @@ module Groonga
 
           @result_sets = []
 
-          @drilldown = PlainDrilldownExecuteContext.new(@input)
+          @plain_drilldown = PlainDrilldownExecuteContext.new(@input)
+          @labeled_drilldowns = LabeledDrilldowns.parse(@input)
         end
 
         def close
@@ -148,7 +190,8 @@ module Groonga
             result_set.close if result_set.temporary?
           end
 
-          @drilldown.close
+          @plain_drilldown.close
+          @labeled_drilldowns.close
         end
       end
 
@@ -190,6 +233,135 @@ module Groonga
             result_set.close
           end
         end
+
+        def have_keys?
+          @keys.size > 0
+        end
+
+        def n_result_sets
+          @result_sets.size
+        end
+      end
+
+      class LabeledDrilldowns
+        class << self
+          def parse(input)
+            drilldowns = {}
+            arguments = input.arguments
+            argument = Record.new(arguments, nil)
+            arguments.each do |argument_id|
+              argument.id = argument_id
+              key = argument.key
+              match_data = /\Adrilldown\[(.+?)\]\.(.+)\z/.match(key)
+              next if match_data.nil?
+              drilldown = (drilldowns[match_data[1]] ||= {})
+              drilldown[match_data[2]] = input[key]
+            end
+
+            contexts = []
+            drilldowns.each do |label, parameters|
+              next if parameters["keys"].nil?
+              contexts << LabeledDrilldownExecuteContext.new(label, parameters)
+            end
+            return nil if contexts.nil?
+
+            new(contexts)
+          end
+        end
+
+        def initialize(contexts)
+          @contexts = contexts
+        end
+
+        def close
+          @contexts.each do |context|
+            context.close
+          end
+        end
+
+        def have_keys?
+          @contexts.size > 0
+        end
+
+        def n_result_sets
+          @contexts.size
+        end
+
+        def each(&block)
+          @contexts.each(&block)
+        end
+      end
+
+      class LabeledDrilldownExecuteContext
+        include KeysParsable
+
+        attr_reader :label
+        attr_reader :keys
+        attr_reader :offset
+        attr_reader :limit
+        attr_reader :sort_keys
+        attr_reader :output_columns
+        attr_reader :output_offset
+        attr_reader :calc_target_name
+        attr_reader :calc_types
+        attr_accessor :result_set
+        attr_accessor :unsorted_result_set
+        def initialize(label, parameters)
+          @label = label
+          @keys = parse_keys(parameters["keys"])
+          @offset = (parameters["offset"] || 0).to_i
+          @limit = (parameters["limit"] || 10).to_i
+          @sort_keys = parse_keys(parameters["sortby"])
+          @output_columns = parameters["output_columns"]
+          @output_columns ||= "_key, _nsubrecs"
+          @calc_target_name = parameters["calc_target"]
+          @calc_types = parse_calc_types(parameters["calc_types"])
+
+          if @sort_keys.empty?
+            @output_offset = @offset
+          else
+            @output_offset = 0
+          end
+
+          @result_set = nil
+          @unsorted_result_set = nil
+        end
+
+        def close
+          @result_set.close if @result_set
+          @unsorted_result_set.close if @unsored_result_set
+        end
+
+        def calc_target(table)
+          return nil if @calc_target_name.nil?
+          table.column(@calc_target_name)
+        end
+
+        private
+        def parse_calc_types(raw_types)
+          return TableGroupFlags::CALC_COUNT if raw_types.nil?
+
+          types = 0
+          raw_types.strip.split(/ *, */).each do |name|
+            case name
+            when "COUNT"
+              types |= TableGroupFlags::CALC_COUNT
+            when "MAX"
+              types |= TableGroupFlags::CALC_MAX
+            when "MIN"
+              types |= TableGroupFlags::CALC_MIN
+            when "SUM"
+              types |= TableGroupFlags::CALC_SUM
+            when "AVG"
+              types |= TableGroupFlags::CALC_AVG
+            when "NONE"
+              # Do nothing
+            else
+              raise InvalidArgument, "invalid drilldown calc type: <#{name}>"
+            end
+          end
+          types
+        end
       end
 
       class Executor
@@ -199,7 +371,11 @@ module Groonga
 
         def execute
           execute_search
-          execute_drilldown
+          if****@conte*****_drilldown.have_keys?
+            execute_plain_drilldown
+          elsif****@conte*****_drilldowns.have_keys?
+            execute_labeled_drilldowns
+          end
         end
 
         private
@@ -228,8 +404,8 @@ module Groonga
           end
         end
 
-        def execute_drilldown
-          drilldown =****@conte*****
+        def execute_plain_drilldown
+          drilldown =****@conte*****_drilldown
           group_result = TableGroupResult.new
           sort_options = {
             :offset => drilldown.offset,
@@ -258,6 +434,43 @@ module Groonga
             group_result.close
           end
         end
+
+        def execute_labeled_drilldowns
+          drilldowns =****@conte*****_drilldowns
+
+          drilldowns.each do |drilldown|
+            group_result = TableGroupResult.new
+            keys = drilldown.keys
+            sort_options = {
+              :offset => drilldown.offset,
+              :limit  => drilldown.limit,
+            }
+            begin
+              group_result.key_begin = 0
+              group_result.key_end = keys.size - 1
+              if keys.size > 1
+                group_result.max_n_sub_records = 1
+              end
+              group_result.limit = 1
+              group_result.flags = drilldown.calc_types
+              @context.result_sets.each do |result_set|
+                group_result.calc_target = drilldown.calc_target(result_set)
+                result_set.group(keys, group_result)
+              end
+              result_set = group_result.table
+              if drilldown.sort_keys.empty?
+                drilldown.result_set = result_set
+              else
+                drilldown.result_set = result_set.sort(drilldown.sort_keys,
+                                                       sort_options)
+                drilldown.unsorted_result_set = result_set
+              end
+              group_result.table = nil
+            ensure
+              group_result.close
+            end
+          end
+        end
       end
 
       class ShardExecutor

  Added: test/command/suite/sharding/logical_select/drilldown/labeled/keys/one.expected (+141 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/sharding/logical_select/drilldown/labeled/keys/one.expected    2015-07-06 16:47:29 +0900 (828d2a1)
@@ -0,0 +1,141 @@
+register sharding
+[[0,0.0,0.0],true]
+table_create Logs_20150203 TABLE_NO_KEY
+[[0,0.0,0.0],true]
+column_create Logs_20150203 timestamp COLUMN_SCALAR Time
+[[0,0.0,0.0],true]
+column_create Logs_20150203 memo COLUMN_SCALAR ShortText
+[[0,0.0,0.0],true]
+column_create Logs_20150203 action COLUMN_SCALAR ShortText
+[[0,0.0,0.0],true]
+table_create Logs_20150204 TABLE_NO_KEY
+[[0,0.0,0.0],true]
+column_create Logs_20150204 timestamp COLUMN_SCALAR Time
+[[0,0.0,0.0],true]
+column_create Logs_20150204 memo COLUMN_SCALAR ShortText
+[[0,0.0,0.0],true]
+column_create Logs_20150204 action COLUMN_SCALAR ShortText
+[[0,0.0,0.0],true]
+table_create Logs_20150205 TABLE_NO_KEY
+[[0,0.0,0.0],true]
+column_create Logs_20150205 timestamp COLUMN_SCALAR Time
+[[0,0.0,0.0],true]
+column_create Logs_20150205 memo COLUMN_SCALAR ShortText
+[[0,0.0,0.0],true]
+column_create Logs_20150205 action COLUMN_SCALAR ShortText
+[[0,0.0,0.0],true]
+load --table Logs_20150203
+[
+{
+  "timestamp": "2015-02-03 12:49:00",
+  "memo":      "2015-02-03 12:49:00",
+  "action":    "Start"
+},
+{
+  "timestamp": "2015-02-03 23:59:59",
+  "memo":      "2015-02-03 23:59:59",
+  "action":    "Shutdown"
+}
+]
+[[0,0.0,0.0],2]
+load --table Logs_20150204
+[
+{
+  "timestamp": "2015-02-04 00:00:00",
+  "memo":      "2015-02-04 00:00:00",
+  "action":    "Start"
+},
+{
+  "timestamp": "2015-02-04 13:49:00",
+  "memo":      "2015-02-04 13:49:00",
+  "action":    "Restart"
+},
+{
+  "timestamp": "2015-02-04 13:50:00",
+  "memo":      "2015-02-04 13:50:00",
+  "action":    "Restart"
+}
+]
+[[0,0.0,0.0],3]
+load --table Logs_20150205
+[
+{
+  "timestamp": "2015-02-05 13:49:00",
+  "memo":      "2015-02-05 13:49:00",
+  "action":    "Restart"
+},
+{
+  "timestamp": "2015-02-05 13:50:00",
+  "memo":      "2015-02-05 13:50:00",
+  "action":    "Restart"
+},
+{
+  "timestamp": "2015-02-05 13:51:00",
+  "memo":      "2015-02-05 13:51:00",
+  "action":    "Restart"
+},
+{
+  "timestamp": "2015-02-05 13:52:00",
+  "memo":      "2015-02-05 13:52:00",
+  "action":    "Restart"
+}
+]
+[[0,0.0,0.0],4]
+logical_select Logs timestamp   --limit 0   --drilldown[action].keys action
+[
+  [
+    0,
+    0.0,
+    0.0
+  ],
+  [
+    [
+      [
+        9
+      ],
+      [
+        [
+          "action",
+          "ShortText"
+        ],
+        [
+          "memo",
+          "ShortText"
+        ],
+        [
+          "timestamp",
+          "Time"
+        ]
+      ]
+    ],
+    {
+      "action": [
+        [
+          3
+        ],
+        [
+          [
+            "_key",
+            "ShortText"
+          ],
+          [
+            "_nsubrecs",
+            "Int32"
+          ]
+        ],
+        [
+          "Start",
+          2
+        ],
+        [
+          "Shutdown",
+          1
+        ],
+        [
+          "Restart",
+          6
+        ]
+      ]
+    }
+  ]
+]

  Added: test/command/suite/sharding/logical_select/drilldown/labeled/keys/one.test (+79 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/sharding/logical_select/drilldown/labeled/keys/one.test    2015-07-06 16:47:29 +0900 (ea68764)
@@ -0,0 +1,79 @@
+#@on-error omit
+register sharding
+#@on-error default
+
+table_create Logs_20150203 TABLE_NO_KEY
+column_create Logs_20150203 timestamp COLUMN_SCALAR Time
+column_create Logs_20150203 memo COLUMN_SCALAR ShortText
+column_create Logs_20150203 action COLUMN_SCALAR ShortText
+
+table_create Logs_20150204 TABLE_NO_KEY
+column_create Logs_20150204 timestamp COLUMN_SCALAR Time
+column_create Logs_20150204 memo COLUMN_SCALAR ShortText
+column_create Logs_20150204 action COLUMN_SCALAR ShortText
+
+table_create Logs_20150205 TABLE_NO_KEY
+column_create Logs_20150205 timestamp COLUMN_SCALAR Time
+column_create Logs_20150205 memo COLUMN_SCALAR ShortText
+column_create Logs_20150205 action COLUMN_SCALAR ShortText
+
+load --table Logs_20150203
+[
+{
+  "timestamp": "2015-02-03 12:49:00",
+  "memo":      "2015-02-03 12:49:00",
+  "action":    "Start"
+},
+{
+  "timestamp": "2015-02-03 23:59:59",
+  "memo":      "2015-02-03 23:59:59",
+  "action":    "Shutdown"
+}
+]
+
+load --table Logs_20150204
+[
+{
+  "timestamp": "2015-02-04 00:00:00",
+  "memo":      "2015-02-04 00:00:00",
+  "action":    "Start"
+},
+{
+  "timestamp": "2015-02-04 13:49:00",
+  "memo":      "2015-02-04 13:49:00",
+  "action":    "Restart"
+},
+{
+  "timestamp": "2015-02-04 13:50:00",
+  "memo":      "2015-02-04 13:50:00",
+  "action":    "Restart"
+}
+]
+
+load --table Logs_20150205
+[
+{
+  "timestamp": "2015-02-05 13:49:00",
+  "memo":      "2015-02-05 13:49:00",
+  "action":    "Restart"
+},
+{
+  "timestamp": "2015-02-05 13:50:00",
+  "memo":      "2015-02-05 13:50:00",
+  "action":    "Restart"
+},
+{
+  "timestamp": "2015-02-05 13:51:00",
+  "memo":      "2015-02-05 13:51:00",
+  "action":    "Restart"
+},
+{
+  "timestamp": "2015-02-05 13:52:00",
+  "memo":      "2015-02-05 13:52:00",
+  "action":    "Restart"
+}
+]
+
+logical_select Logs timestamp \
+  --limit 0 \
+  --drilldown[action].keys action
-------------- next part --------------
HTML����������������������������...
下载 



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