[Groonga-commit] groonga/groonga at 138b6d8 [master] optimizer: support ordering terms by estimated size

Back to archive index

Kouhei Sutou null+****@clear*****
Thu Apr 7 15:28:18 JST 2016


Kouhei Sutou	2016-04-07 15:28:18 +0900 (Thu, 07 Apr 2016)

  New Revision: 138b6d85b30de6c3a8eb6a30134840443db26094
  https://github.com/groonga/groonga/commit/138b6d85b30de6c3a8eb6a30134840443db26094

  Message:
    optimizer: support ordering terms by estimated size

  Added files:
    test/mruby/suite/expression_rewriter/test_and_order.rb
  Modified files:
    lib/mrb/scripts/expression_tree/binary_operation.rb
    lib/mrb/scripts/expression_tree/logical_operation.rb
    plugins/expression_rewriters/optimizer.rb

  Modified: lib/mrb/scripts/expression_tree/binary_operation.rb (+47 -0)
===================================================================
--- lib/mrb/scripts/expression_tree/binary_operation.rb    2016-04-07 15:24:59 +0900 (897c02d)
+++ lib/mrb/scripts/expression_tree/binary_operation.rb    2016-04-07 15:28:18 +0900 (d59c65c)
@@ -15,6 +15,53 @@ module Groonga
         @right.build(expression)
         expression.append_operator(@operator, 2)
       end
+
+      RANGE_OPERATORS = [
+        Operator::LESS,
+        Operator::GREATER,
+        Operator::LESS_EQUAL,
+        Operator::GREATER_EQUAL,
+      ]
+      def estimate_size(table)
+        case @operator
+        when *RANGE_OPERATORS
+          estimate_size_range(table)
+        else
+          table.size
+        end
+      end
+
+      private
+      def estimate_size_range(table)
+        return table.size unles****@left*****_a?(Variable)
+        return table.size unles****@right*****_a?(Constant)
+
+        column =****@left*****
+        value =****@right*****
+        index_info = column.find_index(@operator)
+        return table.size if index_info.nil?
+
+        index_column = index_info.index
+        lexicon = index_column.lexicon
+        options = {}
+        case @operator
+        when Operator::LESS
+          options[:max] = value
+          options[:flags] = TableCursorFlags::LT
+        when Operator::LESS_EQUAL
+          options[:max] = value
+          options[:flags] = TableCursorFlags::LE
+        when Operator::GREATER
+          options[:min] = value
+          options[:flags] = TableCursorFlags::GT
+        when Operator::GREATER_EQUAL
+          options[:min] = value
+          options[:flags] = TableCursorFlags::GE
+        end
+        TableCursor.open(lexicon, options) do |cursor|
+          index_column.estimate_size(:lexicon_cursor => cursor)
+        end
+      end
     end
   end
 end

  Modified: lib/mrb/scripts/expression_tree/logical_operation.rb (+14 -0)
===================================================================
--- lib/mrb/scripts/expression_tree/logical_operation.rb    2016-04-07 15:24:59 +0900 (26ee7e2)
+++ lib/mrb/scripts/expression_tree/logical_operation.rb    2016-04-07 15:28:18 +0900 (e8d494f)
@@ -14,6 +14,20 @@ module Groonga
           expression.append_operator(@operator, 2) if i > 0
         end
       end
+
+      def estimate_size(table)
+        estimated_sizes =****@nodes***** do |node|
+          node.estimate_size(table)
+        end
+        case @operator
+        when Operator::AND
+          estimated_sizes.min
+        when Operator::OR
+          estimated_sizes.max
+        else
+          estimated_sizes.first
+        end
+      end
     end
   end
 end

  Modified: plugins/expression_rewriters/optimizer.rb (+14 -14)
===================================================================
--- plugins/expression_rewriters/optimizer.rb    2016-04-07 15:24:59 +0900 (ed437ba)
+++ plugins/expression_rewriters/optimizer.rb    2016-04-07 15:28:18 +0900 (a9ea003)
@@ -7,30 +7,32 @@ module Groonga
         builder = ExpressionTreeBuilder.new(@expression)
         root_node = builder.build
 
-        optimized_root_node = optimize_node(root_node)
-
         variable = @expression[0]
-        rewritten = Expression.create(context[variable.domain])
+        table = context[variable.domain]
+        optimized_root_node = optimize_node(table, root_node)
+
+        rewritten = Expression.create(table)
         optimized_root_node.build(rewritten)
         rewritten
       end
 
       private
