[Groonga-commit] groonga/groonga at 48193e5 [master] logical_count: support dynamic column

Back to archive index

Kouhei Sutou null+****@clear*****
Tue Nov 7 14:34:15 JST 2017


Kouhei Sutou	2017-11-07 14:34:15 +0900 (Tue, 07 Nov 2017)

  New Revision: 48193e5ad24ace1b00fa8d67c89fe2cc9e5be464
  https://github.com/groonga/groonga/commit/48193e5ad24ace1b00fa8d67c89fe2cc9e5be464

  Message:
    logical_count: support dynamic column
    
      * "initial" stage is only supported because "filtered" stage and
        "output" stage are meaningless.
    
      * Add "reason" to "use range index" log. (It should be done in
        separated commit. :p)
    
    TODO:
    
      * Document

  Added files:
    test/command/suite/sharding/logical_count/cache/columns/initial.expected
    test/command/suite/sharding/logical_count/cache/columns/initial.test
    test/command/suite/sharding/logical_count/columns/stage/initial/filter.expected
    test/command/suite/sharding/logical_count/columns/stage/initial/filter.test
  Modified files:
    plugins/sharding/logical_count.rb
    test/command/suite/sharding/logical_count/log/cover_type_all.expected
    test/command/suite/sharding/logical_count/log/range_index.expected
    test/command/suite/sharding/logical_count/log/select.expected

  Modified: plugins/sharding/logical_count.rb (+139 -106)
===================================================================
--- plugins/sharding/logical_count.rb    2017-11-07 14:33:06 +0900 (8bdd77ef7)
+++ plugins/sharding/logical_count.rb    2017-11-07 14:34:15 +0900 (de0039c20)
@@ -14,12 +14,11 @@ module Groonga
 
       def run_body(input)
         enumerator = LogicalEnumerator.new("logical_count", input)
-        filter = input[:filter]
 
+        counter = Counter.new(input, enumerator.target_range)
         total = 0
         enumerator.each do |shard, shard_range|
-          total += count_n_records(filter, shard, shard_range,
-                                   enumerator.target_range)
+          total += counter.count(shard, shard_range)
         end
         writer.write(total)
       end
@@ -34,133 +33,167 @@ module Groonga
         key << "#{input[:max]}\0"
         key << "#{input[:max_border]}\0"
         key << "#{input[:filter]}\0"
+        dynamic_columns = DynamicColumns.parse(input)
+        key << dynamic_columns.cache_key
         key
       end
 
-      def log_use_range_index(use, table_name, line, method)
-        message = "[logical_count]"
-        if use
-          message << "[range-index]"
-        else
-          message << "[select]"
+      class Counter
+        def initialize(input, target_range)
+          @logger = Context.instance.logger
+          @filter = input[:filter]
+          @dynamic_columns = DynamicColumns.parse(input)
+          @target_range = target_range
         end
-        message << " <#{table_name}>"
-        Context.instance.logger.log(Logger::Level::DEBUG,
-                                    __FILE__,
-                                    line,
-                                    method.to_s,
-                                    message)
-      end
 
-      def count_n_records(filter, shard, shard_range, target_range)
-        cover_type = target_range.cover_type(shard_range)
-        return 0 if cover_type == :none
+        def count(shard, shard_range)
+          cover_type = @target_range.cover_type(shard_range)
+          return 0 if cover_type == :none
 
-        shard_key = shard.key
-        if shard_key.nil?
-          message = "[logical_count] shard_key doesn't exist: " +
-                    "<#{shard.key_name}>"
-          raise InvalidArgument, message
-        end
-        table = shard.table
-        table_name = shard.table_name
-
-        expression_builder = RangeExpressionBuilder.new(shard_key,
-                                                        target_range)
-        expression_builder.filter = filter
-        if cover_type == :all
-          log_use_range_index(false, table_name, __LINE__, __method__)
-          if filter.nil?
-            return table.size
-          else
-            return filtered_count_n_records(table) do |expression|
-              expression_builder.build_all(expression)
+          shard_key = shard.key
+          if shard_key.nil?
+            message = "[logical_count] shard_key doesn't exist: " +
+                      "<#{shard.key_name}>"
+            raise InvalidArgument, message
+          end
+          table_name = shard.table_name
+
+          prepare_table(shard) do |table|
+            if cover_type == :all
+              log_use_range_index(false, table_name, "covered",
+                                  __LINE__, __method__)
+              if @filter
+                return filtered_count_n_records(table, shard_key, cover_type)
+              else
+                return table.size
+              end
+            end
+
+            range_index = nil
+            if @filter
+              log_use_range_index(false, table_name, "need filter",
+                                  __LINE__, __method__)
+            else
+              index_info = shard_key.find_index(Operator::LESS)
+              range_index = index_info.index if index_info
+              if range_index
+                log_use_range_index(true, table_name, "range index is available",
+                                    __LINE__, __method__)
+              else
+                log_use_range_index(false, table_name, "no range index",
+                                    __LINE__, __method__)
+              end
+            end
+
+            if range_index
+              count_n_records_in_range(range_index, cover_type)
+            else
+              filtered_count_n_records(table, shard_key, cover_type)
             end
           end
         end
 
