You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by mb...@apache.org on 2019/10/15 14:44:42 UTC

[asterixdb] 05/06: [ASTERIXDB-2648][COMP] Fix dataset order in broadcast hint

This is an automated email from the ASF dual-hosted git repository.

mblow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git

commit 2ea7323a2a41be6cd9803450527faa9dfb9a4a6a
Author: Shiva <sh...@uci.edu>
AuthorDate: Wed Oct 9 18:04:05 2019 -0700

    [ASTERIXDB-2648][COMP] Fix dataset order in broadcast hint
    
    - user model changes: yes
    - storage format changes: no
    - interface changes: no
    
    details:
    
    - Provides hash-bcast hint to replace bcast hint which makes
    broadcast join consistent with other types of joins for choosing
    the broadcasting dataset based on dataset order in FROM clause.
    - Chooses the build dataset to get broadcast based on the order
    in the FROM clause not the WHERE clause (which was the case for
    bcast hint).
    
    Change-Id: I505fc8e0bc32c760ae0471c6b302bbfd8499be4a
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/3566
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Dmitry Lychagin <dm...@couchbase.com>
---
 .../rules/DisjunctivePredicateToJoinRule.java      |   2 +-
 .../asterix/optimizer/rules/FuzzyJoinRule.java     |   4 +-
 ...nlineLeftNtsInSubplanJoinFlatteningVisitor.java |   3 +-
 .../translator/LangExpressionToPlanTranslator.java |  19 ----
 .../resources/optimizerts/queries/fj-dblp-csx.aql  |   4 +-
 .../optimizerts/queries/fj-phase2-with-hints.aql   |   2 +-
 .../queries/hints/broadcast_hint_1.sqlpp           |   2 +-
 .../queries/hints/broadcast_hint_2.sqlpp           |   2 +-
 .../queries/hints/broadcast_hint_3.sqlpp           |   4 +-
 .../queries/joins/nested_query_with_bcast.sqlpp    |   2 +-
 .../jaccard-similarity-join-dual-order.aql         |   4 +-
 .../jaccard-similarity-join-right-ahead.aql        |   4 +-
 .../queries/tpch/q12_shipping_broadcast.sqlpp      |   2 +-
 .../queries/tpch/q12_shipping_broadcast_ps.sqlpp   |   2 +-
 .../results/hints/broadcast_hint_3.plan            |   4 +-
 .../results/joins/nested_query_with_bcast.plan     |   6 +-
 .../fuzzyjoin/basic-1_2_1/basic-1_2_1.5.query.aql  |   4 +-
 .../fuzzyjoin/basic-1_2_1/basic-1_2_1.6.query.aql  |   4 +-
 .../fuzzyjoin/basic-1_2_1/basic-1_2_1.7.query.aql  |   2 +-
 .../fuzzyjoin/basic-1_2_2/basic-1_2_2.3.query.aql  |   4 +-
 .../fuzzyjoin/basic-1_2_2/basic-1_2_2.4.query.aql  |   4 +-
 .../fuzzyjoin/basic-1_2_2/basic-1_2_2.5.query.aql  |   4 +-
 .../fuzzyjoin/basic-1_2_2/basic-1_2_2.6.query.aql  |   4 +-
 .../fuzzyjoin/basic-1_2_3/basic-1_2_3.3.query.aql  |   8 +-
 .../fuzzyjoin/basic-1_2_4/basic-1_2_4.3.query.aql  |   4 +-
 .../fuzzyjoin/basic-1_2_7/basic-1_2_7.3.query.aql  |   8 +-
 .../fuzzyjoin/basic-1_3_1/basic-1_3_1.5.query.aql  |   4 +-
 .../fuzzyjoin/basic-1_3_1/basic-1_3_1.6.query.aql  |   4 +-
 .../dblp-2.1_5.3.1/dblp-2.1_5.3.1.3.query.aql      |   2 +-
 .../fuzzyjoin/dblp-2.2/dblp-2.2.3.query.aql        |   2 +-
 .../fuzzyjoin/dblp-2_5.2/dblp-2_5.2.3.query.aql    |   2 +-
 .../dblp-2_5.3.1/dblp-2_5.3.1.3.query.aql          |   2 +-
 .../fuzzyjoin/dblp-2_5.3/dblp-2_5.3.3.query.aql    |   2 +-
 .../fuzzyjoin/dblp-3_1.2/dblp-3_1.2.3.query.aql    |   4 +-
 .../dblp-csx-2_5.3.1/dblp-csx-2_5.3.1.3.query.aql  |   4 +-
 .../dblp-csx-2_5.3/dblp-csx-2_5.3.3.query.aql      |   4 +-
 .../dblp-csx-3_5.2/dblp-csx-3_5.2.3.query.aql      |   4 +-
 .../dblp-csx-3_5.3.1/dblp-csx-3_5.3.1.3.query.aql  |   4 +-
 .../dblp-csx-3_5.3/dblp-csx-3_5.3.3.query.aql      |   4 +-
 .../dblp-csx-3_5.4.1/dblp-csx-3_5.4.1.3.query.aql  |   4 +-
 .../dblp-csx-3_5.4/dblp-csx-3_5.4.3.query.aql      |   4 +-
 .../q12_shipping_broadcast.3.query.sqlpp           |   2 +-
 .../test/resources/runtimets/testsuite_sqlpp.xml   |   4 +-
 asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj  |  23 ++---
 .../lang/common/expression/OperatorExpr.java       |  32 +-----
 .../CloneAndSubstituteVariablesVisitor.java        |   2 +-
 .../asterix/lang/sqlpp/parser/SqlppHint.java       |   2 +-
 .../lang/sqlpp/visitor/DeepCopyVisitor.java        |   4 +-
 .../asterix-lang-sqlpp/src/main/javacc/SQLPP.jj    |  13 +--
 .../expressions/BroadcastExpressionAnnotation.java |  15 +--
 .../visitors/BroadcastSideSwitchingVisitor.java    | 108 +++++++++++++++++++++
 .../algebricks/rewriter/util/JoinUtils.java        |  54 +++--------
 52 files changed, 225 insertions(+), 196 deletions(-)

diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
index 7bfe6a4..916fd75 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
@@ -162,7 +162,7 @@ public class DisjunctivePredicateToJoinRule implements IAlgebraicRewriteRule {
                 IndexedNLJoinExpressionAnnotation.INSTANCE);
         BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation();
         bcast.setObject(BroadcastExpressionAnnotation.BroadcastSide.LEFT); // Broadcast the OR predicates branch.
