You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by yo...@apache.org on 2009/10/06 16:13:24 UTC
svn commit: r822286 - in /lucene/solr/trunk/src:
java/org/apache/solr/handler/component/ java/org/apache/solr/request/
java/org/apache/solr/schema/ test/org/apache/solr/
test/org/apache/solr/handler/component/ test/test-files/solr/conf/
Author: yonik
Date: Tue Oct 6 14:13:20 2009
New Revision: 822286
URL: http://svn.apache.org/viewvc?rev=822286&view=rev
Log:
SOLR-1492: add missing support for multivalued stats.facet, add facet and stats support for multi-part trie fields
Modified:
lucene/solr/trunk/src/java/org/apache/solr/handler/component/FieldFacetStats.java
lucene/solr/trunk/src/java/org/apache/solr/handler/component/StatsComponent.java
lucene/solr/trunk/src/java/org/apache/solr/request/SimpleFacets.java
lucene/solr/trunk/src/java/org/apache/solr/request/UnInvertedField.java
lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java
lucene/solr/trunk/src/java/org/apache/solr/schema/TrieField.java
lucene/solr/trunk/src/test/org/apache/solr/TestTrie.java
lucene/solr/trunk/src/test/org/apache/solr/handler/component/StatsComponentTest.java
lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml
Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/component/FieldFacetStats.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/component/FieldFacetStats.java?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/handler/component/FieldFacetStats.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/handler/component/FieldFacetStats.java Tue Oct 6 14:13:20 2009
@@ -103,7 +103,8 @@
}
- //function to keep track of facet counts for term number
+ // Function to keep track of facet counts for term number.
+ // Currently only used by UnInvertedField stats
public boolean facetTermNum(int docID, int statsTermNum) {
int term = termNum[docID];
Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/component/StatsComponent.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/component/StatsComponent.java?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/handler/component/StatsComponent.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/handler/component/StatsComponent.java Tue Oct 6 14:13:20 2009
@@ -34,6 +34,7 @@
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.SchemaField;
+import org.apache.solr.schema.TrieField;
import org.apache.solr.search.DocIterator;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.SolrIndexSearcher;
@@ -224,7 +225,11 @@
SchemaField sf = searcher.getSchema().getField(f);
FieldType ft = sf.getType();
NamedList stv;
- if (ft.isTokenized() || sf.multiValued()) {
+
+ // Currently, only UnInvertedField can deal with multi-part trie fields
+ String prefix = TrieField.getMainValuePrefix(ft);
+
+ if (sf.multiValued() || ft.multiValuedFieldCache() || prefix!=null) {
//use UnInvertedField for multivalued fields
UnInvertedField uif = UnInvertedField.getUnInvertedField(f, searcher);
stv = uif.getStats(searcher, docs, facets).getStatsValues();
Modified: lucene/solr/trunk/src/java/org/apache/solr/request/SimpleFacets.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/request/SimpleFacets.java?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/request/SimpleFacets.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/request/SimpleFacets.java Tue Oct 6 14:13:20 2009
@@ -233,7 +233,14 @@
// Always use filters for booleans... we know the number of values is very small.
enumMethod = true;
}
- boolean multiToken = sf.multiValued() || ft.isTokenized();
+ boolean multiToken = sf.multiValued() || ft.multiValuedFieldCache();
+
+ if (TrieField.getMainValuePrefix(ft) != null) {
+ // A TrieField with multiple parts indexed per value... currently only
+ // UnInvertedField can handle this case, so force it's use.
+ enumMethod = false;
+ multiToken = true;
+ }
// unless the enum method is explicitly specified, use a counting method.
if (enumMethod) {
Modified: lucene/solr/trunk/src/java/org/apache/solr/request/UnInvertedField.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/request/UnInvertedField.java?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/request/UnInvertedField.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/request/UnInvertedField.java Tue Oct 6 14:13:20 2009
@@ -23,12 +23,14 @@
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.TermEnum;
import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TermRangeQuery;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.SolrException;
import org.apache.solr.core.SolrCore;
import org.apache.solr.schema.FieldType;
+import org.apache.solr.schema.TrieField;
import org.apache.solr.search.*;
import org.apache.solr.util.BoundedTreeSet;
import org.apache.solr.handler.component.StatsValues;
@@ -171,7 +173,8 @@
public UnInvertedField(String field, SolrIndexSearcher searcher) throws IOException {
this.field = field;
- this.ti = new TermIndex(field);
+ this.ti = new TermIndex(field,
+ TrieField.getMainValuePrefix(searcher.getSchema().getFieldType(field)));
uninvert(searcher);
}
@@ -641,141 +644,150 @@
int baseSize = docs.size();
int maxDoc = searcher.maxDoc();
- if (baseSize > 0) {
- FieldType ft = searcher.getSchema().getFieldType(field);
+ if (baseSize <= 0) return allstats;
- int i = 0;
- final FieldFacetStats[] finfo = new FieldFacetStats[facet.length];
- //Initialize facetstats, if facets have been passed in
- FieldCache.StringIndex si;
- for (String f : facet) {
- ft = searcher.getSchema().getFieldType(f);
- try {
- si = FieldCache.DEFAULT.getStringIndex(searcher.getReader(), f);
- }
- catch (IOException e) {
- throw new RuntimeException("failed to open field cache for: " + f, e);
- }
- finfo[i++] = new FieldFacetStats(f, si, ft, numTermsInField);
+ FieldType ft = searcher.getSchema().getFieldType(field);
+
+ DocSet missing = docs.andNot( searcher.getDocSet(new TermRangeQuery(field, null, null, false, false)) );
+
+ int i = 0;
+ final FieldFacetStats[] finfo = new FieldFacetStats[facet.length];
+ //Initialize facetstats, if facets have been passed in
+ FieldCache.StringIndex si;
+ for (String f : facet) {
+ FieldType facet_ft = searcher.getSchema().getFieldType(f);
+ try {
+ si = FieldCache.DEFAULT.getStringIndex(searcher.getReader(), f);
}
+ catch (IOException e) {
+ throw new RuntimeException("failed to open field cache for: " + f, e);
+ }
+ finfo[i] = new FieldFacetStats(f, si, facet_ft, numTermsInField);
+ i++;
+ }
- final int[] index = this.index;
- final int[] counts = new int[numTermsInField];//keep track of the number of times we see each word in the field for all the documents in the docset
+ final int[] index = this.index;
+ final int[] counts = new int[numTermsInField];//keep track of the number of times we see each word in the field for all the documents in the docset
- NumberedTermEnum te = ti.getEnumerator(searcher.getReader());
+ NumberedTermEnum te = ti.getEnumerator(searcher.getReader());
- boolean doNegative = false;
- if (finfo.length == 0) {
- //if we're collecting statistics with a facet field, can't do inverted counting
- doNegative = baseSize > maxDoc >> 1 && termInstances > 0
- && docs instanceof BitDocSet;
- }
+ boolean doNegative = false;
+ if (finfo.length == 0) {
+ //if we're collecting statistics with a facet field, can't do inverted counting
+ doNegative = baseSize > maxDoc >> 1 && termInstances > 0
+ && docs instanceof BitDocSet;
+ }
- if (doNegative) {
- OpenBitSet bs = (OpenBitSet) ((BitDocSet) docs).getBits().clone();
- bs.flip(0, maxDoc);
- // TODO: when iterator across negative elements is available, use that
- // instead of creating a new bitset and inverting.
- docs = new BitDocSet(bs, maxDoc - baseSize);
- // simply negating will mean that we have deleted docs in the set.
- // that should be OK, as their entries in our table should be empty.
- }
+ if (doNegative) {
+ OpenBitSet bs = (OpenBitSet) ((BitDocSet) docs).getBits().clone();
+ bs.flip(0, maxDoc);
+ // TODO: when iterator across negative elements is available, use that
+ // instead of creating a new bitset and inverting.
+ docs = new BitDocSet(bs, maxDoc - baseSize);
+ // simply negating will mean that we have deleted docs in the set.
+ // that should be OK, as their entries in our table should be empty.
+ }
- // For the biggest terms, do straight set intersections
- for (TopTerm tt : bigTerms.values()) {
- // TODO: counts could be deferred if sorted==false
- if (tt.termNum >= 0 && tt.termNum < numTermsInField) {
- if (finfo.length == 0) {
- counts[tt.termNum] = searcher.numDocs(new TermQuery(tt.term), docs);
- } else {
- //COULD BE VERY SLOW
- //if we're collecting stats for facet fields, we need to iterate on all matching documents
- DocSet bigTermDocSet = searcher.getDocSet(new TermQuery(tt.term)).intersection(docs);
- DocIterator iter = bigTermDocSet.iterator();
- while (iter.hasNext()) {
- int doc = iter.nextDoc();
- counts[tt.termNum]++;
- for (FieldFacetStats f : finfo) {
- f.facetTermNum(doc, tt.termNum);
- }
+ // For the biggest terms, do straight set intersections
+ for (TopTerm tt : bigTerms.values()) {
+ // TODO: counts could be deferred if sorted==false
+ if (tt.termNum >= 0 && tt.termNum < numTermsInField) {
+ if (finfo.length == 0) {
+ counts[tt.termNum] = searcher.numDocs(new TermQuery(tt.term), docs);
+ } else {
+ //COULD BE VERY SLOW
+ //if we're collecting stats for facet fields, we need to iterate on all matching documents
+ DocSet bigTermDocSet = searcher.getDocSet(new TermQuery(tt.term)).intersection(docs);
+ DocIterator iter = bigTermDocSet.iterator();
+ while (iter.hasNext()) {
+ int doc = iter.nextDoc();
+ counts[tt.termNum]++;
+ for (FieldFacetStats f : finfo) {
+ f.facetTermNum(doc, tt.termNum);
}
}
}
}
+ }
- if (termInstances > 0) {
- DocIterator iter = docs.iterator();
- while (iter.hasNext()) {
- int doc = iter.nextDoc();
- int code = index[doc];
-
- if ((code & 0xff) == 1) {
- int pos = code >>> 8;
- int whichArray = (doc >>> 16) & 0xff;
- byte[] arr = tnums[whichArray];
- int tnum = 0;
+ if (termInstances > 0) {
+ DocIterator iter = docs.iterator();
+ while (iter.hasNext()) {
+ int doc = iter.nextDoc();
+ int code = index[doc];
+
+ if ((code & 0xff) == 1) {
+ int pos = code >>> 8;
+ int whichArray = (doc >>> 16) & 0xff;
+ byte[] arr = tnums[whichArray];
+ int tnum = 0;
+ for (; ;) {
+ int delta = 0;
for (; ;) {
- int delta = 0;
- for (; ;) {
- byte b = arr[pos++];
- delta = (delta << 7) | (b & 0x7f);
- if ((b & 0x80) == 0) break;
- }
+ byte b = arr[pos++];
+ delta = (delta << 7) | (b & 0x7f);
+ if ((b & 0x80) == 0) break;
+ }
+ if (delta == 0) break;
+ tnum += delta - TNUM_OFFSET;
+ counts[tnum]++;
+ for (FieldFacetStats f : finfo) {
+ f.facetTermNum(doc, tnum);
+ }
+ }
+ } else {
+ int tnum = 0;
+ int delta = 0;
+ for (; ;) {
+ delta = (delta << 7) | (code & 0x7f);
+ if ((code & 0x80) == 0) {
if (delta == 0) break;
tnum += delta - TNUM_OFFSET;
counts[tnum]++;
for (FieldFacetStats f : finfo) {
f.facetTermNum(doc, tnum);
}
+ delta = 0;
}
- } else {
- int tnum = 0;
- int delta = 0;
- for (; ;) {
- delta = (delta << 7) | (code & 0x7f);
- if ((code & 0x80) == 0) {
- if (delta == 0) break;
- tnum += delta - TNUM_OFFSET;
- counts[tnum]++;
- for (FieldFacetStats f : finfo) {
- f.facetTermNum(doc, tnum);
- }
- delta = 0;
- }
- code >>>= 8;
- }
+ code >>>= 8;
}
}
}
+ }
- // add results in index order
+ // add results in index order
- for (i = 0; i < numTermsInField; i++) {
- int c = doNegative ? maxTermCounts[i] - counts[i] : counts[i];
- if (c == 0) {
- continue;
- }
- Double value = Double.parseDouble(ft.indexedToReadable(getTermText(te, i)));
- allstats.accumulate(value, c);
- //as we've parsed the termnum into a value, lets also accumulate fieldfacet statistics
- for (FieldFacetStats f : finfo) {
- f.accumulateTermNum(i, value);
- }
+ for (i = 0; i < numTermsInField; i++) {
+ int c = doNegative ? maxTermCounts[i] - counts[i] : counts[i];
+ if (c == 0) continue;
+ Double value = Double.parseDouble(ft.indexedToReadable(getTermText(te, i)));
+ allstats.accumulate(value, c);
+ //as we've parsed the termnum into a value, lets also accumulate fieldfacet statistics
+ for (FieldFacetStats f : finfo) {
+ f.accumulateTermNum(i, value);
}
- te.close();
- int c = SimpleFacets.getFieldMissingCount(searcher, baseDocs, field);
- if (c > 0) {
- allstats.addMissing(c);
- }
- if (finfo.length > 0) {
- allstats.facets = new HashMap<String, Map<String, StatsValues>>();
- for (FieldFacetStats f : finfo) {
- allstats.facets.put(f.name, f.facetStatsValues);
+ }
+ te.close();
+
+ int c = missing.size();
+ allstats.addMissing(c);
+
+ if (finfo.length > 0) {
+ allstats.facets = new HashMap<String, Map<String, StatsValues>>();
+ for (FieldFacetStats f : finfo) {
+ Map<String, StatsValues> facetStatsValues = f.facetStatsValues;
+ FieldType facetType = searcher.getSchema().getFieldType(f.name);
+ for (Map.Entry<String,StatsValues> entry : facetStatsValues.entrySet()) {
+ String termLabel = entry.getKey();
+ int missingCount = searcher.numDocs(new TermQuery(new Term(f.name, facetType.toInternal(termLabel))), missing);
+ entry.getValue().addMissing(missingCount);
}
+ allstats.facets.put(f.name, facetStatsValues);
}
}
+
return allstats;
}
@@ -879,7 +891,10 @@
protected boolean setTerm() {
t = tenum.term();
- if (t==null || t.field() != tindex.fterm.field()) { // intern'd compare
+ if (t==null
+ || t.field() != tindex.fterm.field() // intern'd compare
+ || (tindex.prefix != null && !t.text().startsWith(tindex.prefix,0)) )
+ {
t = null;
return false;
}
@@ -1004,12 +1019,18 @@
final static int interval = 1 << intervalBits;
final Term fterm; // prototype to be used in term construction w/o String.intern overhead
+ final String prefix;
String[] index;
int nTerms;
long sizeOfStrings;
TermIndex(String field) {
+ this(field, null);
+ }
+
+ TermIndex(String field, String prefix) {
this.fterm = new Term(field, "");
+ this.prefix = prefix;
}
Term createTerm(String termVal) {
@@ -1027,7 +1048,7 @@
will be built.
*/
NumberedTermEnum getEnumerator(IndexReader reader) throws IOException {
- if (index==null) return new NumberedTermEnum(reader,this,"",0) {
+ if (index==null) return new NumberedTermEnum(reader,this, prefix==null?"":prefix, 0) {
ArrayList<String> lst;
protected boolean setTerm() {
Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java Tue Oct 6 14:13:20 2009
@@ -72,6 +72,14 @@
return (properties & MULTIVALUED) != 0;
}
+ /** Returns true if a single field value of this type has multiple logical values
+ * for the purposes of faceting, sorting, etc. Text fields normally return
+ * true since each token/word is a logical value.
+ */
+ public boolean multiValuedFieldCache() {
+ return isTokenized();
+ }
+
/** subclasses should initialize themselves with the args provided
* and remove valid arguments. leftover arguments will cause an exception.
* Common boolean properties have already been handled.
Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/TrieField.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/TrieField.java?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/TrieField.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/TrieField.java Tue Oct 6 14:13:20 2009
@@ -207,6 +207,11 @@
return true;
}
+ @Override
+ public boolean multiValuedFieldCache() {
+ return false;
+ }
+
/**
* @return the precisionStep used to index values into the field
*/
@@ -465,6 +470,38 @@
DOUBLE,
DATE
}
+
+
+ static final String INT_PREFIX = new String(new char[]{NumericUtils.SHIFT_START_INT});
+ static final String LONG_PREFIX = new String(new char[]{NumericUtils.SHIFT_START_LONG});
+
+ /** expert internal use, subject to change.
+ * Returns null if no prefix or prefix not needed, or the prefix of the main value of a trie field
+ * that indexes multiple precisions per value.
+ */
+ public static String getMainValuePrefix(FieldType ft) {
+ if (ft instanceof TrieDateField) {
+ int step = ((TrieDateField)ft).getPrecisionStep();
+ if (step <= 0 || step >=64) return null;
+ return LONG_PREFIX;
+ } else if (ft instanceof TrieField) {
+ TrieField trie = (TrieField)ft;
+ if (trie.precisionStep == Integer.MAX_VALUE) return null;
+
+ switch (trie.type) {
+ case INTEGER:
+ case FLOAT:
+ return INT_PREFIX;
+ case LONG:
+ case DOUBLE:
+ case DATE:
+ return LONG_PREFIX;
+ default:
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + trie.type);
+ }
+ }
+ return null;
+ }
}
class TrieDateFieldSource extends LongFieldSource {
Modified: lucene/solr/trunk/src/test/org/apache/solr/TestTrie.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/TestTrie.java?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/TestTrie.java (original)
+++ lucene/solr/trunk/src/test/org/apache/solr/TestTrie.java Tue Oct 6 14:13:20 2009
@@ -18,6 +18,8 @@
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.DateField;
+import org.apache.solr.schema.FieldType;
+import org.apache.solr.schema.TrieField;
import org.apache.solr.util.AbstractSolrTestCase;
import org.apache.solr.util.DateMathParser;
@@ -194,4 +196,78 @@
String fq = "tdouble4:[" + Integer.MAX_VALUE * 2.33d + " TO " + (5l + Integer.MAX_VALUE) * 2.33d + "]";
assertQ("Range filter must match only 5 documents", req("q", "*:*", "fq", fq), "//*[@numFound='6']");
}
+
+ public void testTrieFacet_PrecisionStep() throws Exception {
+ // Future protect - assert 0<precisionStep<64
+ checkPrecisionSteps("tint");
+ checkPrecisionSteps("tfloat");
+ checkPrecisionSteps("tdouble");
+ checkPrecisionSteps("tlong");
+ checkPrecisionSteps("tdate");
+
+ // For tdate tests
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ format.setTimeZone(TimeZone.getTimeZone("UTC"));
+ DateMathParser dmp = new DateMathParser(DateField.UTC, Locale.US);
+
+ for (int i = 0; i < 10; i++) {
+ long l = Integer.MAX_VALUE + i*1L;
+ // index 10 days starting with today
+ String d = format.format(i == 0 ? dmp.parseMath("/DAY") : dmp.parseMath("/DAY+" + i + "DAYS"));
+ assertU(adoc("id", String.valueOf(i), "tint", String.valueOf(i),
+ "tlong", String.valueOf(l),
+ "tfloat", String.valueOf(i * i * 31.11f),
+ "tdouble", String.valueOf(i * 2.33d),
+ "tdate", d));
+ }
+ for (int i = 0; i < 5; i++) {
+ long l = Integer.MAX_VALUE + i*1L;
+ String d = format.format(i == 0 ? dmp.parseMath("/DAY") : dmp.parseMath("/DAY+" + i + "DAYS"));
+ assertU(adoc("id", String.valueOf((i+1)*10), "tint", String.valueOf(i),
+ "tlong", String.valueOf(l),
+ "tfloat", String.valueOf(i * i * 31.11f),
+ "tdouble", String.valueOf(i * 2.33d),
+ "tdate", d));
+ }
+ assertU(commit());
+
+ SolrQueryRequest req = req("q", "*:*", "facet", "true", "rows", "15",
+ "facet.field", "tint",
+ "facet.field", "tlong",
+ "facet.field", "tfloat",
+ "facet.field", "tdouble",
+ "facet.date", "tdate",
+ "facet.date.start", "NOW/DAY",
+ "facet.date.end", "NOW/DAY+6DAYS",
+ "facet.date.gap", "+1DAY");
+ testFacetField(req, "tint", "0", "2");
+ testFacetField(req, "tint", "5", "1");
+ testFacetField(req, "tlong", String.valueOf(Integer.MAX_VALUE), "2");
+ testFacetField(req, "tlong", String.valueOf(Integer.MAX_VALUE+5L), "1");
+ testFacetField(req, "tfloat", String.valueOf(31.11f), "2");
+ testFacetField(req, "tfloat", String.valueOf(5*5*31.11f), "1");
+ testFacetField(req, "tdouble", String.valueOf(2.33d), "2");
+ testFacetField(req, "tdouble", String.valueOf(5*2.33d), "1");
+
+ testFacetDate(req, "tdate", format.format(dmp.parseMath("/DAY")), "4");
+ testFacetDate(req, "tdate", format.format(dmp.parseMath("/DAY+5DAYS")), "2");
+ }
+
+ private void checkPrecisionSteps(String fieldType) {
+ FieldType type = h.getCore().getSchema().getFieldType(fieldType);
+ if (type instanceof TrieField) {
+ TrieField field = (TrieField) type;
+ assertTrue(field.getPrecisionStep() > 0 && field.getPrecisionStep() < 64);
+ }
+ }
+
+ private void testFacetField(SolrQueryRequest req, String field, String value, String count) {
+ String xpath = "//lst[@name='facet_fields']/lst[@name='" + field + "']/int[@name='" + value + "'][.='" + count + "']";
+ assertQ(req, xpath);
+ }
+
+ private void testFacetDate(SolrQueryRequest req, String field, String value, String count) {
+ String xpath = "//lst[@name='facet_dates']/lst[@name='" + field + "']/int[@name='" + value + "'][.='" + count + "']";
+ assertQ(req, xpath);
+ }
}
Modified: lucene/solr/trunk/src/test/org/apache/solr/handler/component/StatsComponentTest.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/handler/component/StatsComponentTest.java?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/handler/component/StatsComponentTest.java (original)
+++ lucene/solr/trunk/src/test/org/apache/solr/handler/component/StatsComponentTest.java Tue Oct 6 14:13:20 2009
@@ -50,14 +50,20 @@
}
public void testStats() throws Exception {
- for (String f : new String[] {"stats_i"}) {
+ for (String f : new String[] {
+ "stats_i","stats_l","stats_f","stats_d",
+ "stats_ti","stats_tl","stats_tf","stats_td"
+ }) {
doTestFieldStatisticsResult(f);
doTestFieldStatisticsMissingResult(f);
doTestFacetStatisticsResult(f);
doTestFacetStatisticsMissingResult(f);
}
- for (String f : new String[] {"stats_ii"}) {
+ for (String f : new String[] {"stats_ii", // plain int
+ "stats_is", // sortable int
+ "stats_tis","stats_tfs","stats_tls","stats_tds" // trie fields
+ }) {
doTestMVFieldStatisticsResult(f);
}
@@ -86,7 +92,6 @@
public void doTestMVFieldStatisticsResult(String f) throws Exception {
assertU(adoc("id", "1", f, "-10", f, "-100", "active_s", "true"));
assertU(adoc("id", "2", f, "-20", f, "200", "active_s", "true"));
-
assertU(adoc("id", "3", f, "-30", f, "-1", "active_s", "false"));
assertU(adoc("id", "4", f, "-40", f, "10", "active_s", "false"));
assertU(adoc("id", "5", "active_s", "false"));
@@ -124,17 +129,17 @@
, "//lst[@name='true']/double[@name='mean'][.='17.5']"
, "//lst[@name='true']/double[@name='stddev'][.='128.16005617976296']"
);
- //Test for fixing multivalued missing
- /*assertQ("test value for active_s=false", req
+
+ assertQ("test value for active_s=false", req("q","*:*", "stats","true", "stats.field",f, "stats.facet","active_s", "indent","true")
, "//lst[@name='false']/double[@name='min'][.='-40.0']"
, "//lst[@name='false']/double[@name='max'][.='10.0']"
, "//lst[@name='false']/double[@name='sum'][.='-61.0']"
, "//lst[@name='false']/long[@name='count'][.='4']"
, "//lst[@name='false']/long[@name='missing'][.='1']"
, "//lst[@name='false']/double[@name='sumOfSquares'][.='2601.0']"
- , "//lst[@name='false']/double[@name='mean'][.='-15.22']"
+ , "//lst[@name='false']/double[@name='mean'][.='-15.25']"
, "//lst[@name='false']/double[@name='stddev'][.='23.59908190304586']"
- );*/
+ );
}
Modified: lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml?rev=822286&r1=822285&r2=822286&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml (original)
+++ lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml Tue Oct 6 14:13:20 2009
@@ -288,6 +288,7 @@
<dynamicField name="*_ss" type="string" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="*_ii" type="integer" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="*_i" type="sint" indexed="true" stored="true"/>
+ <dynamicField name="*_is" type="sint" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="*_l" type="slong" indexed="true" stored="true"/>
<dynamicField name="*_f" type="sfloat" indexed="true" stored="true"/>
<dynamicField name="*_d" type="sdouble" indexed="true" stored="true"/>