question: static protected PipelineOp convertRTOJoinGraph ( PipelineOp left , final JoinGroupNode joinGroup , final Set < IVariable < ? > > doneSet , final AST2BOpContext ctx , final AtomicInteger start ) { final Set < IVariable < ? > > doneSetIn = Collections . unmodifiableSet ( doneSet ) ; if ( onlySimpleJoins && ctx . isQuads ( ) ) { return left ; } final int arity = joinGroup . arity ( ) ; final JoinGroupNode rtoJoinGroup = new JoinGroupNode ( ) ; rtoJoinGroup . setQueryHints ( joinGroup . getQueryHints ( ) ) ; @ SuppressWarnings ( "rawtypes" ) final LinkedList < Predicate > preds = new LinkedList < Predicate > ( ) ; final List < IConstraint > constraints = new LinkedList < IConstraint > ( ) ; int naccepted = 0 ; { final Set < IVariable < ? > > doneSetTmp = new LinkedHashSet < IVariable < ? > > ( doneSet ) ; for ( int i = start . get ( ) ; i < arity ; i ++ ) { final IGroupMemberNode child = ( IGroupMemberNode ) joinGroup . get ( i ) ; if ( child instanceof StatementPatternNode ) { StatementPatternNode sp = ( StatementPatternNode ) child ; final boolean optional = sp . isOptional ( ) ; if ( onlyRequiredJoins && optional ) { break ; } final List < IConstraint > attachedConstraints = getJoinConstraints ( sp ) ; @ SuppressWarnings ( "rawtypes" ) final Map < IConstraint , Set < IVariable < IV > > > needsMaterialization = new LinkedHashMap < IConstraint , Set < IVariable < IV > > > ( ) ; getJoinConstraints ( attachedConstraints , needsMaterialization ) ; if ( onlySimpleJoins && ! needsMaterialization . isEmpty ( ) ) { break ; } sp = ( StatementPatternNode ) sp . clone ( ) ; rtoJoinGroup . addChild ( sp ) ; naccepted ++ ; final Predicate < ? > pred = AST2BOpUtility . toPredicate ( sp , ctx ) ; preds . add ( pred ) ; sp . setProperty ( Annotations . PREDICATE_ID , pred . getId ( ) ) ; if ( attachedConstraints != null ) { constraints . addAll ( attachedConstraints ) ; } } else { if ( onlySPs ) break ; throw new UnsupportedOperationException ( ) ; } } if ( naccepted < RTO_MIN_JOINS ) { return left ; } doneSet . addAll ( doneSetTmp ) ; } final SampleType sampleType = joinGroup . getProperty ( QueryHints . RTO_SAMPLE_TYPE , QueryHints . DEFAULT_RTO_SAMPLE_TYPE ) ; final int limit = joinGroup . getProperty ( QueryHints . RTO_LIMIT , QueryHints . DEFAULT_RTO_LIMIT ) ; final int nedges = joinGroup . getProperty ( QueryHints . RTO_NEDGES , QueryHints . DEFAULT_RTO_NEDGES ) ; left = new JoinGraph ( leftOrEmpty ( left ) , new NV ( BOp . Annotations . BOP_ID , ctx . nextId ( ) ) , new NV ( BOp . Annotations . EVALUATION_CONTEXT , BOpEvaluationContext . CONTROLLER ) , new NV ( BOp . Annotations . CONTROLLER , true ) , new NV ( JoinGraph . Annotations . VERTICES , preds . toArray ( new Predicate [ preds . size ( ) ] ) ) , new NV ( JoinGraph . Annotations . CONSTRAINTS , constraints . toArray ( new IConstraint [ constraints . size ( ) ] ) ) , new NV ( JoinGraph . Annotations . JOIN_GROUP , rtoJoinGroup ) , new NV ( JoinGraph . Annotations . LIMIT , limit ) , new NV ( JoinGraph . Annotations . NEDGES , nedges ) , new NV ( JoinGraph . Annotations . SAMPLE_TYPE , sampleType . name ( ) ) , new NV ( JoinGraph . Annotations . DONE_SET , doneSetIn ) , new NV ( JoinGraph . Annotations . NT , new NT ( ctx . getNamespace ( ) , ctx . getTimestamp ( ) ) ) ) ; start . addAndGet ( naccepted ) ; return left ; }
target:  Inspect the remainder of the join group. If we can isolate a join graph and filters, then we will push them down into an RTO JoinGroup. Since the joins have already been ordered by the static optimizer, we can accept them in sequence along with any attachable filters and (if we get at least 3 predicates) push them down into an RTO join group. <p> Note: Two predicates in a join group is not enough for the RTO to provide a different join ordering. Both the static optimizer and the RTO will always choose the AP with the smaller cardinality to run first. If there are only 2 predicates, then the other predicate will run second. You need at least three predicates before the RTO could provide a different answer.