Test: Let the random parent/child tests use the query and filter parsers instead of creating the queries and filters in a custom way.

By using the query and filter parsers we increase the test coverage and make the random parent/child tests simpler.
This commit is contained in:
Martijn van Groningen 2014-11-15 22:30:16 +01:00
parent 461c20049f
commit 28f3ea1b8d
7 changed files with 85 additions and 131 deletions

View File

@ -26,8 +26,13 @@ import org.apache.lucene.util.BitSet;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.common.compress.CompressedString; import org.elasticsearch.common.compress.CompressedString;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.internal.UidFieldMapper; import org.elasticsearch.index.mapper.internal.UidFieldMapper;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.service.IndexService; import org.elasticsearch.index.service.IndexService;
import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.ElasticsearchSingleNodeLuceneTestCase; import org.elasticsearch.test.ElasticsearchSingleNodeLuceneTestCase;
@ -53,6 +58,9 @@ public abstract class AbstractChildTests extends ElasticsearchSingleNodeLuceneTe
static SearchContext createSearchContext(String indexName, String parentType, String childType) throws IOException { static SearchContext createSearchContext(String indexName, String parentType, String childType) throws IOException {
IndexService indexService = createIndex(indexName); IndexService indexService = createIndex(indexName);
MapperService mapperService = indexService.mapperService(); MapperService mapperService = indexService.mapperService();
// Parent/child parsers require that the parent and child type to be presented in mapping
// Sometimes we want a nested object field in the parent type that triggers nonNestedDocsFilter to be used
mapperService.merge(parentType, new CompressedString(PutMappingRequest.buildFromSimplifiedDef(parentType, "nested_field", random().nextBoolean() ? "type=nested" : "type=object").string()), true);
mapperService.merge(childType, new CompressedString(PutMappingRequest.buildFromSimplifiedDef(childType, "_parent", "type=" + parentType, CHILD_SCORE_NAME, "type=double").string()), true); mapperService.merge(childType, new CompressedString(PutMappingRequest.buildFromSimplifiedDef(childType, "_parent", "type=" + parentType, CHILD_SCORE_NAME, "type=double").string()), true);
return createSearchContext(indexService); return createSearchContext(indexService);
} }
@ -124,8 +132,15 @@ public abstract class AbstractChildTests extends ElasticsearchSingleNodeLuceneTe
return SearchContext.current().filterCache().cache(filter); return SearchContext.current().filterCache().cache(filter);
} }
static BitDocIdSetFilter wrapWithFixedBitSetFilter(Filter filter) { static BitDocIdSetFilter wrapWithBitSetFilter(Filter filter) {
return SearchContext.current().bitsetFilterCache().getBitDocIdSetFilter(filter); return SearchContext.current().bitsetFilterCache().getBitDocIdSetFilter(filter);
} }
static Query parseQuery(QueryBuilder queryBuilder) throws IOException {
QueryParseContext context = new QueryParseContext(new Index("test"), SearchContext.current().queryParserService());
XContentParser parser = XContentHelper.createParser(queryBuilder.buildAsBytes());
context.reset(parser);
return context.parseInnerQuery();
}
} }

View File

@ -24,20 +24,8 @@ import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField; import org.apache.lucene.document.StringField;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.*;
import org.apache.lucene.index.DocsEnum;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.SlowCompositeReaderWrapper;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.queries.TermFilter; import org.apache.lucene.queries.TermFilter;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.FilteredQuery;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryUtils; import org.apache.lucene.search.QueryUtils;
@ -47,13 +35,13 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.common.lease.Releasables; import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.lucene.search.NotFilter;
import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData; import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData;
import org.elasticsearch.index.mapper.Uid; import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.mapper.internal.ParentFieldMapper; import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
import org.elasticsearch.index.mapper.internal.TypeFieldMapper; import org.elasticsearch.index.mapper.internal.TypeFieldMapper;
import org.elasticsearch.index.mapper.internal.UidFieldMapper; import org.elasticsearch.index.mapper.internal.UidFieldMapper;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.search.nested.NonNestedDocsFilter; import org.elasticsearch.index.search.nested.NonNestedDocsFilter;
import org.elasticsearch.search.internal.ContextIndexSearcher; import org.elasticsearch.search.internal.ContextIndexSearcher;
import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.SearchContext;
@ -67,6 +55,8 @@ import java.util.NavigableSet;
import java.util.Random; import java.util.Random;
import java.util.TreeSet; import java.util.TreeSet;
import static org.elasticsearch.index.query.FilterBuilders.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class ChildrenConstantScoreQueryTests extends AbstractChildTests { public class ChildrenConstantScoreQueryTests extends AbstractChildTests {
@ -89,8 +79,8 @@ public class ChildrenConstantScoreQueryTests extends AbstractChildTests {
Query childQuery = new TermQuery(new Term("field", "value")); Query childQuery = new TermQuery(new Term("field", "value"));
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper(); ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper); ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Filter parentFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "parent"))); BitDocIdSetFilter parentFilter = wrapWithBitSetFilter(new TermFilter(new Term(TypeFieldMapper.NAME, "parent")));
Query query = new ChildrenConstantScoreQuery(parentChildIndexFieldData, childQuery, "parent", "child", parentFilter, 12, wrapWithFixedBitSetFilter(NonNestedDocsFilter.INSTANCE)); Query query = new ChildrenConstantScoreQuery(parentChildIndexFieldData, childQuery, "parent", "child", parentFilter, 12, wrapWithBitSetFilter(NonNestedDocsFilter.INSTANCE));
QueryUtils.check(query); QueryUtils.check(query);
} }
@ -122,7 +112,7 @@ public class ChildrenConstantScoreQueryTests extends AbstractChildTests {
)); ));
TermQuery childQuery = new TermQuery(new Term("field1", "value" + (1 + random().nextInt(3)))); TermQuery childQuery = new TermQuery(new Term("field1", "value" + (1 + random().nextInt(3))));
Filter parentFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "parent"))); BitDocIdSetFilter parentFilter = wrapWithBitSetFilter(new TermFilter(new Term(TypeFieldMapper.NAME, "parent")));
int shortCircuitParentDocSet = random().nextInt(5); int shortCircuitParentDocSet = random().nextInt(5);
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper(); ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper); ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
@ -180,7 +170,7 @@ public class ChildrenConstantScoreQueryTests extends AbstractChildTests {
String childValue = childValues[random().nextInt(childValues.length)]; String childValue = childValues[random().nextInt(childValues.length)];
document = new Document(); document = new Document();
document.add(new StringField(UidFieldMapper.NAME, Uid.createUid("child", Integer.toString(childDocId)), Field.Store.NO)); document.add(new StringField(UidFieldMapper.NAME, Uid.createUid("child", Integer.toString(childDocId++)), Field.Store.NO));
document.add(new StringField(TypeFieldMapper.NAME, "child", Field.Store.NO)); document.add(new StringField(TypeFieldMapper.NAME, "child", Field.Store.NO));
document.add(new StringField(ParentFieldMapper.NAME, Uid.createUid("parent", parent), Field.Store.NO)); document.add(new StringField(ParentFieldMapper.NAME, Uid.createUid("parent", parent), Field.Store.NO));
document.add(new StringField("field1", childValue, Field.Store.NO)); document.add(new StringField("field1", childValue, Field.Store.NO));
@ -214,20 +204,8 @@ public class ChildrenConstantScoreQueryTests extends AbstractChildTests {
); );
((TestSearchContext) SearchContext.current()).setSearcher(new ContextIndexSearcher(SearchContext.current(), engineSearcher)); ((TestSearchContext) SearchContext.current()).setSearcher(new ContextIndexSearcher(SearchContext.current(), engineSearcher));
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Filter parentFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "parent")));
Filter rawFilterMe = new NotFilter(new TermFilter(new Term("filter", "me")));
int max = numUniqueChildValues / 4; int max = numUniqueChildValues / 4;
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
// Using this in FQ, will invoke / test the Scorer#advance(..) and also let the Weight#scorer not get live docs as acceptedDocs
Filter filterMe;
if (random().nextBoolean()) {
filterMe = SearchContext.current().filterCache().cache(rawFilterMe);
} else {
filterMe = rawFilterMe;
}
// Simulate a parent update // Simulate a parent update
if (random().nextBoolean()) { if (random().nextBoolean()) {
final int numberOfUpdatableParents = numParentDocs - filteredOrDeletedDocs.size(); final int numberOfUpdatableParents = numParentDocs - filteredOrDeletedDocs.size();
@ -257,22 +235,21 @@ public class ChildrenConstantScoreQueryTests extends AbstractChildTests {
} }
String childValue = childValues[random().nextInt(numUniqueChildValues)]; String childValue = childValues[random().nextInt(numUniqueChildValues)];
TermQuery childQuery = new TermQuery(new Term("field1", childValue));
int shortCircuitParentDocSet = random().nextInt(numParentDocs); int shortCircuitParentDocSet = random().nextInt(numParentDocs);
BitDocIdSetFilter nonNestedDocsFilter = random().nextBoolean() ? wrapWithFixedBitSetFilter(NonNestedDocsFilter.INSTANCE) : null; QueryBuilder queryBuilder;
Query query;
if (random().nextBoolean()) { if (random().nextBoolean()) {
// Usage in HasChildQueryParser queryBuilder = hasChildQuery("child", termQuery("field1", childValue))
query = new ChildrenConstantScoreQuery(parentChildIndexFieldData, childQuery, "parent", "child", parentFilter, shortCircuitParentDocSet, nonNestedDocsFilter); .setShortCircuitCutoff(shortCircuitParentDocSet);
} else { } else {
// Usage in HasChildFilterParser queryBuilder = constantScoreQuery(
query = new ConstantScoreQuery( hasChildFilter("child", termQuery("field1", childValue))
new CustomQueryWrappingFilter( .setShortCircuitCutoff(shortCircuitParentDocSet)
new ChildrenConstantScoreQuery(parentChildIndexFieldData, childQuery, "parent", "child", parentFilter, shortCircuitParentDocSet, nonNestedDocsFilter)
)
); );
} }
query = new FilteredQuery(query, filterMe); // Using a FQ, will invoke / test the Scorer#advance(..) and also let the Weight#scorer not get live docs as acceptedDocs
queryBuilder = filteredQuery(queryBuilder, notFilter(termFilter("filter", "me")));
Query query = parseQuery(queryBuilder);
BitSetCollector collector = new BitSetCollector(indexReader.maxDoc()); BitSetCollector collector = new BitSetCollector(indexReader.maxDoc());
searcher.search(query, collector); searcher.search(query, collector);
FixedBitSet actualResult = collector.getResult(); FixedBitSet actualResult = collector.getResult();

