All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.druid.sql.calcite.rel.DruidUnionRel Maven / Gradle / Ivy

There is a newer version: 30.0.1
Show newest version
/*
 * 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.druid.sql.calcite.rel;

import com.google.common.base.Preconditions;
import com.google.common.collect.FluentIterable;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptCost;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.guava.Sequence;
import org.apache.druid.java.util.common.guava.Sequences;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class DruidUnionRel extends DruidRel
{
  private final RelDataType rowType;
  private final List rels;
  private final int limit;

  private DruidUnionRel(
      final RelOptCluster cluster,
      final RelTraitSet traitSet,
      final QueryMaker queryMaker,
      final RelDataType rowType,
      final List rels,
      final int limit
  )
  {
    super(cluster, traitSet, queryMaker);
    this.rowType = rowType;
    this.rels = rels;
    this.limit = limit;
  }

  public static DruidUnionRel create(
      final QueryMaker queryMaker,
      final RelDataType rowType,
      final List rels,
      final int limit
  )
  {
    Preconditions.checkState(rels.size() > 0, "rels must be nonempty");

    return new DruidUnionRel(
        rels.get(0).getCluster(),
        rels.get(0).getTraitSet(),
        queryMaker,
        rowType,
        new ArrayList<>(rels),
        limit
    );
  }

  @Override
  @Nullable
  public PartialDruidQuery getPartialDruidQuery()
  {
    return null;
  }

  @Override
  public int getQueryCount()
  {
    return rels.stream().mapToInt(rel -> ((DruidRel) rel).getQueryCount()).sum();
  }

  @Override
  @SuppressWarnings("unchecked")
  public Sequence runQuery()
  {
    // Lazy: run each query in sequence, not all at once.
    if (limit == 0) {
      return Sequences.empty();
    } else {
      final Sequence baseSequence = Sequences.concat(
          FluentIterable.from(rels).transform(rel -> ((DruidRel) rel).runQuery())
      );

      return limit > 0 ? baseSequence.limit(limit) : baseSequence;
    }
  }

  @Override
  public DruidUnionRel withPartialQuery(final PartialDruidQuery newQueryBuilder)
  {
    throw new UnsupportedOperationException();
  }

  @Nullable
  @Override
  public DruidQuery toDruidQuery(final boolean finalizeAggregations)
  {
    throw new UnsupportedOperationException();
  }

  @Override
  public DruidQuery toDruidQueryForExplaining()
  {
    throw new UnsupportedOperationException();
  }

  @Override
  public DruidUnionRel asDruidConvention()
  {
    return new DruidUnionRel(
        getCluster(),
        getTraitSet().replace(DruidConvention.instance()),
        getQueryMaker(),
        rowType,
        rels.stream().map(rel -> RelOptRule.convert(rel, DruidConvention.instance())).collect(Collectors.toList()),
        limit
    );
  }

  @Override
  public List getInputs()
  {
    return rels;
  }

  @Override
  public void replaceInput(int ordinalInParent, RelNode p)
  {
    rels.set(ordinalInParent, p);
  }

  @Override
  public RelNode copy(final RelTraitSet traitSet, final List inputs)
  {
    return new DruidUnionRel(
        getCluster(),
        traitSet,
        getQueryMaker(),
        rowType,
        inputs,
        limit
    );
  }

  @Override
  public List getDataSourceNames()
  {
    return rels.stream()
               .flatMap(rel -> ((DruidRel) rel).getDataSourceNames().stream())
               .distinct()
               .collect(Collectors.toList());
  }

  @Override
  public RelWriter explainTerms(RelWriter pw)
  {
    super.explainTerms(pw);

    for (int i = 0; i < rels.size(); i++) {
      pw.input(StringUtils.format("input#%d", i), rels.get(i));
    }

    return pw.item("limit", limit);
  }

  @Override
  protected RelDataType deriveRowType()
  {
    return rowType;
  }

  @Override
  public RelOptCost computeSelfCost(final RelOptPlanner planner, final RelMetadataQuery mq)
  {
    return planner.getCostFactory().makeCost(rels.stream().mapToDouble(mq::getRowCount).sum(), 0, 0);
  }

  public int getLimit()
  {
    return limit;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy