use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.
the class FDBLuceneQueryTest method delayFetchOnLuceneComplexStringAnd.
@ParameterizedTest
@BooleanSource
public void delayFetchOnLuceneComplexStringAnd(boolean shouldDeferFetch) throws Exception {
initializeFlat();
try (FDBRecordContext context = openContext()) {
openRecordStore(context);
final QueryComponent filter1 = new LuceneQueryComponent("(the continuance AND grudge)", Lists.newArrayList());
// Query for full records
RecordQuery query = RecordQuery.newBuilder().setRecordType(TextIndexTestUtils.SIMPLE_DOC).setFilter(filter1).build();
setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
RecordQueryPlan plan = planner.plan(query);
Matcher<RecordQueryPlan> matcher = indexScan(allOf(indexScanType(IndexScanType.BY_LUCENE_FULL_TEXT), indexName("Complex$text_index"), bounds(hasTupleString("[[(the continuance AND grudge)],[(the continuance AND grudge)]]"))));
assertThat(plan, matcher);
List<Long> primaryKeys = recordStore.executeQuery(plan).map(FDBQueriedRecord::getPrimaryKey).map(t -> t.getLong(0)).asList().get();
assertEquals(ImmutableSet.of(4L), ImmutableSet.copyOf(primaryKeys));
if (shouldDeferFetch) {
assertLoadRecord(3, context);
} else {
assertLoadRecord(4, context);
}
}
}
use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.
the class FDBLuceneQueryTest method delayFetchOnLuceneFilterWithSort.
@ParameterizedTest
@BooleanSource
public void delayFetchOnLuceneFilterWithSort(boolean shouldDeferFetch) throws Exception {
initializeFlat();
try (FDBRecordContext context = openContext()) {
openRecordStore(context);
final QueryComponent filter1 = new LuceneQueryComponent("civil blood makes civil hands unclean", Lists.newArrayList("text"), true);
// Query for full records
RecordQuery query = RecordQuery.newBuilder().setRecordType(TextIndexTestUtils.SIMPLE_DOC).setFilter(filter1).setSort(field("doc_id")).build();
setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
RecordQueryPlan plan = planner.plan(query);
List<Long> primaryKeys = recordStore.executeQuery(plan).map(FDBQueriedRecord::getPrimaryKey).map(t -> t.getLong(0)).asList().get();
assertEquals(ImmutableSet.of(2L, 4L), ImmutableSet.copyOf(primaryKeys));
if (shouldDeferFetch) {
assertLoadRecord(5, context);
} else {
assertLoadRecord(6, context);
}
}
}
use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.
the class LucenePlanner method getScanForAndLucene.
private LuceneIndexQueryPlan getScanForAndLucene(@Nonnull Index index, @Nullable String parentFieldName, @Nonnull AndComponent filter, @Nullable FilterSatisfiedMask filterMask, final ScanComparisons groupingComparisons) {
final Iterator<FilterSatisfiedMask> subFilterMasks = filterMask != null ? filterMask.getChildren().iterator() : null;
final List<QueryComponent> filters = filter.getChildren();
LuceneIndexQueryPlan combinedComparison = null;
for (QueryComponent subFilter : filters) {
final FilterSatisfiedMask childMask = subFilterMasks != null ? subFilterMasks.next() : null;
LuceneIndexQueryPlan childComparison = getComparisonsForLuceneFilter(index, parentFieldName, subFilter, childMask, groupingComparisons);
if (childComparison != null && childMask != null) {
childMask.setSatisfied(true);
combinedComparison = combinedComparison == null ? childComparison : LuceneIndexQueryPlan.merge(combinedComparison, childComparison, "AND");
} else if (combinedComparison != null && childComparison == null) {
combinedComparison = null;
break;
}
}
if (filterMask != null && filterMask.getUnsatisfiedFilters().isEmpty()) {
filterMask.setSatisfied(true);
}
return combinedComparison;
}
use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.
the class IndexAggregateFunctionCall method extractFieldPaths.
/**
* Helper method to extract a set of key expressions that are bound through some comparison in the
* query component passed in.
* @param queryComponent the query component
* @param predicate a predicate used for filtering each encountered {@link FieldWithComparison}
* @return a set of {@link KeyExpression}s where each element is a key expression of a field (i.e. a
* {@link com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression}) or a simple nesting field
* (i.e. a {@link com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression}) that is bound
* through some comparison
*/
@Nonnull
public static Set<KeyExpression> extractFieldPaths(@Nonnull QueryComponent queryComponent, @Nonnull final Predicate<FieldWithComparison> predicate) {
if (queryComponent instanceof BaseField) {
final BaseField baseField = (BaseField) queryComponent;
if (baseField instanceof NestedField) {
final NestedField nestedField = (NestedField) baseField;
final Set<KeyExpression> nestedExpressions = extractFieldPaths(nestedField.getChild(), predicate);
return nestedExpressions.stream().map(nestedExpression -> Key.Expressions.field(nestedField.getFieldName()).nest(nestedExpression)).collect(ImmutableSet.toImmutableSet());
}
if (baseField instanceof FieldWithComparison) {
final FieldWithComparison fieldWithComparison = (FieldWithComparison) baseField;
if (predicate.test(fieldWithComparison)) {
return ImmutableSet.of(Key.Expressions.field(fieldWithComparison.getFieldName()));
}
}
return ImmutableSet.of();
} else if (queryComponent instanceof AndComponent) {
final Set<KeyExpression> boundFields = Sets.newHashSet();
final AndComponent andComponent = (AndComponent) queryComponent;
andComponent.getChildren().forEach(child -> boundFields.addAll(extractEqualityBoundFields(child)));
return boundFields;
}
return ImmutableSet.of();
}
use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method planOneOfThemWithComponent.
@Nullable
private ScoredPlan planOneOfThemWithComponent(@Nonnull CandidateScan candidateScan, @Nonnull KeyExpression indexExpr, @Nonnull OneOfThemWithComponent filter, @Nullable KeyExpression sort) {
if (indexExpr instanceof FieldKeyExpression) {
return null;
} else if (indexExpr instanceof ThenKeyExpression) {
ThenKeyExpression then = (ThenKeyExpression) indexExpr;
return planOneOfThemWithComponent(candidateScan, then.getChildren().get(0), filter, sort);
} else if (indexExpr instanceof NestingKeyExpression) {
NestingKeyExpression indexNesting = (NestingKeyExpression) indexExpr;
ScoredPlan plan = null;
if (sort == null) {
plan = planNesting(candidateScan, indexNesting, filter, null);
} else if (sort instanceof FieldKeyExpression) {
plan = null;
} else if (sort instanceof ThenKeyExpression) {
plan = null;
} else if (sort instanceof NestingKeyExpression) {
NestingKeyExpression sortNesting = (NestingKeyExpression) sort;
plan = planNesting(candidateScan, indexNesting, filter, sortNesting);
}
if (plan != null) {
List<QueryComponent> unsatisfied;
if (!plan.unsatisfiedFilters.isEmpty()) {
unsatisfied = Collections.singletonList(filter);
} else {
unsatisfied = Collections.emptyList();
}
// Right now it marks the whole nesting as unsatisfied, in theory there could be plans that handle that
plan = new ScoredPlan(plan.score, plan.plan, unsatisfied, true);
}
return plan;
}
return null;
}
Aggregations