SOLR-44 - simple facet support for StandardRequestHandler and DisMaxRequestHandler

git-svn-id: https://svn.apache.org/repos/asf/incubator/solr/trunk@441175 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Chris M. Hostetter 2006-09-07 18:55:14 +00:00
parent 74f787bede
commit 447ddf06ea
10 changed files with 668 additions and 31 deletions

View File

@ -46,6 +46,9 @@ New Features
be compressed using the compress=true setting. The field type also gains the
ability to specify a size threshold at which field data is compressed.
(klaas, SOLR-45)
24. Simple faceted search support for fields (enumerating terms)
and arbitrary queries added to both StandardRequestHandler and
DisMaxRequestHandler. (hossman, SOLR-44)
Changes in runtime behavior
1. classes reorganized into different packages, package names changed to Apache
@ -59,6 +62,8 @@ Changes in runtime behavior
using a '<lst name="defaults">...</lst>' init param, for backwards
compatability all init prams will be used as defaults if an init param
with that name does not exist. (hossman, SOLR-43)
6. The DisMaxRequestHandler now supports multiple occurances of the "fq"
param. (hossman, SOLR-44)
Optimizations
1. getDocListAndSet can now generate both a DocList and a DocSet from a

View File

@ -22,6 +22,8 @@ import org.apache.solr.core.SolrException;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.DocList;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.DocListAndSet;
import org.apache.solr.search.SolrQueryParser;
import org.apache.solr.search.QueryParsing;
@ -98,6 +100,8 @@ import java.net.URL;
* <li> fq - (Filter Query) a raw lucene query that can be used
* to restrict the super set of products we are interested in - more
* efficient then using bq, but doesn't influence score.
* This param can be specified multiple times, and the filters
* are addative.
* </li>
* </ul>
*
@ -113,7 +117,9 @@ import java.net.URL;
* </ul>
*
* <pre>
* :TODO: make bf,fq,pf,qf multival params now that SolrParams supports them
* :TODO: document facet param support
*
* :TODO: make bf,pf,qf multival params now that SolrParams supports them
* </pre>
*/
public class DisMaxRequestHandler
@ -310,41 +316,47 @@ public class DisMaxRequestHandler
/* * * Restrict Results * * */
List<Query> restrictions = new ArrayList<Query>(1);
/* User Restriction */
String filterQueryString = params.get(DMP.FQ);
Query filterQuery = null;
if (null != filterQueryString && !filterQueryString.equals("")) {
filterQuery = p.parse(filterQueryString);
restrictions.add(filterQuery);
}
List<Query> restrictions = U.parseFilterQueries(req);
/* * * Generate Main Results * * */
flags |= U.setReturnFields(req,rsp);
DocList results = s.getDocList(query, restrictions,
DocListAndSet results = new DocListAndSet();
NamedList facetInfo = null;
if (params.getBool(FACET,false)) {
results = s.getDocListAndSet(query, restrictions,
SolrPluginUtils.getSort(req),
req.getStart(), req.getLimit(),
flags);
rsp.add("search-results",results);
facetInfo = getFacetInfo(req, rsp, results.docSet);
} else {
results.docList = s.getDocList(query, restrictions,
SolrPluginUtils.getSort(req),
req.getStart(), req.getLimit(),
flags);
}
rsp.add("search-results",results.docList);
if (null != facetInfo) rsp.add("facet_counts", facetInfo);
/* * * Debugging Info * * */
try {
NamedList debug = U.doStandardDebug(req, userQuery, query, results);
NamedList debug = U.doStandardDebug(req, userQuery, query, results.docList);
if (null != debug) {
debug.add("boostquery", boostQuery);
debug.add("boostfunc", boostFunc);
debug.add("filterquery", filterQueryString);
if (null != filterQuery) {
debug.add("parsedfilterquery",
QueryParsing.toString(filterQuery, schema));
if (null != restrictions) {
debug.add("filter_queries", params.getParams(FQ));
List<String> fqs = new ArrayList<String>(restrictions.size());
for (Query fq : restrictions) {
fqs.add(QueryParsing.toString(fq, req.getSchema()));
}
debug.add("parsed_filter_queries",fqs);
}
rsp.add("debug", debug);
}
@ -359,8 +371,10 @@ public class DisMaxRequestHandler
BooleanQuery highlightQuery = new BooleanQuery();
U.flattenBooleanQuery(highlightQuery, query);
NamedList sumData = HighlightingUtils.doHighlighting(results, highlightQuery,
req, queryFields.keySet().toArray(new String[0]));
String[] highFields = queryFields.keySet().toArray(new String[0]);
NamedList sumData =
HighlightingUtils.doHighlighting(results.docList, highlightQuery,
req, highFields);
if(sumData != null)
rsp.add("highlighting", sumData);
}
@ -372,4 +386,22 @@ public class DisMaxRequestHandler
}
}
/**
* Fetches information about Facets for this request.
*
* Subclasses may with to override this method to provide more
* advanced faceting behavior.
* @see SimpleFacets#getFacetCounts
*/
protected NamedList getFacetInfo(SolrQueryRequest req,
SolrQueryResponse rsp,
DocSet mainSet) {
SimpleFacets f = new SimpleFacets(req.getSearcher(),
mainSet,
req.getParams());
return f.getFacetCounts();
}
}