View File

@ -35,19 +35,15 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.common.lease.Releasables; import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.lucene.search.NotFilter;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.lucene.search.function.FieldValueFactorFunction;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData; import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.Uid; import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.mapper.internal.IdFieldMapper; import org.elasticsearch.index.mapper.internal.IdFieldMapper;
import org.elasticsearch.index.mapper.internal.ParentFieldMapper; import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
import org.elasticsearch.index.mapper.internal.TypeFieldMapper; import org.elasticsearch.index.mapper.internal.TypeFieldMapper;
import org.elasticsearch.index.mapper.internal.UidFieldMapper; import org.elasticsearch.index.mapper.internal.UidFieldMapper;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.functionscore.fieldvaluefactor.FieldValueFactorFunctionBuilder;
import org.elasticsearch.index.search.nested.NonNestedDocsFilter; import org.elasticsearch.index.search.nested.NonNestedDocsFilter;
import org.elasticsearch.search.internal.ContextIndexSearcher; import org.elasticsearch.search.internal.ContextIndexSearcher;
import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.SearchContext;
@ -57,11 +53,10 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.*;
import java.util.NavigableMap;
import java.util.Random;
import java.util.TreeMap;
import static org.elasticsearch.index.query.FilterBuilders.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.lessThanOrEqualTo;
@ -86,11 +81,11 @@ public class ChildrenQueryTests extends AbstractChildTests {
ScoreType scoreType = ScoreType.values()[random().nextInt(ScoreType.values().length)]; ScoreType scoreType = ScoreType.values()[random().nextInt(ScoreType.values().length)];
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper(); ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper); ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Filter parentFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "parent"))); BitDocIdSetFilter parentFilter = wrapWithBitSetFilter(new TermFilter(new Term(TypeFieldMapper.NAME, "parent")));
int minChildren = random().nextInt(10); int minChildren = random().nextInt(10);
int maxChildren = scaledRandomIntBetween(minChildren, 10); int maxChildren = scaledRandomIntBetween(minChildren, 10);
Query query = new ChildrenQuery(parentChildIndexFieldData, "parent", "child", parentFilter, childQuery, scoreType, minChildren, Query query = new ChildrenQuery(parentChildIndexFieldData, "parent", "child", parentFilter, childQuery, scoreType, minChildren,
maxChildren, 12, wrapWithFixedBitSetFilter(NonNestedDocsFilter.INSTANCE)); maxChildren, 12, wrapWithBitSetFilter(NonNestedDocsFilter.INSTANCE));
QueryUtils.check(query); QueryUtils.check(query);
} }
@ -174,20 +169,8 @@ public class ChildrenQueryTests extends AbstractChildTests {
); );
((TestSearchContext) SearchContext.current()).setSearcher(new ContextIndexSearcher(SearchContext.current(), engineSearcher)); ((TestSearchContext) SearchContext.current()).setSearcher(new ContextIndexSearcher(SearchContext.current(), engineSearcher));
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Filter parentFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "parent")));
Filter rawFilterMe = new NotFilter(new TermFilter(new Term("filter", "me")));
int max = numUniqueChildValues / 4; int max = numUniqueChildValues / 4;
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
// Using this in FQ, will invoke / test the Scorer#advance(..) and also let the Weight#scorer not get live docs as acceptedDocs
Filter filterMe;
if (random().nextBoolean()) {
filterMe = SearchContext.current().filterCache().cache(rawFilterMe);
} else {
filterMe = rawFilterMe;
}
// Simulate a parent update // Simulate a parent update
if (random().nextBoolean()) { if (random().nextBoolean()) {
final int numberOfUpdatableParents = numParentDocs - filteredOrDeletedDocs.size(); final int numberOfUpdatableParents = numParentDocs - filteredOrDeletedDocs.size();
@ -217,18 +200,20 @@ public class ChildrenQueryTests extends AbstractChildTests {
} }
String childValue = childValues[random().nextInt(numUniqueChildValues)]; String childValue = childValues[random().nextInt(numUniqueChildValues)];
Query childQuery = new ConstantScoreQuery(new TermQuery(new Term("field1", childValue)));
int shortCircuitParentDocSet = random().nextInt(numParentDocs); int shortCircuitParentDocSet = random().nextInt(numParentDocs);
ScoreType scoreType = ScoreType.values()[random().nextInt(ScoreType.values().length)]; ScoreType scoreType = ScoreType.values()[random().nextInt(ScoreType.values().length)];
BitDocIdSetFilter nonNestedDocsFilter = random().nextBoolean() ? wrapWithFixedBitSetFilter(NonNestedDocsFilter.INSTANCE) : null;
// leave min/max set to 0 half the time // leave min/max set to 0 half the time
int minChildren = random().nextInt(2) * scaledRandomIntBetween(0, 110); int minChildren = random().nextInt(2) * scaledRandomIntBetween(0, 110);
int maxChildren = random().nextInt(2) * scaledRandomIntBetween(minChildren, 110); int maxChildren = random().nextInt(2) * scaledRandomIntBetween(minChildren, 110);
Query query = new ChildrenQuery(parentChildIndexFieldData, "parent", "child", parentFilter, childQuery, scoreType, minChildren, QueryBuilder queryBuilder = hasChildQuery("child", constantScoreQuery(termQuery("field1", childValue)))
maxChildren, shortCircuitParentDocSet, nonNestedDocsFilter); .scoreType(scoreType.name().toLowerCase(Locale.ENGLISH))
query = new FilteredQuery(query, filterMe); .minChildren(minChildren)
.maxChildren(maxChildren)
.setShortCircuitCutoff(shortCircuitParentDocSet);
// Using a FQ, will invoke / test the Scorer#advance(..) and also let the Weight#scorer not get live docs as acceptedDocs
queryBuilder = filteredQuery(queryBuilder, notFilter(termFilter("filter", "me")));
Query query = parseQuery(queryBuilder);
BitSetCollector collector = new BitSetCollector(indexReader.maxDoc()); BitSetCollector collector = new BitSetCollector(indexReader.maxDoc());
int numHits = 1 + random().nextInt(25); int numHits = 1 + random().nextInt(25);
TopScoreDocCollector actualTopDocsCollector = TopScoreDocCollector.create(numHits, false); TopScoreDocCollector actualTopDocsCollector = TopScoreDocCollector.create(numHits, false);
@ -368,23 +353,15 @@ public class ChildrenQueryTests extends AbstractChildTests {
// setup to read the parent/child map // setup to read the parent/child map
Engine.SimpleSearcher engineSearcher = new Engine.SimpleSearcher(ChildrenQueryTests.class.getSimpleName(), searcher); Engine.SimpleSearcher engineSearcher = new Engine.SimpleSearcher(ChildrenQueryTests.class.getSimpleName(), searcher);
((TestSearchContext)context).setSearcher(new ContextIndexSearcher(context, engineSearcher)); ((TestSearchContext)context).setSearcher(new ContextIndexSearcher(context, engineSearcher));
ParentFieldMapper parentFieldMapper = context.mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = context.fieldData().getForField(parentFieldMapper);
Filter parentFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "parent")));
// child query that returns the score as the value of "childScore" for each child document, // child query that returns the score as the value of "childScore" for each child document, with the parent's score determined by the score type
// with the parent's score determined by the score type QueryBuilder childQueryBuilder = functionScoreQuery(typeFilter("child")).add(new FieldValueFactorFunctionBuilder(CHILD_SCORE_NAME));
FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(CHILD_SCORE_NAME); QueryBuilder queryBuilder = hasChildQuery("child", childQueryBuilder)
IndexNumericFieldData fieldData = context.fieldData().getForField(fieldMapper); .scoreType(scoreType.name().toLowerCase(Locale.ENGLISH))
FieldValueFactorFunction fieldScore = new FieldValueFactorFunction(CHILD_SCORE_NAME, 1, FieldValueFactorFunction.Modifier.NONE, fieldData); .setShortCircuitCutoff(parentDocs);
Query childQuery = new FunctionScoreQuery(new FilteredQuery(Queries.newMatchAllQuery(), new TermFilter(new Term(TypeFieldMapper.NAME, "child"))), fieldScore);
// Perform the search for the documents using the selected score type // Perform the search for the documents using the selected score type
TopDocs docs = TopDocs docs = searcher.search(parseQuery(queryBuilder), parentDocs);
searcher.search(
new ChildrenQuery(parentChildIndexFieldData, "parent", "child", parentFilter, childQuery, scoreType, 0, 0, parentDocs, null),
parentDocs);
assertThat("Expected all parents", docs.totalHits, is(parentDocs)); assertThat("Expected all parents", docs.totalHits, is(parentDocs));
// score should be descending (just a sanity check) // score should be descending (just a sanity check)

