docs: public void validate() {
      if (id == null || id.isEmpty()) {
        throw new IllegalArgumentException("missing or empty id");
      }
      Query.validateId(id);
      
      if (expr == null || expr.isEmpty()) {
        throw new IllegalArgumentException("missing or empty expr");
      }
      
      // parse it just to make sure we're happy and extract the variable names. 
      // Will throw JexlException
      parsed_expression = ExpressionIterator.JEXL_ENGINE.createScript(expr);
      variables = new HashSet<String>();
      for (final List<String> exp_list : 
        ExpressionIterator.JEXL_ENGINE.getVariables(parsed_expression)) {
        for (final String variable : exp_list) {
          variables.add(variable);
        }
      }
      
      // others are optional
      if (join == null) {
        join = Join.Builder().setOperator(SetOperator.UNION).build();
      }
    }