View File

@ -0,0 +1,245 @@
/**
* Copyright 2006 The Apache Software Foundation
*
* 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 org.apache.solr.request;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermEnum;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.*;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrException;
import org.apache.solr.request.SolrParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.request.DefaultSolrParams;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.FieldType;
import org.apache.solr.search.*;
import org.apache.solr.util.NamedList;
import org.apache.solr.util.BoundedTreeSet;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
/**
* A class that generates simple Facet information for a request.
*
* More advanced facet implementations may compose or subclass this class
* to leverage any of it's functionality.
*/
public class SimpleFacets {
/** The main set of documents all facet counts should be relative to */
protected DocSet docs;
/** Configuration params behavior should be driven by */
protected SolrParams params;
/** Searcher to use for all calculations */
protected SolrIndexSearcher searcher;
public SimpleFacets(SolrIndexSearcher searcher,
DocSet docs,
SolrParams params) {
this.searcher = searcher;
this.docs = docs;
this.params = params;
}
/**
* Looks at various Params to determing if any simple Facet Constraint count
* computations are desired.
*
* @see #getFacetQueryCounts
* @see #getFacetFieldCounts
* @see SolrParams#FACET
* @return a NamedList of Facet Count info or null
*/
public NamedList getFacetCounts() {
// if someone called this method, benefit of the doubt: assume true
if (!params.getBool(params.FACET,true))
return null;
NamedList res = new NamedList();
try {
res.add("facet_queries", getFacetQueryCounts());
res.add("facet_fields", getFacetFieldCounts());
} catch (Exception e) {
SolrException.logOnce(SolrCore.log, "Exception during facet counts", e);
res.add("exception", SolrException.toStr(e));
}
return res;
}
/**
* Returns a list of facet counts for each of the facet queries
* specified in the params
*
* @see SolrParams#FACET_QUERY
*/
public NamedList getFacetQueryCounts() throws IOException,ParseException {
NamedList res = new NamedList();
/* Ignore SolrParams.DF - could have init param facet.query assuming
* the schema default with query param DF intented to only affect Q.
* If user doesn't want schema default for facet.query, they should be
* explicit.
*/
SolrQueryParser qp = new SolrQueryParser(searcher.getSchema(),null);
String[] facetQs = params.getParams(SolrParams.FACET_QUERY);
if (null != facetQs && 0 != facetQs.length) {
for (String q : facetQs) {
res.add(q, searcher.numDocs(qp.parse(q), docs));
}
}
return res;
}
/**
* Returns a list of value constraints and the associated facet counts
* for each facet field specified in the params.
*
* @see SolrParams#FACET_FIELD
* @see #getFacetFieldMissingCount
* @see #getFacetTermEnumCounts
*/
public NamedList getFacetFieldCounts()
throws IOException {
NamedList res = new NamedList();
String[] facetFs = params.getParams(SolrParams.FACET_FIELD);
if (null != facetFs && 0 != facetFs.length) {
for (String f : facetFs) {
NamedList counts = getFacetTermEnumCounts(f);
if (params.getFieldBool(f, params.FACET_MISSING, false))
counts.add(null, getFacetFieldMissingCount(f));
res.add(f, counts);
}
}
return res;
}
/**
* Returns a count of the documents in the set which do not have any
* terms for for the specified field.
*
* @see SolrParams#FACET_MISSING
*/
public int getFacetFieldMissingCount(String fieldName)
throws IOException {
DocSet hasVal = searcher.getDocSet
(new ConstantScoreRangeQuery(fieldName, null, null, false, false));
return docs.andNotSize(hasVal);
}
/**
* Returns a list of terms in the specified field along with the
* corrisponding count of documents in the set that match that constraint.
*
* @see SolrParams#FACET_LIMIT
* @see SolrParams#FACET_ZEROS
*/
public NamedList getFacetTermEnumCounts(String fieldName)
throws IOException {
/* :TODO: potential optimization...
* cache the Terms with the highest docFreq and try them first
* don't enum if we get our max from them
*/
IndexSchema schema = searcher.getSchema();
IndexReader r = searcher.getReader();
FieldType ft = schema.getFieldType(fieldName);
Set<CountPair<String,Integer>> counts
= new HashSet<CountPair<String,Integer>>();
String limit = params.getFieldParam(fieldName, params.FACET_LIMIT);
if (null != limit) {
counts = new BoundedTreeSet<CountPair<String,Integer>>
(Integer.parseInt(limit));
}
boolean zeros = params.getFieldBool(fieldName, params.FACET_ZEROS, true);
TermEnum te = r.terms(new Term(fieldName,""));
do {
Term t = te.term();
if (null == t || ! t.field().equals(fieldName))
break;
if (0 < te.docFreq()) { /* all docs may be deleted */
int count = searcher.numDocs(new TermQuery(t),
docs);
/* :TODO: is indexedToReadable correct? */
if (zeros || 0 < count)
counts.add(new CountPair<String,Integer>
(ft.indexedToReadable(t.text()), count));
}
} while (te.next());
NamedList res = new NamedList();
for (CountPair<String,Integer> p : counts) {
res.add(p.key, p.val);
}
return res;
}
/**
* A simple key=>val pair whose natural order is such that
* <b>higher</b> vals come before lower vals.
* In case of tie vals, then <b>lower</b> keys come before higher keys.
*/
public static class CountPair<K extends Comparable<? super K>, V extends Comparable<? super V>>
implements Comparable<CountPair<K,V>> {
public CountPair(K k, V v) {
key = k; val = v;
}
public K key;
public V val;
public int hashCode() {
return key.hashCode() ^ val.hashCode();
}
public boolean equals(Object o) {
return (o instanceof CountPair)
&& (0 == this.compareTo((CountPair<K,V>) o));
}
public int compareTo(CountPair<K,V> o) {
int vc = o.val.compareTo(val);
return (0 != vc ? vc : key.compareTo(o.key));
}
}
}

