private int parseSingleSemiJoinHint(Tree args, int curIdx, Map<String, List<SemiJoinHint>> result)
      throws SemanticException {
    // Check if there are enough entries in the tree to constitute a hint.
    int numEntriesLeft = args.getChildCount() - curIdx;
    if (numEntriesLeft < 3) {
      throw new SemanticException("User provided only 1 entry for the hint with alias "
          + args.getChild(curIdx).getText());
    }

    String source = args.getChild(curIdx++).getText();
    // validate
    if (StringUtils.isNumeric(source)) {
      throw new SemanticException("User provided bloom filter entries when source alias is "
          + "expected. source:" + source);
    }

    String colName = args.getChild(curIdx++).getText();
    // validate
    if (StringUtils.isNumeric(colName)) {
      throw new SemanticException("User provided bloom filter entries when column name is "
          + "expected. colName:" + colName);
    }

    String target = args.getChild(curIdx++).getText();
    // validate
    if (StringUtils.isNumeric(target)) {
      throw new SemanticException("User provided bloom filter entries when target alias is "
          + "expected. target: " + target);
    }

    Integer number = null;
    if (numEntriesLeft > 3) {
      // Check if there exists bloom filter size entry
      try {
        number = Integer.parseInt(args.getChild(curIdx).getText());
        curIdx++;
      } catch (NumberFormatException e) { // Ignore
        LOG.warn("Number format exception when parsing " + number, e);
      }
    }
    result.computeIfAbsent(source, value -> new ArrayList<>()).add(new SemiJoinHint(colName, target, number));
    return curIdx;
  }
Parses semjoin hints in the query and returns the table names mapped to filter size, or -1 if not specified.
 Hints can be in 2 formats
 1. TableName, ColumnName, Target-TableName, bloom filter entries
 2. TableName, ColumnName, Target-TableName
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java