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

com.hazelcast.org.apache.calcite.rel.hint.RelHint Maven / Gradle / Ivy

There is a newer version: 5.4.0
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 com.hazelcast.org.apache.calcite.rel.hint;

import com.hazelcast.com.google.common.base.Preconditions;
import com.hazelcast.com.google.common.collect.ImmutableList;
import com.hazelcast.com.google.common.collect.ImmutableMap;

import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Hint attached to a relation expression.
 *
 * 

A hint can be used to: * *

    *
  • Enforce planner: there's no perfect planner, so it makes sense to implement hints to * allow user better control the execution. For instance, "never merge this subquery with others", * "treat those tables as leading ones" in the join ordering, etc.
  • *
  • Append meta data/statistics: Some statistics like “table index for scan” and * “skew info of some shuffle keys” are somewhat dynamic for the query, it would be very * convenient to config them with hints because our planning metadata from the planner is very * often not that accurate.
  • *
  • Operator resource constraints: For many cases, we would give a default resource * configuration for the execution operators, i.e. min parallelism or * managed memory (resource consuming UDF) or special resource requirement (GPU or SSD disk) * and so on, it would be very flexible to profile the resource with hints per query * (instead of the Job).
  • *
* *

In order to support hint override, each hint has a {@code inheritPath} (integers list) to * record its propagate path from the root node, number `0` represents the hint was propagated * along the first(left) child, number `1` represents the hint was propagated along the * second(right) child. Given a relational expression tree with initial attached hints: * *

 *            Filter (Hint1)
 *                |
 *               Join
 *              /    \
 *            Scan  Project (Hint2)
 *                     |
 *                    Scan2
 * 
* *

The plan would have hints path as follows (assumes each hint can be propagated to all * child nodes): * *

    *
  • Filter → {Hint1[]}
  • *
  • Join → {Hint1[0]}
  • *
  • Scan → {Hint1[0, 0]}
  • *
  • Project → {Hint1[0,1], Hint2[]}
  • *
  • Scan2 → {[Hint1[0, 1, 0], Hint2[0]}
  • *
* *

{@code listOptions} and {@code kvOptions} are supposed to contain the same information, * they are mutually exclusive, that means, they can not both be non-empty. * *

RelHint is immutable. */ public class RelHint { //~ Instance fields -------------------------------------------------------- public final ImmutableList inheritPath; public final String hintName; public final List listOptions; public final Map kvOptions; //~ Constructors ----------------------------------------------------------- /** * Creates a {@code RelHint}. * * @param inheritPath Hint inherit path * @param hintName Hint name * @param listOption Hint options as string list * @param kvOptions Hint options as string key value pair */ private RelHint( Iterable inheritPath, String hintName, @Nullable List listOption, @Nullable Map kvOptions) { Objects.requireNonNull(inheritPath, "inheritPath"); Objects.requireNonNull(hintName, "hintName"); this.inheritPath = ImmutableList.copyOf(inheritPath); this.hintName = hintName; this.listOptions = listOption == null ? ImmutableList.of() : ImmutableList.copyOf(listOption); this.kvOptions = kvOptions == null ? ImmutableMap.of() : ImmutableMap.copyOf(kvOptions); } //~ Methods ---------------------------------------------------------------- /** Creates a hint builder with specified hint name. */ public static Builder builder(String hintName) { return new Builder(hintName); } /** * Returns a copy of this hint with specified inherit path. * * @param inheritPath Hint path * @return the new {@code RelHint} */ public RelHint copy(List inheritPath) { Objects.requireNonNull(inheritPath, "inheritPath"); return new RelHint(inheritPath, hintName, listOptions, kvOptions); } @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } RelHint hint = (RelHint) o; return inheritPath.equals(hint.inheritPath) && hintName.equals(hint.hintName) && Objects.equals(listOptions, hint.listOptions) && Objects.equals(kvOptions, hint.kvOptions); } @Override public int hashCode() { return Objects.hash(this.hintName, this.inheritPath, this.listOptions, this.kvOptions); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("[") .append(this.hintName) .append(" inheritPath:") .append(this.inheritPath); if (this.listOptions.size() > 0 || this.kvOptions.size() > 0) { builder.append(" options:"); if (this.listOptions.size() > 0) { builder.append(this.listOptions.toString()); } else { builder.append(this.kvOptions.toString()); } } builder.append("]"); return builder.toString(); } //~ Inner Class ------------------------------------------------------------ /** Builder for {@link RelHint}. */ public static class Builder { private String hintName; private List inheritPath; private List listOptions; private Map kvOptions; private Builder(String hintName) { this.listOptions = new ArrayList<>(); this.kvOptions = new LinkedHashMap<>(); this.hintName = hintName; this.inheritPath = ImmutableList.of(); } /** Sets up the inherit path with given integer list. */ public Builder inheritPath(Iterable inheritPath) { this.inheritPath = ImmutableList.copyOf(Objects.requireNonNull(inheritPath, "inheritPath")); return this; } /** Sets up the inherit path with given integer array. */ public Builder inheritPath(Integer... inheritPath) { this.inheritPath = Arrays.asList(inheritPath); return this; } /** Add a hint option as string. */ public Builder hintOption(String hintOption) { Objects.requireNonNull(hintOption, "hintOption"); Preconditions.checkState(this.kvOptions.size() == 0, "List options and key value options can not be mixed in"); this.listOptions.add(hintOption); return this; } /** Add multiple string hint options. */ public Builder hintOptions(Iterable hintOptions) { Objects.requireNonNull(hintOptions, "hintOptions"); Preconditions.checkState(this.kvOptions.size() == 0, "List options and key value options can not be mixed in"); this.listOptions = ImmutableList.copyOf(hintOptions); return this; } /** Add a hint option as string key-value pair. */ public Builder hintOption(String optionKey, String optionValue) { Objects.requireNonNull(optionKey, "optionKey"); Objects.requireNonNull(optionValue, "optionValue"); Preconditions.checkState(this.listOptions.size() == 0, "List options and key value options can not be mixed in"); this.kvOptions.put(optionKey, optionValue); return this; } /** Add multiple string key-value pair hint options. */ public Builder hintOptions(Map kvOptions) { Objects.requireNonNull(kvOptions, "kvOptions"); Preconditions.checkState(this.listOptions.size() == 0, "List options and key value options can not be mixed in"); this.kvOptions = kvOptions; return this; } public RelHint build() { return new RelHint(this.inheritPath, this.hintName, this.listOptions, this.kvOptions); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy