Search in sources :

Example 1 with IntersectionCursor

use of com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionCursor 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());
    }
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) StoreTimer(com.apple.foundationdb.record.provider.common.StoreTimer) PriorityQueue(java.util.PriorityQueue) Function(java.util.function.Function) PlanHashable(com.apple.foundationdb.record.PlanHashable) ArrayList(java.util.ArrayList) UnorderedUnionCursor(com.apple.foundationdb.record.provider.foundationdb.cursors.UnorderedUnionCursor) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) IndexScanType(com.apple.foundationdb.record.IndexScanType) Tuple(com.apple.foundationdb.tuple.Tuple) TextIndexMaintainer(com.apple.foundationdb.record.provider.foundationdb.indexes.TextIndexMaintainer) Pair(org.apache.commons.lang3.tuple.Pair) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) ScanProperties(com.apple.foundationdb.record.ScanProperties) UnionCursor(com.apple.foundationdb.record.provider.foundationdb.cursors.UnionCursor) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) FDBRecordStoreBase(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase) ImmutableSet(com.google.common.collect.ImmutableSet) Iterator(java.util.Iterator) FDBStoreTimer(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer) Set(java.util.Set) Collectors(java.util.stream.Collectors) IntersectionCursor(com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionCursor) TupleRange(com.apple.foundationdb.record.TupleRange) Objects(java.util.Objects) TextTokenizer(com.apple.foundationdb.record.provider.common.text.TextTokenizer) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) List(java.util.List) Index(com.apple.foundationdb.record.metadata.Index) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) ObjectPlanHash(com.apple.foundationdb.record.ObjectPlanHash) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) IntersectionMultiCursor(com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionMultiCursor) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) API(com.apple.foundationdb.annotation.API) ProbableIntersectionCursor(com.apple.foundationdb.record.provider.foundationdb.cursors.ProbableIntersectionCursor) Comparator(java.util.Comparator) Collections(java.util.Collections) RecordCursor(com.apple.foundationdb.record.RecordCursor) IndexEntry(com.apple.foundationdb.record.IndexEntry) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) Function(java.util.function.Function) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) ScanProperties(com.apple.foundationdb.record.ScanProperties) ArrayList(java.util.ArrayList) List(java.util.List) Nonnull(javax.annotation.Nonnull)

Aggregations

API (com.apple.foundationdb.annotation.API)1 EvaluationContext (com.apple.foundationdb.record.EvaluationContext)1 ExecuteProperties (com.apple.foundationdb.record.ExecuteProperties)1 IndexEntry (com.apple.foundationdb.record.IndexEntry)1 IndexScanType (com.apple.foundationdb.record.IndexScanType)1 ObjectPlanHash (com.apple.foundationdb.record.ObjectPlanHash)1 PlanHashable (com.apple.foundationdb.record.PlanHashable)1 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)1 RecordCursor (com.apple.foundationdb.record.RecordCursor)1 ScanProperties (com.apple.foundationdb.record.ScanProperties)1 TupleRange (com.apple.foundationdb.record.TupleRange)1 Index (com.apple.foundationdb.record.metadata.Index)1 StoreTimer (com.apple.foundationdb.record.provider.common.StoreTimer)1 TextTokenizer (com.apple.foundationdb.record.provider.common.text.TextTokenizer)1 FDBRecordStoreBase (com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase)1 FDBStoreTimer (com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer)1 IntersectionCursor (com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionCursor)1 IntersectionMultiCursor (com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionMultiCursor)1 ProbableIntersectionCursor (com.apple.foundationdb.record.provider.foundationdb.cursors.ProbableIntersectionCursor)1 UnionCursor (com.apple.foundationdb.record.provider.foundationdb.cursors.UnionCursor)1