use of com.apple.foundationdb.record.query.QueryToKeyMatcher in project fdb-record-layer by FoundationDB.
the class LucenePlanner method planLucene.
@Override
protected ScoredPlan planLucene(@Nonnull CandidateScan candidateScan, @Nonnull Index index, @Nonnull QueryComponent filter, @Nullable KeyExpression sort) {
FilterSatisfiedMask filterMask = FilterSatisfiedMask.of(filter);
KeyExpression rootExp = index.getRootExpression();
ScanComparisons groupingComparisons;
// Getting grouping information from the index key and query filter
if (rootExp instanceof GroupingKeyExpression) {
KeyExpression groupingKey = ((GroupingKeyExpression) rootExp).getGroupingSubKey();
QueryToKeyMatcher.Match groupingMatch = new QueryToKeyMatcher(filter).matchesCoveringKey(groupingKey, filterMask);
if (!groupingMatch.getType().equals((QueryToKeyMatcher.MatchType.EQUALITY))) {
return null;
}
groupingComparisons = new ScanComparisons(groupingMatch.getEqualityComparisons(), Collections.emptySet());
} else {
groupingComparisons = null;
}
LuceneIndexQueryPlan lucenePlan = getComparisonsForLuceneFilter(index, null, filter, filterMask, groupingComparisons);
if (lucenePlan == null) {
return null;
}
RecordQueryPlan plan = lucenePlan;
plan = addTypeFilterIfNeeded(candidateScan, plan, getPossibleTypes(index));
if (filterMask.allSatisfied()) {
filterMask.setSatisfied(true);
}
return new ScoredPlan(plan, filterMask.getUnsatisfiedFilters(), Collections.emptyList(), 11 - filterMask.getUnsatisfiedFilters().size(), lucenePlan.createsDuplicates(), null);
}
use of com.apple.foundationdb.record.query.QueryToKeyMatcher in project fdb-record-layer by FoundationDB.
the class IndexAggregateGroupKeys method conditionsToGroupKeys.
@SuppressWarnings("PMD.EmptyCatchBlock")
public static Optional<IndexAggregateGroupKeys> conditionsToGroupKeys(@Nonnull KeyExpression operand, @Nullable QueryComponent conditions) {
final KeyExpression groupingKey = IndexFunctionHelper.getGroupingKey(operand);
if (conditions == null) {
if (groupingKey.getColumnSize() == 0) {
return Optional.of(new Conditions(Collections.emptyList()));
}
} else {
final QueryToKeyMatcher matcher = new QueryToKeyMatcher(conditions);
final QueryToKeyMatcher.Match match = matcher.matchesSatisfyingQuery(groupingKey);
if (match.getType() != QueryToKeyMatcher.MatchType.NO_MATCH) {
return Optional.of(new Conditions(match.getEqualityComparisons()));
}
}
return Optional.empty();
}
use of com.apple.foundationdb.record.query.QueryToKeyMatcher in project fdb-record-layer by FoundationDB.
the class IndexFunctionHelper method recordFunctionWithSubrecordCondition.
/**
* Given an index record function and condition on repeated fields (such as a key for a map-like field), return a function suitable for use with
* {@link #recordFunctionIndexEntry} to get the matching index entry.
* @param store store against which function will be evaluated
* @param recordFunction function to be evaluated
* @param record record against which to evaluate
* @param condition condition on fields of index entry
* @param <T> return type of function
* @return a new function that remembers the condition for matching
*/
@Nonnull
public static <T> IndexRecordFunction<T> recordFunctionWithSubrecordCondition(@Nonnull FDBRecordStore store, @Nonnull IndexRecordFunction<T> recordFunction, @Nonnull FDBRecord<?> record, @Nonnull QueryComponent condition) {
final IndexMaintainer indexMaintainer = indexMaintainerForRecordFunction(store, recordFunction, record).orElseThrow(() -> new RecordCoreException("Record function " + recordFunction + " requires appropriate index on " + record.getRecordType().getName()));
final Index index = indexMaintainer.state.index;
final List<KeyExpression> indexFields = index.getRootExpression().normalizeKeyForPositions();
int scalarPrefixCount = 0;
KeyExpression firstRepeated = null;
for (KeyExpression indexField : indexFields) {
if (indexField.createsDuplicates()) {
firstRepeated = indexField;
break;
}
scalarPrefixCount++;
}
if (firstRepeated == null) {
throw new RecordCoreException("Record function " + recordFunction + " condition " + condition + " does not select a repeated field in " + indexMaintainer.state.index.getName());
}
final QueryToKeyMatcher matcher = new QueryToKeyMatcher(condition);
final QueryToKeyMatcher.Match match = matcher.matchesSatisfyingQuery(firstRepeated);
if (match.getType() != QueryToKeyMatcher.MatchType.EQUALITY) {
throw new RecordCoreException("Record function " + recordFunction + " condition " + condition + " does not match " + indexMaintainer.state.index.getName());
}
return new IndexRecordFunctionWithSubrecordValues<>(recordFunction, index, scalarPrefixCount, match);
}
use of com.apple.foundationdb.record.query.QueryToKeyMatcher in project fdb-record-layer by FoundationDB.
the class ComposedBitmapIndexAggregate method separateGroupFilters.
private static boolean separateGroupFilters(@Nonnull QueryComponent filter, @Nonnull IndexAggregateFunctionCall indexAggregateFunctionCall, @Nonnull List<QueryComponent> commonFilters, @Nonnull List<QueryComponent> indexFilters) {
QueryToKeyMatcher matcher = new QueryToKeyMatcher(filter);
FilterSatisfiedMask filterMask = FilterSatisfiedMask.of(filter);
QueryToKeyMatcher.Match match = matcher.matchesCoveringKey(indexAggregateFunctionCall.getGroupingKeyExpression().getGroupingSubKey(), filterMask);
if (match.getType() != QueryToKeyMatcher.MatchType.EQUALITY) {
// Did not manage to fully restrict the grouping key.
return false;
}
// The position key(s) can also be constrained with inequalities and those go among the group filters.
matcher.matchesCoveringKey(indexAggregateFunctionCall.getGroupedExpression(), filterMask);
if (filterMask.allSatisfied()) {
// Not enough conditions left over.
return false;
}
for (FilterSatisfiedMask child : filterMask.getChildren()) {
// Any left-over filter not matching either of those must match some per-index key.
if (child.allSatisfied()) {
commonFilters.add(child.getFilter());
} else {
indexFilters.add(child.getFilter());
}
}
return true;
}
use of com.apple.foundationdb.record.query.QueryToKeyMatcher in project fdb-record-layer by FoundationDB.
the class TextScanPlanner method getScanForQuery.
/**
* Get a scan that matches a filter in the list of filters provided. It looks to satisfy the grouping
* key of the index, and then it looks for a text filter within the list of filters and checks to
* see if the given index is compatible with the filter. If it is, it will construct a scan that
* satisfies that filter using the index.
*
* @param index the text index to check
* @param filter a filter that the query must satisfy
* @param hasSort whether the query has a sort associated with it
* @param filterMask a mask over the filter containing state about which filters have been satisfied
* @return a text scan or <code>null</code> if none is found
*/
@Nullable
public static TextScan getScanForQuery(@Nonnull Index index, @Nonnull QueryComponent filter, boolean hasSort, @Nonnull FilterSatisfiedMask filterMask) {
final KeyExpression indexExpression = index.getRootExpression();
final KeyExpression groupedKey;
final FilterSatisfiedMask localMask = FilterSatisfiedMask.of(filter);
final ScanComparisons groupingComparisons;
if (indexExpression instanceof GroupingKeyExpression) {
// Grouping expression present. Make sure this is satisfied.
final KeyExpression groupingKey = ((GroupingKeyExpression) indexExpression).getGroupingSubKey();
groupedKey = ((GroupingKeyExpression) indexExpression).getGroupedSubKey();
QueryToKeyMatcher groupingQueryMatcher = new QueryToKeyMatcher(filter);
QueryToKeyMatcher.Match groupingMatch = groupingQueryMatcher.matchesCoveringKey(groupingKey, localMask);
if (!groupingMatch.getType().equals(QueryToKeyMatcher.MatchType.EQUALITY)) {
return null;
}
groupingComparisons = new ScanComparisons(groupingMatch.getEqualityComparisons(), Collections.emptySet());
} else {
// Grouping expression not present. Use first column.
groupedKey = indexExpression;
groupingComparisons = null;
}
final KeyExpression textExpression = groupedKey.getSubKey(0, 1);
final TextScan foundScan = getScanForFilter(index, textExpression, filter, groupingComparisons, hasSort, localMask);
if (foundScan != null) {
filterMask.mergeWith(localMask);
return foundScan;
}
return null;
}
Aggregations