Wail Alkowaileet has uploaded a new change for review.

  https://asterix-gerrit.ics.uci.edu/2322

Change subject: [ASTERIXDB-2233][COMP] Factor out common conjunct from disjunct
......................................................................

[ASTERIXDB-2233][COMP] Factor out common conjunct from disjunct

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
- Add a rule to factor out common conjunct from disjunct.
- Additional needed rules:
-- Remove redundant boolean expression
   e.g and(a, a)
-- Inline same boolean expressions
   e.g and(a, and(b, c))

Change-Id: I97fe7d94276f9206c076ca94814b2fa794107859
---
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q19_discounted_revenue.sqlpp
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/tpch/q19_discounted_revenue.plan
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.1.ddl.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.2.update.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.3.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.1.ddl.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.2.update.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.3.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.1.ddl.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.2.update.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.3.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.1.ddl.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.2.update.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.3.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/factor-common-conjunct/factor-common-conjunct.1.adm
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/minimum-disjunct/minimum-disjunct.1.adm
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/redundant-conjunct-expression/redundant-conjunct-expression.1.adm
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/redundant-disjunct-expression/redundant-disjunct-expression.1.adm
M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
A 
hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/AbstractConditionExpressionRewriteRule.java
A 
hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/FactorCommonConjunctionFromDisjunctionRule.java
A 
hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineAndRemoveRedundantBooleanExpressionsRule.java
23 files changed, 948 insertions(+), 0 deletions(-)


  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/22/2322/1

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
index bd67ed4..6fa746b 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
@@ -97,8 +97,10 @@
 import org.apache.hyracks.algebricks.rewriter.rules.ExtractCommonOperatorsRule;
 import org.apache.hyracks.algebricks.rewriter.rules.ExtractGbyExpressionsRule;
 import 
org.apache.hyracks.algebricks.rewriter.rules.ExtractGroupByDecorVariablesRule;
+import 
org.apache.hyracks.algebricks.rewriter.rules.FactorCommonConjunctionFromDisjunctionRule;
 import 
org.apache.hyracks.algebricks.rewriter.rules.FactorRedundantGroupAndDecorVarsRule;
 import org.apache.hyracks.algebricks.rewriter.rules.InferTypesRule;
+import 
org.apache.hyracks.algebricks.rewriter.rules.InlineAndRemoveRedundantBooleanExpressionsRule;
 import 
org.apache.hyracks.algebricks.rewriter.rules.InlineAssignIntoAggregateRule;
 import 
org.apache.hyracks.algebricks.rewriter.rules.InlineSingleReferenceVariablesRule;
 import 
org.apache.hyracks.algebricks.rewriter.rules.InsertProjectBeforeUnionRule;
@@ -233,6 +235,8 @@
         // The following rule should be fired after 
PushAggregateIntoNestedSubplanRule because
         // pulling invariants out of a subplan will make 
PushAggregateIntoGroupby harder.
         condPushDownAndJoinInference.add(new 
AsterixMoveFreeVariableOperatorOutOfSubplanRule());
+        condPushDownAndJoinInference.add(new 
InlineAndRemoveRedundantBooleanExpressionsRule());
+        condPushDownAndJoinInference.add(new 
FactorCommonConjunctionFromDisjunctionRule());
 
         return condPushDownAndJoinInference;
     }
@@ -306,6 +310,7 @@
         planCleanupRules.add(new RemoveCartesianProductWithEmptyBranchRule());
         planCleanupRules.add(new InjectTypeCastForSwitchCaseRule());
         planCleanupRules.add(new InjectTypeCastForUnionRule());
+        planCleanupRules.add(new 
InlineAndRemoveRedundantBooleanExpressionsRule());
 
         // Needs to invoke ByNameToByIndexFieldAccessRule as the last logical 
optimization rule because
         // some rules can push a FieldAccessByName to a place where the name 