-        range_index = nil
-        if filter.nil?
-          index_info = shard_key.find_index(Operator::LESS)
-          if index_info
-            range_index = index_info.index
+        private
+        def log_use_range_index(use, table_name, reason, line, method)
+          message = "[logical_count]"
+          if use
+            message << "[range-index]"
+          else
+            message << "[select]"
           end
+          message << " <#{table_name}>: #{reason}"
+          @logger.log(Logger::Level::DEBUG,
+                      __FILE__,
+                      line,
+                      method.to_s,
+                      message)
         end
 
-        use_range_index = (!range_index.nil?)
-        log_use_range_index(use_range_index, table_name, __LINE__, __method__)
+        def prepare_table(shard)
+          table = shard.table
+          return yield(table) if****@filte*****?
 
-        case cover_type
-        when :partial_min
-          if range_index
-            count_n_records_in_range(range_index,
-                                     target_range.min, target_range.min_border,
-                                     nil, nil)
-          else
-            filtered_count_n_records(table) do |expression|
-              expression_builder.build_partial_min(expression)
+          @dynamic_columns.each_initial do |dynamic_column|
+            if table == shard.table
+              table = table.select_all
             end
+            dynamic_column.apply(table)
           end
-        when :partial_max
-          if range_index
-            count_n_records_in_range(range_index,
-                                     nil, nil,
-                                     target_range.max, target_range.max_border)
-          else
-            filtered_count_n_records(table) do |expression|
-              expression_builder.build_partial_max(expression)
-            end
+
+          begin
+            yield(table)
+          ensure
+            table.close if table != shard.table
           end
-        when :partial_min_and_max
-          if range_index
-            count_n_records_in_range(range_index,
-                                     target_range.min, target_range.min_border,
-                                     target_range.max, target_range.max_border)
-          else
-            filtered_count_n_records(table) do |expression|
+        end
+
+        def filtered_count_n_records(table, shard_key, cover_type)
+          expression = nil
+          filtered_table = nil
+
+          expression_builder = RangeExpressionBuilder.new(shard_key,
+                                                          @target_range)
+          expression_builder.filter = @filter
+          begin
+            expression = Expression.create(table)
+            case cover_type
+            when :all
+              expression_builder.build_all(expression)
+            when :partial_min
+              expression_builder.build_partial_min(expression)
+            when :partial_max
+              expression_builder.build_partial_max(expression)
+            when :partial_min_and_max
               expression_builder.build_partial_min_and_max(expression)
             end
+            filtered_table = table.select(expression)
+            filtered_table.size
+          ensure
+            filtered_table.close if filtered_table
+            expression.close if expression
           end
         end
-      end
 
-      def filtered_count_n_records(table)
-        expression = nil
-        filtered_table = nil
-
-        begin
-          expression = Expression.create(table)
-          yield(expression)
-          filtered_table = table.select(expression)
-          filtered_table.size
-        ensure
-          filtered_table.close if filtered_table
-          expression.close if expression
-        end
-      end
+        def count_n_records_in_range(range_index, cover_type)
+          case cover_type
+          when :partial_min
+            min = @target_range.min
+            min_border = @target_range.min_border
+            max = nil
+            max_bordre = nil
+          when :partial_max
+            min = nil
+            min_bordre = nil
+            max = @target_range.max
+            max_border = @target_range.max_border
+          when :partial_min_and_max
+            min = @target_range.min
+            min_border = @target_range.min_border
+            max = @target_range.max
+            max_border = @target_range.max_border
+          end
 
