/* * Licensed 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 com.facebook.presto.operator.index; import com.facebook.presto.metadata.Metadata; import com.facebook.presto.operator.OperatorFactory; import com.facebook.presto.operator.project.PageProcessor; import com.facebook.presto.operator.project.PageProjection; import com.facebook.presto.spi.Page; import com.facebook.presto.spi.block.Block; import com.facebook.presto.spi.type.Type; import com.facebook.presto.sql.gen.PageFunctionCompiler; import com.facebook.presto.sql.planner.plan.PlanNodeId; import com.facebook.presto.sql.relational.Expressions; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Ints; import java.util.List; import java.util.Optional; import java.util.function.Supplier; import java.util.stream.IntStream; import static com.facebook.presto.operator.FilterAndProjectOperator.FilterAndProjectOperatorFactory; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.ImmutableList.toImmutableList; import static java.util.Objects.requireNonNull; public class DynamicTupleFilterFactory { private final int filterOperatorId; private final PlanNodeId planNodeId; private final int[] tupleFilterChannels; private final List<Integer> outputFilterChannels; private final List<Type> filterTypes; private final List<Type> outputTypes; private final List<Supplier<PageProjection>> outputProjections; public DynamicTupleFilterFactory(int filterOperatorId, PlanNodeId planNodeId, int[] tupleFilterChannels, int[] outputFilterChannels, List<Type> outputTypes, Metadata metadata) { requireNonNull(planNodeId, "planNodeId is null"); requireNonNull(tupleFilterChannels, "tupleFilterChannels is null"); checkArgument(tupleFilterChannels.length > 0, "Must have at least one tupleFilterChannel"); requireNonNull(outputFilterChannels, "outputFilterChannels is null"); checkArgument(outputFilterChannels.length == tupleFilterChannels.length, "outputFilterChannels must have same length as tupleFilterChannels"); requireNonNull(outputTypes, "outputTypes is null"); checkArgument(outputTypes.size() >= outputFilterChannels.length, "Must have at least as many output channels as those used for filtering"); requireNonNull(metadata, "metadata is null"); this.filterOperatorId = filterOperatorId; this.planNodeId = planNodeId; this.tupleFilterChannels = tupleFilterChannels.clone(); this.outputFilterChannels = ImmutableList.copyOf(Ints.asList(outputFilterChannels)); this.filterTypes = IntStream.of(outputFilterChannels) .mapToObj(outputTypes::get) .collect(toImmutableList()); this.outputTypes = ImmutableList.copyOf(outputTypes); PageFunctionCompiler pageFunctionCompiler = new PageFunctionCompiler(metadata); this.outputProjections = IntStream.range(0, outputTypes.size()) .mapToObj(field -> pageFunctionCompiler.compileProjection(Expressions.field(field, outputTypes.get(field)))) .collect(toImmutableList()); } public OperatorFactory filterWithTuple(Page tuplePage) { Page filterTuple = getFilterTuple(tuplePage); Supplier<PageProcessor> processor = createPageProcessor(filterTuple); return new FilterAndProjectOperatorFactory(filterOperatorId, planNodeId, processor, outputTypes); } @VisibleForTesting public Supplier<PageProcessor> createPageProcessor(Page filterTuple) { TuplePageFilter filter = new TuplePageFilter(filterTuple, filterTypes, outputFilterChannels); return () -> new PageProcessor( Optional.of(filter), outputProjections.stream() .map(Supplier::get) .collect(toImmutableList())); } private Page getFilterTuple(Page tuplePage) { Block[] normalizedBlocks = new Block[tupleFilterChannels.length]; for (int i = 0; i < tupleFilterChannels.length; i++) { normalizedBlocks[i] = tuplePage.getBlock(tupleFilterChannels[i]); } return new Page(normalizedBlocks); } }