it tries to access is in the closed part.
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q19_discounted_revenue.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q19_discounted_revenue.sqlpp
new file mode 100644
index 0000000..9cb9951
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q19_discounted_revenue.sqlpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+drop dataverse tpch if exists;
+create dataverse tpch;
+use tpch;
+
+create type LineItemType as {
+  l_orderkey: int64,
+  l_partkey: int64,
+  l_suppkey: int64,
+  l_linenumber: int32,
+  l_quantity: int32,
+  l_extendedprice: double,
+  l_discount: double,
+  l_tax: double,
+  l_returnflag: string,
+  l_linestatus: string,
+  l_shipdate: string,
+  l_commitdate: string,
+  l_receiptdate: string,
+  l_shipinstruct: string,
+  l_shipmode: string,
+  l_comment: string
+};
+
+create type OrderType as {
+  o_orderkey: int64,
+  o_custkey: int64,
+  o_orderstatus: string,
+  o_totalprice: double,
+  o_orderdate: string,
+  o_orderpriority: string,
+  o_clerk: string,
+  o_shippriority: int32,
+  o_comment: string
+};
+
+create type CustomerType as {
+  c_custkey: int64,
+  c_name: string,
+  c_address: string,
+  c_nationkey: int32,
+  c_phone: string,
+  c_acctbal: double,
+  c_mktsegment: string,
+  c_comment: string
+};
+
+create type PartType as {
+  p_partkey: int64, 
+  p_name: string,
+  p_mfgr: string,
+  p_brand: string,
+  p_type: string,
+  p_size: int32,
+  p_container: string,
+  p_retailprice: double,
+  p_comment: string
+};
+
+create type PartSuppType as {
+  ps_partkey: int64,
+  ps_suppkey: int64,
+  ps_availqty: int32,
+  ps_supplycost: double,
+  ps_comment: string
+};
+
+create type SupplierType as {
+  s_suppkey: int64,
+  s_name: string,
+  s_address: string,
+  s_nationkey: int32,
+  s_phone: string,
+  s_acctbal: double,
+  s_comment: string
+};
+
+create type NationType as {
+  n_nationkey: int32,
+  n_name: string,
+  n_regionkey: int32,
+  n_comment: string
+};
+
+create type RegionType as {
+  r_regionkey: int32,
+  r_name: string,
+  r_comment: string
+};
+
+create dataset LineItem(LineItemType) primary key l_orderkey, l_linenumber;
+create dataset Orders(OrderType)      primary key o_orderkey;
+create dataset Customer(CustomerType) primary key c_custkey;
+create dataset Part(PartType)         primary key p_partkey;
+create dataset Partsupp(PartSuppType) primary key ps_partkey, ps_suppkey;
+create dataset Supplier(SupplierType) primary key s_suppkey;
+create dataset Region(RegionType)     primary key r_regionkey;
+create dataset Nation(NationType)     primary key n_nationkey;
+
+SELECT VALUE SUM(l.l_extendedprice * (1 - l.l_discount))
+FROM LineItem l
+JOIN Part p
+ON p.p_partkey = l.l_partkey
+  WHERE
+  (
+    p.p_brand = 'Brand#12'
+    AND regexp_contains(p.p_container, 'SM CASE|SM BOX|SM PACK|SM PKG')
+    AND l.l_quantity >= 1 and l.l_quantity <= 11
+    AND p.p_size >= 1 and p.p_size <= 5
+    AND (l.l_shipmode = 'AIR' or l.l_shipmode = 'AIR REG')
+    AND l.l_shipinstruct = 'DELIVER IN PERSON'
+  )
+  OR
+  (
+    p.p_brand = 'Brand#23'
+    AND regexp_contains(p.p_container, 'MED BAG|MED BOX|MED PKG|MED PACK')
+    AND l.l_quantity >= 10 and l.l_quantity <= 20
+    AND p.p_size >= 1 and p.p_size <= 10
+    AND (l.l_shipmode = 'AIR' or l.l_shipmode = 'AIR REG')
+    AND l.l_shipinstruct = 'DELIVER IN PERSON'
+  )
+  OR
+  (
+    p.p_brand = 'Brand#34'
+    AND regexp_contains(p.p_container, 'LG CASE|LG BOX|LG PACK|LG PKG')
+    AND l.l_quantity >= 20 and l.l_quantity <= 30
+    AND p.p_size >= 1 and p.p_size <= 15
+    AND (l.l_shipmode = 'AIR' or l.l_shipmode = 'AIR REG')
+    AND l.l_shipinstruct = 'DELIVER IN PERSON'
+  );
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/tpch/q19_discounted_revenue.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/tpch/q19_discounted_revenue.plan
new file mode 100644
index 0000000..78e65be
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/tpch/q19_discounted_revenue.plan
@@ -0,0 +1,36 @@
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    -- AGGREGATE  |UNPARTITIONED|
+      -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+        -- AGGREGATE  |PARTITIONED|
+          -- STREAM_PROJECT  |PARTITIONED|
+            -- ASSIGN  |PARTITIONED|
+              -- STREAM_PROJECT  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- HYBRID_HASH_JOIN [$$105][$$119]  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- STREAM_SELECT  |PARTITIONED|
+                          -- STREAM_PROJECT  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- HYBRID_HASH_JOIN [$$114][$$111]  |PARTITIONED|
+                                -- HASH_PARTITION_EXCHANGE [$$114]  
|PARTITIONED|
+                                  -- STREAM_PROJECT  |PARTITIONED|
+                                    -- STREAM_SELECT  |PARTITIONED|
+                                      -- ASSIGN  |PARTITIONED|
+                                        -- STREAM_PROJECT  |PARTITIONED|
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                            -- DATASOURCE_SCAN  |PARTITIONED|
+                                              -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
+                                                -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  -- STREAM_SELECT  |PARTITIONED|
+                                    -- STREAM_PROJECT  |PARTITIONED|
+                                      -- ASSIGN  |PARTITIONED|
+                                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                          -- DATASOURCE_SCAN  |PARTITIONED|
+                                            -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
+                                              -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                    -- BROADCAST_EXCHANGE  |PARTITIONED|
+                      -- UNNEST  |UNPARTITIONED|
+                        -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.1.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.1.ddl.sqlpp
new file mode 100644
index 0000000..e47dbdc
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.1.ddl.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Factor out common conjunct from disjunct
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
+ 
+drop dataverse test if exists;
+create dataverse test;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.2.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.2.update.sqlpp
new file mode 100644
index 0000000..b2d7dca
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.2.update.sqlpp
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Factor out common conjunct from disjunct
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.3.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.3.query.sqlpp
new file mode 100644
index 0000000..819634a
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/factor-common-conjunct/factor-common-conjunct.3.query.sqlpp
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Factor out common conjunct from disjunct
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
+
+use test;
+select a, b, c
+from [
+    {"a" : false, "b":false, "c":false},
+    {"a" : false, "b":false, "c":true}, 
+    {"a" : false, "b":true, "c":false}, 
+    {"a" : false, "b":true, "c":true},
+    {"a" : true, "b":false, "c":false},
+    {"a" : true, "b":false, "c":true},
+    {"a" : true, "b":true, "c":false},
+    {"a" : true, "b":true, "c":true}
+] as arrayBoolean
+where (a = b and b = c) or (a = b and c);
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.1.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.1.ddl.sqlpp
new file mode 100644
index 0000000..5097d41
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.1.ddl.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Compute minimum conjunct of disjunct expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
+ 
+drop dataverse test if exists;
+create dataverse test;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.2.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.2.update.sqlpp
new file mode 100644
index 0000000..5c270e1
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.2.update.sqlpp
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Compute minimum conjunct of disjunct expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.3.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.3.query.sqlpp
new file mode 100644
index 0000000..9361b01
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/minimum-disjunct/minimum-disjunct.3.query.sqlpp
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Compute minimum conjunct of disjunct expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
+
+use test;
+select a, b, c
+from [
+    {"a" : false, "b":false, "c":false},
+    {"a" : false, "b":false, "c":true}, 
+    {"a" : false, "b":true, "c":false}, 
+    {"a" : false, "b":true, "c":true},
+    {"a" : true, "b":false, "c":false},
+    {"a" : true, "b":false, "c":true},
+    {"a" : true, "b":true, "c":false},
+    {"a" : true, "b":true, "c":true}
+] as arrayBoolean
+where (a and b) or (a and b and c);
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.1.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.1.ddl.sqlpp
new file mode 100644
index 0000000..3a81a27
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.1.ddl.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Remove redundant boolean expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
+ 
+drop dataverse test if exists;
+create dataverse test;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.2.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.2.update.sqlpp
new file mode 100644
index 0000000..448b47d
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.2.update.sqlpp
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Remove redundant boolean expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.3.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.3.query.sqlpp
new file mode 100644
index 0000000..ca143f5
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-conjunct-expression/redundant-conjunct-expression.3.query.sqlpp
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Remove redundant boolean expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
+
+use test;
+select a, b, c
+from [
+    {"a" : false, "b":false, "c":false},
+    {"a" : false, "b":false, "c":true}, 
+    {"a" : false, "b":true, "c":false}, 
+    {"a" : false, "b":true, "c":true},
+    {"a" : true, "b":false, "c":false},
+    {"a" : true, "b":false, "c":true},
+    {"a" : true, "b":true, "c":false},
+    {"a" : true, "b":true, "c":true}
+] as arrayBoolean
+where a and a;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.1.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.1.ddl.sqlpp
new file mode 100644
index 0000000..3a81a27
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.1.ddl.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Remove redundant boolean expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
+ 
+drop dataverse test if exists;
+create dataverse test;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.2.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.2.update.sqlpp
new file mode 100644
index 0000000..448b47d
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.2.update.sqlpp
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Remove redundant boolean expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.3.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.3.query.sqlpp
new file mode 100644
index 0000000..2cab64f
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/condition/redundant-disjunct-expression/redundant-disjunct-expression.3.query.sqlpp
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description  : Remove redundant boolean expression
+ * Expected Res : Success
+ * Date         : 23 Jan 2017
+ */
+
+use test;
+select a, b, c
+from [
+    {"a" : false, "b":false, "c":false},
+    {"a" : false, "b":false, "c":true}, 
+    {"a" : false, "b":true, "c":false}, 
+    {"a" : false, "b":true, "c":true},
+    {"a" : true, "b":false, "c":false},
+    {"a" : true, "b":false, "c":true},
+    {"a" : true, "b":true, "c":false},
+    {"a" : true, "b":true, "c":true}
+] as arrayBoolean
+where  a or a;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/factor-common-conjunct/factor-common-conjunct.1.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/factor-common-conjunct/factor-common-conjunct.1.adm
new file mode 100644
index 0000000..8268539
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/factor-common-conjunct/factor-common-conjunct.1.adm
@@ -0,0 +1,3 @@
+{ "a": false, "b": false, "c": false }
+{ "a": false, "b": false, "c": true }
+{ "a": true, "b": true, "c": true }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/minimum-disjunct/minimum-disjunct.1.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/minimum-disjunct/minimum-disjunct.1.adm
new file mode 100644
index 0000000..93ee626
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/minimum-disjunct/minimum-disjunct.1.adm
@@ -0,0 +1,2 @@
+{ "a": true, "b": true, "c": false }
+{ "a": true, "b": true, "c": true }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/redundant-conjunct-expression/redundant-conjunct-expression.1.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/redundant-conjunct-expression/redundant-conjunct-expression.1.adm
new file mode 100644
index 0000000..7333e35
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/redundant-conjunct-expression/redundant-conjunct-expression.1.adm
@@ -0,0 +1,4 @@
+{ "a": true, "b": false, "c": false }
+{ "a": true, "b": false, "c": true }
+{ "a": true, "b": true, "c": false }
+{ "a": true, "b": true, "c": true }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/redundant-disjunct-expression/redundant-disjunct-expression.1.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/redundant-disjunct-expression/redundant-disjunct-expression.1.adm
new file mode 100644
index 0000000..7333e35
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/condititon/redundant-disjunct-expression/redundant-disjunct-expression.1.adm
@@ -0,0 +1,4 @@
+{ "a": true, "b": false, "c": false }
+{ "a": true, "b": false, "c": true }
+{ "a": true, "b": true, "c": false }
+{ "a": true, "b": true, "c": true }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml 
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 16fa334..9ec7392 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -9438,4 +9438,26 @@
       </compilation-unit>
     </test-case>
   </test-group>