-        eqExp.getAnnotations().put(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY, bcast);
+        eqExp.getAnnotations().put(bcast, bcast);
 
         InnerJoinOperator jOp = new InnerJoinOperator(new MutableObject<>(eqExp));
         jOp.setSourceLocation(sourceLoc);
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyJoinRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyJoinRule.java
index dabfb82..cc91c06 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyJoinRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyJoinRule.java
@@ -106,7 +106,7 @@ public class FuzzyJoinRule implements IAlgebraicRewriteRule {
             //
             // -- -- -- -
             //
-            + "        where $token = /*+ bcast */ $tokenRanked " + "order by $i " + "return $i "
+            + "        where $token = /*+ hash-bcast */ $tokenRanked " + "order by $i " + "return $i "
             + "      for $prefixTokenRight in subset-collection($tokensRight, 0, prefix-len-%s(len($tokensRight), %ff)) "
             + "      ), " + "( " + "##LEFT_1 " + "let $tokensUnrankedLeft := %s($$LEFT_1) "
             + "      let $lenLeft := len($tokensUnrankedLeft) " + "let $tokensLeft := "
@@ -119,7 +119,7 @@ public class FuzzyJoinRule implements IAlgebraicRewriteRule {
             //
             // -- -- -- -
             //
-            + "        where $token = /*+ bcast */ $tokenRanked " + "order by $i " + "return $i "
+            + "        where $token = /*+ hash-bcast */ $tokenRanked " + "order by $i " + "return $i "
             // We use the input string $tokensUnrankedLeft instead of $tokensLeft to ensure it will not miss similar
             // pairs when the prefix of S has been reduced in case of R ~= S, where some tokens are in S but not in R.
             + "      let $actualPreLen := prefix-len-%s(len($tokensUnrankedLeft), %ff) - $lenLeft + len($tokensLeft) "
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/subplan/InlineLeftNtsInSubplanJoinFlatteningVisitor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/subplan/InlineLeftNtsInSubplanJoinFlatteningVisitor.java
index 8123fcc..12596ff 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/subplan/InlineLeftNtsInSubplanJoinFlatteningVisitor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/subplan/InlineLeftNtsInSubplanJoinFlatteningVisitor.java
@@ -66,6 +66,7 @@ import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOper
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.WindowOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.BroadcastSideSwitchingVisitor;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
 import org.apache.hyracks.algebricks.core.algebra.visitors.IQueryOperatorVisitor;
 
@@ -186,6 +187,7 @@ class InlineLeftNtsInSubplanJoinFlatteningVisitor implements IQueryOperatorVisit
             Mutable<ILogicalOperator> rightBranch = op.getInputs().get(1);
             op.getInputs().set(0, rightBranch);
             op.getInputs().set(1, leftBranch);
+            op.getCondition().getValue().accept(BroadcastSideSwitchingVisitor.getInstance(), null);
         }
         AbstractBinaryJoinOperator returnOp = op;
         // After rewriting, the original inner join should become an left outer join.
@@ -419,5 +421,4 @@ class InlineLeftNtsInSubplanJoinFlatteningVisitor implements IQueryOperatorVisit
         joinOp.getInputs().set(1, new MutableObject<ILogicalOperator>(assignOp));
         nullCheckVars.add(assignVar);
     }
-
 }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index adc6853..5851467 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -116,8 +116,6 @@ import org.apache.hyracks.algebricks.core.algebra.base.OperatorAnnotations;
 import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression.FunctionKind;
 import org.apache.hyracks.algebricks.core.algebra.expressions.AggregateFunctionCallExpression;
-import org.apache.hyracks.algebricks.core.algebra.expressions.BroadcastExpressionAnnotation;
-import org.apache.hyracks.algebricks.core.algebra.expressions.BroadcastExpressionAnnotation.BroadcastSide;
 import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
 import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
@@ -1181,35 +1179,18 @@ class LangExpressionToPlanTranslator
             // now look at the operator
             if (i < nOps) {
                 OperatorType opType = ops.get(i);
-                boolean isCmpOp = OperatorExpr.opIsComparison(opType);
                 AbstractFunctionCallExpression f = createFunctionCallExpressionForBuiltinOperator(opType, sourceLoc);
-
                 // chain the operators
                 if (i == 0) {
                     f.getArguments().add(new MutableObject<>(e));
                     currExpr = f;
-                    if (isCmpOp && op.isBroadcastOperand(i)) {
-                        BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation();
-                        bcast.setObject(BroadcastSide.LEFT);
-                        f.getAnnotations().put(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY, bcast);
-                    }
                 } else {
                     currExpr.getArguments().add(new MutableObject<>(e));
                     f.getArguments().add(new MutableObject<>(currExpr));
                     currExpr = f;
-                    if (isCmpOp && i == 1 && op.isBroadcastOperand(i)) {
-                        BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation();
-                        bcast.setObject(BroadcastSide.RIGHT);
-                        f.getAnnotations().put(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY, bcast);
-                    }
                 }
             } else { // don't forget the last expression...
                 currExpr.getArguments().add(new MutableObject<>(e));
-                if (i == 1 && op.isBroadcastOperand(i)) {
-                    BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation();
-                    bcast.setObject(BroadcastSide.RIGHT);
-                    currExpr.getAnnotations().put(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY, bcast);
-                }
             }
         }
 
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/fj-dblp-csx.aql b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/fj-dblp-csx.aql
index a79afdb..c86c8b9 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/fj-dblp-csx.aql
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/fj-dblp-csx.aql
@@ -65,7 +65,7 @@ let $tokensDBLP :=
         /*+ inmem 16 16384 */
         order by count($id), $tokenGroupped
         return $tokenGroupped
-    where $token = /*+ bcast */ $tokenRanked
+    where $token = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 for $prefixTokenDBLP in subset-collection($tokensDBLP, 0, prefix-len-jaccard(len($tokensDBLP), .8f))
@@ -88,7 +88,7 @@ let $tokensCSX :=
         /*+ inmem 16 16384 */
         order by count($id), $tokenGroupped
         return $tokenGroupped
-    where $token = /*+ bcast */ $tokenRanked
+    where $token = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 let $actualPrefixLen := prefix-len-jaccard(len($unrankedTokensCSX), .8f) - len($unrankedTokensCSX) + len($tokensCSX)
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/fj-phase2-with-hints.aql b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/fj-phase2-with-hints.aql
index 47533a7..6e52a08 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/fj-phase2-with-hints.aql
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/fj-phase2-with-hints.aql
@@ -55,7 +55,7 @@ write output to asterix_nc1:'rttest/fuzzyjoin_078.adm';
             /*+ inmem 1 302 */
             order by count($paper), $tokenGroupped
             return $tokenGroupped
-        where $token = /*+ bcast */ $tokenRanked
+        where $token = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     order by $paperDBLP.id
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_1.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_1.sqlpp
index 02ba35d..f33230c 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_1.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_1.sqlpp
@@ -42,5 +42,5 @@ create  dataset t2(TT) primary key c_key;
 
 select t1.c_4 as c0, t2.c_4 as c1
 from t1 join t2
-on t1.c_1 = t2.c_1 and t1.c_2 /*+ bcast */ = t2.c_2 and t1.c_3 = t2.c_3
+on t1.c_1 = t2.c_1 and t1.c_2 /*+ hash-bcast */ = t2.c_2 and t1.c_3 = t2.c_3
 ;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_2.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_2.sqlpp
index 1feb21f..8d0279c 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_2.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_2.sqlpp
@@ -42,5 +42,5 @@ create  dataset t2(TT) primary key c_key;
 
 select t1.c_4 as c0, t2.c_4 as c1
 from t1 join t2
-on t1.c_1 /*+ bcast */ = t2.c_1 and t1.c_2 /*+ bcast */ = t2.c_2 and t1.c_3 /*+ bcast */ = t2.c_3
+on t1.c_1 /*+ hash-bcast */ = t2.c_1 and t1.c_2 /*+ hash-bcast */ = t2.c_2 and t1.c_3 /*+ bcast */ = t2.c_3
 ;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_3.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_3.sqlpp
index a3fd4f6..f48433e 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_3.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/hints/broadcast_hint_3.sqlpp
@@ -18,7 +18,7 @@
  */
 /*
 * Description  : Test broadcast join hint
-*                Incompatible broadcast sides -> no broadcast
+*                Different operand order in where clause -> Successful broadcast
 * Expected Res : Success
 * Date         : 09/22/2017
 */
@@ -42,5 +42,5 @@ create  dataset t2(TT) primary key c_key;
 
 select t1.c_4 as c0, t2.c_4 as c1
 from t1 join t2
-on t1.c_1 /*+ bcast */ = t2.c_1 and t1.c_2 /*+ bcast */ = t2.c_2 and t2.c_3 /*+ bcast */ = t1.c_3
+on t1.c_1 /*+ hash-bcast */ = t2.c_1 and t1.c_2 /*+ hash-bcast */ = t2.c_2 and t2.c_3 /*+ hash-bcast */ = t1.c_3
 ;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/joins/nested_query_with_bcast.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/joins/nested_query_with_bcast.sqlpp
index 8e7a6e0..2232406 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/joins/nested_query_with_bcast.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/joins/nested_query_with_bcast.sqlpp
@@ -38,4 +38,4 @@ create dataset targetDataset(StoredTweetType) primary key tid autogenerated;
 create dataset countryDataset(Country) primary key country_code;
 create dataset tweetDataset(TweetType) primary key id;
 
-insert into targetDataset (select object_merge(x, {"full-country" : (select value c.country_name from countryDataset c where c.country_code /*+ bcast */ = x.country )}) from tweetDataset x);
\ No newline at end of file
+insert into targetDataset (select object_merge(x, {"full-country" : (select value c.country_name from countryDataset c where c.country_code /*+ hash-bcast */ = x.country )}) from tweetDataset x);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/similarity/jaccard-similarity-join-dual-order.aql b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/similarity/jaccard-similarity-join-dual-order.aql
index d3da872..ca88a9e 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/similarity/jaccard-similarity-join-dual-order.aql
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/similarity/jaccard-similarity-join-dual-order.aql
@@ -65,7 +65,7 @@ let $tokensRight :=
         /*+ inmem 1 302 */ order by $r.rc * $l.lc
         return $r.rt
 
-    where $tokenUnranked = /*+ bcast */ $tokenRanked
+    where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 for $prefixTokenRight in subset-collection($tokensRight, 0, prefix-len-jaccard(len($tokensRight), .8f))
@@ -96,7 +96,7 @@ let $tokensLeft :=
         /*+ inmem 1 302 */ order by $r.rc * $l.lc
         return $r.rt
 
-    where $tokenUnranked = /*+ bcast */ $tokenRanked
+    where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 let $actualPrefixLen := prefix-len-jaccard(len($tokensUnrankedLeft), .8f) - len($tokensUnrankedLeft) + len($tokensLeft)
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/similarity/jaccard-similarity-join-right-ahead.aql b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/similarity/jaccard-similarity-join-right-ahead.aql
index 661ce00..20f6912 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/similarity/jaccard-similarity-join-right-ahead.aql
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/similarity/jaccard-similarity-join-right-ahead.aql
@@ -55,7 +55,7 @@ let $tokensRight :=
             /*+ hash */ group by $tokenRightGrouped := $orderTokenRight with $rightId
         /*+ inmem 1 302 */ order by count($rightId)
         return $tokenRightGrouped
-    where $tokenUnranked = /*+ bcast */ $tokenRanked
+    where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 for $prefixTokenRight in subset-collection($tokensRight, 0, prefix-len-jaccard(len($tokensRight), .8f))
@@ -76,7 +76,7 @@ let $tokensLeft :=
             /*+ hash */ group by $tokenRightGrouped := $orderTokenRight with $rightId
         /*+ inmem 1 302 */ order by count($rightId)
         return $tokenRightGrouped
-    where $tokenUnranked = /*+ bcast */ $tokenRanked
+    where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 let $actualPrefixLen := prefix-len-jaccard(len($tokensUnrankedLeft), .8f) - len($tokensUnrankedLeft) + len($tokensLeft)
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q12_shipping_broadcast.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q12_shipping_broadcast.sqlpp
index 9add5d3..bc86998 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q12_shipping_broadcast.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q12_shipping_broadcast.sqlpp
@@ -48,7 +48,7 @@ SELECT l.l_shipmode,
            END) low_line_count
 FROM  LineItem l,
       Orders o
-WHERE l.l_orderkey /*+ bcast */ = o.o_orderkey AND l.l_commitdate < l.l_receiptdate AND
+WHERE l.l_orderkey /*+ hash-bcast */ = o.o_orderkey AND l.l_commitdate < l.l_receiptdate AND
       l.l_shipdate < l.l_commitdate AND l.l_receiptdate >= '1994-01-01' AND
       l.l_receiptdate < '1995-01-01' AND (l.l_shipmode = 'MAIL' OR l.l_shipmode = 'SHIP')
 GROUP BY l.l_shipmode
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q12_shipping_broadcast_ps.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q12_shipping_broadcast_ps.sqlpp
index 6c55128..e9a53c2 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q12_shipping_broadcast_ps.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/tpch/q12_shipping_broadcast_ps.sqlpp
@@ -46,7 +46,7 @@ SELECT l.l_shipmode,
            END) low_line_count
 FROM  LineItem l,
       Orders o
-WHERE l.l_orderkey /*+ bcast */ = o.o_orderkey AND l.l_commitdate < l.l_receiptdate AND
+WHERE l.l_orderkey /*+ hash-bcast */ = o.o_orderkey AND l.l_commitdate < l.l_receiptdate AND
       l.l_shipdate < l.l_commitdate AND l.l_receiptdate >= '1994-01-01' AND
       l.l_receiptdate < '1995-01-01' AND (l.l_shipmode = 'MAIL' OR l.l_shipmode = 'SHIP')
 GROUP BY l.l_shipmode
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/hints/broadcast_hint_3.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/hints/broadcast_hint_3.plan
index 1e45c0c..8ff31de 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results/hints/broadcast_hint_3.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/hints/broadcast_hint_3.plan
@@ -5,7 +5,7 @@
         -- STREAM_PROJECT  |PARTITIONED|
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
             -- HYBRID_HASH_JOIN [$$37, $$40, $$41][$$38, $$39, $$42]  |PARTITIONED|
-              -- HASH_PARTITION_EXCHANGE [$$37, $$40, $$41]  |PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                 -- STREAM_PROJECT  |PARTITIONED|
                   -- ASSIGN  |PARTITIONED|
                     -- STREAM_PROJECT  |PARTITIONED|
@@ -13,7 +13,7 @@
                         -- DATASOURCE_SCAN  |PARTITIONED|
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                             -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-              -- HASH_PARTITION_EXCHANGE [$$38, $$39, $$42]  |PARTITIONED|
+              -- BROADCAST_EXCHANGE  |PARTITIONED|
                 -- STREAM_PROJECT  |PARTITIONED|
                   -- ASSIGN  |PARTITIONED|
                     -- STREAM_PROJECT  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/joins/nested_query_with_bcast.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/joins/nested_query_with_bcast.plan
index cb1184e..68222ed 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results/joins/nested_query_with_bcast.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/joins/nested_query_with_bcast.plan
@@ -20,17 +20,17 @@
                                     }
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                 -- STABLE_SORT [$$36(ASC)]  |PARTITIONED|
-                                  -- HASH_PARTITION_EXCHANGE [$$36]  |PARTITIONED|
+                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                     -- STREAM_PROJECT  |PARTITIONED|
                                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                         -- HYBRID_HASH_JOIN [$$39][$$37]  |PARTITIONED|
-                                          -- HASH_PARTITION_EXCHANGE [$$39]  |PARTITIONED|
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                             -- ASSIGN  |PARTITIONED|
                                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                                 -- DATASOURCE_SCAN  |PARTITIONED|
                                                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                                     -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                          -- BROADCAST_EXCHANGE  |PARTITIONED|
                                             -- STREAM_PROJECT  |PARTITIONED|
                                               -- ASSIGN  |PARTITIONED|
                                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.5.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.5.query.aql