View File

@ -37,6 +37,8 @@ public abstract class SolrParams {
public static final String WT ="wt";
/** query string */
public static final String Q ="q";
/** Lucene query string(s) for filtering the results without affecting scoring */
public static final String FQ ="fq";
/** zero based offset of matching documents to retrieve */
public static final String START ="start";
/** number of documents to return starting at "start" */
@ -62,7 +64,38 @@ public abstract class SolrParams {
/** override default highlight Formatter class */
public static final String HIGHLIGHT_FORMATTER_CLASS = "highlightFormatterClass";
/**
* Should facet counts be calculated?
*/
public static final String FACET = "facet";
/**
* Any lucene formated queries the user would like to use for
* Facet Contraint Counts (multi-value)
*/
public static final String FACET_QUERY = "facet.query";
/**
* Any field whose terms the user wants to enumerate over for
* Facet Contraint Counts (multi-value)
*/
public static final String FACET_FIELD = "facet.field";
/**
* Numeric option indicating the maximum number of facet field counts
* be included in the response for each field - in descending order of count.
* Can be overriden on a per field basis.
*/
public static final String FACET_LIMIT = "facet.limit";
/**
* Boolean option indicating whether facet field counts of "0" should
* be included in the response. Can be overriden on a per field basis.
*/
public static final String FACET_ZEROS = "facet.zeros";
/**
* Boolean option indicating whether the response should include a
* facet field count for all records which have no value for the
* facet field. Can be overriden on a per field basis.
*/
public static final String FACET_MISSING = "facet.missing";
/** returns the String value of a param, or null if not set */

View File

@ -18,6 +18,7 @@ package org.apache.solr.request;
import org.apache.lucene.search.*;
import java.util.ArrayList;
import java.util.List;
import java.net.URL;
@ -107,20 +108,46 @@ public class StandardRequestHandler implements SolrRequestHandler, SolrInfoMBean
}
}
DocList results = req.getSearcher().getDocList(query, null, sort, p.getInt(START,0), p.getInt(ROWS,10), flags);
rsp.add(null,results);
DocListAndSet results = new DocListAndSet();
NamedList facetInfo = null;
List<Query> filters = U.parseFilterQueries(req);
SolrIndexSearcher s = req.getSearcher();
if (p.getBool(FACET,false)) {
results = s.getDocListAndSet(query, filters, sort,
p.getInt(START,0), p.getInt(ROWS,10),
flags);
facetInfo = getFacetInfo(req, rsp, results.docSet);
} else {
results.docList = s.getDocList(query, filters, sort,
p.getInt(START,0), p.getInt(ROWS,10),
flags);
}
rsp.add(null,results.docList);
if (null != facetInfo) rsp.add("facet_counts", facetInfo);
try {
NamedList dbg = U.doStandardDebug(req, qs, query, results);
if (null != dbg)
NamedList dbg = U.doStandardDebug(req, qs, query, results.docList);
if (null != dbg) {
if (null != filters) {
dbg.add("filter_queries",req.getParams().getParams(FQ));
List<String> fqs = new ArrayList<String>(filters.size());
for (Query fq : filters) {
fqs.add(QueryParsing.toString(fq, req.getSchema()));
}
dbg.add("parsed_filter_queries",fqs);
}
rsp.add("debug", dbg);
}
} catch (Exception e) {
SolrException.logOnce(SolrCore.log, "Exception durring debug", e);
rsp.add("exception_during_debug", SolrException.toStr(e));
}
NamedList sumData = HighlightingUtils.doHighlighting(
results, query, req, new String[]{defaultField});
results.docList, query, req, new String[]{defaultField});
if(sumData != null)
rsp.add("highlighting", sumData);
@ -136,6 +163,25 @@ public class StandardRequestHandler implements SolrRequestHandler, SolrInfoMBean
}
}
/**
* Fetches information about Facets for this request.
*
* Subclasses may with to override this method to provide more
* advanced faceting behavior.
* @see SimpleFacets#getFacetCounts
*/
protected NamedList getFacetInfo(SolrQueryRequest req,
SolrQueryResponse rsp,
DocSet mainSet) {
SimpleFacets f = new SimpleFacets(req.getSearcher(),
mainSet,
req.getParams());
return f.getFacetCounts();
}
//////////////////////// SolrInfoMBeans methods //////////////////////