+  <test-group name="condititon">
+    <test-case FilePath="condititon">
+      <compilation-unit name="factor-common-conjunct">
+        <output-dir compare="Text">factor-common-conjunct</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="condititon">
+      <compilation-unit name="minimum-disjunct">
+        <output-dir compare="Text">minimum-disjunct</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="condititon">
+      <compilation-unit name="redundant-conjunct-expression">
+        <output-dir compare="Text">redundant-conjunct-expression</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="condititon">
+      <compilation-unit name="minimum-disjunct">
+        <output-dir compare="Text">redundant-disjunct-expression</output-dir>
+      </compilation-unit>
+    </test-case>
+  </test-group>
 </test-suite>
diff --git 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/AbstractConditionExpressionRewriteRule.java
 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/AbstractConditionExpressionRewriteRule.java
new file mode 100644
index 0000000..29b2cd4
--- /dev/null
+++ 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/AbstractConditionExpressionRewriteRule.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.hyracks.algebricks.rewriter.rules;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public abstract class AbstractConditionExpressionRewriteRule implements 
IAlgebraicRewriteRule {
+    private static final List<Mutable<ILogicalExpression>> 
EMPTY_EXPRESSION_LIST =
+            Collections.unmodifiableList(new ArrayList<>());
+    private IOptimizationContext context;
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
+            throws AlgebricksException {
+        final ILogicalOperator op = opRef.getValue();
+        final Mutable<ILogicalExpression> condRef;
+        switch (op.getOperatorTag()) {
+            case SELECT:
+                final SelectOperator select = (SelectOperator) op;
+                condRef = select.getCondition();
+                break;
+            case INNERJOIN:
+            case LEFTOUTERJOIN:
+                final AbstractBinaryJoinOperator join = 
(AbstractBinaryJoinOperator) op;
+                condRef = join.getCondition();
+                break;
+            default:
+                return false;
+        }
+
+        this.context = context;
+
+        boolean changed = transform(condRef);
+        if (changed) {
+            context.computeAndSetTypeEnvironmentForOperator(op);
+        }
+
+        return changed;
+    }
+
+    protected final AbstractFunctionCallExpression 
getFunctionExpression(ILogicalExpression expression) {
+        if (expression.getExpressionTag() != 
LogicalExpressionTag.FUNCTION_CALL) {
+            return null;
+        }
+
+        return (AbstractFunctionCallExpression) expression;
+    }
+
+    protected final List<Mutable<ILogicalExpression>> 
getDisjunctiveExpressions(Mutable<ILogicalExpression> exprRef) {
+
+        final AbstractFunctionCallExpression function = 
getFunctionExpression(exprRef.getValue());
+        if (function == null || 
!AlgebricksBuiltinFunctions.OR.equals(function.getFunctionIdentifier())) {
+            return EMPTY_EXPRESSION_LIST;
+        }
+
+        return function.getArguments();
+    }
+
+    protected final IFunctionInfo getFunctionInfo(FunctionIdentifier fid) {
+        return context.getMetadataProvider().lookupFunction(fid);
+    }
+
+    /**
+     * Transform condition expression
+     *
+     * @param condRef
+     *            SELECT or join condition reference
+     * @return
+     *         {@code <code>true</code>} condition has been modified
+     *         {@code <code>false</code>} otherwise.
+     */
+    protected abstract boolean transform(Mutable<ILogicalExpression> condRef);
+}
diff --git 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/FactorCommonConjunctionFromDisjunctionRule.java
 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/FactorCommonConjunctionFromDisjunctionRule.java