View File

@ -26,18 +26,22 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField; import org.apache.lucene.document.StringField;
import org.apache.lucene.index.*; import org.apache.lucene.index.*;
import org.apache.lucene.queries.TermFilter; import org.apache.lucene.queries.TermFilter;
import org.apache.lucene.search.*; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryUtils;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.join.BitDocIdSetFilter;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.common.lease.Releasables; import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.lucene.search.NotFilter;
import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData; import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData;
import org.elasticsearch.index.mapper.Uid; import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.mapper.internal.ParentFieldMapper; import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
import org.elasticsearch.index.mapper.internal.TypeFieldMapper; import org.elasticsearch.index.mapper.internal.TypeFieldMapper;
import org.elasticsearch.index.mapper.internal.UidFieldMapper; import org.elasticsearch.index.mapper.internal.UidFieldMapper;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.internal.ContextIndexSearcher; import org.elasticsearch.search.internal.ContextIndexSearcher;
import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.TestSearchContext; import org.elasticsearch.test.TestSearchContext;
@ -50,6 +54,9 @@ import java.util.NavigableSet;
import java.util.Random; import java.util.Random;
import java.util.TreeSet; import java.util.TreeSet;
import static org.elasticsearch.index.query.FilterBuilders.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
/** /**
*/ */
public class ParentConstantScoreQueryTests extends AbstractChildTests { public class ParentConstantScoreQueryTests extends AbstractChildTests {
@ -72,7 +79,7 @@ public class ParentConstantScoreQueryTests extends AbstractChildTests {
Query parentQuery = new TermQuery(new Term("field", "value")); Query parentQuery = new TermQuery(new Term("field", "value"));
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper(); ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper); ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Filter childrenFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "child"))); BitDocIdSetFilter childrenFilter = wrapWithBitSetFilter(new TermFilter(new Term(TypeFieldMapper.NAME, "child")));
Query query = new ParentConstantScoreQuery(parentChildIndexFieldData, parentQuery, "parent", childrenFilter); Query query = new ParentConstantScoreQuery(parentChildIndexFieldData, parentQuery, "parent", childrenFilter);
QueryUtils.check(query); QueryUtils.check(query);
} }
@ -156,20 +163,8 @@ public class ParentConstantScoreQueryTests extends AbstractChildTests {
); );
((TestSearchContext) SearchContext.current()).setSearcher(new ContextIndexSearcher(SearchContext.current(), engineSearcher)); ((TestSearchContext) SearchContext.current()).setSearcher(new ContextIndexSearcher(SearchContext.current(), engineSearcher));
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Filter childrenFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "child")));
Filter rawFilterMe = new NotFilter(new TermFilter(new Term("filter", "me")));
int max = numUniqueParentValues / 4; int max = numUniqueParentValues / 4;
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
// Using this in FQ, will invoke / test the Scorer#advance(..) and also let the Weight#scorer not get live docs as acceptedDocs
Filter filterMe;
if (random().nextBoolean()) {
filterMe = SearchContext.current().filterCache().cache(rawFilterMe);
} else {
filterMe = rawFilterMe;
}
// Simulate a child update // Simulate a child update
if (random().nextBoolean()) { if (random().nextBoolean()) {
int numberOfUpdates = childIdToParentId.isEmpty() ? 0 : scaledRandomIntBetween(1, 25); int numberOfUpdates = childIdToParentId.isEmpty() ? 0 : scaledRandomIntBetween(1, 25);
@ -197,20 +192,15 @@ public class ParentConstantScoreQueryTests extends AbstractChildTests {
} }
String parentValue = parentValues[random().nextInt(numUniqueParentValues)]; String parentValue = parentValues[random().nextInt(numUniqueParentValues)];
TermQuery parentQuery = new TermQuery(new Term("field1", parentValue)); QueryBuilder queryBuilder;
Query query;
if (random().nextBoolean()) { if (random().nextBoolean()) {
// Usage in HasParentQueryParser queryBuilder = hasParentQuery("parent", termQuery("field1", parentValue));
query = new ParentConstantScoreQuery(parentChildIndexFieldData, parentQuery, "parent", childrenFilter);
} else { } else {
// Usage in HasParentFilterParser queryBuilder = constantScoreQuery(hasParentFilter("parent", termFilter("field1", parentValue)));
query = new ConstantScoreQuery(
new CustomQueryWrappingFilter(
new ParentConstantScoreQuery(parentChildIndexFieldData, parentQuery, "parent", childrenFilter)
)
);
} }
query = new FilteredQuery(query, filterMe); // Using a FQ, will invoke / test the Scorer#advance(..) and also let the Weight#scorer not get live docs as acceptedDocs
queryBuilder = filteredQuery(queryBuilder, notFilter(termFilter("filter", "me")));
Query query = parseQuery(queryBuilder);
BitSetCollector collector = new BitSetCollector(indexReader.maxDoc()); BitSetCollector collector = new BitSetCollector(indexReader.maxDoc());
searcher.search(query, collector); searcher.search(query, collector);
FixedBitSet actualResult = collector.getResult(); FixedBitSet actualResult = collector.getResult();

View File

@ -28,17 +28,18 @@ import org.apache.lucene.document.StringField;
import org.apache.lucene.index.*; import org.apache.lucene.index.*;
import org.apache.lucene.queries.TermFilter; import org.apache.lucene.queries.TermFilter;
import org.apache.lucene.search.*; import org.apache.lucene.search.*;
import org.apache.lucene.search.join.BitDocIdSetFilter;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.common.lease.Releasables; import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.lucene.search.NotFilter;
import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData; import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData;
import org.elasticsearch.index.mapper.Uid; import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.mapper.internal.ParentFieldMapper; import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
import org.elasticsearch.index.mapper.internal.TypeFieldMapper; import org.elasticsearch.index.mapper.internal.TypeFieldMapper;
import org.elasticsearch.index.mapper.internal.UidFieldMapper; import org.elasticsearch.index.mapper.internal.UidFieldMapper;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.internal.ContextIndexSearcher; import org.elasticsearch.search.internal.ContextIndexSearcher;
import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.TestSearchContext; import org.elasticsearch.test.TestSearchContext;
@ -52,6 +53,10 @@ import java.util.NavigableMap;
import java.util.Random; import java.util.Random;
import java.util.TreeMap; import java.util.TreeMap;
import static org.elasticsearch.index.query.FilterBuilders.notFilter;
import static org.elasticsearch.index.query.FilterBuilders.termFilter;
import static org.elasticsearch.index.query.QueryBuilders.*;
public class ParentQueryTests extends AbstractChildTests { public class ParentQueryTests extends AbstractChildTests {
@BeforeClass @BeforeClass
@ -72,7 +77,7 @@ public class ParentQueryTests extends AbstractChildTests {
Query parentQuery = new TermQuery(new Term("field", "value")); Query parentQuery = new TermQuery(new Term("field", "value"));
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper(); ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper); ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Filter childrenFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "child"))); BitDocIdSetFilter childrenFilter = wrapWithBitSetFilter(new TermFilter(new Term(TypeFieldMapper.NAME, "child")));
Query query = new ParentQuery(parentChildIndexFieldData, parentQuery, "parent", childrenFilter); Query query = new ParentQuery(parentChildIndexFieldData, parentQuery, "parent", childrenFilter);
QueryUtils.check(query); QueryUtils.check(query);
} }
@ -156,20 +161,8 @@ public class ParentQueryTests extends AbstractChildTests {
); );
((TestSearchContext) SearchContext.current()).setSearcher(new ContextIndexSearcher(SearchContext.current(), engineSearcher)); ((TestSearchContext) SearchContext.current()).setSearcher(new ContextIndexSearcher(SearchContext.current(), engineSearcher));
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Filter childrenFilter = wrap(new TermFilter(new Term(TypeFieldMapper.NAME, "child")));
Filter rawFilterMe = new NotFilter(new TermFilter(new Term("filter", "me")));
int max = numUniqueParentValues / 4; int max = numUniqueParentValues / 4;
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
// Using this in FQ, will invoke / test the Scorer#advance(..) and also let the Weight#scorer not get live docs as acceptedDocs
Filter filterMe;
if (random().nextBoolean()) {
filterMe = SearchContext.current().filterCache().cache(rawFilterMe);
} else {
filterMe = rawFilterMe;
}
// Simulate a child update // Simulate a child update
if (random().nextBoolean()) { if (random().nextBoolean()) {
int numberOfUpdates = childIdToParentId.isEmpty() ? 0 : scaledRandomIntBetween(1, 5); int numberOfUpdates = childIdToParentId.isEmpty() ? 0 : scaledRandomIntBetween(1, 5);
@ -197,9 +190,11 @@ public class ParentQueryTests extends AbstractChildTests {
} }
String parentValue = parentValues[random().nextInt(numUniqueParentValues)]; String parentValue = parentValues[random().nextInt(numUniqueParentValues)];
Query parentQuery = new ConstantScoreQuery(new TermQuery(new Term("field1", parentValue))); QueryBuilder queryBuilder = hasParentQuery("parent", constantScoreQuery(termQuery("field1", parentValue)));
Query query = new ParentQuery(parentChildIndexFieldData, parentQuery,"parent", childrenFilter); // Using a FQ, will invoke / test the Scorer#advance(..) and also let the Weight#scorer not get live docs as acceptedDocs
query = new FilteredQuery(query, filterMe); queryBuilder = filteredQuery(queryBuilder, notFilter(termFilter("filter", "me")));
Query query = parseQuery(queryBuilder);
BitSetCollector collector = new BitSetCollector(indexReader.maxDoc()); BitSetCollector collector = new BitSetCollector(indexReader.maxDoc());
int numHits = 1 + random().nextInt(25); int numHits = 1 + random().nextInt(25);
TopScoreDocCollector actualTopDocsCollector = TopScoreDocCollector.create(numHits, false); TopScoreDocCollector actualTopDocsCollector = TopScoreDocCollector.create(numHits, false);

View File

@ -57,7 +57,7 @@ public class TopChildrenQueryTests extends AbstractChildTests {
ScoreType scoreType = ScoreType.values()[random().nextInt(ScoreType.values().length)]; ScoreType scoreType = ScoreType.values()[random().nextInt(ScoreType.values().length)];
ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper(); ParentFieldMapper parentFieldMapper = SearchContext.current().mapperService().documentMapper("child").parentFieldMapper();
ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper); ParentChildIndexFieldData parentChildIndexFieldData = SearchContext.current().fieldData().getForField(parentFieldMapper);
Query query = new TopChildrenQuery(parentChildIndexFieldData, childQuery, "child", "parent", scoreType, 1, 1, wrapWithFixedBitSetFilter(NonNestedDocsFilter.INSTANCE)); Query query = new TopChildrenQuery(parentChildIndexFieldData, childQuery, "child", "parent", scoreType, 1, 1, wrapWithBitSetFilter(NonNestedDocsFilter.INSTANCE));
QueryUtils.check(query); QueryUtils.check(query);
} }

View File

@ -286,7 +286,7 @@ public class TestSearchContext extends SearchContext {
@Override @Override
public IndexQueryParserService queryParserService() { public IndexQueryParserService queryParserService() {
return null; return indexService.queryParserService();
} }
@Override @Override