-      def optimize_node(node)
+      def optimize_node(table, node)
         case node
         when ExpressionTree::LogicalOperation
           optimized_sub_nodes = node.nodes.collect do |sub_node|
-            optimize_node(sub_node)
+            optimize_node(table, sub_node)
           end
           case node.operator
           when Operator::AND
-            optimized_sub_nodes = optimize_and_sub_nodes(optimized_sub_nodes)
+            optimized_sub_nodes =
+              optimize_and_sub_nodes(table, optimized_sub_nodes)
           end
           ExpressionTree::LogicalOperation.new(node.operator,
                                                optimized_sub_nodes)
         when ExpressionTree::BinaryOperation
-          optimized_left = optimize_node(node.left)
-          optimized_right = optimize_node(node.right)
+          optimized_left = optimize_node(table, node.left)
+          optimized_right = optimize_node(table, node.right)
           if optimized_left.is_a?(ExpressionTree::Constant) and
               optimized_right.is_a?(ExpressionTree::Variable)
             ExpressionTree::BinaryOperation.new(node.operator,
@@ -48,7 +50,7 @@ module Groonga
         end
       end
 
-      def optimize_and_sub_nodes(sub_nodes)
+      def optimize_and_sub_nodes(table, sub_nodes)
         grouped_sub_nodes = sub_nodes.group_by do |sub_node|
           case sub_node
           when ExpressionTree::BinaryOperation
@@ -70,11 +72,9 @@ module Groonga
           optimized_nodes.concat(grouped_nodes)
         end
 
-        optimized_nodes
-        # TODO
-        # optimized_nodes.sort_by do |node|
-        #   node.estimate_size
-        # end
+        optimized_nodes.sort_by do |node|
+          node.estimate_size(table)
+        end
       end
 
       COMPARISON_OPERATORS = [

  Added: test/mruby/suite/expression_rewriter/test_and_order.rb (+70 -0) 100644
===================================================================
--- /dev/null
+++ test/mruby/suite/expression_rewriter/test_and_order.rb    2016-04-07 15:28:18 +0900 (14abd85)
@@ -0,0 +1,70 @@
+class TestAndOrder < ExpressionRewriterTestCase
+  def setup
+    Groonga::Schema.define do |schema|
+      schema.create_table("expression_rewriters",
+                          :type => :hash,
+                          :key_type => :short_text) do |table|
+        table.text("plugin_name")
+      end
+
+      schema.create_table("Logs") do |table|
+        table.time("created_at")
+        table.time("updated_at")
+      end
+
+      schema.create_table("Timestamps",
+                          :type => :patricia_trie,
+                          :key_type => :time) do |table|
+        table.index("Logs.created_at")
+        table.index("Logs.updated_at")
+      end
+    end
+
+    @rewriters = Groonga["expression_rewriters"]
+    @rewriters.add("optimizer",
+                   :plugin_name => "expression_rewriters/optimizer")
+
+    @logs = Groonga["Logs"]
+    setup_logs
+    setup_expression(@logs)
+  end
+
+  def setup_logs
+    100.times do
+      @logs.add(:created_at => "2015-10-01 00:00:00",
+                :updated_at => "2015-10-01 00:00:00")
+    end
+
+    50.times do
+      @logs.add(:created_at => "2015-10-02 00:00:00",
+                :updated_at => "2015-10-02 00:00:00")
+    end
+
+    10.times do
+      @logs.add(:created_at => "2015-10-03 00:00:00",
+                :updated_at => "2015-10-03 00:00:00")
+    end
+  end
+
+  def teardown
+    teardown_expression
+  end
+
+  def test_range
+    code =
+      "created_at <= '2015-10-01 00:00:00' && " +
+      "updated_at >= '2015-10-03 00:00:00'"
+    assert_equal(<<-DUMP, dump_rewritten_plan(code))
+[0]
+  op:         <greater_equal>
+  logical_op: <or>
+  query:      <"2015-10-03 00:00:00">
+  expr:       <0..2>
+[1]
+  op:         <less_equal>
+  logical_op: <and>
+  query:      <"2015-10-01 00:00:00">
+  expr:       <3..5>
+    DUMP
+  end
+end
-------------- next part --------------
HTML����������������������������...
Télécharger 



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