You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@quickstep.apache.org by ji...@apache.org on 2016/09/09 04:10:32 UTC

incubator-quickstep git commit: Optimizer updates

Repository: incubator-quickstep
Updated Branches:
  refs/heads/lip-refactor b1639fa28 -> c311b4bad


Optimizer updates


Project: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/commit/c311b4ba
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/tree/c311b4ba
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/diff/c311b4ba

Branch: refs/heads/lip-refactor
Commit: c311b4bad63f83fee356d3d5b6aa34f9a7f21d81
Parents: b1639fa
Author: Jianqiao Zhu <ji...@cs.wisc.edu>
Authored: Thu Sep 8 23:10:22 2016 -0500
Committer: Jianqiao Zhu <ji...@cs.wisc.edu>
Committed: Thu Sep 8 23:10:22 2016 -0500

----------------------------------------------------------------------
 query_optimizer/CMakeLists.txt                  |   1 +
 query_optimizer/PhysicalGenerator.cpp           |   5 +-
 query_optimizer/physical/Aggregate.hpp          |  36 ++-
 query_optimizer/physical/CMakeLists.txt         |  10 +
 query_optimizer/physical/HashJoin.hpp           |  33 ++-
 .../physical/LIPFilterConfiguration.hpp         | 121 +++++++++
 query_optimizer/physical/Physical.hpp           |  13 +-
 query_optimizer/physical/Selection.cpp          |   2 +-
 query_optimizer/physical/Selection.hpp          |  22 +-
 query_optimizer/rules/AttachLIPFilters.cpp      | 272 +++++++++++++++++++
 query_optimizer/rules/AttachLIPFilters.hpp      | 143 ++++++++++
 query_optimizer/rules/CMakeLists.txt            |  16 ++
 utility/CMakeLists.txt                          |   4 +
 utility/LIPFilter.cpp                           |  24 ++
 utility/LIPFilter.hpp                           |  44 +++
 utility/LIPFilterAdapter.hpp                    |   0
 utility/LIPFilterBuilder.hpp                    |   0
 utility/PlanVisualizer.cpp                      |  36 ++-
 utility/PlanVisualizer.hpp                      |   1 +
 19 files changed, 759 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/CMakeLists.txt b/query_optimizer/CMakeLists.txt
