@@ -302,89 +302,100 @@ object OptimizeIn extends Rule[LogicalPlan] {
302
302
object BooleanSimplification extends Rule [LogicalPlan ] with PredicateHelper {
303
303
def apply (plan : LogicalPlan ): LogicalPlan = plan transform {
304
304
case q : LogicalPlan => q transformExpressionsUp {
305
- case and @ And (left, right) =>
306
- (left, right) match {
307
- case (Literal (true , BooleanType ), r) => r
308
- case (l, Literal (true , BooleanType )) => l
309
- case (Literal (false , BooleanType ), _) => Literal (false )
310
- case (_, Literal (false , BooleanType )) => Literal (false )
311
- // a && a => a
312
- case (l, r) if l fastEquals r => l
313
- case (_, _) =>
314
- /* Do optimize for predicates using formula (a || b) && (a || c) => a || (b && c)
315
- * 1. Split left and right to get the disjunctive predicates,
316
- * i.e. lhsSet = (a, b), rhsSet = (a, c)
317
- * 2. Find the common predict between lhsSet and rhsSet, i.e. common = (a)
318
- * 3. Remove common predict from lhsSet and rhsSet, i.e. ldiff = (b), rdiff = (c)
319
- * 4. Apply the formula, get the optimized predict: common || (ldiff && rdiff)
320
- */
321
- val lhsSet = splitDisjunctivePredicates(left).toSet
322
- val rhsSet = splitDisjunctivePredicates(right).toSet
323
- val common = lhsSet.intersect(rhsSet)
324
- val ldiff = lhsSet.diff(common)
325
- val rdiff = rhsSet.diff(common)
326
- if (ldiff.size == 0 || rdiff.size == 0 ) {
327
- // a && (a || b) => a
328
- common.reduce(Or )
329
- } else {
330
- // (a || b || c || ...) && (a || b || d || ...) && (a || b || e || ...) ... =>
331
- // (a || b) || ((c || ...) && (f || ...) && (e || ...) && ...)
332
- (ldiff.reduceOption(Or ) ++ rdiff.reduceOption(Or ))
333
- .reduceOption(And )
334
- .map(_ :: common.toList)
335
- .getOrElse(common.toList)
336
- .reduce(Or )
337
- }
338
- }
339
-
340
- case or @ Or (left, right) =>
341
- (left, right) match {
342
- case (Literal (true , BooleanType ), _) => Literal (true )
343
- case (_, Literal (true , BooleanType )) => Literal (true )
344
- case (Literal (false , BooleanType ), r) => r
345
- case (l, Literal (false , BooleanType )) => l
346
- // a || a => a
347
- case (l, r) if l fastEquals r => l
348
- case (_, _) =>
349
- /* Do optimize for predicates using formula (a && b) || (a && c) => a && (b || c)
350
- * 1. Split left and right to get the conjunctive predicates,
351
- * i.e. lhsSet = (a, b), rhsSet = (a, c)
352
- * 2. Find the common predict between lhsSet and rhsSet, i.e. common = (a)
353
- * 3. Remove common predict from lhsSet and rhsSet, i.e. ldiff = (b), rdiff = (c)
354
- * 4. Apply the formula, get the optimized predict: common && (ldiff || rdiff)
355
- */
356
- val lhsSet = splitConjunctivePredicates(left).toSet
357
- val rhsSet = splitConjunctivePredicates(right).toSet
358
- val common = lhsSet.intersect(rhsSet)
359
- val ldiff = lhsSet.diff(common)
360
- val rdiff = rhsSet.diff(common)
361
- if ( ldiff.size == 0 || rdiff.size == 0 ) {
362
- // a || (b && a) => a
363
- common.reduce(And )
364
- } else {
365
- // (a && b && c && ...) || (a && b && d && ...) || (a && b && e && ...) ... =>
366
- // a && b && ((c && ...) || (d && ...) || (e && ...) || ...)
367
- (ldiff.reduceOption(And ) ++ rdiff.reduceOption(And ))
368
- .reduceOption(Or )
369
- .map(_ :: common.toList)
370
- .getOrElse(common.toList)
371
- .reduce(And )
372
- }
373
- }
374
-
375
- case not @ Not (exp) =>
376
- exp match {
377
- case Literal (true , BooleanType ) => Literal (false )
378
- case Literal (false , BooleanType ) => Literal (true )
379
- case GreaterThan (l, r) => LessThanOrEqual (l, r)
380
- case GreaterThanOrEqual (l, r) => LessThan (l, r)
381
- case LessThan (l, r) => GreaterThanOrEqual (l, r)
382
- case LessThanOrEqual (l, r) => GreaterThan (l, r)
383
- case Not (e) => e
384
- case _ => not
385
- }
386
-
387
- // Turn "if (true) a else b" into "a", and if (false) a else b" into "b".
305
+ case and @ And (left, right) => (left, right) match {
306
+ // true && r => r
307
+ case (Literal (true , BooleanType ), r) => r
308
+ // l && true => l
309
+ case (l, Literal (true , BooleanType )) => l
310
+ // false && r => false
311
+ case (Literal (false , BooleanType ), _) => Literal (false )
312
+ // l && false => false
313
+ case (_, Literal (false , BooleanType )) => Literal (false )
314
+ // a && a => a
315
+ case (l, r) if l fastEquals r => l
316
+ // (a || b) && (a || c) => a || (b && c)
317
+ case (_, _) =>
318
+ // 1. Split left and right to get the disjunctive predicates,
319
+ // i.e. lhsSet = (a, b), rhsSet = (a, c)
320
+ // 2. Find the common predict between lhsSet and rhsSet, i.e. common = (a)
321
+ // 3. Remove common predict from lhsSet and rhsSet, i.e. ldiff = (b), rdiff = (c)
322
+ // 4. Apply the formula, get the optimized predicate: common || (ldiff && rdiff)
323
+ val lhsSet = splitDisjunctivePredicates(left).toSet
324
+ val rhsSet = splitDisjunctivePredicates(right).toSet
325
+ val common = lhsSet.intersect(rhsSet)
326
+ val ldiff = lhsSet.diff(common)
327
+ val rdiff = rhsSet.diff(common)
328
+ if (ldiff.size == 0 || rdiff.size == 0 ) {
329
+ // a && (a || b) => a
330
+ common.reduce(Or )
331
+ } else {
332
+ // (a || b || c || ...) && (a || b || d || ...) && (a || b || e || ...) ... =>
333
+ // (a || b) || ((c || ...) && (f || ...) && (e || ...) && ...)
334
+ (ldiff.reduceOption(Or ) ++ rdiff.reduceOption(Or ))
335
+ .reduceOption(And )
336
+ .map(_ :: common.toList)
337
+ .getOrElse(common.toList)
338
+ .reduce(Or )
339
+ }
340
+ } // end of And(left, right)
341
+
342
+ case or @ Or (left, right) => (left, right) match {
343
+ // true || r => true
344
+ case (Literal (true , BooleanType ), _) => Literal (true )
345
+ // r || true => true
346
+ case (_, Literal (true , BooleanType )) => Literal (true )
347
+ // false || r => r
348
+ case (Literal (false , BooleanType ), r) => r
349
+ // l || false => l
350
+ case (l, Literal (false , BooleanType )) => l
351
+ // a || a => a
352
+ case (l, r) if l fastEquals r => l
353
+ // (a && b) || (a && c) => a && (b || c)
354
+ case (_, _) =>
355
+ // 1. Split left and right to get the conjunctive predicates,
356
+ // i.e. lhsSet = (a, b), rhsSet = (a, c)
357
+ // 2. Find the common predict between lhsSet and rhsSet, i.e. common = (a)
358
+ // 3. Remove common predict from lhsSet and rhsSet, i.e. ldiff = (b), rdiff = (c)
359
+ // 4. Apply the formula, get the optimized predicate: common && (ldiff || rdiff)
360
+ val lhsSet = splitConjunctivePredicates(left).toSet
361
+ val rhsSet = splitConjunctivePredicates(right).toSet
362
+ val common = lhsSet.intersect(rhsSet)
363
+ val ldiff = lhsSet.diff(common)
364
+ val rdiff = rhsSet.diff(common)
365
+ if ( ldiff.size == 0 || rdiff.size == 0 ) {
366
+ // a || (b && a) => a
367
+ common.reduce(And )
368
+ } else {
369
+ // (a && b && c && ...) || (a && b && d && ...) || (a && b && e && ...) ... =>
370
+ // a && b && ((c && ...) || (d && ...) || (e && ...) || ...)
371
+ (ldiff.reduceOption(And ) ++ rdiff.reduceOption(And ))
372
+ .reduceOption(Or )
373
+ .map(_ :: common.toList)
374
+ .getOrElse(common.toList)
375
+ .reduce(And )
376
+ }
377
+ } // end of Or(left, right)
378
+
379
+ case not @ Not (exp) => exp match {
380
+ // not(true) => false
381
+ case Literal (true , BooleanType ) => Literal (false )
382
+ // not(false) => true
383
+ case Literal (false , BooleanType ) => Literal (true )
384
+ // not(l > r) => l <= r
385
+ case GreaterThan (l, r) => LessThanOrEqual (l, r)
386
+ // not(l >= r) => l < r
387
+ case GreaterThanOrEqual (l, r) => LessThan (l, r)
388
+ // not(l < r) => l >= r
389
+ case LessThan (l, r) => GreaterThanOrEqual (l, r)
390
+ // not(l <= r) => l > r
391
+ case LessThanOrEqual (l, r) => GreaterThan (l, r)
392
+ // not(not(e)) => e
393
+ case Not (e) => e
394
+ case _ => not
395
+ } // end of Not(exp)
396
+
397
+ // if (true) a else b => a
398
+ // if (false) a else b => b
388
399
case e @ If (Literal (v, _), trueValue, falseValue) => if (v == true ) trueValue else falseValue
389
400
}
390
401
}
0 commit comments