new file mode 100644
index 0000000..3ef86bc
--- /dev/null
+++ 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/FactorCommonConjunctionFromDisjunctionRule.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.hyracks.algebricks.rewriter.rules;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
+
+/**
+ * Factor out common conjuncts from disjuncts.
+ * Example:
+ * (a and b and c) or c -> c
+ * (a and b and c) or (a and b and d) -> a and b and (c or d)
+ */
+public class FactorCommonConjunctionFromDisjunctionRule extends 
AbstractConditionExpressionRewriteRule {
+
+    @Override
+    protected boolean transform(Mutable<ILogicalExpression> condRef) {
+
+        final List<Mutable<ILogicalExpression>> disjunctExprs = 
getDisjunctiveExpressions(condRef);
+        boolean changed = false;
+        if (!disjunctExprs.isEmpty()) {
+            changed |= computeMinimumDisjunct(disjunctExprs);
+            changed |= factorOutCommonConjunct(disjunctExprs);
+        }
+
+        //Special case: disjuncts have been factored out into a single 
expression
+        if (changed && disjunctExprs.size() == 1) {
+            condRef.setValue(disjunctExprs.get(0).getValue());
+        }
+
+        final AbstractFunctionCallExpression function = 
getFunctionExpression(condRef.getValue());
+        if (function != null) {
+            for (Mutable<ILogicalExpression> argRef : function.getArguments()) 
{
+                changed |= transform(argRef);
+            }
+        }
+
+        return changed;
+    }
+
+    private boolean computeMinimumDisjunct(List<Mutable<ILogicalExpression>> 
disjunctExprs) {
+        final int originalSize = disjunctExprs.size();
+        int i = 0;
+        while (i < disjunctExprs.size()) {
+            int j = i + 1;
+            while (j < disjunctExprs.size()) {
+                if (containsAll(disjunctExprs.get(i), disjunctExprs.get(j))) {
+                    disjunctExprs.remove(i);
+                } else if (containsAll(disjunctExprs.get(j), 
disjunctExprs.get(i))) {
+                    disjunctExprs.remove(j);
+                } else {
+                    j++;
+                }
+            }
+            i++;
+        }
+
+        return disjunctExprs.size() != originalSize;
+    }
+
+    private boolean factorOutCommonConjunct(List<Mutable<ILogicalExpression>> 
disjunctExprs) {
+        final int originalSize = disjunctExprs.size();
+        int i = 0;
+        while (i < disjunctExprs.size()) {
+            int j = i + 1;
+            while (j < disjunctExprs.size()) {
+                final ILogicalExpression expr1 = 
disjunctExprs.get(i).getValue();
+                final ILogicalExpression expr2 = 
disjunctExprs.get(j).getValue();
+                final Mutable<ILogicalExpression> combinedExprs = 
extractCommonConjunct(expr1, expr2);
+                if (combinedExprs != null) {
+                    disjunctExprs.set(i, combinedExprs);
+                    disjunctExprs.remove(j);
+                } else {
+                    j++;
+                }
+            }
+            i++;
+        }
+
+        return originalSize != disjunctExprs.size();
+    }
+
+    private boolean containsAll(Mutable<ILogicalExpression> exprRef1, 
Mutable<ILogicalExpression> exprRef2) {
+        final AbstractFunctionCallExpression function1 = 
getFunctionExpression(exprRef1.getValue());
+
+        if (function1 == null || 
!AlgebricksBuiltinFunctions.AND.equals(function1.getFunctionIdentifier())) {
+            return false;
+        }
+
+        final AbstractFunctionCallExpression function2 = 
getFunctionExpression(exprRef2.getValue());
+
+        if (function2 != null && 
AlgebricksBuiltinFunctions.AND.equals(function2.getFunctionIdentifier())) {
+            return 
function1.getArguments().containsAll(function2.getArguments());
+        }
+
+        return function1.getArguments().contains(exprRef2);
+    }
+
+    private Mutable<ILogicalExpression> 
extractCommonConjunct(ILogicalExpression expr1, ILogicalExpression expr2) {
+        final AbstractFunctionCallExpression function1 = 
getFunctionExpression(expr1);
+        final AbstractFunctionCallExpression function2 = 
getFunctionExpression(expr2);
+        if (function1 == null || function2 == null
+                || 
!AlgebricksBuiltinFunctions.AND.equals(function1.getFunctionIdentifier())
+                || 
!AlgebricksBuiltinFunctions.AND.equals(function2.getFunctionIdentifier())) {
+            return null;
+        }
+
+        final List<Mutable<ILogicalExpression>> conjList1 = 
function1.getArguments();
+        final List<Mutable<ILogicalExpression>> conjList2 = 
function2.getArguments();
+        final List<Mutable<ILogicalExpression>> commonConj = new ArrayList<>();
+
+        for (Mutable<ILogicalExpression> conj : conjList1) {
+            if (conjList2.contains(conj)) {
+                commonConj.add(conj);
+            }
+        }
+
+        if (commonConj.isEmpty()) {
+            return null;
+        }
+
+        conjList1.removeAll(commonConj);
+        conjList2.removeAll(commonConj);
+
+        final AbstractFunctionCallExpression innerDisjunct =
+                new 
ScalarFunctionCallExpression(getFunctionInfo(AlgebricksBuiltinFunctions.OR));
+        innerDisjunct.getArguments().add(wrapInConjunct(conjList1));
+        innerDisjunct.getArguments().add(wrapInConjunct(conjList2));
+
+        commonConj.add(new MutableObject<>(innerDisjunct));
+        return wrapInConjunct(commonConj);
+    }
+
+    private Mutable<ILogicalExpression> 
wrapInConjunct(List<Mutable<ILogicalExpression>> exprs) {
+        if (exprs.size() == 1) {
+            return exprs.get(0);
+        }
+        final AbstractFunctionCallExpression conj =
+                new 
ScalarFunctionCallExpression(getFunctionInfo(AlgebricksBuiltinFunctions.AND));
+        conj.getArguments().addAll(exprs);
+
+        return new MutableObject<>(conj);
+    }
+
+}
diff --git 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineAndRemoveRedundantBooleanExpressionsRule.java
 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineAndRemoveRedundantBooleanExpressionsRule.java