index 2b521ec..5dfd9c0 100644
--- a/query_optimizer/CMakeLists.txt
+++ b/query_optimizer/CMakeLists.txt
@@ -186,6 +186,7 @@ target_link_libraries(quickstep_queryoptimizer_PhysicalGenerator
                       quickstep_queryoptimizer_LogicalToPhysicalMapper
                       quickstep_queryoptimizer_logical_Logical
                       quickstep_queryoptimizer_physical_Physical
+                      quickstep_queryoptimizer_rules_AttachLIPFilters
                       quickstep_queryoptimizer_rules_PruneColumns
                       quickstep_queryoptimizer_rules_StarSchemaHashJoinOrderOptimization
                       quickstep_queryoptimizer_rules_SwapProbeBuild

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/PhysicalGenerator.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/PhysicalGenerator.cpp b/query_optimizer/PhysicalGenerator.cpp
index 8f19702..a3fedc9 100644
--- a/query_optimizer/PhysicalGenerator.cpp
+++ b/query_optimizer/PhysicalGenerator.cpp
@@ -26,6 +26,7 @@
 #include "query_optimizer/Validator.hpp"
 #include "query_optimizer/logical/Logical.hpp"
 #include "query_optimizer/physical/Physical.hpp"
+#include "query_optimizer/rules/AttachLIPFilters.hpp"
 #include "query_optimizer/rules/PruneColumns.hpp"
 #include "query_optimizer/rules/StarSchemaHashJoinOrderOptimization.hpp"
 #include "query_optimizer/rules/SwapProbeBuild.hpp"
@@ -100,6 +101,7 @@ P::PhysicalPtr PhysicalGenerator::optimizePlan() {
   }
   rules.emplace_back(new PruneColumns());
   rules.emplace_back(new SwapProbeBuild());
+  rules.emplace_back(new AttachLIPFilters());
 
   for (std::unique_ptr<Rule<P::Physical>> &rule : rules) {
     physical_plan_ = rule->apply(physical_plan_);
@@ -110,9 +112,10 @@ P::PhysicalPtr PhysicalGenerator::optimizePlan() {
   DVLOG(4) << "Optimized physical plan:\n" << physical_plan_->toString();
 
   if (FLAGS_visualize_plan) {
-  quickstep::PlanVisualizer plan_visualizer;
+    quickstep::PlanVisualizer plan_visualizer;
     std::cerr << "\n" << plan_visualizer.visualize(physical_plan_) << "\n";
   }
+  exit(0);
 
 #ifdef QUICKSTEP_DEBUG
   Validate(physical_plan_);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/physical/Aggregate.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/physical/Aggregate.hpp b/query_optimizer/physical/Aggregate.hpp
index de36cc3..db655a9 100644
--- a/query_optimizer/physical/Aggregate.hpp
+++ b/query_optimizer/physical/Aggregate.hpp
@@ -30,6 +30,7 @@
 #include "query_optimizer/expressions/ExpressionUtil.hpp"
 #include "query_optimizer/expressions/NamedExpression.hpp"
 #include "query_optimizer/expressions/Predicate.hpp"
+#include "query_optimizer/physical/LIPFilterConfiguration.hpp"
 #include "query_optimizer/physical/Physical.hpp"
 #include "query_optimizer/physical/PhysicalType.hpp"
 #include "utility/Macros.hpp"
@@ -86,7 +87,11 @@ class Aggregate : public Physical {
   PhysicalPtr copyWithNewChildren(
       const std::vector<PhysicalPtr> &new_children) const override {
     DCHECK_EQ(getNumChildren(), new_children.size());
-    return Create(new_children[0], grouping_expressions_, aggregate_expressions_, filter_predicate_);
+    return Create(new_children[0],
+                  grouping_expressions_,
+                  aggregate_expressions_,
+                  filter_predicate_,
+                  lip_filter_conf_);
   }
 
   std::vector<expressions::AttributeReferencePtr> getOutputAttributes() const override;
@@ -100,6 +105,19 @@ class Aggregate : public Physical {
     return false;
   }
 
+  PhysicalPtr copyWithLIPFilterConfiguration(
+      const LIPFilterConfigurationPtr &new_lip_filter_conf) const override {
+    return Create(input_,
+                  grouping_expressions_,
+                  aggregate_expressions_,
+                  filter_predicate_,
+                  new_lip_filter_conf);
+  }
+
+  LIPFilterConfigurationPtr getLIPFilterConfiguration() const override {
+    return lip_filter_conf_;
+  }
+
   /**
    * @brief Creates an Aggregate physical node.
    *
@@ -113,9 +131,14 @@ class Aggregate : public Physical {
       PhysicalPtr input,
       const std::vector<expressions::NamedExpressionPtr> &grouping_expressions,
       const std::vector<expressions::AliasPtr> &aggregate_expressions,
-      const expressions::PredicatePtr &filter_predicate) {
+      const expressions::PredicatePtr &filter_predicate,
+      const LIPFilterConfigurationPtr &lip_filter_conf = nullptr) {
     return AggregatePtr(
-        new Aggregate(input, grouping_expressions, aggregate_expressions, filter_predicate));
+        new Aggregate(input,
+                      grouping_expressions,
+                      aggregate_expressions,
+                      filter_predicate,
+                      lip_filter_conf));
   }
 
  protected:
@@ -132,11 +155,13 @@ class Aggregate : public Physical {
       PhysicalPtr input,
       const std::vector<expressions::NamedExpressionPtr> &grouping_expressions,
       const std::vector<expressions::AliasPtr> &aggregate_expressions,
-      const expressions::PredicatePtr &filter_predicate)
+      const expressions::PredicatePtr &filter_predicate,
+      const LIPFilterConfigurationPtr &lip_filter_conf)
       : input_(input),
         grouping_expressions_(grouping_expressions),
         aggregate_expressions_(aggregate_expressions),
-        filter_predicate_(filter_predicate) {
+        filter_predicate_(filter_predicate),
+        lip_filter_conf_(lip_filter_conf) {
     addChild(input_);
   }
 
@@ -144,6 +169,7 @@ class Aggregate : public Physical {
   std::vector<expressions::NamedExpressionPtr> grouping_expressions_;
   std::vector<expressions::AliasPtr> aggregate_expressions_;
   expressions::PredicatePtr filter_predicate_;
+  LIPFilterConfigurationPtr lip_filter_conf_;
 
   DISALLOW_COPY_AND_ASSIGN(Aggregate);
 };

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/physical/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/physical/CMakeLists.txt b/query_optimizer/physical/CMakeLists.txt
index 3b7d3f0..83682b3 100644
--- a/query_optimizer/physical/CMakeLists.txt
+++ b/query_optimizer/physical/CMakeLists.txt
@@ -27,6 +27,7 @@ add_library(quickstep_queryoptimizer_physical_HashJoin HashJoin.cpp HashJoin.hpp
 add_library(quickstep_queryoptimizer_physical_InsertSelection InsertSelection.cpp InsertSelection.hpp)
 add_library(quickstep_queryoptimizer_physical_InsertTuple InsertTuple.cpp InsertTuple.hpp)
 add_library(quickstep_queryoptimizer_physical_Join ../../empty_src.cpp Join.hpp)
+add_library(quickstep_queryoptimizer_physical_LIPFilterConfiguration ../../empty_src.cpp LIPFilterConfiguration.hpp)
 add_library(quickstep_queryoptimizer_physical_NestedLoopsJoin NestedLoopsJoin.cpp NestedLoopsJoin.hpp)
 add_library(quickstep_queryoptimizer_physical_PatternMatcher ../../empty_src.cpp PatternMatcher.hpp)
 add_library(quickstep_queryoptimizer_physical_Physical ../../empty_src.cpp Physical.hpp)
@@ -51,6 +52,7 @@ target_link_libraries(quickstep_queryoptimizer_physical_Aggregate
                       quickstep_queryoptimizer_expressions_ExpressionUtil
                       quickstep_queryoptimizer_expressions_NamedExpression
                       quickstep_queryoptimizer_expressions_Predicate
+                      quickstep_queryoptimizer_physical_LIPFilterConfiguration
                       quickstep_queryoptimizer_physical_Physical
                       quickstep_queryoptimizer_physical_PhysicalType
                       quickstep_utility_Cast
@@ -121,6 +123,7 @@ target_link_libraries(quickstep_queryoptimizer_physical_HashJoin
                       quickstep_queryoptimizer_expressions_NamedExpression
                       quickstep_queryoptimizer_expressions_Predicate
                       quickstep_queryoptimizer_physical_BinaryJoin
+                      quickstep_queryoptimizer_physical_LIPFilterConfiguration
                       quickstep_queryoptimizer_physical_Physical
                       quickstep_queryoptimizer_physical_PhysicalType
                       quickstep_utility_Cast
@@ -150,6 +153,10 @@ target_link_libraries(quickstep_queryoptimizer_physical_Join
                       quickstep_queryoptimizer_expressions_NamedExpression
                       quickstep_queryoptimizer_physical_Physical
                       quickstep_utility_Macros)
+target_link_libraries(quickstep_queryoptimizer_physical_LIPFilterConfiguration
+                      quickstep_queryoptimizer_expressions_AttributeReference
+                      quickstep_utility_LIPFilter
+                      quickstep_utility_Macros)
 target_link_libraries(quickstep_queryoptimizer_physical_NestedLoopsJoin
                       glog
                       quickstep_queryoptimizer_OptimizerTree
@@ -167,6 +174,7 @@ target_link_libraries(quickstep_queryoptimizer_physical_Physical
                       quickstep_queryoptimizer_OptimizerTree
                       quickstep_queryoptimizer_expressions_AttributeReference
                       quickstep_queryoptimizer_expressions_ExpressionUtil
+                      quickstep_queryoptimizer_physical_LIPFilterConfiguration
                       quickstep_queryoptimizer_physical_PhysicalType
                       quickstep_utility_Macros)
 target_link_libraries(quickstep_queryoptimizer_physical_Sample
@@ -187,6 +195,7 @@ target_link_libraries(quickstep_queryoptimizer_physical_Selection
                       quickstep_queryoptimizer_expressions_LogicalAnd
                       quickstep_queryoptimizer_expressions_NamedExpression
                       quickstep_queryoptimizer_expressions_Predicate
+                      quickstep_queryoptimizer_physical_LIPFilterConfiguration
                       quickstep_queryoptimizer_physical_Physical
                       quickstep_queryoptimizer_physical_PhysicalType
                       quickstep_utility_Cast
@@ -279,6 +288,7 @@ target_link_libraries(quickstep_queryoptimizer_physical
                       quickstep_queryoptimizer_physical_InsertSelection
                       quickstep_queryoptimizer_physical_InsertTuple
                       quickstep_queryoptimizer_physical_Join
+                      quickstep_queryoptimizer_physical_LIPFilterConfiguration
                       quickstep_queryoptimizer_physical_NestedLoopsJoin
                       quickstep_queryoptimizer_physical_PatternMatcher
                       quickstep_queryoptimizer_physical_Physical

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/physical/HashJoin.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/physical/HashJoin.hpp b/query_optimizer/physical/HashJoin.hpp
index c513f77..554dc39 100644
--- a/query_optimizer/physical/HashJoin.hpp
+++ b/query_optimizer/physical/HashJoin.hpp
@@ -32,6 +32,7 @@
 #include "query_optimizer/expressions/NamedExpression.hpp"
 #include "query_optimizer/expressions/Predicate.hpp"
 #include "query_optimizer/physical/BinaryJoin.hpp"
+#include "query_optimizer/physical/LIPFilterConfiguration.hpp"
 #include "query_optimizer/physical/Physical.hpp"
 #include "query_optimizer/physical/PhysicalType.hpp"
 #include "utility/Macros.hpp"
@@ -116,7 +117,8 @@ class HashJoin : public BinaryJoin {
                   right_join_attributes_,
                   residual_predicate_,
                   project_expressions(),
-                  join_type_);
+                  join_type_,
+                  lip_filter_conf_);
   }
 
   std::vector<expressions::AttributeReferencePtr> getReferencedAttributes() const override;
@@ -125,6 +127,22 @@ class HashJoin : public BinaryJoin {
       const expressions::UnorderedNamedExpressionSet &referenced_expressions,
       PhysicalPtr *output) const override;
 
+  PhysicalPtr copyWithLIPFilterConfiguration(
+      const LIPFilterConfigurationPtr &new_lip_filter_conf) const override {
+    return Create(left(),
+                  right(),
+                  left_join_attributes(),
+                  right_join_attributes(),
+                  residual_predicate_,
+                  project_expressions(),
+                  join_type_,
+                  new_lip_filter_conf);
+  }
+
+  LIPFilterConfigurationPtr getLIPFilterConfiguration() const override {
+    return lip_filter_conf_;
+  }
+
   /**
    * @brief Creates a physical HashJoin. The left/right operand does not correspond to
    *        probe/build operand.
@@ -145,7 +163,8 @@ class HashJoin : public BinaryJoin {
       const std::vector<expressions::AttributeReferencePtr> &right_join_attributes,
       const expressions::PredicatePtr &residual_predicate,
       const std::vector<expressions::NamedExpressionPtr> &project_expressions,
-      const JoinType join_type) {
+      const JoinType join_type,
+      const LIPFilterConfigurationPtr &lip_filter_conf = nullptr) {
     return HashJoinPtr(
         new HashJoin(left,
                      right,
@@ -153,7 +172,8 @@ class HashJoin : public BinaryJoin {
                      right_join_attributes,
                      residual_predicate,
                      project_expressions,
-                     join_type));
+                     join_type,
+                     lip_filter_conf));
   }
 
  protected:
@@ -173,18 +193,21 @@ class HashJoin : public BinaryJoin {
       const std::vector<expressions::AttributeReferencePtr> &right_join_attributes,
       const expressions::PredicatePtr &residual_predicate,
       const std::vector<expressions::NamedExpressionPtr> &project_expressions,
-      const JoinType join_type)
+      const JoinType join_type,
+      const LIPFilterConfigurationPtr &lip_filter_conf)
       : BinaryJoin(left, right, project_expressions),
         left_join_attributes_(left_join_attributes),
         right_join_attributes_(right_join_attributes),
         residual_predicate_(residual_predicate),
-        join_type_(join_type) {
+        join_type_(join_type),
+        lip_filter_conf_(lip_filter_conf) {
   }
 
   std::vector<expressions::AttributeReferencePtr> left_join_attributes_;
   std::vector<expressions::AttributeReferencePtr> right_join_attributes_;
   expressions::PredicatePtr residual_predicate_;
   JoinType join_type_;
+  LIPFilterConfigurationPtr lip_filter_conf_;
 
   DISALLOW_COPY_AND_ASSIGN(HashJoin);
 };

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/physical/LIPFilterConfiguration.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/physical/LIPFilterConfiguration.hpp b/query_optimizer/physical/LIPFilterConfiguration.hpp
new file mode 100644
index 0000000..53e5789
--- /dev/null
+++ b/query_optimizer/physical/LIPFilterConfiguration.hpp
@@ -0,0 +1,121 @@
+/**
+ * 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.
+ **/
+
+#ifndef QUICKSTEP_QUERY_OPTIMIZER_PHYSICAL_LIP_FILTER_CONFIGURATION_HPP_
+#define QUICKSTEP_QUERY_OPTIMIZER_PHYSICAL_LIP_FILTER_CONFIGURATION_HPP_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "query_optimizer/expressions/AttributeReference.hpp"
+#include "utility/LIPFilter.hpp"
+#include "utility/Macros.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+namespace optimizer {
+namespace physical {
+
+/** \addtogroup OptimizerPhysical
+ *  @{
+ */
+
+class Physical;
+typedef std::shared_ptr<const Physical> PhysicalPtr;
+
+struct LIPFilterBuildInfo{
+  LIPFilterBuildInfo(const expressions::AttributeReferencePtr &build_attribute_in,
+                     const PhysicalPtr &builder_in,
+                     const LIPFilterType &filter_type_in)
+      : build_attribute(build_attribute_in),
+        builder(builder_in),
+        filter_type(filter_type_in) {
+  }
+  expressions::AttributeReferencePtr build_attribute;
+  PhysicalPtr builder;
+  LIPFilterType filter_type;
+};
+
+struct LIPFilterProbeInfo {
+  LIPFilterProbeInfo(const expressions::AttributeReferencePtr &probe_attribute_in,
+                     const PhysicalPtr &target_in,
+                     const expressions::AttributeReferencePtr &build_attribute_in,
+                     const PhysicalPtr &builder_in,
+                     const LIPFilterType &filter_type_in)
+      : probe_attribute(probe_attribute_in),
+        target(target_in),
+        build_attribute(build_attribute_in),
+        builder(builder_in),
+        filter_type(filter_type_in) {
+  }
+  expressions::AttributeReferencePtr probe_attribute;
+  PhysicalPtr target;
+  expressions::AttributeReferencePtr build_attribute;
+  PhysicalPtr builder;
+  LIPFilterType filter_type;
+};
+
+
+class LIPFilterConfiguration;
+typedef std::shared_ptr<const LIPFilterConfiguration> LIPFilterConfigurationPtr;
+
+class LIPFilterConfiguration {
+ public:
+  LIPFilterConfiguration() {
+  }
+
+  void addBuildInfo(const expressions::AttributeReferencePtr &build_attribute,
+                    const PhysicalPtr &builder,
+                    const LIPFilterType &filter_type) {
+    build_info_.emplace_back(build_attribute, builder, filter_type);
+  }
+
+  void addProbeInfo(const expressions::AttributeReferencePtr &probe_attribute,
+                    const PhysicalPtr &target,
+                    const expressions::AttributeReferencePtr &build_attribute,
+                    const PhysicalPtr &builder,
+                    const LIPFilterType &filter_type) {
+    probe_info_.emplace_back(
+        probe_attribute, target, build_attribute, builder, filter_type);
+  }
+
+  const std::vector<LIPFilterBuildInfo>& getBuildInfo() const {
+    return build_info_;
+  }
+
+  const std::vector<LIPFilterProbeInfo>& getProbeInfo() const {
+    return probe_info_;
+  }
+
+ private:
+  std::vector<LIPFilterBuildInfo> build_info_;
+  std::vector<LIPFilterProbeInfo> probe_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(LIPFilterConfiguration);
+};
+
+/** @} */
+
+}  // namespace physical
+}  // namespace optimizer
+}  // namespace quickstep
+
+#endif /* QUICKSTEP_QUERY_OPTIMIZER_PHYSICAL_LIP_FILTER_CONFIGURATION_HPP_ */

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/physical/Physical.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/physical/Physical.hpp b/query_optimizer/physical/Physical.hpp
index 4bed593..33aaea0 100644
--- a/query_optimizer/physical/Physical.hpp
+++ b/query_optimizer/physical/Physical.hpp
@@ -26,10 +26,12 @@
 #include "query_optimizer/OptimizerTree.hpp"
 #include "query_optimizer/expressions/AttributeReference.hpp"
 #include "query_optimizer/expressions/ExpressionUtil.hpp"
+#include "query_optimizer/physical/LIPFilterConfiguration.hpp"
 #include "query_optimizer/physical/PhysicalType.hpp"
-
 #include "utility/Macros.hpp"
 
+#include "glog/logging.h"
+
 namespace quickstep {
 namespace optimizer {
 namespace physical {
@@ -86,6 +88,15 @@ class Physical : public OptimizerTree<Physical> {
       const expressions::UnorderedNamedExpressionSet &referenced_expressions,
       PhysicalPtr *output) const = 0;
 
+  virtual PhysicalPtr copyWithLIPFilterConfiguration(
+      const LIPFilterConfigurationPtr &new_lip_filter_conf) const {
+    LOG(FATAL) << getName() << " does not support attachment of LIP filters";
+  }
+
+  virtual LIPFilterConfigurationPtr getLIPFilterConfiguration() const {
+    return nullptr;
+  }
+
  protected:
   /**
    * @brief Constructor.

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/physical/Selection.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/physical/Selection.cpp b/query_optimizer/physical/Selection.cpp
index 36ade04..595de49 100644
--- a/query_optimizer/physical/Selection.cpp
+++ b/query_optimizer/physical/Selection.cpp
@@ -39,7 +39,7 @@ namespace E = ::quickstep::optimizer::expressions;
 PhysicalPtr Selection::copyWithNewChildren(
     const std::vector<PhysicalPtr> &new_children) const {
   DCHECK_EQ(children().size(), new_children.size());
-  return Create(new_children[0], project_expressions_, filter_predicate_);
+  return Create(new_children[0], project_expressions_, filter_predicate_, lip_filter_conf_);
 }
 
 std::vector<E::AttributeReferencePtr> Selection::getOutputAttributes() const {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/physical/Selection.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/physical/Selection.hpp b/query_optimizer/physical/Selection.hpp
index b6874a1..a9c9984 100644
--- a/query_optimizer/physical/Selection.hpp
+++ b/query_optimizer/physical/Selection.hpp
@@ -30,6 +30,7 @@
 #include "query_optimizer/expressions/NamedExpression.hpp"
 #include "query_optimizer/expressions/LogicalAnd.hpp"
 #include "query_optimizer/expressions/Predicate.hpp"
+#include "query_optimizer/physical/LIPFilterConfiguration.hpp"
 #include "query_optimizer/physical/Physical.hpp"
 #include "query_optimizer/physical/PhysicalType.hpp"
 #include "utility/Macros.hpp"
@@ -86,6 +87,15 @@ class Selection : public Physical {
       const expressions::UnorderedNamedExpressionSet &referenced_attributes,
       PhysicalPtr *output) const override;
 
+  PhysicalPtr copyWithLIPFilterConfiguration(
+      const LIPFilterConfigurationPtr &new_lip_filter_conf) const override {
+    return Create(children()[0], project_expressions_, filter_predicate_, new_lip_filter_conf);
+  }
+
+  LIPFilterConfigurationPtr getLIPFilterConfiguration() const override {
+    return lip_filter_conf_;
+  }
+
   /**
    * @brief Creates a Selection.
    *
@@ -97,9 +107,10 @@ class Selection : public Physical {
   static SelectionPtr Create(
       const PhysicalPtr &input,
       const std::vector<expressions::NamedExpressionPtr> &project_expressions,
-      const expressions::PredicatePtr &filter_predicate) {
+      const expressions::PredicatePtr &filter_predicate,
+      const LIPFilterConfigurationPtr &lip_filter_conf = nullptr) {
     return SelectionPtr(
-        new Selection(input, project_expressions, filter_predicate));
+        new Selection(input, project_expressions, filter_predicate, lip_filter_conf));
   }
 
   /**
@@ -140,15 +151,18 @@ class Selection : public Physical {
   Selection(
       const PhysicalPtr &input,
       const std::vector<expressions::NamedExpressionPtr> &project_expressions,
-      const expressions::PredicatePtr &filter_predicate)
+      const expressions::PredicatePtr &filter_predicate,
+      const LIPFilterConfigurationPtr &lip_filter_conf)
       : project_expressions_(project_expressions),
-        filter_predicate_(filter_predicate) {
+        filter_predicate_(filter_predicate),
+        lip_filter_conf_(lip_filter_conf) {
     addChild(input);
   }
 
   std::vector<expressions::NamedExpressionPtr> project_expressions_;
   // Can be NULL. If NULL, the filter predicate is treated as the literal true.
   expressions::PredicatePtr filter_predicate_;
+  LIPFilterConfigurationPtr lip_filter_conf_;
 
   DISALLOW_COPY_AND_ASSIGN(Selection);
 };

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/rules/AttachLIPFilters.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/rules/AttachLIPFilters.cpp b/query_optimizer/rules/AttachLIPFilters.cpp
new file mode 100644
index 0000000..f73cdb9
--- /dev/null
+++ b/query_optimizer/rules/AttachLIPFilters.cpp
@@ -0,0 +1,272 @@
+/**
+ * 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.
+ **/
+
+#include "query_optimizer/rules/AttachLIPFilters.hpp"
+
+#include <algorithm>
+#include <iterator>
+#include <memory>
+#include <set>
+#include <stack>
+#include <unordered_set>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "query_optimizer/cost_model/StarSchemaSimpleCostModel.hpp"
+#include "query_optimizer/expressions/AttributeReference.hpp"
+#include "query_optimizer/expressions/NamedExpression.hpp"
+#include "query_optimizer/expressions/PatternMatcher.hpp"
+#include "query_optimizer/physical/LIPFilterConfiguration.hpp"
+#include "query_optimizer/physical/HashJoin.hpp"
+#include "query_optimizer/physical/PatternMatcher.hpp"
+#include "query_optimizer/physical/Physical.hpp"
+#include "query_optimizer/physical/PhysicalType.hpp"
+#include "query_optimizer/physical/TopLevelPlan.hpp"
+#include "utility/LIPFilter.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+namespace optimizer {
+
+namespace E = ::quickstep::optimizer::expressions;
+namespace P = ::quickstep::optimizer::physical;
+
+P::PhysicalPtr AttachLIPFilters::apply(const P::PhysicalPtr &input) {
+  DCHECK(input->getPhysicalType() == P::PhysicalType::kTopLevelPlan);
+  cost_model_.reset(
+      new cost::StarSchemaSimpleCostModel(
+          std::static_pointer_cast<const P::TopLevelPlan>(input)->shared_subplans()));
+
+  std::set<E::ExprId> already_filtered_attributes;
+  attachLIPFilters(NodeList(input), &already_filtered_attributes);
+
+  return applyTransform(input);
+}
+
+void AttachLIPFilters::attachLIPFilters(
+    const NodeList &path,
+    std::set<expressions::ExprId> *already_filtered_attributes) {
+  const P::PhysicalPtr &node = path.node;
+
+  // First process child nodes
+  for (const auto &child : node->children()) {
+    std::set<E::ExprId> child_filtered_attributes;
+    attachLIPFilters(path.cons(child), &child_filtered_attributes);
+    already_filtered_attributes->insert(child_filtered_attributes.begin(),
+                                        child_filtered_attributes.end());
+  }
+
+  // Attach LIP filters to HashJoin/Selection/Aggregate nodes
+  P::PhysicalPtr probe_child = nullptr;
+  switch (node->getPhysicalType()) {
+    case P::PhysicalType::kHashJoin:
+      probe_child = std::static_pointer_cast<const P::HashJoin>(node)->left();
+      break;
+    case P::PhysicalType::kSelection:
+      probe_child = std::static_pointer_cast<const P::Selection>(node)->input();
+      break;
+    case P::PhysicalType::kAggregate:
+      probe_child = std::static_pointer_cast<const P::Aggregate>(node)->input();
+      break;
+    default:
+      break;
+  }
+
+  if (probe_child != nullptr) {
+    const auto &candidate_lip_filters = getProbeSideInfo(path.cons(probe_child));
+    if (!candidate_lip_filters.empty() &&
+        cost_model_->estimateCardinality(probe_child) > 10000000) {
+      std::map<E::AttributeReferencePtr, LIPFilterInfoPtr> selected_filters;
+      for (const auto &info : candidate_lip_filters) {
+        auto it = selected_filters.find(info->attribute);
+        if (it == selected_filters.end()) {
+          selected_filters.emplace(info->attribute, info);
+        } else if (LIPFilterInfo::isBetterThan(*info, *it->second)) {
+          it->second = info;
+        }
+      }
+
+      auto *probe_conf = getLIPFilterConfiguration(node);
+      for (const auto &pair : selected_filters) {
+        const E::ExprId source_attr_id =  pair.second->source_attribute->id();
+        if (already_filtered_attributes->find(source_attr_id)
+                == already_filtered_attributes->end()) {
+          auto *build_conf = getLIPFilterConfiguration(pair.second->source);
+          build_conf->addBuildInfo(pair.second->source_attribute,
+                                   pair.second->source,
+                                   LIPFilterType::kSingleIdentityHashFilter);
+          probe_conf->addProbeInfo(pair.first,
+                                   probe_child,
+                                   pair.second->source_attribute,
+                                   pair.second->source,
+                                   LIPFilterType::kSingleIdentityHashFilter);
+          already_filtered_attributes->emplace(source_attr_id);
+        }
+      }
+    }
+  }
+}
+
+P::PhysicalPtr AttachLIPFilters::applyTransform(const physical::PhysicalPtr &node) {
+  std::vector<P::PhysicalPtr> new_children;
+  bool has_changed = false;
+  for (const auto &child : node->children()) {
+    P::PhysicalPtr new_child = applyTransform(child);
+    if (new_child != child) {
+      has_changed = true;
+    }
+    new_children.emplace_back(new_child);
+  }
+
+  auto attach_it = attaches_.find(node);
+  P::PhysicalPtr new_node = node;
+  if (attach_it != attaches_.end()) {
+    switch (node->getPhysicalType()) {
+      case P::PhysicalType::kHashJoin:
+      case P::PhysicalType::kSelection:
+      case P::PhysicalType::kAggregate:
+        new_node = node->copyWithLIPFilterConfiguration(
+            P::LIPFilterConfigurationPtr(attach_it->second.release()));
+        break;
+      default:
+        break;
+    }
+  }
+
+  if (has_changed) {
+    return new_node->copyWithNewChildren(new_children);
+  }
+  return new_node;
+}
+
+const std::vector<AttachLIPFilters::LIPFilterInfoPtr>& AttachLIPFilters
+    ::getBuildSideInfo(const NodeList &path) {
+  const P::PhysicalPtr &node = path.node;
+  if (build_side_info_.find(node) == build_side_info_.end()) {
+    std::vector<LIPFilterInfoPtr> lip_filters;
+
+    // 1. Gather candidate LIP filters propagated from descendant nodes.
+    std::unordered_set<E::ExprId> output_attribute_ids;
+    for (const auto &attr : node->getOutputAttributes()) {
+      output_attribute_ids.emplace(attr->id());
+    }
+    switch (node->getPhysicalType()) {
+      case P::PhysicalType::kAggregate:
+      case P::PhysicalType::kSelection:
+      case P::PhysicalType::kHashJoin: {
+        for (const P::PhysicalPtr &child : node->children()) {
+          for (const LIPFilterInfoPtr &info : getBuildSideInfo(path.cons(child))) {
+            lip_filters.emplace_back(info);
+          }
+        }
+      }
+      default:
+        break;
+    }
+
+    // 2. Consider the current physical node. If it is a HashJoin,
+    // then each build-side join attribute is a candidate LIP filter
+    // which can be built by the BuildHashOperator that corresponds
+    // to this HashJoin node.
+    P::HashJoinPtr hash_join;
+    if (P::SomeHashJoin::MatchesWithConditionalCast(node, &hash_join)) {
+      const P::PhysicalPtr &build_node = hash_join->right();
+      // TODO(jianqiao): consider probe-side info to allow cascading propagation.
+      double selectivity = cost_model_->estimateSelectivity(build_node);
+      // Only consider attributes that are selective.
+      if (selectivity < 1.0) {
+        for (const auto &attr : hash_join->right_join_attributes()) {
+          lip_filters.emplace_back(
+              std::make_shared<LIPFilterInfo>(attr, node, path.depth, selectivity));
+        }
+      }
+    }
+    build_side_info_.emplace(node, std::move(lip_filters));
+  }
+  return build_side_info_.at(node);
+}
+
+const std::vector<AttachLIPFilters::LIPFilterInfoPtr>& AttachLIPFilters
+    ::getProbeSideInfo(const NodeList &path) {
+  const P::PhysicalPtr &node = path.node;
+  if (probe_side_info_.find(node) == probe_side_info_.end()) {
+    std::vector<LIPFilterInfoPtr> lip_filters;
+    if (path.cdr() != nullptr) {
+      // 1. Gather candidate LIP filters propagated from ancestor nodes.
+      const auto &parent_lip_filters = getProbeSideInfo(*path.cdr());
+      if (!parent_lip_filters.empty()) {
+        std::unordered_set<E::ExprId> output_attribute_ids;
+        for (const auto &attr : node->getOutputAttributes()) {
+          output_attribute_ids.emplace(attr->id());
+        }
+        for (const auto &info : parent_lip_filters) {
+          if (output_attribute_ids.find(info->attribute->id()) != output_attribute_ids.end()) {
+            lip_filters.emplace_back(info);
+          }
+        }
+      }
+
+      // 2. Consider the parent physical node. If it is an InnerHashJoin or
+      // LeftSemiHashJoin, then we can propagate the build-side LIP filters
+      // to the probe-side.
+      P::HashJoinPtr hash_join;
+      if (P::SomeHashJoin::MatchesWithConditionalCast(path.cdr()->node, &hash_join) &&
+          (hash_join->join_type() == P::HashJoin::JoinType::kInnerJoin ||
+           hash_join->join_type() == P::HashJoin::JoinType::kLeftSemiJoin)) {
+        const P::PhysicalPtr &build_side_child = hash_join->right();
+        std::unordered_map<E::ExprId, E::AttributeReferencePtr> join_attribute_pairs;
+        for (std::size_t i = 0; i < hash_join->left_join_attributes().size(); ++i) {
+          const E::AttributeReferencePtr probe_side_join_attribute =
+              hash_join->left_join_attributes()[i];
+          const E::AttributeReferencePtr build_side_join_attribute =
+              hash_join->right_join_attributes()[i];
+          join_attribute_pairs.emplace(build_side_join_attribute->id(),
+                                       probe_side_join_attribute);
+        }
+        for (const auto &info : getBuildSideInfo(build_side_child)) {
+          const auto pair_it = join_attribute_pairs.find(info->attribute->id());
+          if (pair_it != join_attribute_pairs.end()) {
+            lip_filters.emplace_back(
+                std::make_shared<LIPFilterInfo>(pair_it->second,
+                                                info->source,
+                                                info->depth,
+                                                info->estimated_selectivity,
+                                                info->attribute));
+          }
+        }
+      }
+    }
+    probe_side_info_.emplace(node, std::move(lip_filters));
+  }
+  return probe_side_info_.at(node);
+}
+
+P::LIPFilterConfiguration* AttachLIPFilters::getLIPFilterConfiguration(
+    const P::PhysicalPtr &node) {
+  if (attaches_.find(node) == attaches_.end()) {
+    attaches_.emplace(node, std::make_unique<P::LIPFilterConfiguration>());
+  }
+  return attaches_.at(node).get();
+}
+
+
+}  // namespace optimizer
+}  // namespace quickstep
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/rules/AttachLIPFilters.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/rules/AttachLIPFilters.hpp b/query_optimizer/rules/AttachLIPFilters.hpp
new file mode 100644
index 0000000..ef1a8f0
--- /dev/null
+++ b/query_optimizer/rules/AttachLIPFilters.hpp
@@ -0,0 +1,143 @@
+/**
+ * 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.
+ **/
+
+#ifndef QUICKSTEP_QUERY_OPTIMIZER_RULES_ATTACH_LIP_FILTERS_HPP_
+#define QUICKSTEP_QUERY_OPTIMIZER_RULES_ATTACH_LIP_FILTERS_HPP_
+
+#include <cstddef>
+#include <map>
+#include <memory>
+#include <set>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "query_optimizer/cost_model/StarSchemaSimpleCostModel.hpp"
+#include "query_optimizer/expressions/ExprId.hpp"
+#include "query_optimizer/expressions/NamedExpression.hpp"
+#include "query_optimizer/expressions/Predicate.hpp"
+#include "query_optimizer/physical/LIPFilterConfiguration.hpp"
+#include "query_optimizer/physical/Physical.hpp"
+#include "query_optimizer/physical/HashJoin.hpp"
+#include "query_optimizer/rules/Rule.hpp"
+#include "utility/Macros.hpp"
+
+namespace quickstep {
+namespace optimizer {
+
+/** \addtogroup OptimizerRules
+ *  @{
+ */
+
+class AttachLIPFilters : public Rule<physical::Physical> {
+ public:
+  AttachLIPFilters() {}
+
+  ~AttachLIPFilters() override {}
+
+  std::string getName() const override {
+    return "AttachLIPFilters";
+  }
+
+  physical::PhysicalPtr apply(const physical::PhysicalPtr &input) override;
+
+ private:
+  struct LIPFilterInfo {
+    LIPFilterInfo(const expressions::AttributeReferencePtr &attribute_in,
+                  const physical::PhysicalPtr &source_in,
+                  const int depth_in,
+                  const double estimated_selectivity_in,
+                  const expressions::AttributeReferencePtr &source_attribute_in = nullptr)
+        : attribute(attribute_in),
+          source(source_in),
+          depth(depth_in),
+          estimated_selectivity(estimated_selectivity_in),
+          source_attribute(
+              source_attribute_in == nullptr
+                  ? attribute_in
+                  : source_attribute_in) {
+
+    }
+    static bool isBetterThan(const LIPFilterInfo &a, const LIPFilterInfo &b) {
+      if (a.estimated_selectivity == b.estimated_selectivity) {
+        return a.depth > b.depth;
+      } else {
+        return a.estimated_selectivity < b.estimated_selectivity;
+      }
+    }
+    expressions::AttributeReferencePtr attribute;
+    physical::PhysicalPtr source;
+    int depth;
+    double estimated_selectivity;
+    expressions::AttributeReferencePtr source_attribute;
+  };
+
+  typedef std::shared_ptr<const LIPFilterInfo> LIPFilterInfoPtr;
+
+  struct NodeList {
+    NodeList(const physical::PhysicalPtr &node_in)
+        : node(node_in),
+          next(nullptr),
+          depth(0) {
+    }
+    NodeList(const physical::PhysicalPtr &node_in,
+             const NodeList *next_in,
+             const int depth_in)
+        : node(node_in),
+          next(next_in),
+          depth(depth_in) {
+    }
+    inline const NodeList *cdr() const {
+      return next;
+    }
+    inline const NodeList cons(const physical::PhysicalPtr &new_node) const {
+      return NodeList(new_node, this, depth+1);
+    }
+    const physical::PhysicalPtr node;
+    const NodeList *next;
+    const int depth;
+  };
+
+  void attachLIPFilters(const NodeList &path,
+                        std::set<expressions::ExprId> *already_filtered_attributes);
+
+  physical::PhysicalPtr applyTransform(const physical::PhysicalPtr &node);
+
+  const std::vector<LIPFilterInfoPtr>& getBuildSideInfo(const NodeList &path);
+
+  const std::vector<LIPFilterInfoPtr>& getProbeSideInfo(const NodeList &path);
+
+  physical::LIPFilterConfiguration* getLIPFilterConfiguration(
+      const physical::PhysicalPtr &node);
+
+  std::unique_ptr<cost::StarSchemaSimpleCostModel> cost_model_;
+  std::map<physical::PhysicalPtr, std::vector<LIPFilterInfoPtr>> build_side_info_;
+  std::map<physical::PhysicalPtr, std::vector<LIPFilterInfoPtr>> probe_side_info_;
+  std::map<physical::PhysicalPtr, std::unique_ptr<physical::LIPFilterConfiguration>> attaches_;
+
+  DISALLOW_COPY_AND_ASSIGN(AttachLIPFilters);
+};
+
+/** @} */
+
+}  // namespace optimizer
+}  // namespace quickstep
+
+#endif /* QUICKSTEP_QUERY_OPTIMIZER_RULES_ATTACH_LIP_FILTERS_HPP_ */

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/query_optimizer/rules/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/rules/CMakeLists.txt b/query_optimizer/rules/CMakeLists.txt
index d9709ce..9dc6118 100644
--- a/query_optimizer/rules/CMakeLists.txt
+++ b/query_optimizer/rules/CMakeLists.txt
@@ -18,6 +18,7 @@
 add_subdirectory(tests)
 
 # Declare micro-libs:
+add_library(quickstep_queryoptimizer_rules_AttachLIPFilters AttachLIPFilters.cpp AttachLIPFilters.hpp)
 add_library(quickstep_queryoptimizer_rules_BottomUpRule ../../empty_src.cpp BottomUpRule.hpp)
 add_library(quickstep_queryoptimizer_rules_CollapseProject CollapseProject.cpp CollapseProject.hpp)
 add_library(quickstep_queryoptimizer_rules_GenerateJoins GenerateJoins.cpp GenerateJoins.hpp)
@@ -36,6 +37,20 @@ add_library(quickstep_queryoptimizer_rules_UnnestSubqueries UnnestSubqueries.cpp
 
 
 # Link dependencies:
+target_link_libraries(quickstep_queryoptimizer_rules_AttachLIPFilters
+                      quickstep_queryoptimizer_costmodel_StarSchemaSimpleCostModel
+                      quickstep_queryoptimizer_expressions_AttributeReference
+                      quickstep_queryoptimizer_expressions_ExprId
+                      quickstep_queryoptimizer_expressions_NamedExpression
+                      quickstep_queryoptimizer_expressions_PatternMatcher
+                      quickstep_queryoptimizer_expressions_Predicate
+                      quickstep_queryoptimizer_physical_HashJoin
+                      quickstep_queryoptimizer_physical_PatternMatcher
+                      quickstep_queryoptimizer_physical_Physical
+                      quickstep_queryoptimizer_physical_PhysicalType
+                      quickstep_queryoptimizer_physical_TopLevelPlan
+                      quickstep_queryoptimizer_rules_Rule
+                      quickstep_utility_Macros)
 target_link_libraries(quickstep_queryoptimizer_rules_BottomUpRule
                       glog
                       quickstep_queryoptimizer_rules_Rule
@@ -187,6 +202,7 @@ target_link_libraries(quickstep_queryoptimizer_rules_UpdateExpression
 # Module all-in-one library:
 add_library(quickstep_queryoptimizer_rules ../../empty_src.cpp OptimizerRulesModule.hpp)
 target_link_libraries(quickstep_queryoptimizer_rules
+                      quickstep_queryoptimizer_rules_AttachLIPFilters
                       quickstep_queryoptimizer_rules_BottomUpRule
                       quickstep_queryoptimizer_rules_CollapseProject
                       quickstep_queryoptimizer_rules_GenerateJoins

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/utility/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/utility/CMakeLists.txt b/utility/CMakeLists.txt
index ddaae45..8a2c7ae 100644
--- a/utility/CMakeLists.txt
+++ b/utility/CMakeLists.txt
@@ -174,6 +174,7 @@ add_library(quickstep_utility_ExecutionDAGVisualizer
             ExecutionDAGVisualizer.hpp)
 add_library(quickstep_utility_Glob Glob.cpp Glob.hpp)
 add_library(quickstep_utility_HashPair ../empty_src.cpp HashPair.hpp)
+add_library(quickstep_utility_LIPFilter LIPFilter.cpp LIPFilter.hpp)
 add_library(quickstep_utility_Macros ../empty_src.cpp Macros.hpp)
 add_library(quickstep_utility_MemStream ../empty_src.cpp MemStream.hpp)
 add_library(quickstep_utility_PlanVisualizer PlanVisualizer.cpp PlanVisualizer.hpp)
@@ -244,6 +245,8 @@ target_link_libraries(quickstep_utility_ExecutionDAGVisualizer
                       quickstep_utility_StringUtil)
 target_link_libraries(quickstep_utility_Glob
                       glog)
+target_link_libraries(quickstep_utility_LIPFilter
+                      glog)
 target_link_libraries(quickstep_utility_MemStream
                       glog
                       quickstep_utility_Macros)
@@ -323,6 +326,7 @@ target_link_libraries(quickstep_utility
                       quickstep_utility_ExecutionDAGVisualizer
                       quickstep_utility_Glob
                       quickstep_utility_HashPair
+                      quickstep_utility_LIPFilter
                       quickstep_utility_Macros
                       quickstep_utility_MemStream
                       quickstep_utility_PlanVisualizer

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/utility/LIPFilter.cpp
----------------------------------------------------------------------
diff --git a/utility/LIPFilter.cpp b/utility/LIPFilter.cpp
new file mode 100644
index 0000000..f503f4f
--- /dev/null
+++ b/utility/LIPFilter.cpp
@@ -0,0 +1,24 @@
+/**
+ * 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.
+ **/
+
+#include "utility/LIPFilter.hpp"
+
+namespace quickstep {
+
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/utility/LIPFilter.hpp
----------------------------------------------------------------------
diff --git a/utility/LIPFilter.hpp b/utility/LIPFilter.hpp
new file mode 100644
index 0000000..12a19d7
--- /dev/null
+++ b/utility/LIPFilter.hpp
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ **/
+
+#ifndef QUICKSTEP_UTILITY_LIP_FILTER_HPP_
+#define QUICKSTEP_UTILITY_LIP_FILTER_HPP_
+
+#include <vector>
+
+#include "glog/logging.h"
+
+namespace quickstep {
+
+/** \addtogroup Utility
+ *  @{
+ */
+
+enum class LIPFilterType {
+  kBloomFilter,
+  kExactFilter,
+  kSingleIdentityHashFilter
+};
+
+
+/** @} */
+
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_UTILITY_LIP_FILTER_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/utility/LIPFilterAdapter.hpp
----------------------------------------------------------------------
diff --git a/utility/LIPFilterAdapter.hpp b/utility/LIPFilterAdapter.hpp
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/utility/LIPFilterBuilder.hpp
----------------------------------------------------------------------
diff --git a/utility/LIPFilterBuilder.hpp b/utility/LIPFilterBuilder.hpp
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/utility/PlanVisualizer.cpp
----------------------------------------------------------------------
diff --git a/utility/PlanVisualizer.cpp b/utility/PlanVisualizer.cpp
index 50cf7f0..929e873 100644
--- a/utility/PlanVisualizer.cpp
+++ b/utility/PlanVisualizer.cpp
@@ -21,18 +21,22 @@
 
 #include <cstddef>
 #include <memory>
+#include <set>
 #include <sstream>
 #include <string>
 #include <unordered_map>
 #include <vector>
 
 #include "catalog/CatalogRelation.hpp"
-
+#include "catalog/CatalogRelationStatistics.hpp"
+#include "catalog/CatalogTypedefs.hpp"
 #include "query_optimizer/cost_model/StarSchemaSimpleCostModel.hpp"
 #include "query_optimizer/expressions/AttributeReference.hpp"
+#include "query_optimizer/physical/Aggregate.hpp"
 #include "query_optimizer/physical/HashJoin.hpp"
 #include "query_optimizer/physical/Physical.hpp"
 #include "query_optimizer/physical/PhysicalType.hpp"
+#include "query_optimizer/physical/Selection.hpp"
 #include "query_optimizer/physical/TableReference.hpp"
 #include "query_optimizer/physical/TopLevelPlan.hpp"
 #include "utility/StringUtil.hpp"
@@ -86,6 +90,9 @@ std::string PlanVisualizer::visualize(const P::PhysicalPtr &input) {
   for (const EdgeInfo &edge_info : edges_) {
     graph_oss << "  " << edge_info.src_node_id << " -> "
               << edge_info.dst_node_id << " [";
+    if (edge_info.dashed) {
+      graph_oss << "style=dashed ";
+    }
     if (!edge_info.labels.empty()) {
       graph_oss << "label=\""
                 << EscapeSpecialChars(JoinToString(edge_info.labels, "&#10;"))
@@ -103,6 +110,10 @@ void PlanVisualizer::visit(const P::PhysicalPtr &input) {
   int node_id = ++id_counter_;
   node_id_map_.emplace(input, node_id);
 
+  std::set<E::ExprId> referenced_ids;
+  for (const auto &attr : input->getReferencedAttributes()) {
+    referenced_ids.emplace(attr->id());
+  }
   for (const auto &child : input->children()) {
     visit(child);
 
@@ -112,13 +123,11 @@ void PlanVisualizer::visit(const P::PhysicalPtr &input) {
     EdgeInfo &edge_info = edges_.back();
     edge_info.src_node_id = child_id;
     edge_info.dst_node_id = node_id;
+    edge_info.dashed = false;
 
-    // Print output attributes except for TableReference -- there are just too many
-    // attributes out of TableReference.
-    if (child->getPhysicalType() != P::PhysicalType::kTableReference) {
-      for (const auto &attr : child->getOutputAttributes()) {
-        edge_info.labels.emplace_back(attr->attribute_alias());
-      }
+    if (input->getPhysicalType() == P::PhysicalType::kHashJoin &&
+        child == input->children()[1]) {
+      edge_info.dashed = true;
     }
   }
 
@@ -154,6 +163,19 @@ void PlanVisualizer::visit(const P::PhysicalPtr &input) {
       break;
     }
   }
+
+  const auto lip_filter_conf = input->getLIPFilterConfiguration();
+  if (lip_filter_conf != nullptr) {
+    for (const auto &build_info : lip_filter_conf->getBuildInfo()) {
+      node_info.labels.emplace_back(
+          std::string("[LIP build] ") + build_info.build_attribute->attribute_alias());
+    }
+    for (const auto &probe_info : lip_filter_conf->getProbeInfo()) {
+      node_info.labels.emplace_back(
+          std::string("[LIP probe] ") + probe_info.probe_attribute->attribute_alias());
+    }
+  }
+
   node_info.labels.emplace_back(
       "est. # = " + std::to_string(cost_model_->estimateCardinality(input)));
   node_info.labels.emplace_back(

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/c311b4ba/utility/PlanVisualizer.hpp
----------------------------------------------------------------------
diff --git a/utility/PlanVisualizer.hpp b/utility/PlanVisualizer.hpp
index 1c0df77..e4e3957 100644
--- a/utility/PlanVisualizer.hpp
+++ b/utility/PlanVisualizer.hpp
@@ -73,6 +73,7 @@ class PlanVisualizer {
     int src_node_id;
     int dst_node_id;
     std::vector<std::string> labels;
+    bool dashed;
   };
 
   void visit(const optimizer::physical::PhysicalPtr &input);