View File

@ -0,0 +1,67 @@
/**
* Copyright 2006 The Apache Software Foundation
*
* 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 org.apache.solr.util;
import java.util.*;
/**
* A TreeSet that ensures it never grows beyond a max size.
* <code>last()</code> is removed if the <code>size()</code>
* get's bigger then <code>getMaxSize()</code>
*/
public class BoundedTreeSet<E> extends TreeSet<E> {
private int maxSize = Integer.MAX_VALUE;
public BoundedTreeSet(int maxSize) {
super();
this.setMaxSize(maxSize);
}
public BoundedTreeSet(int maxSize, Collection<? extends E> c) {
super(c);
this.setMaxSize(maxSize);
}
public BoundedTreeSet(int maxSize, Comparator<? super E> c) {
super(c);
this.setMaxSize(maxSize);
}
public BoundedTreeSet(int maxSize, SortedSet<E> s) {
super(s);
this.setMaxSize(maxSize);
}
public int getMaxSize() {
return maxSize;
}
public void setMaxSize(int max) {
maxSize = max;
adjust();
}
private void adjust() {
while (maxSize < size()) {
remove(last());
}
}
public boolean add(E item) {
boolean out = super.add(item);
adjust();
return out;
}
public boolean addAll(Collection<? extends E> c) {
boolean out = super.addAll(c);
adjust();
return out;
}
}