new file mode 100644
index 0000000..5819041
--- /dev/null
+++ 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineAndRemoveRedundantBooleanExpressionsRule.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.hyracks.algebricks.rewriter.rules;
+
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+
+/**
+ * Inline and remove redundant boolean expressions
+ *
+ * Inline Example:
+ * and(x, and(y, and(z, w))) -> and(x, y, z, w)
+ * 
+ * Remove redundant example:
+ * or(x, y, y) -> or(x, y)
+ */
+public class InlineAndRemoveRedundantBooleanExpressionsRule extends 
AbstractConditionExpressionRewriteRule {
+
+    @Override
+    protected boolean transform(Mutable<ILogicalExpression> condRef) {
+        AbstractFunctionCallExpression function = 
getFunctionExpression(condRef.getValue());
+        if (function == null) {
+            return false;
+        }
+
+        boolean changed = false;
+        final FunctionIdentifier fid = function.getFunctionIdentifier();
+        if (AlgebricksBuiltinFunctions.AND.equals(fid) || 
AlgebricksBuiltinFunctions.OR.equals(fid)) {
+            changed |= inlineCondititon(function);
+            changed |= removeRedundantExpressions(function.getArguments());
+        }
+
+        if (changed && function.getArguments().size() == 1) {
+            final ILogicalExpression newCond = 
function.getArguments().get(0).getValue();
+            condRef.setValue(newCond);
+            transform(condRef);
+            return true;
+        }
+
+        for (Mutable<ILogicalExpression> argRef : function.getArguments()) {
+            changed |= transform(argRef);
+        }
+        return changed;
+    }
+
+    private boolean inlineCondititon(AbstractFunctionCallExpression function) {
+        final FunctionIdentifier fid = function.getFunctionIdentifier();
+        final List<Mutable<ILogicalExpression>> args = function.getArguments();
+
+        int i = 0;
+        boolean changed = false;
+        while (i < args.size()) {
+            final AbstractFunctionCallExpression argFunction = 
getFunctionExpression(args.get(i).getValue());
+            if (argFunction != null && 
fid.equals(argFunction.getFunctionIdentifier())) {
+                args.remove(i);
+                args.addAll(i, argFunction.getArguments());
+                changed = true;
+            } else {
+                i++;
+            }
+        }
+
+        return changed;
+    }
+
+    /**
+     * remove redundant boolean expressions
+     *
+     * Example:
+     * and(x, y, y) -> and(x, y)
+     */
+    private boolean 
removeRedundantExpressions(List<Mutable<ILogicalExpression>> exprs) {
+        final int originalSize = exprs.size();
+        int i = 0;
+        while (i < exprs.size()) {
+            int j = i + 1;
+            while (j < exprs.size()) {
+                if (exprs.get(i).equals(exprs.get(j))) {
+                    exprs.remove(j);
+                } else {
+                    j++;
+                }
+            }
+            i++;
+        }
+
+        return exprs.size() != originalSize;
+    }
+
+}

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/2322
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I97fe7d94276f9206c076ca94814b2fa794107859
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Wail Alkowaileet <[email protected]>

Reply via email to