-      def count_n_records_in_range(range_index,
-                                   min, min_border, max, max_border)
-        flags = TableCursorFlags::BY_KEY
-        case min_border
-        when :include
-          flags |= TableCursorFlags::GE
-        when :exclude
-          flags |= TableCursorFlags::GT
-        end
-        case max_border
-        when :include
-          flags |= TableCursorFlags::LE
-        when :exclude
-          flags |= TableCursorFlags::LT
-        end
+          flags = TableCursorFlags::BY_KEY
+          case min_border
+          when :include
+            flags |= TableCursorFlags::GE
+          when :exclude
+            flags |= TableCursorFlags::GT
+          end
+          case max_border
+          when :include
+            flags |= TableCursorFlags::LE
+          when :exclude
+            flags |= TableCursorFlags::LT
+          end
 
-        TableCursor.open(range_index.table,
-                         :min => min,
-                         :max => max,
-                         :flags => flags) do |table_cursor|
-          IndexCursor.open(table_cursor, range_index) do |index_cursor|
-            index_cursor.count
+          TableCursor.open(range_index.table,
+                           :min => min,
+                           :max => max,
+                           :flags => flags) do |table_cursor|
+            IndexCursor.open(table_cursor, range_index) do |index_cursor|
+              index_cursor.count
+            end
           end
         end
       end

  Added: test/command/suite/sharding/logical_count/cache/columns/initial.expected (+26 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/sharding/logical_count/cache/columns/initial.expected    2017-11-07 14:34:15 +0900 (482bfd226)
@@ -0,0 +1,26 @@
+plugin_register sharding
+[[0,0.0,0.0],true]
+table_create Logs_20170315 TABLE_NO_KEY
+[[0,0.0,0.0],true]
+column_create Logs_20170315 timestamp COLUMN_SCALAR Time
+[[0,0.0,0.0],true]
+column_create Logs_20170315 price COLUMN_SCALAR UInt32
+[[0,0.0,0.0],true]
+load --table Logs_20170315
+[
+{"timestamp": "2017/03/15 00:00:00", "price": 1000},
+{"timestamp": "2017/03/15 01:00:00", "price":  900},
+{"timestamp": "2017/03/15 02:00:00", "price":  300}
+]
+[[0,0.0,0.0],3]
+logical_count Logs   --shard_key timestamp   --columns[price_with_tax].stage initial   --columns[price_with_tax].type UInt32   --columns[price_with_tax].flags COLUMN_SCALAR   --columns[price_with_tax].value 'price * 1.08'   --filter 'price_with_tax > 550'
+[[0,0.0,0.0],2]
+#>logical_count --columns[price_with_tax].flags "COLUMN_SCALAR" --columns[price_with_tax].stage "initial" --columns[price_with_tax].type "UInt32" --columns[price_with_tax].value "price * 1.08" --filter "price_with_tax > 550" --logical_table "Logs" --shard_key "timestamp"
+#:000000000000000 filter(3)
+#:000000000000000 filter(2)
+#<000000000000000 rc=0
+logical_count Logs   --shard_key timestamp   --columns[price_with_tax].stage initial   --columns[price_with_tax].type UInt32   --columns[price_with_tax].flags COLUMN_SCALAR   --columns[price_with_tax].value 'price * 1.08'   --filter 'price_with_tax > 550'
+[[0,0.0,0.0],2]
+#>logical_count --columns[price_with_tax].flags "COLUMN_SCALAR" --columns[price_with_tax].stage "initial" --columns[price_with_tax].type "UInt32" --columns[price_with_tax].value "price * 1.08" --filter "price_with_tax > 550" --logical_table "Logs" --shard_key "timestamp"
+#:000000000000000 cache(0)
+#<000000000000000 rc=0

  Added: test/command/suite/sharding/logical_count/cache/columns/initial.test (+33 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/sharding/logical_count/cache/columns/initial.test    2017-11-07 14:34:15 +0900 (cfc11407b)
@@ -0,0 +1,33 @@
+#@on-error omit
+plugin_register sharding
+#@on-error default
+
+table_create Logs_20170315 TABLE_NO_KEY
+column_create Logs_20170315 timestamp COLUMN_SCALAR Time
+column_create Logs_20170315 price COLUMN_SCALAR UInt32
+
+load --table Logs_20170315
+[
+{"timestamp": "2017/03/15 00:00:00", "price": 1000},
+{"timestamp": "2017/03/15 01:00:00", "price":  900},
+{"timestamp": "2017/03/15 02:00:00", "price":  300}
+]
+
+#@sleep 1
+
+#@collect-query-log true
+logical_count Logs \
+  --shard_key timestamp \
+  --columns[price_with_tax].stage initial \
+  --columns[price_with_tax].type UInt32 \
+  --columns[price_with_tax].flags COLUMN_SCALAR \
+  --columns[price_with_tax].value 'price * 1.08' \
+  --filter 'price_with_tax > 550'
+logical_count Logs \
+  --shard_key timestamp \
+  --columns[price_with_tax].stage initial \
+  --columns[price_with_tax].type UInt32 \
+  --columns[price_with_tax].flags COLUMN_SCALAR \
+  --columns[price_with_tax].value 'price * 1.08' \
+  --filter 'price_with_tax > 550'
+#@collect-query-log false

  Added: test/command/suite/sharding/logical_count/columns/stage/initial/filter.expected (+58 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/sharding/logical_count/columns/stage/initial/filter.expected    2017-11-07 14:34:15 +0900 (636add034)
@@ -0,0 +1,58 @@
+plugin_register sharding
+[[0,0.0,0.0],true]
+table_create Logs_20170315 TABLE_NO_KEY
+[[0,0.0,0.0],true]
+column_create Logs_20170315 timestamp COLUMN_SCALAR Time
+[[0,0.0,0.0],true]
+column_create Logs_20170315 price COLUMN_SCALAR UInt32
+[[0,0.0,0.0],true]
+table_create Logs_20170316 TABLE_NO_KEY
+[[0,0.0,0.0],true]
+column_create Logs_20170316 timestamp COLUMN_SCALAR Time
+[[0,0.0,0.0],true]
+column_create Logs_20170316 price COLUMN_SCALAR UInt32
+[[0,0.0,0.0],true]
+table_create Logs_20170317 TABLE_NO_KEY
+[[0,0.0,0.0],true]
+column_create Logs_20170317 timestamp COLUMN_SCALAR Time
+[[0,0.0,0.0],true]
+column_create Logs_20170317 price COLUMN_SCALAR UInt32
+[[0,0.0,0.0],true]
+load --table Logs_20170315
+[
+{"timestamp": "2017/03/15 00:00:00", "price": 1000},
+{"timestamp": "2017/03/15 01:00:00", "price":  900},
+{"timestamp": "2017/03/15 02:00:00", "price":  300}
+]
+[[0,0.0,0.0],3]
+load --table Logs_20170316
+[
+{"timestamp": "2017/03/16 10:00:00", "price":  530},
+{"timestamp": "2017/03/16 11:00:00", "price":  520},
+{"timestamp": "2017/03/16 12:00:00", "price":  110}
+]
+[[0,0.0,0.0],3]
+load --table Logs_20170317
+[
+{"timestamp": "2017/03/17 20:00:00", "price":  800},
+{"timestamp": "2017/03/17 21:00:00", "price":  400},
+{"timestamp": "2017/03/17 22:00:00", "price":  300}
+]
+[[0,0.0,0.0],3]
+table_create Times TABLE_PAT_KEY Time
+[[0,0.0,0.0],true]
+column_create Times logs_20170315 COLUMN_INDEX Logs_20170315 timestamp
+[[0,0.0,0.0],true]
+column_create Times logs_20170316 COLUMN_INDEX Logs_20170316 timestamp
+[[0,0.0,0.0],true]
+column_create Times logs_20170317 COLUMN_INDEX Logs_20170317 timestamp
+[[0,0.0,0.0],true]
+log_level --level debug
+[[0,0.0,0.0],true]
+logical_count Logs   --shard_key timestamp   --columns[price_with_tax].stage initial   --columns[price_with_tax].type UInt32   --columns[price_with_tax].flags COLUMN_SCALAR   --columns[price_with_tax].value 'price * 1.08'   --filter 'price_with_tax > 550'
+[[0,0.0,0.0],5]
+#|d| [logical_count][select] <Logs_20170315>: covered
+#|d| [logical_count][select] <Logs_20170316>: covered
+#|d| [logical_count][select] <Logs_20170317>: covered
+log_level --level notice
+[[0,0.0,0.0],true]

  Added: test/command/suite/sharding/logical_count/columns/stage/initial/filter.test (+53 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/sharding/logical_count/columns/stage/initial/filter.test    2017-11-07 14:34:15 +0900 (bc5efed1f)
@@ -0,0 +1,53 @@
+#@on-error omit
+plugin_register sharding
+#@on-error default
+
+table_create Logs_20170315 TABLE_NO_KEY
+column_create Logs_20170315 timestamp COLUMN_SCALAR Time
+column_create Logs_20170315 price COLUMN_SCALAR UInt32
+
+table_create Logs_20170316 TABLE_NO_KEY
+column_create Logs_20170316 timestamp COLUMN_SCALAR Time
+column_create Logs_20170316 price COLUMN_SCALAR UInt32
+
+table_create Logs_20170317 TABLE_NO_KEY
+column_create Logs_20170317 timestamp COLUMN_SCALAR Time
+column_create Logs_20170317 price COLUMN_SCALAR UInt32
+
+load --table Logs_20170315
+[
+{"timestamp": "2017/03/15 00:00:00", "price": 1000},
+{"timestamp": "2017/03/15 01:00:00", "price":  900},
+{"timestamp": "2017/03/15 02:00:00", "price":  300}
+]
+
+load --table Logs_20170316
+[
+{"timestamp": "2017/03/16 10:00:00", "price":  530},
+{"timestamp": "2017/03/16 11:00:00", "price":  520},
+{"timestamp": "2017/03/16 12:00:00", "price":  110}
+]
+
+load --table Logs_20170317
+[
+{"timestamp": "2017/03/17 20:00:00", "price":  800},
+{"timestamp": "2017/03/17 21:00:00", "price":  400},
+{"timestamp": "2017/03/17 22:00:00", "price":  300}
+]
+
+table_create Times TABLE_PAT_KEY Time
+column_create Times logs_20170315 COLUMN_INDEX Logs_20170315 timestamp
+column_create Times logs_20170316 COLUMN_INDEX Logs_20170316 timestamp
+column_create Times logs_20170317 COLUMN_INDEX Logs_20170317 timestamp
+
+#@add-important-log-levels debug
+log_level --level debug
+logical_count Logs \
+  --shard_key timestamp \
+  --columns[price_with_tax].stage initial \
+  --columns[price_with_tax].type UInt32 \
+  --columns[price_with_tax].flags COLUMN_SCALAR \
+  --columns[price_with_tax].value 'price * 1.08' \
+  --filter 'price_with_tax > 550'
+log_level --level notice
+#@remove-important-log-levels debug

  Modified: test/command/suite/sharding/logical_count/log/cover_type_all.expected (+1 -1)
===================================================================
--- test/command/suite/sharding/logical_count/log/cover_type_all.expected    2017-11-07 14:33:06 +0900 (ec5dab88e)
+++ test/command/suite/sharding/logical_count/log/cover_type_all.expected    2017-11-07 14:34:15 +0900 (cbd126a23)
@@ -12,6 +12,6 @@ log_level --level debug
 [[0,0.0,0.0],true]
 logical_count Logs timestamp
 [[0,0.0,0.0],0]
-#|d| [logical_count][select] <Logs_20150709>
+#|d| [logical_count][select] <Logs_20150709>: covered
 log_level --level notice
 [[0,0.0,0.0],true]

  Modified: test/command/suite/sharding/logical_count/log/range_index.expected (+1 -1)
===================================================================
--- test/command/suite/sharding/logical_count/log/range_index.expected    2017-11-07 14:33:06 +0900 (2ba1c1e51)
+++ test/command/suite/sharding/logical_count/log/range_index.expected    2017-11-07 14:34:15 +0900 (1cefdda52)
@@ -12,6 +12,6 @@ log_level --level debug
 [[0,0.0,0.0],true]
 logical_count Logs timestamp   --min "2015/07/09 00:00:00"   --max "2015/07/09 12:00:00"
 [[0,0.0,0.0],0]
-#|d| [logical_count][range-index] <Logs_20150709>
+#|d| [logical_count][range-index] <Logs_20150709>: range index is available
 log_level --level notice
 [[0,0.0,0.0],true]

  Modified: test/command/suite/sharding/logical_count/log/select.expected (+1 -1)
===================================================================
--- test/command/suite/sharding/logical_count/log/select.expected    2017-11-07 14:33:06 +0900 (737d2f07b)
+++ test/command/suite/sharding/logical_count/log/select.expected    2017-11-07 14:34:15 +0900 (fa5d02a76)
@@ -8,6 +8,6 @@ log_level --level debug
 [[0,0.0,0.0],true]
 logical_count Logs timestamp   --min "2015/07/09 00:00:00"   --max "2015/07/09 12:00:00"
 [[0,0.0,0.0],0]
-#|d| [logical_count][select] <Logs_20150709>
+#|d| [logical_count][select] <Logs_20150709>: no range index
 log_level --level notice
 [[0,0.0,0.0],true]
-------------- next part --------------
HTML����������������������������...
URL: https://lists.osdn.me/mailman/archives/groonga-commit/attachments/20171107/0ed1bdef/attachment-0001.htm 



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