Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*-
* #%L
* athena-dynamodb
* %%
* Copyright (C) 2019 Amazon Web Services
* %%
* 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.
* #L%
*/
package com.amazonaws.athena.connectors.dynamodb.util;
import com.amazonaws.athena.connector.lambda.domain.predicate.EquatableValueSet;
import com.amazonaws.athena.connector.lambda.domain.predicate.Marker;
import com.amazonaws.athena.connector.lambda.domain.predicate.Range;
import com.amazonaws.athena.connector.lambda.domain.predicate.SortedRangeSet;
import com.amazonaws.athena.connector.lambda.domain.predicate.ValueSet;
import com.amazonaws.athena.connectors.dynamodb.model.DynamoDBIndex;
import com.amazonaws.athena.connectors.dynamodb.model.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.document.ItemUtils;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ProjectionType;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
/**
* Provides utility methods relating to predicate handling.
*/
public class DDBPredicateUtils
{
private DDBPredicateUtils() {}
private static final Joiner AND_JOINER = Joiner.on(" AND ");
private static final Joiner COMMA_JOINER = Joiner.on(",");
private static final Joiner OR_JOINER = Joiner.on(" OR ");
/**
* Attempts to pick an optimal index (if any) from the given predicates. Returns the original table index if
* one was not found.
*
* @param table the original table
* @param predicates the predicates
* @return the optimal index if found, otherwise the original table index
*/
public static DynamoDBIndex getBestIndexForPredicates(DynamoDBTable table, List requestedCols, Map predicates)
{
Set columnNames = predicates.keySet();
ImmutableList.Builder hashKeyMatchesBuilder = ImmutableList.builder();
// create the original table index
DynamoDBIndex tableIndex = new DynamoDBIndex(table.getName(), table.getHashKey(), table.getRangeKey(), ProjectionType.ALL, ImmutableList.of());
// if the original table has a hash key matching a predicate, start with that
if (columnNames.contains(tableIndex.getHashKey())) {
// here, treat table as a special index
hashKeyMatchesBuilder.add(tableIndex);
}
// requested columns must be projected in index
List candidateIndices = table.getIndexes().stream()
.filter(index -> indexContainsAllRequiredColumns(requestedCols, index, table))
.collect(Collectors.toList());
// get indices with hash keys that match a predicate
candidateIndices.stream()
.filter(index -> columnNames.contains(index.getHashKey()) && !getHashKeyAttributeValues(predicates.get(index.getHashKey())).isEmpty())
.forEach(hashKeyMatchesBuilder::add);
List hashKeyMatches = hashKeyMatchesBuilder.build();
// if the original table has a range key matching a predicate, start with that
ImmutableList.Builder rangeKeyMatchesBuilder = ImmutableList.builder();
if (tableIndex.getRangeKey().isPresent() && columnNames.contains(tableIndex.getRangeKey().get())) {
rangeKeyMatchesBuilder.add(tableIndex);
}
// get indices with range keys that match a predicate
candidateIndices.stream()
.filter(index -> index.getRangeKey().isPresent() && columnNames.contains(index.getRangeKey().get()))
.forEach(rangeKeyMatchesBuilder::add);
List rangeKeyMatches = rangeKeyMatchesBuilder.build();
// return first index where both hash and range key can be specified with predicates
for (DynamoDBIndex index : hashKeyMatches) {
if (rangeKeyMatches.contains(index)) {
return index;
}
}
// else return the first index with a hash key predicate, or the original table if there are none
return hashKeyMatches.isEmpty() ? tableIndex : hashKeyMatches.get(0);
}
/**
* Generates a list of distinct values from the given {@link ValueSet} or an empty list if not possible.
*
* @param valueSet the value set to generate from
* @return the list of distinct values
*/
public static List