Package org.apache.drill.exec.ref.rops

Source Code of org.apache.drill.exec.ref.rops.JoinROP$InnerIterator

/**
* 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.drill.exec.ref.rops;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.drill.common.exceptions.DrillRuntimeException;
import org.apache.drill.common.logical.data.Join;
import org.apache.drill.common.logical.data.JoinCondition;
import org.apache.drill.exec.ref.IteratorRegistry;
import org.apache.drill.exec.ref.RecordIterator;
import org.apache.drill.exec.ref.RecordPointer;
import org.apache.drill.exec.ref.UnbackedRecord;
import org.apache.drill.exec.ref.eval.EvaluatorFactory;
import org.apache.drill.exec.ref.eval.fn.ComparisonEvaluators;
import org.apache.drill.exec.ref.exceptions.SetupException;
import org.apache.drill.exec.ref.values.ComparableValue;
import org.apache.drill.exec.ref.values.DataValue;

import java.util.List;

public class JoinROP extends ROPBase<Join> {
    static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(JoinROP.class);

    private RecordIterator left;
    private RecordIterator right;
    private UnbackedRecord record;
    private EvaluatorFactory factory;

    public JoinROP(Join config) {
        super(config);
        record = new UnbackedRecord();
    }

    @Override
    protected void setupIterators(IteratorRegistry builder) {
        left = Iterables.getOnlyElement(builder.getOperator(config.getLeft()));
        right = Iterables.getOnlyElement(builder.getOperator(config.getRight()));
    }

    @Override
    protected void setupEvals(EvaluatorFactory builder) throws SetupException {
        factory = builder;
    }

    @Override
    protected RecordIterator getIteratorInternal() {
        return createIteratorFromJoin(config.getJointType());
    }

    private RecordIterator createIteratorFromJoin(Join.JoinType type) {
        switch (type) {
            case LEFT:
                return new LeftIterator();
            case INNER:
                return new InnerIterator();
            case OUTER:
                return new OuterIterator();
            default:
                throw new UnsupportedOperationException("Type not supported: " + type);
        }
    }

    private class RecordBuffer {
        final boolean schemaChanged;
        final RecordPointer pointer;
        boolean hasJoined = false;

        private RecordBuffer(RecordPointer pointer, boolean schemaChanged) {
            this.pointer = pointer;
            this.schemaChanged = schemaChanged;
        }

        public void setHasJoined(boolean hasJoined) {
            this.hasJoined = hasJoined;
        }
    }

    abstract class JoinIterator implements RecordIterator {
        protected List<RecordBuffer> buffer;
        protected int curIdx = 0;
        protected int bufferLength = 0;

        protected abstract int setupBuffer();

        protected int setupBufferForIterator(RecordIterator iterator) {
            int count = 0;
            NextOutcome outcome = iterator.next();
            while (outcome != NextOutcome.NONE_LEFT) {
                buffer.add(new RecordBuffer(
                        iterator.getRecordPointer().copy(),
                        outcome == NextOutcome.INCREMENTED_SCHEMA_CHANGED)
                );
                ++count;
                outcome = iterator.next();
            }
            return count;
        }

        @Override
        public RecordPointer getRecordPointer() {
            return record;
        }

        public NextOutcome next() {
            if (buffer == null) {
                buffer = Lists.newArrayList();
                setupBuffer();
                bufferLength = buffer.size();
            }
            return getNext();
        }

        public abstract NextOutcome getNext();

        protected void setOutputRecord(RecordPointer... inputs) {
            boolean first = true;
            for(RecordPointer input : inputs) {
                if(input == null) {
                    continue;
                }

                if(first) {
                    first = false;
                    record.copyFrom(input);
                } else {
                    record.merge(input);
                }
            }
        }

        public boolean eval(DataValue leftVal, DataValue rightVal, String relationship) {
            // Skip join if no comparison can be made
            if (!ComparisonEvaluators.isComparable(leftVal, rightVal)) {
                return false;
            }

            //Somehow utilize ComparisonEvaluators?
            switch (relationship) {
                case "!=":
                    return !leftVal.equals(rightVal);
                case "==":
                    return leftVal.equals(rightVal);
                case "<":
                    return ((ComparableValue) leftVal).compareTo(rightVal) < 0;
                case "<=":
                    return ((ComparableValue) leftVal).compareTo(rightVal) <= 0;
                case ">":
                    return ((ComparableValue) leftVal).compareTo(rightVal) > 0;
                case ">=":
                    return ((ComparableValue) leftVal).compareTo(rightVal) >= 0;
                default:
                    throw new DrillRuntimeException("Relationship not supported: " + relationship);
            }
        }

        @Override
        public ROP getParent() {
            return JoinROP.this;
        }
    }

    class InnerIterator extends JoinIterator {
        NextOutcome rightOutcome;

        @Override
        protected int setupBuffer() {
            return setupBufferForIterator(left);
        }

        @Override
        public NextOutcome getNext() {
            final RecordPointer rightPointer = right.getRecordPointer();
            while (true) {
                if (curIdx == 0) {
                    rightOutcome = right.next();

                    if (rightOutcome == NextOutcome.NONE_LEFT) {
                        break;
                    }
                }

                final RecordBuffer bufferObj = buffer.get(curIdx++);
                Optional<JoinCondition> option = Iterables.tryFind(Lists.newArrayList(config.getConditions()), new Predicate<JoinCondition>() {
                    @Override
                    public boolean apply(JoinCondition condition) {
                        return eval(factory.getBasicEvaluator(rightPointer, condition.getRight()).eval(),
                                factory.getBasicEvaluator(bufferObj.pointer, condition.getLeft()).eval(), condition.getRelationship());
                    }
                });

                if (curIdx >= bufferLength) {
                   curIdx = 0;
                }

                if (option.isPresent()) {
                    setOutputRecord(rightPointer, bufferObj.pointer);
                    return (bufferObj.schemaChanged || rightOutcome == NextOutcome.INCREMENTED_SCHEMA_CHANGED) ?
                            NextOutcome.INCREMENTED_SCHEMA_CHANGED :
                            NextOutcome.INCREMENTED_SCHEMA_UNCHANGED;
                }

            }

            return NextOutcome.NONE_LEFT;
        }
    }

    class LeftIterator extends JoinIterator {
        private NextOutcome leftOutcome;

        @Override
        protected int setupBuffer() {
            return setupBufferForIterator(right);
        }

        @Override
        public NextOutcome getNext() {
            final RecordPointer leftPointer = left.getRecordPointer();
            boolean isFound = true;
            if(curIdx >= bufferLength) {
                return NextOutcome.NONE_LEFT;
            }

            while (true) {
                if (curIdx == 0) {
                    if (!isFound) {
                        setOutputRecord(leftPointer);
                        return leftOutcome;
                    }

                    leftOutcome = left.next();

                    if (leftOutcome == NextOutcome.NONE_LEFT) {
                        break;
                    }

                    isFound = false;
                }

                final RecordBuffer bufferObj = buffer.get(curIdx++);
                Optional<JoinCondition> option = Iterables.tryFind(Lists.newArrayList(config.getConditions()), new Predicate<JoinCondition>() {
                    @Override
                    public boolean apply(JoinCondition condition) {
                        return eval(factory.getBasicEvaluator(leftPointer, condition.getLeft()).eval(),
                                factory.getBasicEvaluator(bufferObj.pointer, condition.getRight()).eval(), condition.getRelationship());
                    }
                });

                if (option.isPresent()) {
                    setOutputRecord(leftPointer, bufferObj.pointer);
                    bufferObj.setHasJoined(true);
                    return (bufferObj.schemaChanged || leftOutcome == NextOutcome.INCREMENTED_SCHEMA_CHANGED) ?
                            NextOutcome.INCREMENTED_SCHEMA_CHANGED :
                            NextOutcome.INCREMENTED_SCHEMA_UNCHANGED;
                }

                if (curIdx >= bufferLength) {
                    curIdx = 0;
                }
            }

            return NextOutcome.NONE_LEFT;
        }
    }

    class OuterIterator extends LeftIterator {
        boolean innerJoinCompleted = false;

        @Override
        public NextOutcome getNext() {
            if (innerJoinCompleted && curIdx >= bufferLength) {
                return NextOutcome.NONE_LEFT;
            }

            if (!innerJoinCompleted) {
                NextOutcome outcome = super.getNext();
                if (outcome != NextOutcome.NONE_LEFT) {
                    return outcome;
                } else {
                    innerJoinCompleted = true;
                    curIdx = 0;
                }
            }

            if (innerJoinCompleted) {
                while (curIdx < bufferLength) {
                    RecordBuffer recordBuffer = buffer.get(curIdx++);
                    if (!recordBuffer.hasJoined) {
                        setOutputRecord(recordBuffer.pointer, null);
                        return recordBuffer.schemaChanged ? NextOutcome.INCREMENTED_SCHEMA_CHANGED : NextOutcome.INCREMENTED_SCHEMA_UNCHANGED;
                    }
                }
            }
            return NextOutcome.NONE_LEFT;
        }
    }
}
TOP

Related Classes of org.apache.drill.exec.ref.rops.JoinROP$InnerIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.