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

org.apache.flink.table.plan.schema.IndexKey Maven / Gradle / Ivy

There is a newer version: 1.5.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.flink.table.plan.schema;

import org.apache.flink.annotation.Internal;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.table.types.DataType;

import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
 * Represents internal structure of an Index, and may carry constant key(s) info during optimization.
 */
@Internal
public class IndexKey implements Comparable, Serializable {

	private static final long serialVersionUID = -7842311969684389493L;

	// BitSets are packed into arrays of "words."  Currently a word is
	// a long, which consists of 64 bits, requiring 6 address bits.
	// The choice of word size is determined purely by performance concerns.
	private static final int ADDRESS_BITS_PER_WORD = 6;

	private static final long[] EMPTY_LONGS = new long[0];

	private static final BitSet EMPTY = BitSet.valueOf(EMPTY_LONGS);

	private final List definedColumns;

	private final Map> constantsMap = new HashMap<>();

	private final BitSet columnSet;

	private final boolean unique;

	private IndexKey(List columns, boolean unique) {
		BitSet columnSet = createBitSet(columns);
		if (columnSet.isEmpty()) {
			throw new IllegalArgumentException("Index key must contains at least one column.");
		}
		this.definedColumns = columns;
		this.columnSet = columnSet;
		this.unique = unique;
	}

	/**
	 * Returns true if the composite columns contains a valid index.
	 */
	public boolean isIndex(int[] columns) {
		List cols = Arrays.stream(columns).boxed().collect(Collectors.toList());
		BitSet other = createBitSet(cols);
		for (int i = columnSet.nextSetBit(0); i >= 0; i = columnSet.nextSetBit(i + 1)) {
			if (!other.get(i)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Create an IndexKey with column indices.
	 */
	public static IndexKey of(boolean unique, int... columns) {
		List cols = Arrays.stream(columns).boxed().collect(Collectors.toList());
		return new IndexKey(cols, unique);
	}

	public static IndexKey of(boolean unique, Iterable columns) {
		List cols = StreamSupport.stream(columns.spliterator(), false).collect(Collectors.toList());
		return new IndexKey(cols, unique);
	}

	public void addConstantKey(int columnIndex, Tuple2 constantValue) {
		if (!definedColumns.contains(columnIndex)) {
			throw new IllegalArgumentException("Given columnIndex:" + columnIndex + " is invalid of Index(" + StringUtils.join(definedColumns, ",") + ")");
		}
		this.constantsMap.put(columnIndex, constantValue);
	}

	public Map> getConstantsMap() {
		return constantsMap;
	}

	/**
	 * Returns column indexes(zero-based) in defined order of Index clause NOT column list.
	 * For example: a table Person has an Index(FirstName, LastName)
	 * 
	 * CREATE TABLE Person (
	 *  ID bigint,
	 *  LastName varchar,
	 *  FirstName varchar,
	 *  Nick varchar,
	 *  Age int,
	 *  INDEX(FirstName, LastName)
	 *  )
	 * 
* Then this method will return List(2, 1) */ public List getDefinedColumns() { return definedColumns; } public boolean isUnique() { return unique; } /** * Converts this unique key to an asc-ordered array. * Or uses #getDefinedColumns() to get column indexes in defined order. * *

Each entry of the array is the ordinal of a column. The array is * sorted by ascending order. * * @return Array of unique key */ @Internal public int[] toArray() { final int[] integers = new int[columnSet.cardinality()]; int j = 0; for (int i = columnSet.nextSetBit(0); i >= 0; i = columnSet.nextSetBit(i + 1)) { integers[j++] = i; } return integers; } /** * Returns a string representation of this unique key. */ public String toString() { return columnSet.toString(); } private static BitSet createBitSet(Iterable bits) { int max = -1; for (int bit : bits) { max = Math.max(bit, max); } if (max == -1) { return EMPTY; } long[] words = new long[wordIndex(max) + 1]; for (int bit : bits) { int wordIndex = wordIndex(bit); words[wordIndex] |= 1L << bit; } return BitSet.valueOf(words); } /** * Given a bit index, return word index containing it. */ private static int wordIndex(int bitIndex) { return bitIndex >> ADDRESS_BITS_PER_WORD; } @Override public int compareTo(IndexKey o) { // follow ascending order & null last int tp = this.unique ? 0 : 1; int op = null == o ? 2 : (o.unique ? 0 : 1); return tp - op; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy