/** * 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.hadoop.hive.ql.plan; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Join operator Descriptor implementation. * */ @Explain(displayName = "Join Operator") public class JoinDesc implements Serializable { private static final long serialVersionUID = 1L; public static final int INNER_JOIN = 0; public static final int LEFT_OUTER_JOIN = 1; public static final int RIGHT_OUTER_JOIN = 2; public static final int FULL_OUTER_JOIN = 3; public static final int UNIQUE_JOIN = 4; public static final int LEFT_SEMI_JOIN = 5; // used to handle skew join private boolean handleSkewJoin = false; private int skewKeyDefinition = -1; private Map<Byte, String> bigKeysDirMap; private Map<Byte, Map<Byte, String>> smallKeysDirMap; private Map<Byte, TableDesc> skewKeysValuesTables; // alias to key mapping private Map<Byte, List<ExprNodeDesc>> exprs; // alias to filter mapping private Map<Byte, List<ExprNodeDesc>> filters; // key index to nullsafe join flag private boolean[] nullsafes; // used for create joinOutputObjectInspector protected List<String> outputColumnNames; // key:column output name, value:tag private transient Map<String, Byte> reversedExprs; // No outer join involved protected boolean noOuterJoin; protected JoinCondDesc[] conds; protected Byte[] tagOrder; private TableDesc keyTableDesc; public JoinDesc() { } public JoinDesc(final Map<Byte, List<ExprNodeDesc>> exprs, List<String> outputColumnNames, final boolean noOuterJoin, final JoinCondDesc[] conds, final Map<Byte, List<ExprNodeDesc>> filters) { this.exprs = exprs; this.outputColumnNames = outputColumnNames; this.noOuterJoin = noOuterJoin; this.conds = conds; this.filters = filters; tagOrder = new Byte[exprs.size()]; for (int i = 0; i < tagOrder.length; i++) { tagOrder[i] = (byte) i; } } public JoinDesc(final Map<Byte, List<ExprNodeDesc>> exprs, List<String> outputColumnNames, final boolean noOuterJoin, final JoinCondDesc[] conds) { this(exprs, outputColumnNames, noOuterJoin, conds, null); } public JoinDesc(final Map<Byte, List<ExprNodeDesc>> exprs, List<String> outputColumnNames) { this(exprs, outputColumnNames, true, null); } public JoinDesc(final Map<Byte, List<ExprNodeDesc>> exprs, List<String> outputColumnNames, final JoinCondDesc[] conds) { this(exprs, outputColumnNames, true, conds, null); } public JoinDesc(JoinDesc clone) { this.bigKeysDirMap = clone.bigKeysDirMap; this.conds = clone.conds; this.exprs = clone.exprs; this.nullsafes = clone.nullsafes; this.handleSkewJoin = clone.handleSkewJoin; this.keyTableDesc = clone.keyTableDesc; this.noOuterJoin = clone.noOuterJoin; this.outputColumnNames = clone.outputColumnNames; this.reversedExprs = clone.reversedExprs; this.skewKeyDefinition = clone.skewKeyDefinition; this.skewKeysValuesTables = clone.skewKeysValuesTables; this.smallKeysDirMap = clone.smallKeysDirMap; this.tagOrder = clone.tagOrder; this.filters = clone.filters; } public Map<Byte, List<ExprNodeDesc>> getExprs() { return exprs; } public Map<String, Byte> getReversedExprs() { return reversedExprs; } public void setReversedExprs(Map<String, Byte> reversedExprs) { this.reversedExprs = reversedExprs; } @Explain(displayName = "condition expressions") public Map<Byte, String> getExprsStringMap() { if (getExprs() == null) { return null; } LinkedHashMap<Byte, String> ret = new LinkedHashMap<Byte, String>(); for (Map.Entry<Byte, List<ExprNodeDesc>> ent : getExprs().entrySet()) { StringBuilder sb = new StringBuilder(); boolean first = true; if (ent.getValue() != null) { for (ExprNodeDesc expr : ent.getValue()) { if (!first) { sb.append(" "); } first = false; sb.append("{"); sb.append(expr.getExprString()); sb.append("}"); } } ret.put(ent.getKey(), sb.toString()); } return ret; } public void setExprs(final Map<Byte, List<ExprNodeDesc>> exprs) { this.exprs = exprs; } /** * Get the string representation of filters. * * Returns null if they are no filters. * * @return Map from alias to filters on the alias. */ @Explain(displayName = "filter predicates") public Map<Byte, String> getFiltersStringMap() { if (getFilters() == null || getFilters().size() == 0) { return null; } LinkedHashMap<Byte, String> ret = new LinkedHashMap<Byte, String>(); boolean filtersPresent = false; for (Map.Entry<Byte, List<ExprNodeDesc>> ent : getFilters().entrySet()) { StringBuilder sb = new StringBuilder(); boolean first = true; if (ent.getValue() != null) { if (ent.getValue().size() != 0) { filtersPresent = true; } for (ExprNodeDesc expr : ent.getValue()) { if (!first) { sb.append(" "); } first = false; sb.append("{"); sb.append(expr.getExprString()); sb.append("}"); } } ret.put(ent.getKey(), sb.toString()); } if (filtersPresent) { return ret; } else { return null; } } public Map<Byte, List<ExprNodeDesc>> getFilters() { return filters; } public void setFilters(Map<Byte, List<ExprNodeDesc>> filters) { this.filters = filters; } @Explain(displayName = "outputColumnNames") public List<String> getOutputColumnNames() { return outputColumnNames; } public void setOutputColumnNames( List<String> outputColumnNames) { this.outputColumnNames = outputColumnNames; } public boolean getNoOuterJoin() { return noOuterJoin; } public void setNoOuterJoin(final boolean noOuterJoin) { this.noOuterJoin = noOuterJoin; } @Explain(displayName = "condition map") public List<JoinCondDesc> getCondsList() { if (conds == null) { return null; } ArrayList<JoinCondDesc> l = new ArrayList<JoinCondDesc>(); for (JoinCondDesc cond : conds) { l.add(cond); } return l; } public JoinCondDesc[] getConds() { return conds; } public void setConds(final JoinCondDesc[] conds) { this.conds = conds; } /** * The order in which tables should be processed when joining. * * @return Array of tags */ public Byte[] getTagOrder() { return tagOrder; } /** * The order in which tables should be processed when joining. * * @param tagOrder * Array of tags */ public void setTagOrder(Byte[] tagOrder) { this.tagOrder = tagOrder; } @Explain(displayName = "handleSkewJoin") public boolean getHandleSkewJoin() { return handleSkewJoin; } /** * set to handle skew join in this join op. * * @param handleSkewJoin */ public void setHandleSkewJoin(boolean handleSkewJoin) { this.handleSkewJoin = handleSkewJoin; } /** * @return mapping from tbl to dir for big keys. */ public Map<Byte, String> getBigKeysDirMap() { return bigKeysDirMap; } /** * set the mapping from tbl to dir for big keys. * * @param bigKeysDirMap */ public void setBigKeysDirMap(Map<Byte, String> bigKeysDirMap) { this.bigKeysDirMap = bigKeysDirMap; } /** * @return mapping from tbl to dir for small keys */ public Map<Byte, Map<Byte, String>> getSmallKeysDirMap() { return smallKeysDirMap; } /** * set the mapping from tbl to dir for small keys. * * @param smallKeysDirMap */ public void setSmallKeysDirMap(Map<Byte, Map<Byte, String>> smallKeysDirMap) { this.smallKeysDirMap = smallKeysDirMap; } /** * @return skew key definition. If we see a key's associated entries' number * is bigger than this, we will define this key as a skew key. */ public int getSkewKeyDefinition() { return skewKeyDefinition; } /** * set skew key definition. * * @param skewKeyDefinition */ public void setSkewKeyDefinition(int skewKeyDefinition) { this.skewKeyDefinition = skewKeyDefinition; } /** * @return the table desc for storing skew keys and their corresponding value; */ public Map<Byte, TableDesc> getSkewKeysValuesTables() { return skewKeysValuesTables; } /** * @param skewKeysValuesTables * set the table desc for storing skew keys and their corresponding * value; */ public void setSkewKeysValuesTables(Map<Byte, TableDesc> skewKeysValuesTables) { this.skewKeysValuesTables = skewKeysValuesTables; } public boolean isNoOuterJoin() { return noOuterJoin; } public void setKeyTableDesc(TableDesc keyTblDesc) { keyTableDesc = keyTblDesc; } public TableDesc getKeyTableDesc() { return keyTableDesc; } public boolean[] getNullSafes() { return nullsafes; } public void setNullSafes(boolean[] nullSafes) { this.nullsafes = nullSafes; } @Explain(displayName = "nullSafes") public String getNullSafeString() { if (nullsafes == null) { return null; } boolean hasNS = false; for (boolean ns : nullsafes) { hasNS |= ns; } return hasNS ? Arrays.toString(nullsafes) : null; } }