View File

@ -60,7 +60,9 @@ import java.io.IOException;
public static String BQ = "bq";
/** query and init param for boosting functions */
public static String BF = "bf";
/** query and init param for filtering query */
/** query and init param for filtering query
* @deprecated use SolrParams.FQ or SolrPluginUtils.parseFilterQueries
*/
public static String FQ = "fq";
/** query and init param for field list */
public static String GEN = "gen";

View File

@ -719,6 +719,30 @@ public class SolrPluginUtils {
return ss.getSort();
}
/**
* Builds a list of Query objects that should be used to filter results
* @see SolrParams#FQ
* @return null if no filter queries
*/
public static List<Query> parseFilterQueries(SolrQueryRequest req) throws ParseException {
String[] in = req.getParams().getParams(SolrParams.FQ);
if (null == in || 0 == in.length) return null;
List<Query> out = new LinkedList<Query>();
SolrIndexSearcher s = req.getSearcher();
/* Ignore SolrParams.DF - could have init param FQs assuming the
* schema default with query param DF intented to only affect Q.
* If user doesn't want schema default, they should be explicit in the FQ.
*/
SolrQueryParser qp = new SolrQueryParser(s.getSchema(), null);
for (String q : in) {
if (null != q && 0 != q.trim().length()) {
out.add(qp.parse(q));
}
}
return out;
}
/**
* A CacheRegenerator that can be used whenever the items in the cache

View File

@ -167,7 +167,7 @@ public class BasicFunctionalityTest extends AbstractSolrTestCase {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
builder.parse(new ByteArrayInputStream
(writer.toString().getBytes("UTF-8")));
(writer.toString().getBytes("UTF-8")));
}
public void testLocalSolrQueryRequestParams() {
@ -319,7 +319,173 @@ public class BasicFunctionalityTest extends AbstractSolrTestCase {
}
public void testSimpleFacetCounts() {
assertU(adoc("id", "42", "trait_s", "Tool", "trait_s", "Obnoxious",
"name", "Zapp Brannigan"));
assertU(adoc("id", "43" ,
"title", "Democratic Order of Planets"));
assertU(adoc("id", "44", "trait_s", "Tool",
"name", "The Zapper"));
assertU(adoc("id", "45", "trait_s", "Chauvinist",
"title", "25 star General"));
assertU(adoc("id", "46", "trait_s", "Obnoxious",
"subject", "Defeated the pacifists of the Gandhi nebula"));
assertU(adoc("id", "47", "trait_s", "Pig",
"text", "line up and fly directly at the enemy death cannons, clogging them with wreckage!"));
assertU(commit());
assertQ("standard request handler returns all matches",
req("id:[42 TO 47]"),
"*[count(//doc)=6]"
);
assertQ("filter results using fq",
req("q","id:[42 TO 46]",
"fq", "id:[43 TO 47]"),
"*[count(//doc)=4]"
);
assertQ("don't filter results using blank fq",
req("q","id:[42 TO 46]",
"fq", " "),
"*[count(//doc)=5]"
);
assertQ("filter results using multiple fq params",
req("q","id:[42 TO 46]",
"fq", "trait_s:Obnoxious",
"fq", "id:[43 TO 47]"),
"*[count(//doc)=1]"
);
assertQ("check counts for facet queries",
req("q", "id:[42 TO 47]"
,"facet", "true"
,"facet.query", "trait_s:Obnoxious"
,"facet.query", "id:[42 TO 45]"
,"facet.query", "id:[43 TO 47]"
,"facet.field", "trait_s"
)
,"*[count(//doc)=6]"
,"//lst[@name='facet_counts']/lst[@name='facet_queries']"
,"//lst[@name='facet_queries']/int[@name='trait_s:Obnoxious'][.='2']"
,"//lst[@name='facet_queries']/int[@name='id:[42 TO 45]'][.='4']"
,"//lst[@name='facet_queries']/int[@name='id:[43 TO 47]'][.='5']"
,"//lst[@name='facet_counts']/lst[@name='facet_fields']"
,"//lst[@name='facet_fields']/lst[@name='trait_s']"
,"*[count(//lst[@name='trait_s']/int)=4]"
,"//lst[@name='trait_s']/int[@name='Tool'][.='2']"
,"//lst[@name='trait_s']/int[@name='Obnoxious'][.='2']"
,"//lst[@name='trait_s']/int[@name='Pig'][.='1']"
);
assertQ("check counts for applied facet queries using filtering (fq)",
req("q", "id:[42 TO 47]"
,"facet", "true"
,"fq", "id:[42 TO 45]"
,"facet.field", "trait_s"
,"facet.query", "id:[42 TO 45]"
,"facet.query", "id:[43 TO 47]"
)
,"*[count(//doc)=4]"
,"//lst[@name='facet_counts']/lst[@name='facet_queries']"
,"//lst[@name='facet_queries']/int[@name='id:[42 TO 45]'][.='4']"
,"//lst[@name='facet_queries']/int[@name='id:[43 TO 47]'][.='3']"
,"*[count(//lst[@name='trait_s']/int)=4]"
,"//lst[@name='trait_s']/int[@name='Tool'][.='2']"
,"//lst[@name='trait_s']/int[@name='Obnoxious'][.='1']"
,"//lst[@name='trait_s']/int[@name='Chauvinist'][.='1']"
,"//lst[@name='trait_s']/int[@name='Pig'][.='0']"
);
assertQ("check counts with facet.zero=false&facet.missing=true using fq",
req("q", "id:[42 TO 47]"
,"facet", "true"
,"facet.zeros", "false"
,"f.trait_s.facet.missing", "true"
,"fq", "id:[42 TO 45]"
,"facet.field", "trait_s"
)
,"*[count(//doc)=4]"
,"*[count(//lst[@name='trait_s']/int)=4]"
,"//lst[@name='trait_s']/int[@name='Tool'][.='2']"
,"//lst[@name='trait_s']/int[@name='Obnoxious'][.='1']"
,"//lst[@name='trait_s']/int[@name='Chauvinist'][.='1']"
,"//lst[@name='trait_s']/int[not(@name)][.='1']"
);
}
public void testSimpleFacetCountsWithLimits() {
assertU(adoc("id", "1", "t_s", "A"));
assertU(adoc("id", "2", "t_s", "B"));
assertU(adoc("id", "3", "t_s", "C"));
assertU(adoc("id", "4", "t_s", "C"));
assertU(adoc("id", "5", "t_s", "D"));
assertU(adoc("id", "6", "t_s", "E"));
assertU(adoc("id", "7", "t_s", "E"));
assertU(adoc("id", "8", "t_s", "E"));
assertU(adoc("id", "9", "t_s", "F"));
assertU(adoc("id", "10", "t_s", "G"));
assertU(adoc("id", "11", "t_s", "G"));
assertU(adoc("id", "12", "t_s", "G"));
assertU(adoc("id", "13", "t_s", "G"));
assertU(adoc("id", "14", "t_s", "G"));
assertU(commit());
assertQ("check counts for unlimited facet",
req("q", "id:[* TO *]"
,"facet", "true"
,"facet.field", "t_s"
)
,"*[count(//lst[@name='facet_fields']/lst[@name='t_s']/int)=7]"
,"//lst[@name='t_s']/int[@name='G'][.='5']"
,"//lst[@name='t_s']/int[@name='E'][.='3']"
,"//lst[@name='t_s']/int[@name='C'][.='2']"
,"//lst[@name='t_s']/int[@name='A'][.='1']"
,"//lst[@name='t_s']/int[@name='B'][.='1']"
,"//lst[@name='t_s']/int[@name='D'][.='1']"
,"//lst[@name='t_s']/int[@name='F'][.='1']"
);
assertQ("check counts for facet with generous limit",
req("q", "id:[* TO *]"
,"facet", "true"
,"facet.limit", "100"
,"facet.field", "t_s"
)
,"*[count(//lst[@name='facet_fields']/lst[@name='t_s']/int)=7]"
,"//lst[@name='t_s']/int[1][@name='G'][.='5']"
,"//lst[@name='t_s']/int[2][@name='E'][.='3']"
,"//lst[@name='t_s']/int[3][@name='C'][.='2']"
,"//lst[@name='t_s']/int[@name='A'][.='1']"
,"//lst[@name='t_s']/int[@name='B'][.='1']"
,"//lst[@name='t_s']/int[@name='D'][.='1']"
,"//lst[@name='t_s']/int[@name='F'][.='1']"
);
assertQ("check counts for limited facet",
req("q", "id:[* TO *]"
,"facet", "true"
,"facet.limit", "2"
,"facet.field", "t_s"
)
,"*[count(//lst[@name='facet_fields']/lst[@name='t_s']/int)=2]"
,"//lst[@name='t_s']/int[1][@name='G'][.='5']"
,"//lst[@name='t_s']/int[2][@name='E'][.='3']"
);
}
private String mkstr(int len) {
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {

View File

@ -39,31 +39,39 @@ public class DisMaxRequestHandlerTest extends AbstractSolrTestCase {
public void setUp() throws Exception {
super.setUp();
lrf = h.getRequestFactory
("dismax",0,20,"version","2.0");
("dismax", 0, 20,
"version","2.0",
"facet", "true",
"facet.field","t_s"
);
}
public void testSomeStuff() throws Exception {
assertU(adoc("id", "666",
"features_t", "cool and scary stuff",
"subject", "traveling in hell",
"t_s", "movie",
"title", "The Omen",
"weight", "87.9",
"iind", "666"));
assertU(adoc("id", "42",
"features_t", "cool stuff",
"subject", "traveling the galaxy",
"t_s", "movie", "t_s", "book",
"title", "Hitch Hiker's Guide to the Galaxy",
"weight", "99.45",
"iind", "42"));
assertU(adoc("id", "1",
"features_t", "nothing",
"subject", "garbage",
"t_s", "book",
"title", "Most Boring Guide Ever",
"weight", "77",
"iind", "4"));
assertU(adoc("id", "8675309",
"features_t", "Wikedly memorable chorus and stuff",
"subject", "One Cool Hot Chick",
"t_s", "song",
"title", "Jenny",
"weight", "97.3",
"iind", "8675309"));
@ -72,6 +80,10 @@ public class DisMaxRequestHandlerTest extends AbstractSolrTestCase {
assertQ("basic match",
req("guide")
,"//*[@numFound='2']"
,"//lst[@name='facet_fields']/lst[@name='t_s']"
,"*[count(//lst[@name='t_s']/int)=3]"
,"//lst[@name='t_s']/int[@name='book'][.='2']"
,"//lst[@name='t_s']/int[@name='movie'][.='1']"
);
assertQ("basic cross field matching, boost on same field matching",
@ -94,12 +106,17 @@ public class DisMaxRequestHandlerTest extends AbstractSolrTestCase {
,"//*[@numFound='3']"
);
}
public void testOldStyleDefaults() throws Exception {
lrf = h.getRequestFactory
("dismaxOldStyleDefaults",0,20,"version","2.0");
("dismax", 0, 20,
"version","2.0",
"facet", "true",
"facet.field","t_s"
);
testSomeStuff();
}