mirror of https://github.com/apache/lucene.git
LUCENE-4750: convert DrillDown to DrillDownQuery
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1444482 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
91b1e22789
commit
456b429d10
|
@ -66,6 +66,9 @@ Changes in backwards compatibility policy
|
|||
* LUCENE-4761: Facet packages reorganized. Should be easy to fix your import
|
||||
statements, if you use an IDE such as Eclipse. (Shai Erera)
|
||||
|
||||
* LUCENE-4750: Convert DrillDown to DrillDownQuery, so you can initialize it
|
||||
and add drill-down categories to it. (Michael McCandless, Shai Erera)
|
||||
|
||||
Optimizations
|
||||
|
||||
* LUCENE-4687: BloomFilterPostingsFormat now lazily initializes delegate
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.apache.lucene.demo.facet.ExampleUtils;
|
|||
import org.apache.lucene.facet.params.FacetIndexingParams;
|
||||
import org.apache.lucene.facet.params.FacetSearchParams;
|
||||
import org.apache.lucene.facet.search.CountFacetRequest;
|
||||
import org.apache.lucene.facet.search.DrillDown;
|
||||
import org.apache.lucene.facet.search.DrillDownQuery;
|
||||
import org.apache.lucene.facet.search.FacetRequest;
|
||||
import org.apache.lucene.facet.search.FacetResult;
|
||||
import org.apache.lucene.facet.search.FacetResultNode;
|
||||
|
@ -16,7 +16,6 @@ import org.apache.lucene.facet.taxonomy.CategoryPath;
|
|||
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.MultiCollector;
|
||||
import org.apache.lucene.search.Query;
|
||||
|
@ -156,7 +155,8 @@ public class SimpleSearcher {
|
|||
CategoryPath categoryOfInterest = resIterator.next().label;
|
||||
|
||||
// drill-down preparation: turn the base query into a drill-down query for the category of interest
|
||||
Query q2 = DrillDown.query(indexingParams, baseQuery, Occur.MUST, categoryOfInterest);
|
||||
DrillDownQuery q2 = new DrillDownQuery(indexingParams, baseQuery);
|
||||
q2.add(categoryOfInterest);
|
||||
|
||||
// that's it - search with the new query and we're done!
|
||||
// only documents both matching the base query AND containing the
|
||||
|
|
|
@ -612,7 +612,8 @@ data set into a portion of it by specifying a certain category, is what we call
|
|||
We now show the required code lines for implementing such a drill-down.
|
||||
<pre class="prettyprint lang-java linenums">
|
||||
Query baseQuery = queryParser.parse("tennis racquet");
|
||||
Query q2 = DrillDown.query(baseQuery, new CategoryPath("make", "head"), 10));
|
||||
DrillDownQuery q2 = new DrillDownQuery(indexingParams, baseQuery);
|
||||
q2.add(new CategoryPath("make", "head"), 10));
|
||||
</pre>
|
||||
<p>
|
||||
In line 1 the original user query is created and then used to obtain information on
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.apache.lucene.search.DocIdSetIterator;
|
|||
import org.apache.lucene.util.Bits;
|
||||
|
||||
import org.apache.lucene.facet.params.FacetSearchParams;
|
||||
import org.apache.lucene.facet.search.DrillDown;
|
||||
import org.apache.lucene.facet.search.DrillDownQuery;
|
||||
import org.apache.lucene.facet.search.FacetResult;
|
||||
import org.apache.lucene.facet.search.FacetResultNode;
|
||||
import org.apache.lucene.facet.search.ScoredDocIDs;
|
||||
|
@ -105,7 +105,7 @@ class TakmiSampleFixer implements SampleFixer {
|
|||
}
|
||||
CategoryPath catPath = fresNode.label;
|
||||
|
||||
Term drillDownTerm = DrillDown.term(searchParams, catPath);
|
||||
Term drillDownTerm = DrillDownQuery.term(searchParams.indexingParams, catPath);
|
||||
// TODO (Facet): avoid Multi*?
|
||||
Bits liveDocs = MultiFields.getLiveDocs(indexReader);
|
||||
int updatedCount = countIntersection(MultiFields.getTermDocsEnum(indexReader, liveDocs,
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
package org.apache.lucene.facet.search;
|
||||
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
|
||||
import org.apache.lucene.facet.params.CategoryListParams;
|
||||
import org.apache.lucene.facet.params.FacetIndexingParams;
|
||||
import org.apache.lucene.facet.params.FacetSearchParams;
|
||||
import org.apache.lucene.facet.taxonomy.CategoryPath;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utility class for creating drill-down {@link Query queries} or {@link Term
|
||||
* terms} over {@link CategoryPath}. This can be used to e.g. narrow down a
|
||||
* user's search to selected categories.
|
||||
* <p>
|
||||
* <b>NOTE:</b> if you choose to create your own {@link Query} by calling
|
||||
* {@link #term}, it is recommended to wrap it with {@link ConstantScoreQuery}
|
||||
* and set the {@link ConstantScoreQuery#setBoost(float) boost} to {@code 0.0f},
|
||||
* so that it does not affect the scores of the documents.
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public final class DrillDown {
|
||||
|
||||
/**
|
||||
* @see #term(FacetIndexingParams, CategoryPath)
|
||||
*/
|
||||
public static final Term term(FacetSearchParams sParams, CategoryPath path) {
|
||||
return term(sParams.indexingParams, path);
|
||||
}
|
||||
|
||||
/** Return a drill-down {@link Term} for a category. */
|
||||
public static final Term term(FacetIndexingParams iParams, CategoryPath path) {
|
||||
CategoryListParams clp = iParams.getCategoryListParams(path);
|
||||
char[] buffer = new char[path.fullPathLength()];
|
||||
iParams.drillDownTermText(path, buffer);
|
||||
return new Term(clp.field, String.valueOf(buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a given {@link Query} by a drill-down query over the given
|
||||
* categories. {@link Occur} defines the relationship between the cateories
|
||||
* (e.g. {@code OR} or {@code AND}. If you need to construct a more
|
||||
* complicated relationship, e.g. {@code AND} of {@code ORs}), call this
|
||||
* method with every group of categories with the same relationship and then
|
||||
* construct a {@link BooleanQuery} which will wrap all returned queries. It
|
||||
* is advised to construct that boolean query with coord disabled, and also
|
||||
* wrap the final query with {@link ConstantScoreQuery} and set its boost to
|
||||
* {@code 0.0f}.
|
||||
* <p>
|
||||
* <b>NOTE:</b> {@link Occur} only makes sense when there is more than one
|
||||
* {@link CategoryPath} given.
|
||||
* <p>
|
||||
* <b>NOTE:</b> {@code baseQuery} can be {@code null}, in which case only the
|
||||
* {@link Query} over the categories will is returned.
|
||||
*/
|
||||
public static final Query query(FacetIndexingParams iParams, Query baseQuery, Occur occur, CategoryPath... paths) {
|
||||
if (paths == null || paths.length == 0) {
|
||||
throw new IllegalArgumentException("Empty category path not allowed for drill down query!");
|
||||
}
|
||||
|
||||
final Query q;
|
||||
if (paths.length == 1) {
|
||||
q = new TermQuery(term(iParams, paths[0]));
|
||||
} else {
|
||||
BooleanQuery bq = new BooleanQuery(true); // disable coord
|
||||
for (CategoryPath cp : paths) {
|
||||
bq.add(new TermQuery(term(iParams, cp)), occur);
|
||||
}
|
||||
q = bq;
|
||||
}
|
||||
|
||||
final ConstantScoreQuery drillDownQuery = new ConstantScoreQuery(q);
|
||||
drillDownQuery.setBoost(0.0f);
|
||||
|
||||
if (baseQuery == null) {
|
||||
return drillDownQuery;
|
||||
} else {
|
||||
BooleanQuery res = new BooleanQuery(true);
|
||||
res.add(baseQuery, Occur.MUST);
|
||||
res.add(drillDownQuery, Occur.MUST);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #query
|
||||
*/
|
||||
public static final Query query(FacetSearchParams sParams, Query baseQuery, Occur occur, CategoryPath... paths) {
|
||||
return query(sParams.indexingParams, baseQuery, occur, paths);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package org.apache.lucene.facet.search;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.lucene.facet.params.CategoryListParams;
|
||||
import org.apache.lucene.facet.params.FacetIndexingParams;
|
||||
import org.apache.lucene.facet.taxonomy.CategoryPath;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
|
||||
/**
|
||||
* A {@link Query} for drill-down over {@link CategoryPath categories}. You
|
||||
* should call {@link #add(CategoryPath...)} for every group of categories you
|
||||
* want to drill-down over. Each category in the group is {@code OR'ed} with
|
||||
* the others, and groups are {@code AND'ed}.
|
||||
* <p>
|
||||
* <b>NOTE:</b> if you choose to create your own {@link Query} by calling
|
||||
* {@link #term}, it is recommended to wrap it with {@link ConstantScoreQuery}
|
||||
* and set the {@link ConstantScoreQuery#setBoost(float) boost} to {@code 0.0f},
|
||||
* so that it does not affect the scores of the documents.
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public final class DrillDownQuery extends Query {
|
||||
|
||||
/** Return a drill-down {@link Term} for a category. */
|
||||
public static final Term term(FacetIndexingParams iParams, CategoryPath path) {
|
||||
CategoryListParams clp = iParams.getCategoryListParams(path);
|
||||
char[] buffer = new char[path.fullPathLength()];
|
||||
iParams.drillDownTermText(path, buffer);
|
||||
return new Term(clp.field, String.valueOf(buffer));
|
||||
}
|
||||
|
||||
private final BooleanQuery query;
|
||||
private final Set<String> drillDownDims = new HashSet<String>();
|
||||
|
||||
private final FacetIndexingParams fip;
|
||||
|
||||
/* Used by clone() */
|
||||
private DrillDownQuery(FacetIndexingParams fip, BooleanQuery query, Set<String> drillDownDims) {
|
||||
this.fip = fip;
|
||||
this.query = query.clone();
|
||||
this.drillDownDims.addAll(drillDownDims);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DrillDownQuery} without a base query, which means that
|
||||
* you intend to perfor a pure browsing query (equivalent to using
|
||||
* {@link MatchAllDocsQuery} as base.
|
||||
*/
|
||||
public DrillDownQuery(FacetIndexingParams fip) {
|
||||
this(fip, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DrillDownQuery} over the given base query. Can be
|
||||
* {@code null}, in which case the result {@link Query} from
|
||||
* {@link #rewrite(IndexReader)} will be a pure browsing query, filtering on
|
||||
* the added categories only.
|
||||
*/
|
||||
public DrillDownQuery(FacetIndexingParams fip, Query baseQuery) {
|
||||
query = new BooleanQuery(true); // disable coord
|
||||
if (baseQuery != null) {
|
||||
query.add(baseQuery, Occur.MUST);
|
||||
}
|
||||
this.fip = fip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one dimension of drill downs; if you pass multiple values they are
|
||||
* OR'd, and then the entire dimension is AND'd against the base query.
|
||||
*/
|
||||
public void add(CategoryPath... paths) {
|
||||
Query q;
|
||||
String dim = paths[0].components[0];
|
||||
if (drillDownDims.contains(dim)) {
|
||||
throw new IllegalArgumentException("dimension '" + dim + "' was already added");
|
||||
}
|
||||
if (paths.length == 1) {
|
||||
if (paths[0].length == 0) {
|
||||
throw new IllegalArgumentException("all CategoryPaths must have length > 0");
|
||||
}
|
||||
q = new TermQuery(term(fip, paths[0]));
|
||||
} else {
|
||||
BooleanQuery bq = new BooleanQuery(true); // disable coord
|
||||
for (CategoryPath cp : paths) {
|
||||
if (cp.length == 0) {
|
||||
throw new IllegalArgumentException("all CategoryPaths must have length > 0");
|
||||
}
|
||||
if (!cp.components[0].equals(dim)) {
|
||||
throw new IllegalArgumentException("multiple (OR'd) drill-down paths must be under same dimension; got '"
|
||||
+ dim + "' and '" + cp.components[0] + "'");
|
||||
}
|
||||
bq.add(new TermQuery(term(fip, cp)), Occur.SHOULD);
|
||||
}
|
||||
q = bq;
|
||||
}
|
||||
drillDownDims.add(dim);
|
||||
|
||||
final ConstantScoreQuery drillDownQuery = new ConstantScoreQuery(q);
|
||||
drillDownQuery.setBoost(0.0f);
|
||||
query.add(drillDownQuery, Occur.MUST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrillDownQuery clone() {
|
||||
return new DrillDownQuery(fip, query, drillDownDims);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return query.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DrillDownQuery)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DrillDownQuery other = (DrillDownQuery) obj;
|
||||
return query.equals(other.query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query rewrite(IndexReader r) throws IOException {
|
||||
if (query.clauses().size() == 0) {
|
||||
// baseQuery given to the ctor was null + no drill-downs were added
|
||||
// note that if only baseQuery was given to the ctor, but no drill-down terms
|
||||
// is fine, since the rewritten query will be the original base query.
|
||||
throw new IllegalStateException("no base query or drill-down categories given");
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(String field) {
|
||||
return query.toString(field);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,7 @@ package org.apache.lucene.facet.params;
|
|||
import org.apache.lucene.facet.FacetTestCase;
|
||||
import org.apache.lucene.facet.params.CategoryListParams;
|
||||
import org.apache.lucene.facet.params.FacetIndexingParams;
|
||||
import org.apache.lucene.facet.search.DrillDown;
|
||||
import org.apache.lucene.facet.search.DrillDownQuery;
|
||||
import org.apache.lucene.facet.taxonomy.CategoryPath;
|
||||
import org.apache.lucene.facet.util.PartitionsUtils;
|
||||
import org.apache.lucene.index.Term;
|
||||
|
@ -39,7 +39,7 @@ public class FacetIndexingParamsTest extends FacetTestCase {
|
|||
+ dfip.getFacetDelimChar() + "b";
|
||||
CategoryPath cp = new CategoryPath("a", "b");
|
||||
assertEquals("wrong drill-down term", new Term("$facets",
|
||||
expectedDDText), DrillDown.term(dfip,cp));
|
||||
expectedDDText), DrillDownQuery.term(dfip,cp));
|
||||
char[] buf = new char[20];
|
||||
int numchars = dfip.drillDownTermText(cp, buf);
|
||||
assertEquals("3 characters should be written", 3, numchars);
|
||||
|
|
|
@ -6,7 +6,7 @@ import org.apache.lucene.facet.FacetTestCase;
|
|||
import org.apache.lucene.facet.params.CategoryListParams;
|
||||
import org.apache.lucene.facet.params.FacetIndexingParams;
|
||||
import org.apache.lucene.facet.params.PerDimensionIndexingParams;
|
||||
import org.apache.lucene.facet.search.DrillDown;
|
||||
import org.apache.lucene.facet.search.DrillDownQuery;
|
||||
import org.apache.lucene.facet.taxonomy.CategoryPath;
|
||||
import org.apache.lucene.facet.util.PartitionsUtils;
|
||||
import org.apache.lucene.index.Term;
|
||||
|
@ -38,7 +38,7 @@ public class PerDimensionIndexingParamsTest extends FacetTestCase {
|
|||
assertEquals("Expected default category list field is $facets", "$facets", ifip.getCategoryListParams(null).field);
|
||||
String expectedDDText = "a" + ifip.getFacetDelimChar() + "b";
|
||||
CategoryPath cp = new CategoryPath("a", "b");
|
||||
assertEquals("wrong drill-down term", new Term("$facets", expectedDDText), DrillDown.term(ifip,cp));
|
||||
assertEquals("wrong drill-down term", new Term("$facets", expectedDDText), DrillDownQuery.term(ifip,cp));
|
||||
char[] buf = new char[20];
|
||||
int numchars = ifip.drillDownTermText(cp, buf);
|
||||
assertEquals("3 characters should be written", 3, numchars);
|
||||
|
|
|
@ -1,9 +1,44 @@
|
|||
package org.apache.lucene.facet.search;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.lucene.analysis.MockAnalyzer;
|
||||
import org.apache.lucene.analysis.MockTokenizer;
|
||||
|
@ -23,12 +58,13 @@ import org.apache.lucene.index.IndexReader;
|
|||
import org.apache.lucene.index.RandomIndexWriter;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.ScoreDoc;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.TopDocs;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
@ -50,28 +86,27 @@ import org.junit.Test;
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
public class DrillDownTest extends FacetTestCase {
|
||||
public class DrillDownQueryTest extends FacetTestCase {
|
||||
|
||||
private FacetIndexingParams defaultParams;
|
||||
private PerDimensionIndexingParams nonDefaultParams;
|
||||
private static IndexReader reader;
|
||||
private static DirectoryTaxonomyReader taxo;
|
||||
private static Directory dir;
|
||||
private static Directory taxoDir;
|
||||
|
||||
public DrillDownTest() {
|
||||
Map<CategoryPath,CategoryListParams> paramsMap = new HashMap<CategoryPath,CategoryListParams>();
|
||||
paramsMap.put(new CategoryPath("a"), randomCategoryListParams("testing_facets_a"));
|
||||
paramsMap.put(new CategoryPath("b"), randomCategoryListParams("testing_facets_b"));
|
||||
nonDefaultParams = new PerDimensionIndexingParams(paramsMap);
|
||||
defaultParams = new FacetIndexingParams(randomCategoryListParams(CategoryListParams.DEFAULT_FIELD));
|
||||
private FacetIndexingParams defaultParams;
|
||||
private PerDimensionIndexingParams nonDefaultParams;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassDrillDownQueryTest() throws Exception {
|
||||
IOUtils.close(reader, taxo, dir, taxoDir);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void createIndexes() throws IOException {
|
||||
public static void beforeClassDrillDownQueryTest() throws Exception {
|
||||
dir = newDirectory();
|
||||
RandomIndexWriter writer = new RandomIndexWriter(random(), dir,
|
||||
newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random(), MockTokenizer.KEYWORD, false)));
|
||||
Random r = random();
|
||||
RandomIndexWriter writer = new RandomIndexWriter(r, dir,
|
||||
newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(r, MockTokenizer.KEYWORD, false)));
|
||||
|
||||
taxoDir = newDirectory();
|
||||
TaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir);
|
||||
|
@ -86,7 +121,11 @@ public class DrillDownTest extends FacetTestCase {
|
|||
doc.add(new TextField("content", "bar", Field.Store.NO));
|
||||
}
|
||||
if (i % 4 == 0) { // 25
|
||||
paths.add(new CategoryPath("a"));
|
||||
if (r.nextBoolean()) {
|
||||
paths.add(new CategoryPath("a/1", '/'));
|
||||
} else {
|
||||
paths.add(new CategoryPath("a/2", '/'));
|
||||
}
|
||||
}
|
||||
if (i % 5 == 0) { // 20
|
||||
paths.add(new CategoryPath("b"));
|
||||
|
@ -105,50 +144,66 @@ public class DrillDownTest extends FacetTestCase {
|
|||
taxo = new DirectoryTaxonomyReader(taxoDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTermNonDefault() {
|
||||
Term termA = DrillDown.term(nonDefaultParams, new CategoryPath("a"));
|
||||
assertEquals(new Term("testing_facets_a", "a"), termA);
|
||||
|
||||
Term termB = DrillDown.term(nonDefaultParams, new CategoryPath("b"));
|
||||
assertEquals(new Term("testing_facets_b", "b"), termB);
|
||||
public DrillDownQueryTest() {
|
||||
Map<CategoryPath,CategoryListParams> paramsMap = new HashMap<CategoryPath,CategoryListParams>();
|
||||
paramsMap.put(new CategoryPath("a"), randomCategoryListParams("testing_facets_a"));
|
||||
paramsMap.put(new CategoryPath("b"), randomCategoryListParams("testing_facets_b"));
|
||||
nonDefaultParams = new PerDimensionIndexingParams(paramsMap);
|
||||
defaultParams = new FacetIndexingParams(randomCategoryListParams(CategoryListParams.DEFAULT_FIELD));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultField() {
|
||||
String defaultField = CategoryListParams.DEFAULT_FIELD;
|
||||
|
||||
Term termA = DrillDown.term(defaultParams, new CategoryPath("a"));
|
||||
Term termA = DrillDownQuery.term(defaultParams, new CategoryPath("a"));
|
||||
assertEquals(new Term(defaultField, "a"), termA);
|
||||
|
||||
Term termB = DrillDown.term(defaultParams, new CategoryPath("b"));
|
||||
Term termB = DrillDownQuery.term(defaultParams, new CategoryPath("b"));
|
||||
assertEquals(new Term(defaultField, "b"), termB);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAndOrs() throws Exception {
|
||||
IndexSearcher searcher = newSearcher(reader);
|
||||
|
||||
// test (a/1 OR a/2) AND b
|
||||
DrillDownQuery q = new DrillDownQuery(defaultParams);
|
||||
q.add(new CategoryPath("a/1", '/'), new CategoryPath("a/2", '/'));
|
||||
q.add(new CategoryPath("b"));
|
||||
TopDocs docs = searcher.search(q, 100);
|
||||
assertEquals(5, docs.totalHits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() throws IOException {
|
||||
IndexSearcher searcher = newSearcher(reader);
|
||||
|
||||
// Making sure the query yields 25 documents with the facet "a"
|
||||
Query q = DrillDown.query(defaultParams, null, Occur.MUST, new CategoryPath("a"));
|
||||
DrillDownQuery q = new DrillDownQuery(defaultParams);
|
||||
q.add(new CategoryPath("a"));
|
||||
TopDocs docs = searcher.search(q, 100);
|
||||
assertEquals(25, docs.totalHits);
|
||||
|
||||
// Making sure the query yields 5 documents with the facet "b" and the
|
||||
// previous (facet "a") query as a base query
|
||||
Query q2 = DrillDown.query(defaultParams, q, Occur.MUST, new CategoryPath("b"));
|
||||
DrillDownQuery q2 = new DrillDownQuery(defaultParams, q);
|
||||
q2.add(new CategoryPath("b"));
|
||||
docs = searcher.search(q2, 100);
|
||||
assertEquals(5, docs.totalHits);
|
||||
|
||||
// Making sure that a query of both facet "a" and facet "b" yields 5 results
|
||||
Query q3 = DrillDown.query(defaultParams, null, Occur.MUST, new CategoryPath("a"), new CategoryPath("b"));
|
||||
DrillDownQuery q3 = new DrillDownQuery(defaultParams);
|
||||
q3.add(new CategoryPath("a"));
|
||||
q3.add(new CategoryPath("b"));
|
||||
docs = searcher.search(q3, 100);
|
||||
assertEquals(5, docs.totalHits);
|
||||
|
||||
assertEquals(5, docs.totalHits);
|
||||
// Check that content:foo (which yields 50% results) and facet/b (which yields 20%)
|
||||
// would gather together 10 results (10%..)
|
||||
Query fooQuery = new TermQuery(new Term("content", "foo"));
|
||||
Query q4 = DrillDown.query(defaultParams, fooQuery, Occur.MUST, new CategoryPath("b"));
|
||||
DrillDownQuery q4 = new DrillDownQuery(defaultParams, fooQuery);
|
||||
q4.add(new CategoryPath("b"));
|
||||
docs = searcher.search(q4, 100);
|
||||
assertEquals(10, docs.totalHits);
|
||||
}
|
||||
|
@ -158,38 +213,25 @@ public class DrillDownTest extends FacetTestCase {
|
|||
IndexSearcher searcher = newSearcher(reader);
|
||||
|
||||
// Create the base query to start with
|
||||
Query q = DrillDown.query(defaultParams, null, Occur.MUST, new CategoryPath("a"));
|
||||
DrillDownQuery q = new DrillDownQuery(defaultParams);
|
||||
q.add(new CategoryPath("a"));
|
||||
|
||||
// Making sure the query yields 5 documents with the facet "b" and the
|
||||
// previous (facet "a") query as a base query
|
||||
Query q2 = DrillDown.query(defaultParams, q, Occur.MUST, new CategoryPath("b"));
|
||||
DrillDownQuery q2 = new DrillDownQuery(defaultParams, q);
|
||||
q2.add(new CategoryPath("b"));
|
||||
TopDocs docs = searcher.search(q2, 100);
|
||||
assertEquals(5, docs.totalHits);
|
||||
|
||||
// Check that content:foo (which yields 50% results) and facet/b (which yields 20%)
|
||||
// would gather together 10 results (10%..)
|
||||
Query fooQuery = new TermQuery(new Term("content", "foo"));
|
||||
Query q4 = DrillDown.query(defaultParams, fooQuery, Occur.MUST, new CategoryPath("b"));
|
||||
DrillDownQuery q4 = new DrillDownQuery(defaultParams, fooQuery);
|
||||
q4.add(new CategoryPath("b"));
|
||||
docs = searcher.search(q4, 100);
|
||||
assertEquals(10, docs.totalHits);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void closeIndexes() throws IOException {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
reader = null;
|
||||
}
|
||||
|
||||
if (taxo != null) {
|
||||
taxo.close();
|
||||
taxo = null;
|
||||
}
|
||||
|
||||
dir.close();
|
||||
taxoDir.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScoring() throws IOException {
|
||||
// verify that drill-down queries do not modify scores
|
||||
|
@ -204,8 +246,9 @@ public class DrillDownTest extends FacetTestCase {
|
|||
}
|
||||
|
||||
// create a drill-down query with category "a", scores should not change
|
||||
q = DrillDown.query(defaultParams, q, Occur.MUST, new CategoryPath("a"));
|
||||
docs = searcher.search(q, reader.maxDoc()); // fetch all available docs to this query
|
||||
DrillDownQuery q2 = new DrillDownQuery(defaultParams, q);
|
||||
q2.add(new CategoryPath("a"));
|
||||
docs = searcher.search(q2, reader.maxDoc()); // fetch all available docs to this query
|
||||
for (ScoreDoc sd : docs.scoreDocs) {
|
||||
assertEquals("score of doc=" + sd.doc + " modified", scores[sd.doc], sd.score, 0f);
|
||||
}
|
||||
|
@ -216,7 +259,8 @@ public class DrillDownTest extends FacetTestCase {
|
|||
// verify that drill-down queries (with no base query) returns 0.0 score
|
||||
IndexSearcher searcher = newSearcher(reader);
|
||||
|
||||
Query q = DrillDown.query(defaultParams, null, Occur.MUST, new CategoryPath("a"));
|
||||
DrillDownQuery q = new DrillDownQuery(defaultParams);
|
||||
q.add(new CategoryPath("a"));
|
||||
TopDocs docs = searcher.search(q, reader.maxDoc()); // fetch all available docs to this query
|
||||
for (ScoreDoc sd : docs.scoreDocs) {
|
||||
assertEquals(0f, sd.score, 0f);
|
||||
|
@ -224,13 +268,36 @@ public class DrillDownTest extends FacetTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testOrQuery() throws Exception {
|
||||
IndexSearcher searcher = newSearcher(reader);
|
||||
|
||||
// Making sure that a query of facet "a" or facet "b" yields 0 results
|
||||
Query q = DrillDown.query(defaultParams, null, Occur.SHOULD, new CategoryPath("a"), new CategoryPath("b"));
|
||||
TopDocs docs = searcher.search(q, 100);
|
||||
assertEquals(40, docs.totalHits);
|
||||
}
|
||||
public void testTermNonDefault() {
|
||||
Term termA = DrillDownQuery.term(nonDefaultParams, new CategoryPath("a"));
|
||||
assertEquals(new Term("testing_facets_a", "a"), termA);
|
||||
|
||||
Term termB = DrillDownQuery.term(nonDefaultParams, new CategoryPath("b"));
|
||||
assertEquals(new Term("testing_facets_b", "b"), termB);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClone() throws Exception {
|
||||
DrillDownQuery q = new DrillDownQuery(defaultParams, new MatchAllDocsQuery());
|
||||
q.add(new CategoryPath("a"));
|
||||
|
||||
DrillDownQuery clone = q.clone();
|
||||
clone.add(new CategoryPath("b"));
|
||||
|
||||
assertFalse("query wasn't cloned: source=" + q + " clone=" + clone, q.toString().equals(clone.toString()));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testNoBaseNorDrillDown() throws Exception {
|
||||
DrillDownQuery q = new DrillDownQuery(defaultParams);
|
||||
q.rewrite(reader);
|
||||
}
|
||||
|
||||
public void testNoDrillDown() throws Exception {
|
||||
Query base = new MatchAllDocsQuery();
|
||||
DrillDownQuery q = new DrillDownQuery(defaultParams, base);
|
||||
Query rewrite = q.rewrite(reader).rewrite(reader);
|
||||
assertSame(base, rewrite);
|
||||
}
|
||||
|
||||
}
|
|
@ -37,8 +37,6 @@ import org.apache.lucene.index.IndexWriterConfig;
|
|||
import org.apache.lucene.index.RandomIndexWriter;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.store.Directory;
|
||||
|
||||
public class TestDemoFacets extends FacetTestCase {
|
||||
|
@ -110,7 +108,8 @@ public class TestDemoFacets extends FacetTestCase {
|
|||
|
||||
// Now user drills down on Publish Date/2010:
|
||||
fsp = new FacetSearchParams(new CountFacetRequest(new CategoryPath("Author"), 10));
|
||||
Query q2 = DrillDown.query(fsp, new MatchAllDocsQuery(), Occur.MUST, new CategoryPath("Publish Date/2010", '/'));
|
||||
DrillDownQuery q2 = new DrillDownQuery(fsp.indexingParams, new MatchAllDocsQuery());
|
||||
q2.add(new CategoryPath("Publish Date/2010", '/'));
|
||||
c = FacetsCollector.create(fsp, searcher.getIndexReader(), taxoReader);
|
||||
searcher.search(q2, c);
|
||||
results = c.getFacetResults();
|
||||
|
|
|
@ -24,14 +24,14 @@ import org.apache.lucene.document.TextField;
|
|||
import org.apache.lucene.facet.FacetTestCase;
|
||||
import org.apache.lucene.facet.index.FacetFields;
|
||||
import org.apache.lucene.facet.params.CategoryListParams;
|
||||
import org.apache.lucene.facet.params.CategoryListParams.OrdinalPolicy;
|
||||
import org.apache.lucene.facet.params.FacetIndexingParams;
|
||||
import org.apache.lucene.facet.params.FacetSearchParams;
|
||||
import org.apache.lucene.facet.params.PerDimensionIndexingParams;
|
||||
import org.apache.lucene.facet.params.PerDimensionOrdinalPolicy;
|
||||
import org.apache.lucene.facet.params.CategoryListParams.OrdinalPolicy;
|
||||
import org.apache.lucene.facet.search.CategoryListIterator;
|
||||
import org.apache.lucene.facet.search.CountFacetRequest;
|
||||
import org.apache.lucene.facet.search.DrillDown;
|
||||
import org.apache.lucene.facet.search.DrillDownQuery;
|
||||
import org.apache.lucene.facet.search.FacetRequest;
|
||||
import org.apache.lucene.facet.search.FacetResult;
|
||||
import org.apache.lucene.facet.search.FacetResultNode;
|
||||
|
@ -41,8 +41,6 @@ import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
|||
import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
|
||||
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
|
||||
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
|
||||
import org.apache.lucene.facet.util.FacetsPayloadMigrationReader;
|
||||
import org.apache.lucene.facet.util.PartitionsUtils;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.DirectoryReader;
|
||||
|
@ -60,9 +58,7 @@ import org.apache.lucene.search.IndexSearcher;
|
|||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.MultiCollector;
|
||||
import org.apache.lucene.search.PrefixQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TotalHitCountCollector;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
|
@ -289,7 +285,8 @@ public class TestFacetsPayloadMigrationReader extends FacetTestCase {
|
|||
for (String dim : expectedCounts.keySet()) {
|
||||
CategoryPath drillDownCP = new CategoryPath(dim);
|
||||
FacetSearchParams fsp = new FacetSearchParams(fip, new CountFacetRequest(drillDownCP, 10));
|
||||
Query drillDown = DrillDown.query(fsp, new MatchAllDocsQuery(), Occur.MUST, drillDownCP);
|
||||
DrillDownQuery drillDown = new DrillDownQuery(fip, new MatchAllDocsQuery());
|
||||
drillDown.add(drillDownCP);
|
||||
TotalHitCountCollector total = new TotalHitCountCollector();
|
||||
FacetsCollector fc = FacetsCollector.create(fsp, indexReader, taxoReader);
|
||||
searcher.search(drillDown, MultiCollector.wrap(fc, total));
|
||||
|
|
Loading…
Reference in New Issue