index 9696695..7ae1beb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.5.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.5.query.aql
@@ -39,7 +39,7 @@ let $tokenLeftVerify := (
             for $token in $tokenUnrankedLeft
             let $index :=
                 for $tokenRanked at $i in $rankedTokens
-                    where $token = /*+ bcast */ $tokenRanked
+                    where $token = /*+ hash-bcast */ $tokenRanked
                 return $i
             order by $index
             return $index
@@ -54,7 +54,7 @@ let $tokenLeft := (
         let $lenLeft := len($tokenUnrankedLeft)
         for $token in $tokenUnrankedLeft
         for $tokenRanked at $i in $rankedTokens
-            where $token = /*+ bcast */ $tokenRanked
+            where $token = /*+ hash-bcast */ $tokenRanked
         order by $i
     return $i
 )
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.6.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.6.query.aql
index 310caa9..caed85c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.6.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.6.query.aql
@@ -38,7 +38,7 @@ let $tokenRightVerify := (
             for $token in $tokenUnrankedLeft
             let $index :=
                 for $tokenRanked at $i in $rankedTokens
-                    where $token = /*+ bcast */ $tokenRanked
+                    where $token = /*+ hash-bcast */ $tokenRanked
                 return $i
             order by $index
             return $index
@@ -51,7 +51,7 @@ let $tokenRight := (
         let $tokenUnrankedRight := word-tokens($right.authors)
         for $token in $tokenUnrankedRight
         for $tokenRanked at $i in $rankedTokens
-            where $token = /*+ bcast */ $tokenRanked
+            where $token = /*+ hash-bcast */ $tokenRanked
         order by $i
     return $i
 )
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.7.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.7.query.aql
index 4e51613..82e6189 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.7.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_1/basic-1_2_1.7.query.aql
@@ -38,7 +38,7 @@ for $paperDBLP in dataset('right')
                 /*+ inmem 1 302 */
                 order by count($id), $tokenGrouped
                 return $tokenGrouped
-            where $tokenUnranked = /*+ bcast */ $tokenRanked
+            where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
             return $i
         order by $index[0]
         return $index[0]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.3.query.aql
index 510c1f0..10bc05f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.3.query.aql
@@ -39,7 +39,7 @@ let $r := count(
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection($tokensDBLP, 0, prefix-len-jaccard(len($tokensDBLP), .8f))
@@ -62,7 +62,7 @@ let $r := count(
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenCSX in subset-collection($tokensCSX, 0, prefix-len-jaccard(len($tokensCSX), .8f))
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.4.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.4.query.aql
index b903881..3d440dd 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.4.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.4.query.aql
@@ -39,7 +39,7 @@ let $s := count(
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection($tokensDBLP, 0, prefix-len-jaccard(len($tokensDBLP), .8f))
@@ -62,7 +62,7 @@ let $s := count(
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     let $actualPrefixLen := prefix-len-jaccard(len($tokensUnrankedCSX), .8f) - len($tokensUnrankedCSX) + len($tokensCSX)
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.5.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.5.query.aql
index 119520a..fb0391c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.5.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.5.query.aql
@@ -39,7 +39,7 @@ let $t := count(
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection($tokensDBLP, 0, prefix-len-jaccard(len($tokensDBLP), .8f))
@@ -62,7 +62,7 @@ let $t := count(
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     let $actualPrefixLen := prefix-len-jaccard(len($tokensUnrankedCSX), .8f) - len($tokensUnrankedCSX) + len($tokensCSX)
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.6.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.6.query.aql
index 465cda9..92cea6f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.6.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_2/basic-1_2_2.6.query.aql
@@ -38,7 +38,7 @@ let $tokensDBLP :=
         /*+ inmem 1 302 */
         order by count($id), $tokenGrouped
         return $tokenGrouped
-    where $tokenUnranked = /*+ bcast */ $tokenRanked
+    where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 for $prefixTokenDBLP in subset-collection($tokensDBLP, 0, prefix-len-jaccard(len($tokensDBLP), .8f))
@@ -61,7 +61,7 @@ let $tokensCSX :=
         /*+ inmem 1 302 */
         order by count($id), $tokenGrouped
         return $tokenGrouped
-    where $tokenUnranked = /*+ bcast */ $tokenRanked
+    where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 let $actualPrefixLen := prefix-len-jaccard(len($tokensUnrankedCSX), .8f) - len($tokensUnrankedCSX) + len($tokensCSX)
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_3/basic-1_2_3.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_3/basic-1_2_3.3.query.aql
index 009c2b9..dc4bf72 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_3/basic-1_2_3.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_3/basic-1_2_3.3.query.aql
@@ -69,10 +69,10 @@ where count($d.simpairs) = 0
     let $sstr := for $t in word-tokens($d.sstr) order by $t return $t
     let $rlen := len(for $t in word-tokens($d.rstr) order by $t return $t)
     let $slen := len(for $t in word-tokens($d.sstr) order by $t return $t)
-    let $orstr := for $t in word-tokens($d.rstr) for $token at $i in $orderedTokens where $t /*+ bcast */ = $token order by $i return $i
-    let $osstr := for $t in word-tokens($d.sstr) for $token at $i in $orderedTokens where $t /*+ bcast */ = $token order by $i return $i
-    let $lorstr := len(for $t in word-tokens($d.rstr) for $token at $i in $orderedTokens where $t /*+ bcast */ = $token order by $i return $i)
-    let $losstr := len(for $t in word-tokens($d.sstr) for $token at $i in $orderedTokens where $t /*+ bcast */ = $token order by $i return $i)
+    let $orstr := for $t in word-tokens($d.rstr) for $token at $i in $orderedTokens where $t /*+ hash-bcast */ = $token order by $i return $i
+    let $osstr := for $t in word-tokens($d.sstr) for $token at $i in $orderedTokens where $t /*+ hash-bcast */ = $token order by $i return $i
+    let $lorstr := len(for $t in word-tokens($d.rstr) for $token at $i in $orderedTokens where $t /*+ hash-bcast */ = $token order by $i return $i)
+    let $losstr := len(for $t in word-tokens($d.sstr) for $token at $i in $orderedTokens where $t /*+ hash-bcast */ = $token order by $i return $i)
 return {
         "rid": $rid,
         "sid": $sid,
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_4/basic-1_2_4.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_4/basic-1_2_4.3.query.aql
index b6976bd..9a82b6e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_4/basic-1_2_4.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_4/basic-1_2_4.3.query.aql
@@ -41,7 +41,7 @@ let $tokensLeft :=
         /*+ inmem 1 302 */
         order by count($id), $tokenGrouped
         return $tokenGrouped
-    where $tokenUnranked = /*+ bcast */ $tokenRanked
+    where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 
@@ -60,7 +60,7 @@ let $tokensRight :=
         /*+ inmem 1 302 */
         order by count($id), $tokenGrouped
         return $tokenGrouped
-    where $tokenUnranked = /*+ bcast */ $tokenRanked
+    where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
     order by $i
     return $i
 
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_7/basic-1_2_7.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_7/basic-1_2_7.3.query.aql
index 597e8a1..a8aee97 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_7/basic-1_2_7.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_2_7/basic-1_2_7.3.query.aql
@@ -69,10 +69,10 @@ where count($d.simpairs) = 0
     let $sstr := for $t in word-tokens($d.sstr) order by $t return $t
     let $rlen := len(for $t in word-tokens($d.rstr) order by $t return $t)
     let $slen := len(for $t in word-tokens($d.sstr) order by $t return $t)
-    let $orstr := for $t in word-tokens($d.rstr) for $token at $i in $orderedTokens where $t /*+ bcast */ = $token order by $i return $i
-    let $osstr := for $t in word-tokens($d.sstr) for $token at $i in $orderedTokens where $t /*+ bcast */ = $token order by $i return $i
-    let $lorstr := len(for $t in word-tokens($d.rstr) for $token at $i in $orderedTokens where $t /*+ bcast */ = $token order by $i return $i)
-    let $losstr := len(for $t in word-tokens($d.sstr) for $token at $i in $orderedTokens where $t /*+ bcast */ = $token order by $i return $i)
+    let $orstr := for $t in word-tokens($d.rstr) for $token at $i in $orderedTokens where $t /*+ hash-bcast */ = $token order by $i return $i
+    let $osstr := for $t in word-tokens($d.sstr) for $token at $i in $orderedTokens where $t /*+ hash-bcast */ = $token order by $i return $i
+    let $lorstr := len(for $t in word-tokens($d.rstr) for $token at $i in $orderedTokens where $t /*+ hash-bcast */ = $token order by $i return $i)
+    let $losstr := len(for $t in word-tokens($d.sstr) for $token at $i in $orderedTokens where $t /*+ hash-bcast */ = $token order by $i return $i)
 return {
         "rid": $rid,
         "sid": $sid,
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_3_1/basic-1_3_1.5.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_3_1/basic-1_3_1.5.query.aql
index ad93db1..f8d75e6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_3_1/basic-1_3_1.5.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_3_1/basic-1_3_1.5.query.aql
@@ -37,7 +37,7 @@ let $r := count(
                 /*+ hash */ group by $tokenRightGrouped := $orderTokenRight with $rightId
             /*+ inmem 1 302 */ order by count($rightId)
             return $tokenRightGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenRight in subset-collection($tokensRight, 0, prefix-len-jaccard(len($tokensRight), .8f))
@@ -58,7 +58,7 @@ let $r := count(
                 /*+ hash */ group by $tokenRightGrouped := $orderTokenRight with $rightId
             /*+ inmem 1 302 */ order by count($rightId)
             return $tokenRightGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     let $actualPrefixLen := prefix-len-jaccard(len($tokensUnrankedLeft), .8f) - len($tokensUnrankedLeft) + len($tokensLeft)
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_3_1/basic-1_3_1.6.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_3_1/basic-1_3_1.6.query.aql
index 5594de3..273c270 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_3_1/basic-1_3_1.6.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/basic-1_3_1/basic-1_3_1.6.query.aql
@@ -47,7 +47,7 @@ let $r := count(
             /*+ inmem 1 302 */ order by $r.rc * $l.lc
             return $r.rt
 
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenRight in subset-collection($tokensRight, 0, prefix-len-jaccard(len($tokensRight), .8f))
@@ -78,7 +78,7 @@ let $r := count(
             /*+ inmem 1 302 */ order by $r.rc * $l.lc
             return $r.rt
 
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     let $actualPrefixLen := prefix-len-jaccard(len($tokensUnrankedLeft), .8f) - len($tokensUnrankedLeft) + len($tokensLeft)
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2.1_5.3.1/dblp-2.1_5.3.1.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2.1_5.3.1/dblp-2.1_5.3.1.3.query.aql
index f227271..c189503 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2.1_5.3.1/dblp-2.1_5.3.1.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2.1_5.3.1/dblp-2.1_5.3.1.3.query.aql
@@ -39,7 +39,7 @@ set import-private-functions 'true';
             /*+ inmem 1 302 */
             order by count($id), $tokenGroupped
             return $tokenGroupped
-        where $tokenUnranked = /*+ bcast*/ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast*/ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2.2/dblp-2.2.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2.2/dblp-2.2.3.query.aql
index ab85714..84a1d4f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2.2/dblp-2.2.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2.2/dblp-2.2.3.query.aql
@@ -29,7 +29,7 @@ set import-private-functions 'true';
     let $tokensDBLP :=
         for $tokenUnranked in $tokensUnrankedDBLP
         for $tokenRanked in dataset('TOKENSRANKEDADM')
-        where $tokenUnranked = /*+ bcast*/ $tokenRanked.token
+        where $tokenUnranked = /*+ hash-bcast*/ $tokenRanked.token
         order by $tokenRanked.rank
         return $tokenRanked.rank
     for $prefixTokenDBLP in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.2/dblp-2_5.2.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.2/dblp-2_5.2.3.query.aql
index 3bf04f9..335b0c5 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.2/dblp-2_5.2.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.2/dblp-2_5.2.3.query.aql
@@ -39,7 +39,7 @@ set import-private-functions 'true';
             group by $tokenGrouped := $token with $id
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast*/ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast*/ $tokenRanked
         order by $i
         return $i
     order by $idDBLP
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.3.1/dblp-2_5.3.1.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.3.1/dblp-2_5.3.1.3.query.aql
index d07f2ff..2c76d3f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.3.1/dblp-2_5.3.1.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.3.1/dblp-2_5.3.1.3.query.aql
@@ -40,7 +40,7 @@ set import-private-functions 'true';
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast*/ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast*/ $tokenRanked
         order by $i
         return $i
     order by $idDBLP
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.3/dblp-2_5.3.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.3/dblp-2_5.3.3.query.aql
index d07f2ff..2c76d3f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.3/dblp-2_5.3.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-2_5.3/dblp-2_5.3.3.query.aql
@@ -40,7 +40,7 @@ set import-private-functions 'true';
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast*/ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast*/ $tokenRanked
         order by $i
         return $i
     order by $idDBLP
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-3_1.2/dblp-3_1.2.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-3_1.2/dblp-3_1.2.3.query.aql
index 938cc7a..cc3eccc 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-3_1.2/dblp-3_1.2.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-3_1.2/dblp-3_1.2.3.query.aql
@@ -40,7 +40,7 @@ for $ridpair in
             group by $tokenGroupped := $token with $paper
             order by count($paper), $tokenGroupped
             return $tokenGroupped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenLeft in subset-collection(
@@ -62,7 +62,7 @@ for $ridpair in
             group by $tokenGroupped := $token with $paper
             order by count($paper), $tokenGroupped
             return $tokenGroupped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenRight in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-2_5.3.1/dblp-csx-2_5.3.1.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-2_5.3.1/dblp-csx-2_5.3.1.3.query.aql
index b552dd1..c085e8e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-2_5.3.1/dblp-csx-2_5.3.1.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-2_5.3.1/dblp-csx-2_5.3.1.3.query.aql
@@ -40,7 +40,7 @@ set import-private-functions 'true';
             /*+ inmem 1 302 */
             order by count($id), $tokenGroupped
             return $tokenGroupped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection(
@@ -66,7 +66,7 @@ set import-private-functions 'true';
             /*+ inmem 1 302 */
             order by count($id), $tokenGroupped
             return $tokenGroupped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenCSX in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-2_5.3/dblp-csx-2_5.3.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-2_5.3/dblp-csx-2_5.3.3.query.aql
index e095fa3..d2b026b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-2_5.3/dblp-csx-2_5.3.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-2_5.3/dblp-csx-2_5.3.3.query.aql
@@ -40,7 +40,7 @@ set import-private-functions 'true';
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection(
@@ -66,7 +66,7 @@ set import-private-functions 'true';
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenCSX in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.2/dblp-csx-3_5.2.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.2/dblp-csx-3_5.2.3.query.aql
index dd9b3b7..ee73947 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.2/dblp-csx-3_5.2.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.2/dblp-csx-3_5.2.3.query.aql
@@ -43,7 +43,7 @@ for $ridpair in
             group by $tokenGrouped := $token with $id
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection(
@@ -68,7 +68,7 @@ for $ridpair in
             group by $tokenGrouped := $token with $id
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenCSX in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.3.1/dblp-csx-3_5.3.1.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.3.1/dblp-csx-3_5.3.1.3.query.aql
index ebe7ab0..857b5b3 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.3.1/dblp-csx-3_5.3.1.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.3.1/dblp-csx-3_5.3.1.3.query.aql
@@ -44,7 +44,7 @@ for $ridpair in
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection(
@@ -70,7 +70,7 @@ for $ridpair in
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenCSX in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.3/dblp-csx-3_5.3.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.3/dblp-csx-3_5.3.3.query.aql
index eacdd2e..3a45ff5 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.3/dblp-csx-3_5.3.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.3/dblp-csx-3_5.3.3.query.aql
@@ -44,7 +44,7 @@ for $ridpair in
             /*+ inmem 1 302 */
             order by count($id), $tokenGroupped
             return $tokenGroupped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection(
@@ -70,7 +70,7 @@ for $ridpair in
             /*+ inmem 1 302 */
             order by count($id), $tokenGroupped
             return $tokenGroupped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenCSX in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.4.1/dblp-csx-3_5.4.1.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.4.1/dblp-csx-3_5.4.1.3.query.aql
index c0fc0f0..4e3a821 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.4.1/dblp-csx-3_5.4.1.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.4.1/dblp-csx-3_5.4.1.3.query.aql
@@ -47,7 +47,7 @@ for $ridpair in
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection(
@@ -73,7 +73,7 @@ for $ridpair in
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenCSX in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.4/dblp-csx-3_5.4.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.4/dblp-csx-3_5.4.3.query.aql
index 6706129..872d1c7 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.4/dblp-csx-3_5.4.3.query.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-csx-3_5.4/dblp-csx-3_5.4.3.query.aql
@@ -47,7 +47,7 @@ for $ridpair in
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenDBLP in subset-collection(
@@ -73,7 +73,7 @@ for $ridpair in
             /*+ inmem 1 302 */
             order by count($id), $tokenGrouped
             return $tokenGrouped
-        where $tokenUnranked = /*+ bcast */ $tokenRanked
+        where $tokenUnranked = /*+ hash-bcast */ $tokenRanked
         order by $i
         return $i
     for $prefixTokenCSX in subset-collection(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/tpch-sql-sugar/q12_shipping_broadcast/q12_shipping_broadcast.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/tpch-sql-sugar/q12_shipping_broadcast/q12_shipping_broadcast.3.query.sqlpp
index 28c9a9b..c61357c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/tpch-sql-sugar/q12_shipping_broadcast/q12_shipping_broadcast.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/tpch-sql-sugar/q12_shipping_broadcast/q12_shipping_broadcast.3.query.sqlpp
@@ -25,7 +25,7 @@ SELECT l_shipmode,
        sum(CASE o.o_orderpriority = '1-URGENT' or o.o_orderpriority = '2-HIGH' WHEN true THEN 0 ELSE 1 END) low_line_count
 FROM  LineItem l,
       Orders o
-WHERE l.l_orderkey /*+ bcast */ = o.o_orderkey AND l.l_commitdate < l.l_receiptdate AND
+WHERE l.l_orderkey /*+ hash-bcast */ = o.o_orderkey AND l.l_commitdate < l.l_receiptdate AND
       l.l_shipdate < l.l_commitdate AND l.l_receiptdate >= '1994-01-01' AND
       l.l_receiptdate < '1995-01-01' AND (l.l_shipmode = 'MAIL' OR l.l_shipmode = 'SHIP')
 GROUP BY l.l_shipmode
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 4dce07f..0f82c9e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -12489,7 +12489,7 @@
         <output-dir compare="Text">inapplicable-hint-warning</output-dir>
         <expected-warn>HYR10006: Could not apply Group By hint: hash</expected-warn>
         <expected-warn>ASX1107: Unexpected hint: indexnl. "hash" expected at this location</expected-warn>
-        <expected-warn>ASX1107: Unexpected hint: hash. "indexnl", "skip-index", "bcast" expected at this location</expected-warn>
+        <expected-warn>ASX1107: Unexpected hint: hash. "indexnl", "skip-index", "hash-bcast" expected at this location</expected-warn>
         <expected-warn>ASX1107: Unexpected hint: auto. "indexnl", "skip-index" expected at this location</expected-warn>
         <expected-warn>ASX1107: Unexpected hint: hash. "indexnl", "skip-index" expected at this location</expected-warn>
         <expected-warn>ASX1107: Unexpected hint: hash. None expected at this location</expected-warn>
@@ -12512,7 +12512,7 @@
       <compilation-unit name="unknown-hint-warning">
         <output-dir compare="Text">unknown-hint-warning</output-dir>
         <expected-warn>ASX1107: Unexpected hint: unknown_hint_groupby. "hash" expected at this location</expected-warn>
-        <expected-warn>ASX1107: Unexpected hint: unknown_hint_relexpr. "indexnl", "skip-index", "bcast" expected at this location</expected-warn>
+        <expected-warn>ASX1107: Unexpected hint: unknown_hint_relexpr. "indexnl", "skip-index", "hash-bcast" expected at this location</expected-warn>
         <expected-warn>ASX1107: Unexpected hint: unknown_hint_between. "indexnl", "skip-index" expected at this location</expected-warn>
         <expected-warn>ASX1107: Unexpected hint: unknown_hint_funcall. "indexnl", "skip-index" expected at this location</expected-warn>
         <expected-warn>ASX1107: Unexpected hint: unknown_hint_elsewhere. None expected at this location</expected-warn>
diff --git a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
index 3bb70c1..4c8820f 100644
--- a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
+++ b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
@@ -155,6 +155,7 @@ import org.apache.asterix.metadata.utils.MetadataConstants;
 import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.expressions.BroadcastExpressionAnnotation;
 import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
 import org.apache.hyracks.algebricks.core.algebra.expressions.IndexedNLJoinExpressionAnnotation;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
@@ -164,7 +165,7 @@ class AQLParser extends ScopeChecker implements IParser {
 
     // optimizer hints
     private static final String AUTO_HINT = "auto";
-    private static final String BROADCAST_JOIN_HINT = "bcast";
+    private static final String HASH_BROADCAST_JOIN_HINT = "hash-bcast";
     private static final String COMPOSE_VAL_FILES_HINT = "compose-val-files";
     private static final String DATE_BETWEEN_YEARS_HINT = "date-between-years";
     private static final String DATETIME_ADD_RAND_HOURS_HINT = "datetime-add-rand-hours";
@@ -1745,19 +1746,10 @@ Expression RelExpr()throws ParseException:
 {
   OperatorExpr op = null;
   Expression operand = null;
-  boolean broadcast = false;
   IExpressionAnnotation annotation = null;
 }
 {
     operand = AddExpr()
-    {
-      if (operand instanceof VariableExpr) {
-        String hint = getHint(token);
-        if (hint != null && hint.equals(BROADCAST_JOIN_HINT)) {
-          broadcast = true;
-        }
-      }
-    }
 
     (
       LOOKAHEAD(2)( <LT> | <GT> | <LE> | <GE> | <EQ> | <NE> |<SIMILAR>)
@@ -1772,9 +1764,8 @@ Expression RelExpr()throws ParseException:
         }
           if (op == null) {
             op = new OperatorExpr();
-            op.addOperand(operand, broadcast);
+            op.addOperand(operand);
           op.setCurrentop(true);
-          broadcast = false;
           }
          try{
            op.addOperator(token.image);
@@ -1785,14 +1776,14 @@ Expression RelExpr()throws ParseException:
 
        operand = AddExpr()
       {
-         broadcast = false;
          if (operand instanceof VariableExpr) {
            String hint = getHint(token);
-           if (hint != null && hint.equals(BROADCAST_JOIN_HINT)) {
-             broadcast = true;
+           if (hint != null && hint.equals(HASH_BROADCAST_JOIN_HINT)) {
+             annotation = new BroadcastExpressionAnnotation();
+             annotation.setObject(BroadcastExpressionAnnotation.BroadcastSide.RIGHT);
            }
          }
-         op.addOperand(operand, broadcast);
+         op.addOperand(operand);
       }
     )?
 
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/OperatorExpr.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/OperatorExpr.java
index 9521469..a37a366 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/OperatorExpr.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/OperatorExpr.java
@@ -31,20 +31,16 @@ import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
 public class OperatorExpr extends AbstractExpression {
     private List<Expression> exprList;
     private List<OperatorType> opList;
-    private List<Integer> exprBroadcastIdx;
     private boolean currentop;
 
     public OperatorExpr() {
         super();
         exprList = new ArrayList<>();
-        exprBroadcastIdx = new ArrayList<>();
         opList = new ArrayList<>();
     }
 
-    public OperatorExpr(List<Expression> exprList, List<Integer> exprBroadcastIdx, List<OperatorType> opList,
-            boolean currentop) {
+    public OperatorExpr(List<Expression> exprList, List<OperatorType> opList, boolean currentop) {
         this.exprList = exprList;
-        this.exprBroadcastIdx = exprBroadcastIdx;
         this.opList = opList;
         this.currentop = currentop;
     }
@@ -61,10 +57,6 @@ public class OperatorExpr extends AbstractExpression {
         return exprList;
     }
 
-    public List<Integer> getExprBroadcastIdx() {
-        return exprBroadcastIdx;
-    }
-
     public List<OperatorType> getOpList() {
         return opList;
     }
@@ -74,13 +66,6 @@ public class OperatorExpr extends AbstractExpression {
     }
 
     public void addOperand(Expression operand) {
-        addOperand(operand, false);
-    }
-
-    public void addOperand(Expression operand, boolean broadcast) {
-        if (broadcast) {
-            exprBroadcastIdx.add(exprList.size());
-        }
         exprList.add(operand);
     }
 
@@ -123,18 +108,9 @@ public class OperatorExpr extends AbstractExpression {
         return visitor.visit(this, arg);
     }
 
-    public boolean isBroadcastOperand(int idx) {
-        for (Integer i : exprBroadcastIdx) {
-            if (i == idx) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     @Override
     public int hashCode() {
-        return Objects.hash(currentop, exprBroadcastIdx, exprList, opList);
+        return Objects.hash(currentop, exprList, opList);
     }
 
     @Override
@@ -146,7 +122,7 @@ public class OperatorExpr extends AbstractExpression {
             return false;
         }
         OperatorExpr target = (OperatorExpr) object;
-        return currentop == target.isCurrentop() && Objects.equals(exprBroadcastIdx, target.exprBroadcastIdx)
-                && Objects.equals(exprList, target.exprList) && Objects.equals(opList, target.opList);
+        return currentop == target.isCurrentop() && Objects.equals(exprList, target.exprList)
+                && Objects.equals(opList, target.opList);
     }
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
index 3a19254..6efb2ce 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
@@ -227,7 +227,7 @@ public class CloneAndSubstituteVariablesVisitor extends
             Pair<ILangExpression, VariableSubstitutionEnvironment> p1 = e.accept(this, env);
             exprs.add((Expression) p1.first);
         }
-        OperatorExpr oe = new OperatorExpr(exprs, op.getExprBroadcastIdx(), op.getOpList(), op.isCurrentop());
+        OperatorExpr oe = new OperatorExpr(exprs, op.getOpList(), op.isCurrentop());
         oe.setSourceLocation(op.getSourceLocation());
         oe.addHints(op.getHints());
         return new Pair<>(oe, env);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SqlppHint.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SqlppHint.java
index 4770581..27e2fa0 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SqlppHint.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SqlppHint.java
@@ -27,7 +27,7 @@ public enum SqlppHint {
 
     // optimizer hints
     AUTO_HINT("auto"),
-    BROADCAST_JOIN_HINT("bcast"),
+    HASH_BROADCAST_JOIN_HINT("hash-bcast"),
     COMPOSE_VAL_FILES_HINT("compose-val-files"),
     DATE_BETWEEN_YEARS_HINT("date-between-years"),
     DATETIME_ADD_RAND_HOURS_HINT("datetime-add-rand-hours"),
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
index b1b39e6..56f160b 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
@@ -396,8 +396,8 @@ public class DeepCopyVisitor extends AbstractSqlppQueryExpressionVisitor<ILangEx
 
     @Override
     public OperatorExpr visit(OperatorExpr operatorExpr, Void arg) throws CompilationException {
-        OperatorExpr copy = new OperatorExpr(copyExprList(operatorExpr.getExprList(), arg),
-                operatorExpr.getExprBroadcastIdx(), operatorExpr.getOpList(), operatorExpr.isCurrentop());
+        OperatorExpr copy = new OperatorExpr(copyExprList(operatorExpr.getExprList(), arg), operatorExpr.getOpList(),
+                operatorExpr.isCurrentop());
         copy.setSourceLocation(operatorExpr.getSourceLocation());
         copy.addHints(operatorExpr.getHints());
         return copy;
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 60cdf2e..e0a4341 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -186,6 +186,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.expressions.BroadcastExpressionAnnotation;
 import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
 import org.apache.hyracks.algebricks.core.algebra.expressions.IndexedNLJoinExpressionAnnotation;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
@@ -2054,7 +2055,6 @@ Expression RelExpr() throws ParseException:
   boolean not = false;
   OperatorExpr op = null;
   Expression operand = null;
-  boolean broadcast = false;
   IExpressionAnnotation annotation = null;
 }
 {
@@ -2064,7 +2064,7 @@ Expression RelExpr() throws ParseException:
       LOOKAHEAD(2)( <LT> | <GT> | <LE> | <GE> | <EQ> | <NE> | <LG> |<SIMILAR> | (<NOT> { not = true; })? <IN>)
         {
           Token hintToken = fetchHint(token, SqlppHint.INDEXED_NESTED_LOOP_JOIN_HINT,
-            SqlppHint.SKIP_SECONDARY_INDEX_SEARCH_HINT, SqlppHint.BROADCAST_JOIN_HINT);
+            SqlppHint.SKIP_SECONDARY_INDEX_SEARCH_HINT, SqlppHint.HASH_BROADCAST_JOIN_HINT);
           if (hintToken != null) {
             switch (hintToken.hint) {
               case INDEXED_NESTED_LOOP_JOIN_HINT:
@@ -2073,8 +2073,9 @@ Expression RelExpr() throws ParseException:
               case SKIP_SECONDARY_INDEX_SEARCH_HINT:
                 annotation = SkipSecondaryIndexSearchExpressionAnnotation.INSTANCE;
                 break;
-              case BROADCAST_JOIN_HINT:
-                broadcast = true;
+              case HASH_BROADCAST_JOIN_HINT:
+                annotation = new BroadcastExpressionAnnotation();
+                annotation.setObject(BroadcastExpressionAnnotation.BroadcastSide.RIGHT);
                 break;
             }
           }
@@ -2088,7 +2089,7 @@ Expression RelExpr() throws ParseException:
           }
           if (op == null) {
             op = new OperatorExpr();
-            op.addOperand(operand, false); // broadcast is always for the right branch
+            op.addOperand(operand);
             op.setCurrentop(true);
             addSourceLocation(op, token);
           }
@@ -2101,7 +2102,7 @@ Expression RelExpr() throws ParseException:
 
        operand = BetweenExpr()
        {
-         op.addOperand(operand, broadcast);
+         op.addOperand(operand);
        }
     )?
 
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/expressions/BroadcastExpressionAnnotation.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/expressions/BroadcastExpressionAnnotation.java
index 6c47b82..9eef8f6 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/expressions/BroadcastExpressionAnnotation.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/expressions/BroadcastExpressionAnnotation.java
@@ -20,12 +20,10 @@ package org.apache.hyracks.algebricks.core.algebra.expressions;
 
 public class BroadcastExpressionAnnotation implements IExpressionAnnotation {
 
-    public static final String BROADCAST_ANNOTATION_KEY = "broadcast";
-
     public enum BroadcastSide {
         LEFT,
         RIGHT
-    };
+    }
 
     private BroadcastSide side;
 
@@ -41,14 +39,9 @@ public class BroadcastExpressionAnnotation implements IExpressionAnnotation {
 
     @Override
     public IExpressionAnnotation copy() {
-        BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation();
-        bcast.side = side;
-        return bcast;
-    }
-
-    @Override
-    public String toString() {
-        return BROADCAST_ANNOTATION_KEY;
+        BroadcastExpressionAnnotation hashBcast = new BroadcastExpressionAnnotation();
+        hashBcast.side = side;
+        return hashBcast;
     }
 
 }
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/BroadcastSideSwitchingVisitor.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/BroadcastSideSwitchingVisitor.java
new file mode 100644
index 0000000..c9da3f6
--- /dev/null
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/BroadcastSideSwitchingVisitor.java
@@ -0,0 +1,108 @@
+/*
+ * 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.core.algebra.operators.logical.visitors;
+
+import java.util.Iterator;
+import java.util.Map;
+
+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.expressions.AggregateFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.BroadcastExpressionAnnotation;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.StatefulFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+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.visitors.ILogicalExpressionVisitor;
+
+public class BroadcastSideSwitchingVisitor implements ILogicalExpressionVisitor<ILogicalExpression, Void> {
+    private static BroadcastSideSwitchingVisitor instance = null;
+
+    private BroadcastSideSwitchingVisitor() {
+    }
+
+    public static BroadcastSideSwitchingVisitor getInstance() {
+        if (instance == null) {
+            instance = new BroadcastSideSwitchingVisitor();
+        }
+        return instance;
+    }
+
+    @Override
+    public ILogicalExpression visitConstantExpression(ConstantExpression expr, Void arg) {
+        return null;
+    }
+
+    @Override
+    public ILogicalExpression visitVariableReferenceExpression(VariableReferenceExpression expr, Void arg) {
+        return null;
+    }
+
+    @Override
+    public ILogicalExpression visitAggregateFunctionCallExpression(AggregateFunctionCallExpression expr, Void arg) {
+        return null;
+    }
+
+    @Override
+    public ILogicalExpression visitScalarFunctionCallExpression(ScalarFunctionCallExpression expr, Void arg)
+            throws AlgebricksException {
+        BroadcastExpressionAnnotation.BroadcastSide bSide;
+        FunctionIdentifier fi = expr.getFunctionIdentifier();
+        if (fi.equals(AlgebricksBuiltinFunctions.AND)) {
+            for (Mutable<ILogicalExpression> a : expr.getArguments()) {
+                a.getValue().accept(this, null);
+            }
+        }
+        Iterator it = expr.getAnnotations().entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry pair = (Map.Entry) it.next();
+            if (pair.getKey() instanceof BroadcastExpressionAnnotation) {
+                bSide = (BroadcastExpressionAnnotation.BroadcastSide) ((BroadcastExpressionAnnotation) pair.getValue())
+                        .getObject();
+                switch (bSide) {
+                    case RIGHT:
+                        bSide = BroadcastExpressionAnnotation.BroadcastSide.LEFT;
+                        break;
+                    case LEFT:
+                        bSide = BroadcastExpressionAnnotation.BroadcastSide.RIGHT;
+                        break;
+                    default:
+                        bSide = null;
+                        break;
+                }
+                ((BroadcastExpressionAnnotation) pair.getValue()).setObject(bSide);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ILogicalExpression visitStatefulFunctionCallExpression(StatefulFunctionCallExpression expr, Void arg) {
+        return null;
+    }
+
+    @Override
+    public ILogicalExpression visitUnnestingFunctionCallExpression(UnnestingFunctionCallExpression expr, Void arg) {
+        return null;
+    }
+}
diff --git a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/util/JoinUtils.java b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/util/JoinUtils.java
index 7dfeeb5..6eede7f 100644
--- a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/util/JoinUtils.java
+++ b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/util/JoinUtils.java
@@ -18,10 +18,10 @@
  */
 package org.apache.hyracks.algebricks.rewriter.util;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -67,7 +67,7 @@ public class JoinUtils {
         List<LogicalVariable> varsRight = op.getInputs().get(1).getValue().getSchema();
         ILogicalExpression conditionExpr = op.getCondition().getValue();
         if (isHashJoinCondition(conditionExpr, varsLeft, varsRight, sideLeft, sideRight)) {
-            BroadcastSide side = getBroadcastJoinSide(conditionExpr, varsLeft, varsRight);
+            BroadcastSide side = getBroadcastJoinSide(conditionExpr);
             if (side == null) {
                 setHashJoinOp(op, JoinPartitioningType.PAIRWISE, sideLeft, sideRight, context);
             } else {
@@ -190,55 +190,33 @@ public class JoinUtils {
         }
     }
 
-    private static BroadcastSide getBroadcastJoinSide(ILogicalExpression e, List<LogicalVariable> varsLeft,
-            List<LogicalVariable> varsRight) {
+    private static BroadcastSide getBroadcastJoinSide(ILogicalExpression e) {
+        BroadcastSide side = null;
         if (e.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
             return null;
         }
         AbstractFunctionCallExpression fexp = (AbstractFunctionCallExpression) e;
         FunctionIdentifier fi = fexp.getFunctionIdentifier();
         if (fi.equals(AlgebricksBuiltinFunctions.AND)) {
-            BroadcastSide fBcastSide = null;
             for (Mutable<ILogicalExpression> a : fexp.getArguments()) {
-                BroadcastSide aBcastSide = getBroadcastJoinSide(a.getValue(), varsLeft, varsRight);
-                if (fBcastSide == null) {
-                    fBcastSide = aBcastSide;
-                } else if (aBcastSide != null && !aBcastSide.equals(fBcastSide)) {
+                BroadcastSide newSide = getBroadcastJoinSide(a.getValue());
+                if (side == null) {
+                    side = newSide;
+                } else if (newSide != null && !newSide.equals(side)) {
                     return null;
                 }
             }
-            return fBcastSide;
+            return side;
         } else {
-            IExpressionAnnotation ann =
-                    fexp.getAnnotations().get(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY);
-            if (ann == null) {
-                return null;
-            }
-            BroadcastSide side = (BroadcastSide) ann.getObject();
-            if (side == null) {
-                return null;
-            }
-            int i;
-            switch (side) {
-                case LEFT:
-                    i = 0;
-                    break;
-                case RIGHT:
-                    i = 1;
-                    break;
-                default:
-                    return null;
-            }
-            ArrayList<LogicalVariable> vars = new ArrayList<>();
-            fexp.getArguments().get(i).getValue().getUsedVariables(vars);
-            if (varsLeft.containsAll(vars)) {
-                return BroadcastSide.LEFT;
-            } else if (varsRight.containsAll(vars)) {
-                return BroadcastSide.RIGHT;
-            } else {
-                return null;
+            Set<Object> annotationSet = fexp.getAnnotations().keySet();
+            for (Object o : annotationSet) {
+                if (o instanceof BroadcastExpressionAnnotation) {
+                    IExpressionAnnotation ann = (BroadcastExpressionAnnotation) o;
+                    return (BroadcastSide) ann.getObject();
+                }
             }
         }
+        return null;
     }
 
     private static void warnIfCrossProduct(ILogicalExpression conditionExpr, SourceLocation sourceLoc,