use of com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase in project fdb-record-layer by FoundationDB.
the class RecordQueryInUnionPlan method executePlan.
@Nonnull
@Override
public <M extends Message> RecordCursor<QueryResult> executePlan(@Nonnull final FDBRecordStoreBase<M> store, @Nonnull final EvaluationContext context, @Nullable final byte[] continuation, @Nonnull final ExecuteProperties executeProperties) {
int size = getValuesSize(context);
if (size > maxNumberOfValuesAllowed) {
throw new RecordCoreException("too many IN values").addLogInfo("size", size);
}
if (size == 0) {
return RecordCursor.empty();
}
final RecordQueryPlan childPlan = getInnerPlan();
if (size == 1) {
final EvaluationContext childContext = getValuesContexts(context).get(0);
return childPlan.executePlan(store, childContext, continuation, executeProperties);
}
final ExecuteProperties childExecuteProperties;
// Can pass the limit down to all sides, since that is the most we'll take total.
if (executeProperties.getSkip() > 0) {
childExecuteProperties = executeProperties.clearSkipAndAdjustLimit();
} else {
childExecuteProperties = executeProperties;
}
final List<Function<byte[], RecordCursor<FDBQueriedRecord<M>>>> childCursorFunctions = getValuesContexts(context).stream().map(childContext -> (Function<byte[], RecordCursor<FDBQueriedRecord<M>>>) childContinuation -> childPlan.execute(store, childContext, childContinuation, childExecuteProperties)).collect(Collectors.toList());
return UnionCursor.create(store, comparisonKey, reverse, childCursorFunctions, continuation).skipThenLimit(executeProperties.getSkip(), executeProperties.getReturnedRowLimit()).map(QueryResult::of);
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase in project fdb-record-layer by FoundationDB.
the class TextScan method scan.
@Nonnull
// try-with-resources - the two cursors returned cannot be closed because they are wrapped and returned
@SuppressWarnings("squid:S2095")
private <M extends Message> RecordCursor<IndexEntry> scan(@Nonnull FDBRecordStoreBase<M> store, @Nonnull EvaluationContext context, @Nullable Tuple prefix, @Nullable TupleRange suffix, @Nonnull Index index, @Nonnull List<String> tokenList, @Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
if (tokenList.isEmpty()) {
return RecordCursor.empty();
}
final int prefixEntries = 1 + (prefix != null ? prefix.size() : 0);
final Comparisons.Type comparisonType = textComparison.getType();
if (comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_PREFIX) || (tokenList.size() == 1 && (comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_ALL_PREFIXES) || comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_ANY_PREFIX)))) {
if (tokenList.size() != 1) {
throw new RecordCoreException("text prefix comparison included " + tokenList.size() + " comparands instead of one");
}
return scanTokenPrefix(store, tokenList.get(0), prefix, suffix, index, scanProperties).apply(continuation);
} else if (tokenList.size() == 1) {
// is necessary, not just nice to have.
return scanToken(store, tokenList.get(0), prefix, suffix, index, scanProperties).apply(continuation);
} else if (comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_ALL)) {
// Take the intersection of all children. Note that to handle skip and the returned row limit correctly,
// the skip and limit are both removed and then applied later.
final ScanProperties childScanProperties = scanProperties.with(ExecuteProperties::clearSkipAndLimit);
List<Function<byte[], RecordCursor<IndexEntry>>> intersectionChildren = tokenList.stream().map(token -> scanToken(store, token, prefix, suffix, index, childScanProperties)).collect(Collectors.toList());
return IntersectionCursor.create(suffixComparisonKeyFunction(prefixEntries), scanProperties.isReverse(), intersectionChildren, continuation, store.getTimer()).skip(scanProperties.getExecuteProperties().getSkip()).limitRowsTo(scanProperties.getExecuteProperties().getReturnedRowLimit());
} else if (comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_ALL_PREFIXES)) {
final Comparisons.TextContainsAllPrefixesComparison allPrefixesComparison = (Comparisons.TextContainsAllPrefixesComparison) textComparison;
final ScanProperties childScanProperties = scanProperties.with(ExecuteProperties::clearSkipAndLimit);
List<Function<byte[], RecordCursor<IndexEntry>>> intersectionChildren = tokenList.stream().map(token -> scanTokenPrefix(store, token, prefix, suffix, index, childScanProperties)).collect(Collectors.toList());
return ProbableIntersectionCursor.create(suffixComparisonKeyFunction(prefixEntries), intersectionChildren, allPrefixesComparison.getExpectedRecords(), allPrefixesComparison.getFalsePositivePercentage(), continuation, store.getTimer()).skip(scanProperties.getExecuteProperties().getSkip()).limitRowsTo(scanProperties.getExecuteProperties().getReturnedRowLimit());
} else if (comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_ANY)) {
// Take the union of all children. Note that to handle skip and the returned row limit correctly,
// the skip is removed from the children and applied to the returned cursor. Also, the limit
// is adjusted upwards and then must be applied again to returned union.
final ScanProperties childScanProperties = scanProperties.with(ExecuteProperties::clearSkipAndAdjustLimit);
List<Function<byte[], RecordCursor<IndexEntry>>> unionChildren = tokenList.stream().map(token -> scanToken(store, token, prefix, suffix, index, childScanProperties)).collect(Collectors.toList());
return UnionCursor.create(suffixComparisonKeyFunction(prefixEntries), scanProperties.isReverse(), unionChildren, continuation, store.getTimer()).skip(scanProperties.getExecuteProperties().getSkip()).limitRowsTo(scanProperties.getExecuteProperties().getReturnedRowLimit());
} else if (comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_ANY_PREFIX)) {
final ScanProperties childScanProperties = scanProperties.with(ExecuteProperties::clearSkipAndAdjustLimit);
List<Function<byte[], RecordCursor<IndexEntry>>> unionChildren = tokenList.stream().map(token -> scanTokenPrefix(store, token, prefix, suffix, index, childScanProperties)).collect(Collectors.toList());
return UnorderedUnionCursor.create(unionChildren, continuation, store.getTimer()).skip(scanProperties.getExecuteProperties().getSkip()).limitRowsTo(scanProperties.getExecuteProperties().getReturnedRowLimit());
} else {
// Apply the filter based on the position lists
final Function<List<IndexEntry>, Boolean> predicate;
if (comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_ALL_WITHIN) && textComparison instanceof Comparisons.TextWithMaxDistanceComparison) {
int maxDistance = ((Comparisons.TextWithMaxDistanceComparison) textComparison).getMaxDistance();
predicate = entries -> entriesContainAllWithin(entries, maxDistance);
} else if (comparisonType.equals(Comparisons.Type.TEXT_CONTAINS_PHRASE)) {
List<String> tokensWithStopWords = getTokenList(store, context, false);
predicate = entries -> entriesContainPhrase(entries, tokensWithStopWords);
} else {
throw new RecordCoreException("unsupported comparison type for text query: " + comparisonType);
}
// It's either TEXT_CONTAINS_ALL_WITHIN_DISTANCE or TEXT_CONTAINS_PHRASE. In any case, we need to scan
// all tokens, intersect, and then apply a filter on the returned list.
final ScanProperties childScanProperties = scanProperties.with(ExecuteProperties::clearSkipAndLimit);
List<Function<byte[], RecordCursor<IndexEntry>>> intersectionChildren = tokenList.stream().map(token -> scanToken(store, token, prefix, suffix, index, childScanProperties)).collect(Collectors.toList());
final RecordCursor<List<IndexEntry>> intersectionCursor = IntersectionMultiCursor.create(suffixComparisonKeyFunction(prefixEntries), scanProperties.isReverse(), intersectionChildren, continuation, store.getTimer());
return intersectionCursor.filterInstrumented(predicate, store.getTimer(), inCounts, duringEvents, successCounts, failureCounts).map(indexEntries -> indexEntries.get(0)).skip(scanProperties.getExecuteProperties().getSkip()).limitRowsTo(scanProperties.getExecuteProperties().getReturnedRowLimit());
}
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase in project fdb-record-layer by FoundationDB.
the class RecordQueryScoreForRankPlan method bindScores.
private <M extends Message> CompletableFuture<EvaluationContext> bindScores(@Nonnull FDBRecordStoreBase<M> store, @Nonnull EvaluationContext context, @Nonnull IsolationLevel isolationLevel) {
final List<CompletableFuture<Tuple>> scores = ranks.stream().map(r -> bindScore(store, context, r, isolationLevel)).collect(Collectors.toList());
return AsyncUtil.whenAll(scores).thenApply(vignore -> {
EvaluationContextBuilder builder = context.childBuilder();
for (int i = 0; i < scores.size(); i++) {
final ScoreForRank rank = ranks.get(i);
final Tuple score = store.getContext().joinNow(scores.get(i));
final Object binding;
if (score == null) {
binding = null;
} else if (score == RankedSetIndexHelper.COMPARISON_SKIPPED_SCORE) {
binding = Comparisons.COMPARISON_SKIPPED_BINDING;
} else {
binding = rank.bindingFunction.apply(score);
}
builder.setBinding(rank.bindingName, binding);
}
return builder.build();
});
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase in project fdb-record-layer by FoundationDB.
the class ComposedBitmapIndexQueryPlan method executePlan.
@Nonnull
@Override
public <M extends Message> RecordCursor<QueryResult> executePlan(@Nonnull final FDBRecordStoreBase<M> store, @Nonnull final EvaluationContext context, @Nullable final byte[] continuation, @Nonnull final ExecuteProperties executeProperties) {
final ExecuteProperties scanExecuteProperties = executeProperties.getSkip() > 0 ? executeProperties.clearSkipAndAdjustLimit() : executeProperties;
final List<Function<byte[], RecordCursor<IndexEntry>>> cursorFunctions = indexPlans.stream().map(RecordQueryCoveringIndexPlan::getIndexPlan).map(scan -> (Function<byte[], RecordCursor<IndexEntry>>) childContinuation -> scan.executeEntries(store, context, childContinuation, scanExecuteProperties)).collect(Collectors.toList());
return ComposedBitmapIndexCursor.create(cursorFunctions, composer, continuation, store.getTimer()).filter(indexEntry -> indexEntry.getValue().get(0) != null).map(indexPlans.get(0).indexEntryToQueriedRecord(store)).map(QueryResult::of);
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase in project fdb-record-layer by FoundationDB.
the class QueryPlanUtils method getCoveringIndexEntryToPartialRecordFunction.
/**
* The method to get a function from an {@link IndexEntry} to a {@link FDBQueriedRecord} representing a partial record.
*/
@SuppressWarnings("unchecked")
public static <M extends Message> Function<IndexEntry, FDBQueriedRecord<M>> getCoveringIndexEntryToPartialRecordFunction(@Nonnull final FDBRecordStoreBase<M> store, @Nonnull final String recordTypeName, @Nonnull final String indexName, @Nonnull final IndexKeyValueToPartialRecord toRecord, @Nonnull final IndexScanType scanType) {
final RecordMetaData metaData = store.getRecordMetaData();
final RecordType recordType = metaData.getRecordType(recordTypeName);
final Index index = metaData.getIndex(indexName);
final Descriptors.Descriptor recordDescriptor = recordType.getDescriptor();
boolean hasPrimaryKey = scanType != IndexScanType.BY_GROUP && scanType != IndexScanType.BY_LUCENE_AUTO_COMPLETE && scanType != IndexScanType.BY_LUCENE_SPELLCHECK;
return indexEntry -> store.coveredIndexQueriedRecord(index, indexEntry, recordType, (M) toRecord.toRecord(recordDescriptor, indexEntry), hasPrimaryKey);
}
Aggregations