@@ -36,6 +36,8 @@ object DefaultOptimizer extends Optimizer {
3636    //  SubQueries are only needed for analysis and can be removed before execution.
3737    Batch (" Remove SubQueries" FixedPoint (100 ),
3838      EliminateSubQueries ) :: 
39+     Batch (" Transform Condition" FixedPoint (100 ),
40+       TransformCondition ) :: 
3941    Batch (" Operator Reordering" FixedPoint (100 ),
4042      UnionPushdown ,
4143      CombineFilters ,
@@ -60,6 +62,80 @@ object DefaultOptimizer extends Optimizer {
6062      ConvertToLocalRelation ) ::  Nil 
6163}
6264
65+ /** 
66+  * Transform and/or Condition: 
67+  * 1. a && a  =>  a 
68+  * 2. (a || b) && (a || c)  =>  a || (b && c) 
69+  * 3. a || a  =>  a 
70+  * 4. (a && b) || (a && c)  =>  a && (b || c) 
71+  */  
72+ object  TransformCondition  extends  Rule [LogicalPlan ] with  PredicateHelper  {
73+   def  apply (plan : LogicalPlan ):  LogicalPlan  =  plan transform {
74+     case  q : LogicalPlan  =>  q transformExpressionsUp {
75+       case  and @  And (left, right) =>  (left, right) match  {
76+ 
77+         //  a && a  =>  a
78+         case  (l, r) if  l fastEquals r =>  l
79+         //  (a || b) && (a || c)  =>  a || (b && c)
80+         case  _ => 
81+           //  1. Split left and right to get the disjunctive predicates,
82+           //    i.e. lhsSet = (a, b), rhsSet = (a, c)
83+           //  2. Find the common predict between lhsSet and rhsSet, i.e. common = (a)
84+           //  3. Remove common predict from lhsSet and rhsSet, i.e. ldiff = (b), rdiff = (c)
85+           //  4. Apply the formula, get the optimized predicate: common || (ldiff && rdiff)
86+           val  lhsSet  =  splitDisjunctivePredicates(left).toSet
87+           val  rhsSet  =  splitDisjunctivePredicates(right).toSet
88+           val  common  =  lhsSet.intersect(rhsSet)
89+           if  (common.isEmpty) {
90+             //  No common factors, return the original predicate
91+             and
92+           } else  {
93+             val  ldiff  =  lhsSet.diff(common)
94+             val  rdiff  =  rhsSet.diff(common)
95+             if  (ldiff.isEmpty ||  rdiff.isEmpty) {
96+               //  (a || b || c || ...) && (a || b) => (a || b)
97+               common.reduce(Or )
98+             } else  {
99+               //  (a || b || c || ...) && (a || b || d || ...) =>
100+               //  ((c || ...) && (d || ...)) || a || b
101+               (common +  And (ldiff.reduce(Or ), rdiff.reduce(Or ))).reduce(Or )
102+             }
103+           }
104+       }  //  end of And(left, right)
105+ 
106+       case  or @  Or (left, right) =>  (left, right) match  {
107+ 
108+         case  (l, r) if  l fastEquals r =>  l
109+         //  (a && b) || (a && c)  =>  a && (b || c)
110+         case  _ => 
111+           //  1. Split left and right to get the conjunctive predicates,
112+           //    i.e.  lhsSet = (a, b), rhsSet = (a, c)
113+           //  2. Find the common predict between lhsSet and rhsSet, i.e. common = (a)
114+           //  3. Remove common predict from lhsSet and rhsSet, i.e. ldiff = (b), rdiff = (c)
115+           //  4. Apply the formula, get the optimized predicate: common && (ldiff || rdiff)
116+           val  lhsSet  =  splitConjunctivePredicates(left).toSet
117+           val  rhsSet  =  splitConjunctivePredicates(right).toSet
118+           val  common  =  lhsSet.intersect(rhsSet)
119+           if  (common.isEmpty) {
120+             //  No common factors, return the original predicate
121+             or
122+           } else  {
123+             val  ldiff  =  lhsSet.diff(common)
124+             val  rdiff  =  rhsSet.diff(common)
125+             if  (ldiff.isEmpty ||  rdiff.isEmpty) {
126+               //  (a && b) || (a && b && c && ...) => a && b
127+               common.reduce(And )
128+             } else  {
129+               //  (a && b && c && ...) || (a && b && d && ...) =>
130+               //  ((c && ...) || (d && ...)) && a && b
131+               (common +  Or (ldiff.reduce(And ), rdiff.reduce(And ))).reduce(And )
132+             }
133+           }
134+       }  //  end of Or(left, right)
135+     }
136+   }
137+ }
138+ 
63139/** 
64140  *  Pushes operations to either side of a Union. 
65141  */  
@@ -347,32 +423,7 @@ object BooleanSimplification extends Rule[LogicalPlan] with PredicateHelper {
347423        //  l && false  =>  false
348424        case  (_, Literal (false , BooleanType )) =>  Literal (false )
349425        //  a && a  =>  a
350-         case  (l, r) if  l fastEquals r =>  l
351-         //  (a || b) && (a || c)  =>  a || (b && c)
352-         case  _ => 
353-           //  1. Split left and right to get the disjunctive predicates,
354-           //    i.e. lhsSet = (a, b), rhsSet = (a, c)
355-           //  2. Find the common predict between lhsSet and rhsSet, i.e. common = (a)
356-           //  3. Remove common predict from lhsSet and rhsSet, i.e. ldiff = (b), rdiff = (c)
357-           //  4. Apply the formula, get the optimized predicate: common || (ldiff && rdiff)
358-           val  lhsSet  =  splitDisjunctivePredicates(left).toSet
359-           val  rhsSet  =  splitDisjunctivePredicates(right).toSet
360-           val  common  =  lhsSet.intersect(rhsSet)
361-           if  (common.isEmpty) {
362-             //  No common factors, return the original predicate
363-             and
364-           } else  {
365-             val  ldiff  =  lhsSet.diff(common)
366-             val  rdiff  =  rhsSet.diff(common)
367-             if  (ldiff.isEmpty ||  rdiff.isEmpty) {
368-               //  (a || b || c || ...) && (a || b) => (a || b)
369-               common.reduce(Or )
370-             } else  {
371-               //  (a || b || c || ...) && (a || b || d || ...) =>
372-               //  ((c || ...) && (d || ...)) || a || b
373-               (common +  And (ldiff.reduce(Or ), rdiff.reduce(Or ))).reduce(Or )
374-             }
375-           }
426+         case  _ =>  and
376427      }  //  end of And(left, right)
377428
378429      case  or @  Or (left, right) =>  (left, right) match  {
@@ -384,33 +435,7 @@ object BooleanSimplification extends Rule[LogicalPlan] with PredicateHelper {
384435        case  (Literal (false , BooleanType ), r) =>  r
385436        //  l || false  =>  l
386437        case  (l, Literal (false , BooleanType )) =>  l
387-         //  a || a => a
388-         case  (l, r) if  l fastEquals r =>  l
389-         //  (a && b) || (a && c)  =>  a && (b || c)
390-         case  _ => 
391-            //  1. Split left and right to get the conjunctive predicates,
392-            //    i.e.  lhsSet = (a, b), rhsSet = (a, c)
393-            //  2. Find the common predict between lhsSet and rhsSet, i.e. common = (a)
394-            //  3. Remove common predict from lhsSet and rhsSet, i.e. ldiff = (b), rdiff = (c)
395-            //  4. Apply the formula, get the optimized predicate: common && (ldiff || rdiff)
396-           val  lhsSet  =  splitConjunctivePredicates(left).toSet
397-           val  rhsSet  =  splitConjunctivePredicates(right).toSet
398-           val  common  =  lhsSet.intersect(rhsSet)
399-           if  (common.isEmpty) {
400-             //  No common factors, return the original predicate
401-             or
402-           } else  {
403-             val  ldiff  =  lhsSet.diff(common)
404-             val  rdiff  =  rhsSet.diff(common)
405-             if  (ldiff.isEmpty ||  rdiff.isEmpty) {
406-               //  (a && b) || (a && b && c && ...) => a && b
407-               common.reduce(And )
408-             } else  {
409-               //  (a && b && c && ...) || (a && b && d && ...) =>
410-               //  ((c && ...) || (d && ...)) && a && b
411-               (common +  Or (ldiff.reduce(And ), rdiff.reduce(And ))).reduce(And )
412-             }
413-           }
438+         case  _ =>  or
414439      }  //  end of Or(left, right)
415440
416441      case  not @  Not (exp) =>  exp match  {
0 commit comments