Skip to content

Commit

Permalink
Scott's test case for FoundationDB#1927: Unable to construct a coveri…
Browse files Browse the repository at this point in the history
…ng plan for a Lucene index over a Synthetic Record Type
  • Loading branch information
MMcM committed Nov 18, 2022
1 parent c2b3445 commit 2e7d936
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
Expand Up @@ -123,6 +123,7 @@ message OrderWithHeader {
optional int32 order_no = 3 [(field).primary_key = true];
optional int32 quantity = 4;
repeated Ref cc = 5;
optional string order_desc = 6;
}

message RecordTypeUnion {
Expand Down
@@ -0,0 +1,123 @@
/*
* LuceneSyntheticPlannerTest.java
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2015-2022 Apple Inc. and the FoundationDB project authors
*
* 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.
*/

package com.apple.foundationdb.record.lucene;

import com.apple.foundationdb.record.RecordMetaData;
import com.apple.foundationdb.record.RecordMetaDataBuilder;
import com.apple.foundationdb.record.TestRecordsJoinIndexProto;
import com.apple.foundationdb.record.TestRecordsTextProto;
import com.apple.foundationdb.record.metadata.Index;
import com.apple.foundationdb.record.metadata.IndexTypes;
import com.apple.foundationdb.record.metadata.JoinedRecordTypeBuilder;
import com.apple.foundationdb.record.metadata.Key;
import com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext;
import com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreTestBase;
import com.apple.foundationdb.record.provider.foundationdb.indexes.TextIndexTestUtils;
import com.apple.foundationdb.record.query.RecordQuery;
import com.apple.foundationdb.record.query.expressions.AndComponent;
import com.apple.foundationdb.record.query.expressions.Comparisons;
import com.apple.foundationdb.record.query.expressions.FieldWithComparison;
import com.apple.foundationdb.record.query.expressions.NestedField;
import com.apple.foundationdb.record.query.expressions.QueryComponent;
import com.apple.foundationdb.record.query.plan.PlannableIndexTypes;
import com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan;
import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan;
import com.google.common.collect.Sets;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.List;

import static com.apple.foundationdb.record.metadata.Key.Expressions.concat;
import static com.apple.foundationdb.record.metadata.Key.Expressions.concatenateFields;
import static com.apple.foundationdb.record.metadata.Key.Expressions.field;
import static com.apple.foundationdb.record.metadata.Key.Expressions.function;

/**
* Tests about applying the Lucene index when used as part of a SyntheticRecord join.
*/
public class LuceneSyntheticPlannerTest extends FDBRecordStoreTestBase {

protected void openRecordStore(FDBRecordContext context, FDBRecordStoreTestBase.RecordMetaDataHook hook, boolean attemptWholeFilter) {
RecordMetaDataBuilder metaDataBuilder = RecordMetaData.newBuilder().setRecords(TestRecordsJoinIndexProto.getDescriptor());
hook.apply(metaDataBuilder);
recordStore = getStoreBuilder(context, metaDataBuilder.getRecordMetaData()).createOrOpen();

PlannableIndexTypes indexTypes = new PlannableIndexTypes(
Sets.newHashSet(IndexTypes.VALUE, IndexTypes.VERSION),
Sets.newHashSet(IndexTypes.RANK, IndexTypes.TIME_WINDOW_LEADERBOARD),
Sets.newHashSet(IndexTypes.TEXT),
Sets.newHashSet(LuceneIndexTypes.LUCENE)
);
planner = new LucenePlanner(recordStore.getRecordMetaData(), recordStore.getRecordStoreState(), indexTypes, recordStore.getTimer());
planner.setConfiguration(planner.getConfiguration()
.asBuilder()
.setPlanOtherAttemptWholeFilter(attemptWholeFilter)
.build());
}

@Test
void canPlanQueryAgainstSyntheticLuceneType() {
try (FDBRecordContext context = openContext()) {
openRecordStore(context, metaDataBuilder -> {
metaDataBuilder.getRecordType("CustomerWithHeader")
.setPrimaryKey(Key.Expressions.concat(field("___header").nest("z_key"), field("___header").nest("rec_id")));
metaDataBuilder.getRecordType("OrderWithHeader")
.setPrimaryKey(Key.Expressions.concat(field("___header").nest("z_key"), field("___header").nest("rec_id")));

//set up the joined index
final JoinedRecordTypeBuilder joined = metaDataBuilder.addJoinedRecordType("luceneJoinedIdx");
joined.addConstituent("order", "OrderWithHeader");
joined.addConstituent("cust", "CustomerWithHeader");
joined.addJoin("order", field("___header").nest("z_key"),
"cust", field("___header").nest("z_key"));
joined.addJoin("order", field("custRef").nest("string_value"),
"cust", field("___header").nest("rec_id"));

metaDataBuilder.addIndex(joined, new Index("joinNestedConcat", concat(
field("cust").nest(function(LuceneFunctionNames.LUCENE_STORED, field("name"))),
field("order").nest(concat(function(LuceneFunctionNames.LUCENE_STORED, field("order_no")),
function(LuceneFunctionNames.LUCENE_TEXT, field("order_desc"))
))
), LuceneIndexTypes.LUCENE));
metaDataBuilder.addIndex("OrderWithHeader", "order$custRef", concat(field("___header").nest("z_key"), field("custRef").nest("string_value")));
}, false);

// QueryComponent filter = new AndComponent(List.of(
// new NestedField("order",new NestedField("___header",new FieldWithComparison("z_key", new Comparisons.NullComparison(Comparisons.Type.IS_NULL)))),
// new LuceneQueryComponent("order_order_desc: \"twelve pineapple\" and cust_name: \"steve\"",List.of("order","cust"))
// ));

QueryComponent filter = new LuceneQueryComponent("order_order_desc: \"twelve pineapple\" and cust_name: \"steve\"",List.of("order","cust"));


RecordQuery query = RecordQuery.newBuilder()
.setRecordType("luceneJoinedIdx")
.setFilter(filter)
.setRequiredResults(List.of(Key.Expressions.field("order").nest("order_no")))
.build();
final RecordQueryPlan plan = planner.plan(query);
Assertions.assertTrue(plan.hasIndexScan("joinNestedConcat"),"Incorrect index scan");
Assertions.assertTrue(plan instanceof RecordQueryCoveringIndexPlan, "Is not a covering scan!");
}

}
}

0 comments on commit 2e7d936

Please sign in to comment.