Return-Path: X-Original-To: apmail-lucene-commits-archive@www.apache.org Delivered-To: apmail-lucene-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1F4C217DD5 for ; Wed, 10 Jun 2015 16:23:05 +0000 (UTC) Received: (qmail 2605 invoked by uid 500); 10 Jun 2015 16:23:01 -0000 Mailing-List: contact commits-help@lucene.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@lucene.apache.org Delivered-To: mailing list commits@lucene.apache.org Received: (qmail 2534 invoked by uid 99); 10 Jun 2015 16:23:01 -0000 Received: from eris.apache.org (HELO hades.apache.org) (140.211.11.105) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 10 Jun 2015 16:23:01 +0000 Received: from hades.apache.org (localhost [127.0.0.1]) by hades.apache.org (ASF Mail Server at hades.apache.org) with ESMTP id 90A6FAC01A7 for ; Wed, 10 Jun 2015 16:23:01 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1684704 - in /lucene/dev/trunk: lucene/ lucene/misc/src/java/org/apache/lucene/uninverting/ lucene/misc/src/test/org/apache/lucene/uninverting/ solr/core/src/test/org/apache/solr/search/ Date: Wed, 10 Jun 2015 16:23:01 -0000 To: commits@lucene.apache.org From: hossman@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20150610162301.90A6FAC01A7@hades.apache.org> Author: hossman Date: Wed Jun 10 16:23:00 2015 New Revision: 1684704 URL: http://svn.apache.org/r1684704 Log: LUCENE-6529: Removed an optimization in UninvertingReader that was causing incorrect results for Numeric fields using precisionStep Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestTrieFacet.java (with props) Modified: lucene/dev/trunk/lucene/CHANGES.txt lucene/dev/trunk/lucene/misc/src/java/org/apache/lucene/uninverting/DocTermOrds.java lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestDocTermOrds.java lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCache.java lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCacheVsDocValues.java lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestUninvertingReader.java Modified: lucene/dev/trunk/lucene/CHANGES.txt URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1684704&r1=1684703&r2=1684704&view=diff ============================================================================== --- lucene/dev/trunk/lucene/CHANGES.txt (original) +++ lucene/dev/trunk/lucene/CHANGES.txt Wed Jun 10 16:23:00 2015 @@ -81,6 +81,10 @@ API Changes SpanPayloadNearCheckQuery have moved from the .spans package to the .payloads package. (Alan Woodward, David Smiley, Paul Elschot, Robert Muir) +* LUCENE-6529: Removed an optimization in UninvertingReader that was causing + incorrect results for Numeric fields using precisionStep + (hossman, Robert Muir) + Bug fixes * LUCENE-6500: ParallelCompositeReader did not always call Modified: lucene/dev/trunk/lucene/misc/src/java/org/apache/lucene/uninverting/DocTermOrds.java URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/misc/src/java/org/apache/lucene/uninverting/DocTermOrds.java?rev=1684704&r1=1684703&r2=1684704&view=diff ============================================================================== --- lucene/dev/trunk/lucene/misc/src/java/org/apache/lucene/uninverting/DocTermOrds.java (original) +++ lucene/dev/trunk/lucene/misc/src/java/org/apache/lucene/uninverting/DocTermOrds.java Wed Jun 10 16:23:00 2015 @@ -67,13 +67,11 @@ import org.apache.lucene.util.StringHelp * are also de-dup'd (ie if doc has same term more than once * in this field, you'll only get that ord back once). * - * This class tests whether the provided reader is able to - * retrieve terms by ord (ie, it's single segment, and it - * uses an ord-capable terms index). If not, this class + * This class * will create its own term index internally, allowing to * create a wrapped TermsEnum that can handle ord. The * {@link #getOrdTermsEnum} method then provides this - * wrapped enum, if necessary. + * wrapped enum. * * The RAM consumption of this class can be high! * @@ -152,7 +150,7 @@ public class DocTermOrds implements Acco protected long sizeOfIndexedStrings; /** Holds the indexed (by default every 128th) terms. */ - protected BytesRef[] indexedTermsArray; + protected BytesRef[] indexedTermsArray = new BytesRef[0]; /** If non-null, only terms matching this prefix were * indexed. */ @@ -219,27 +217,27 @@ public class DocTermOrds implements Acco indexInterval = 1 << indexIntervalBits; } - /** Returns a TermsEnum that implements ord. If the - * provided reader supports ord, we just return its - * TermsEnum; if it does not, we build a "private" terms + /** + * Returns a TermsEnum that implements ord, or null if no terms in field. + *

+ * we build a "private" terms * index internally (WARNING: consumes RAM) and use that * index to implement ord. This also enables ord on top * of a composite reader. The returned TermsEnum is * unpositioned. This returns null if there are no terms. - * + *

*

NOTE: you must pass the same reader that was - * used when creating this class */ + * used when creating this class + */ public TermsEnum getOrdTermsEnum(LeafReader reader) throws IOException { - if (indexedTermsArray == null) { - //System.out.println("GET normal enum"); - final Terms terms = reader.terms(field); - if (terms == null) { - return null; - } else { - return terms.iterator(); - } + // NOTE: see LUCENE-6529 before attempting to optimize this method to + // return a TermsEnum directly from the reader if it already supports ord(). + + assert null != indexedTermsArray; + + if (0 == indexedTermsArray.length) { + return null; } else { - //System.out.println("GET wrapped enum ordBase=" + ordBase); return new OrdWrappedTermsEnum(reader); } } @@ -297,12 +295,9 @@ public class DocTermOrds implements Acco return; } - // If we need our "term index wrapper", these will be - // init'd below: - List indexedTerms = null; - PagedBytes indexedTermsBytes = null; - - boolean testedOrd = false; + // For our "term index wrapper" + final List indexedTerms = new ArrayList<>(); + final PagedBytes indexedTermsBytes = new PagedBytes(15); // we need a minimum of 9 bytes, but round up to 12 since the space would // be wasted with most allocators anyway. @@ -336,23 +331,9 @@ public class DocTermOrds implements Acco } //System.out.println("visit term=" + t.utf8ToString() + " " + t + " termNum=" + termNum); - if (!testedOrd) { - try { - ordBase = (int) te.ord(); - //System.out.println("got ordBase=" + ordBase); - } catch (UnsupportedOperationException uoe) { - // Reader cannot provide ord support, so we wrap - // our own support by creating our own terms index: - indexedTerms = new ArrayList<>(); - indexedTermsBytes = new PagedBytes(15); - //System.out.println("NO ORDS"); - } - testedOrd = true; - } - visitTerm(te, termNum); - if (indexedTerms != null && (termNum & indexIntervalMask) == 0) { + if ((termNum & indexIntervalMask) == 0) { // Index this term sizeOfIndexedStrings += t.length; BytesRef indexedTerm = new BytesRef(); @@ -547,9 +528,7 @@ public class DocTermOrds implements Acco } } - if (indexedTerms != null) { - indexedTermsArray = indexedTerms.toArray(new BytesRef[indexedTerms.size()]); - } + indexedTermsArray = indexedTerms.toArray(new BytesRef[indexedTerms.size()]); long endTime = System.currentTimeMillis(); @@ -598,9 +577,10 @@ public class DocTermOrds implements Acco return pos; } - /* Only used if original IndexReader doesn't implement - * ord; in this case we "wrap" our own terms index - * around it. */ + /** + * "wrap" our own terms index around the original IndexReader. + * Only valid if there are terms for this field rom the original reader + */ private final class OrdWrappedTermsEnum extends TermsEnum { private final TermsEnum termsEnum; private BytesRef term; @@ -608,6 +588,7 @@ public class DocTermOrds implements Acco public OrdWrappedTermsEnum(LeafReader reader) throws IOException { assert indexedTermsArray != null; + assert 0 != indexedTermsArray.length; termsEnum = reader.fields().terms(field).iterator(); } Modified: lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestDocTermOrds.java URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestDocTermOrds.java?rev=1684704&r1=1684703&r2=1684704&view=diff ============================================================================== --- lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestDocTermOrds.java (original) +++ lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestDocTermOrds.java Wed Jun 10 16:23:00 2015 @@ -63,6 +63,36 @@ import org.apache.lucene.util.TestUtil; public class TestDocTermOrds extends LuceneTestCase { + public void testEmptyIndex() throws IOException { + final Directory dir = newDirectory(); + final IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig(new MockAnalyzer(random()))); + iw.close(); + + final DirectoryReader ir = DirectoryReader.open(dir); + TestUtil.checkReader(ir); + + final LeafReader composite = SlowCompositeReaderWrapper.wrap(ir); + TestUtil.checkReader(composite); + + // check the leaves + // (normally there are none for an empty index, so this is really just future + // proofing in case that changes for some reason) + for (LeafReaderContext rc : ir.leaves()) { + final LeafReader r = rc.reader(); + final DocTermOrds dto = new DocTermOrds(r, r.getLiveDocs(), "any_field"); + assertNull("OrdTermsEnum should be null (leaf)", dto.getOrdTermsEnum(r)); + assertEquals("iterator should be empty (leaf)", 0, dto.iterator(r).getValueCount()); + } + + // check the composite + final DocTermOrds dto = new DocTermOrds(composite, composite.getLiveDocs(), "any_field"); + assertNull("OrdTermsEnum should be null (composite)", dto.getOrdTermsEnum(composite)); + assertEquals("iterator should be empty (composite)", 0, dto.iterator(composite).getValueCount()); + + ir.close(); + dir.close(); + } + public void testSimple() throws Exception { Directory dir = newDirectory(); final RandomIndexWriter w = new RandomIndexWriter(random(), dir, newIndexWriterConfig(new MockAnalyzer(random())).setMergePolicy(newLogMergePolicy())); @@ -82,6 +112,7 @@ public class TestDocTermOrds extends Luc w.close(); final LeafReader ar = SlowCompositeReaderWrapper.wrap(r); + TestUtil.checkReader(ar); final DocTermOrds dto = new DocTermOrds(ar, ar.getLiveDocs(), "field"); SortedSetDocValues iter = dto.iterator(ar); @@ -185,6 +216,7 @@ public class TestDocTermOrds extends Luc System.out.println("TEST: top reader"); } LeafReader slowR = SlowCompositeReaderWrapper.wrap(r); + TestUtil.checkReader(slowR); verify(slowR, idToOrds, termsArray, null); FieldCache.DEFAULT.purgeByCacheKey(slowR.getCoreCacheKey()); @@ -270,6 +302,7 @@ public class TestDocTermOrds extends Luc } LeafReader slowR = SlowCompositeReaderWrapper.wrap(r); + TestUtil.checkReader(slowR); for(String prefix : prefixesArray) { final BytesRef prefixRef = prefix == null ? null : new BytesRef(prefix); Modified: lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCache.java URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCache.java?rev=1684704&r1=1684703&r2=1684704&view=diff ============================================================================== --- lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCache.java (original) +++ lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCache.java Wed Jun 10 16:23:00 2015 @@ -119,6 +119,7 @@ public class TestFieldCache extends Luce } IndexReader r = writer.getReader(); reader = SlowCompositeReaderWrapper.wrap(r); + TestUtil.checkReader(reader); writer.close(); } @@ -293,6 +294,7 @@ public class TestFieldCache extends Luce writer.close(); IndexReader r = DirectoryReader.open(dir); LeafReader reader = SlowCompositeReaderWrapper.wrap(r); + TestUtil.checkReader(reader); FieldCache.DEFAULT.getTerms(reader, "foobar", true); FieldCache.DEFAULT.getTermsIndex(reader, "foobar"); FieldCache.DEFAULT.purgeByCacheKey(reader.getCoreCacheKey()); Modified: lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCacheVsDocValues.java URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCacheVsDocValues.java?rev=1684704&r1=1684703&r2=1684704&view=diff ============================================================================== --- lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCacheVsDocValues.java (original) +++ lucene/dev/trunk/lucene/misc/src/test/org/apache/lucene/uninverting/TestFieldCacheVsDocValues.java Wed Jun 10 16:23:00 2015 @@ -192,6 +192,7 @@ public class TestFieldCacheVsDocValues e w.close(); LeafReader ar = SlowCompositeReaderWrapper.wrap(r); + TestUtil.checkReader(ar); BinaryDocValues s = FieldCache.DEFAULT.getTerms(ar, "field", false); for(int docID=0;docID UNINVERT_MAP = new LinkedHashMap(); + UNINVERT_MAP.put("notrie_single", Type.SORTED_SET_INTEGER); + UNINVERT_MAP.put("notrie_multi", Type.SORTED_SET_INTEGER); + UNINVERT_MAP.put("trie_single", Type.SORTED_SET_INTEGER); + UNINVERT_MAP.put("trie_multi", Type.SORTED_SET_INTEGER); + final Set MULTI_VALUES = new LinkedHashSet(); + MULTI_VALUES.add("trie_multi"); + MULTI_VALUES.add("notrie_multi"); + + + final int NUM_DOCS = TestUtil.nextInt(random(), 200, 1500); + final int MIN = TestUtil.nextInt(random(), 10, 100); + final int MAX = MIN + TestUtil.nextInt(random(), 10, 100); + final long EXPECTED_VALSET_SIZE = 1 + MAX - MIN; + + { // (at least) one doc should have every value, so that at least one segment has every value + final Document doc = new Document(); + for (int i = MIN; i <= MAX; i++) { + doc.add(new IntField("trie_multi", i, Field.Store.NO)); + doc.add(new IntField("notrie_multi", i, NO_TRIE_TYPE)); + } + iw.addDocument(doc); + } + + // now add some more random docs (note: starting at i=1 because of previously added doc) + for (int i = 1; i < NUM_DOCS; i++) { + final Document doc = new Document(); + if (0 != TestUtil.nextInt(random(), 0, 9)) { + int val = TestUtil.nextInt(random(), MIN, MAX); + doc.add(new IntField("trie_single", val, Field.Store.NO)); + doc.add(new IntField("notrie_single", val, NO_TRIE_TYPE)); + } + if (0 != TestUtil.nextInt(random(), 0, 9)) { + int numMulti = atLeast(1); + while (0 < numMulti--) { + int val = TestUtil.nextInt(random(), MIN, MAX); + doc.add(new IntField("trie_multi", val, Field.Store.NO)); + doc.add(new IntField("notrie_multi", val, NO_TRIE_TYPE)); + } + } + iw.addDocument(doc); + } + + iw.close(); + + final DirectoryReader ir = UninvertingReader.wrap(DirectoryReader.open(dir), UNINVERT_MAP); + TestUtil.checkReader(ir); + + final int NUM_LEAVES = ir.leaves().size(); + + // check the leaves: no more then total set size + for (LeafReaderContext rc : ir.leaves()) { + final LeafReader ar = rc.reader(); + for (String f : UNINVERT_MAP.keySet()) { + final SortedSetDocValues v = ar.getSortedSetDocValues(f); + final long valSetSize = v.getValueCount(); + assertTrue(f + ": Expected no more then " + EXPECTED_VALSET_SIZE + " values per segment, got " + + valSetSize + " from: " + ar.toString(), + valSetSize <= EXPECTED_VALSET_SIZE); + + if (1 == NUM_LEAVES && MULTI_VALUES.contains(f)) { + // tighter check on multi fields in single segment index since we know one doc has all of them + assertEquals(f + ": Single segment LeafReader's value set should have had exactly expected size", + EXPECTED_VALSET_SIZE, valSetSize); + } + } + } + + // check the composite of all leaves: exact expectation of set size + final LeafReader composite = SlowCompositeReaderWrapper.wrap(ir); + TestUtil.checkReader(composite); + + for (String f : MULTI_VALUES) { + final SortedSetDocValues v = composite.getSortedSetDocValues(f); + final long valSetSize = v.getValueCount(); + assertEquals(f + ": Composite reader value set should have had exactly expected size", + EXPECTED_VALSET_SIZE, valSetSize); + } + + ir.close(); + dir.close(); + } + + public void testSortedSetEmptyIndex() throws IOException { + final Directory dir = newDirectory(); + final IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig(null)); + iw.close(); + + final Map UNINVERT_MAP = new LinkedHashMap(); + for (Type t : EnumSet.allOf(Type.class)) { + UNINVERT_MAP.put(t.name(), t); + } + + final DirectoryReader ir = UninvertingReader.wrap(DirectoryReader.open(dir), UNINVERT_MAP); + TestUtil.checkReader(ir); + + final LeafReader composite = SlowCompositeReaderWrapper.wrap(ir); + TestUtil.checkReader(composite); + + for (String f : UNINVERT_MAP.keySet()) { + // check the leaves + // (normally there are none for an empty index, so this is really just future + // proofing in case that changes for some reason) + for (LeafReaderContext rc : ir.leaves()) { + final LeafReader ar = rc.reader(); + assertNull(f + ": Expected no doc values from empty index (leaf)", + ar.getSortedSetDocValues(f)); + } + + // check the composite + assertNull(f + ": Expected no doc values from empty index (composite)", + composite.getSortedSetDocValues(f)); + + } + + ir.close(); + dir.close(); + } + } Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestTrieFacet.java URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestTrieFacet.java?rev=1684704&view=auto ============================================================================== --- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestTrieFacet.java (added) +++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestTrieFacet.java Wed Jun 10 16:23:00 2015 @@ -0,0 +1,201 @@ +/* + * 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. + */ + +package org.apache.solr.search; + +import org.apache.lucene.util.TestUtil; + +import org.apache.solr.schema.SchemaField; +import org.apache.solr.schema.TrieIntField; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.SolrTestCaseJ4; + +import org.junit.BeforeClass; + +public class TestTrieFacet extends SolrTestCaseJ4 { + + final static int MIN_VALUE = 20; + final static int MAX_VALUE = 60; + + final static String TRIE_INT_P8_S_VALUED = "foo_ti1"; + final static String TRIE_INT_P8_M_VALUED = "foo_ti"; + + final static String TRIE_INT_P0_S_VALUED = "foo_i1"; + final static String TRIE_INT_P0_M_VALUED = "foo_i"; + + final static String[] M_VALUED = new String[] { TRIE_INT_P0_M_VALUED, TRIE_INT_P8_M_VALUED }; + final static String[] S_VALUED = new String[] { TRIE_INT_P0_S_VALUED, TRIE_INT_P8_S_VALUED }; + + final static String[] P0 = new String[] { TRIE_INT_P0_M_VALUED, TRIE_INT_P0_S_VALUED }; + final static String[] P8 = new String[] { TRIE_INT_P8_M_VALUED, TRIE_INT_P8_S_VALUED }; + + static int NUM_DOCS; + + private static TrieIntField assertCastFieldType(SchemaField f) { + assertTrue("who changed the schema? test isn't valid: " + f.getName(), + f.getType() instanceof TrieIntField); + return (TrieIntField) f.getType(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + + initCore("solrconfig-tlog.xml","schema.xml"); + + // don't break the test + assertTrue("min value must be less then max value", MIN_VALUE < MAX_VALUE); + assertTrue("min value must be greater then zero", 0 < MIN_VALUE); + + // sanity check no one breaks the schema out from under us... + for (String f : M_VALUED) { + SchemaField sf = h.getCore().getLatestSchema().getField(f); + assertTrue("who changed the schema? test isn't valid: " + f, sf.multiValued()); + } + + for (String f : S_VALUED) { + SchemaField sf = h.getCore().getLatestSchema().getField(f); + assertFalse("who changed the schema? test isn't valid: " + f, sf.multiValued()); + } + + for (String f : P0) { + SchemaField sf = h.getCore().getLatestSchema().getField(f); + assertEquals("who changed the schema? test isn't valid: " + f, + 0, assertCastFieldType(sf).getPrecisionStep()); + } + for (String f : P8) { + SchemaField sf = h.getCore().getLatestSchema().getField(f); + assertEquals("who changed the schema? test isn't valid: " + f, + 8, assertCastFieldType(sf).getPrecisionStep()); + } + + // we don't need a lot of docs -- at least one failure only had ~1000 + NUM_DOCS = TestUtil.nextInt(random(), 200, 1500); + + { // ensure at least one doc has every valid value in the multivalued fields + SolrInputDocument doc = sdoc("id", "0"); + for (int val = MIN_VALUE; val <= MAX_VALUE; val++) { + for (String f : M_VALUED) { + doc.addField(f, val); + } + } + assertU(adoc(doc)); + } + + // randomized docs (note: starting at i=1) + for (int i=1; i < NUM_DOCS; i++) { + SolrInputDocument doc = sdoc("id", i+""); + if (useField()) { + int val = TestUtil.nextInt(random(), MIN_VALUE, MAX_VALUE); + for (String f : S_VALUED) { + doc.addField(f, val); + } + } + if (useField()) { + int numMulti = atLeast(1); + while (0 < numMulti--) { + int val = TestUtil.nextInt(random(), MIN_VALUE, MAX_VALUE); + for (String f: M_VALUED) { + doc.addField(f, val); + } + } + } + assertU(adoc(doc)); + } + assertU(commit()); + } + + /** + * Similar to usually() but we want it to happen just as often regardless + * of test multiplier and nightly status + */ + private static boolean useField() { + return 0 != TestUtil.nextInt(random(), 0, 9); + } + + private static void doTestNoZeros(final String field, final String method) throws Exception { + + assertQ("sanity check # docs in index: " + NUM_DOCS, + req("q", "*:*", "rows", "0") + ,"//result[@numFound="+NUM_DOCS+"]"); + assertQ("sanity check that no docs match 0 failed", + req("q", field+":0", "rows", "0") + ,"//result[@numFound=0]"); + assertQ("sanity check that no docs match [0 TO 0] failed", + req("q", field+":[0 TO 0]", "rows", "0") + ,"//result[@numFound=0]"); + + assertQ("*:* facet with mincount 0 found unexpected 0 value", + req("q", "*:*" + ,"rows", "0" + ,"indent","true" + ,"facet", "true" + ,"facet.field", field + ,"facet.limit", "-1" + ,"facet.mincount", "0" + ,"facet.method", method + ) + // trivial sanity check we're at least getting facet counts in output + ,"*[count(//lst[@name='facet_fields']/lst[@name='"+field+"']/int)!=0]" + // main point of test + ,"*[count(//lst[@name='facet_fields']/lst[@name='"+field+"']/int[@name='0'])=0]" + ); + } + + // enum + public void testSingleValuedTrieP0_enum() throws Exception { + doTestNoZeros(TRIE_INT_P0_S_VALUED, "enum"); + } + public void testMultiValuedTrieP0_enum() throws Exception { + doTestNoZeros(TRIE_INT_P0_M_VALUED, "enum"); + } + public void testSingleValuedTrieP8_enum() throws Exception { + doTestNoZeros(TRIE_INT_P8_S_VALUED, "enum"); + } + public void testMultiValuedTrieP8_enum() throws Exception { + doTestNoZeros(TRIE_INT_P8_M_VALUED, "enum"); + } + + // fc + public void testSingleValuedTrieP0_fc() throws Exception { + doTestNoZeros(TRIE_INT_P0_S_VALUED, "fc"); + } + public void testMultiValuedTrieP0_fc() throws Exception { + doTestNoZeros(TRIE_INT_P0_M_VALUED, "fc"); + } + public void testSingleValuedTrieP8_fc() throws Exception { + doTestNoZeros(TRIE_INT_P8_S_VALUED, "fc"); + } + public void testMultiValuedTrieP8_fc() throws Exception { + doTestNoZeros(TRIE_INT_P8_M_VALUED, "fc"); + } + + // fcs + public void testSingleValuedTrieP0_fcs() throws Exception { + doTestNoZeros(TRIE_INT_P0_S_VALUED, "fcs"); + } + public void testMultiValuedTrieP0_fcs() throws Exception { + doTestNoZeros(TRIE_INT_P0_M_VALUED, "fcs"); + } + public void testSingleValuedTrieP8_fcs() throws Exception { + doTestNoZeros(TRIE_INT_P8_S_VALUED, "fcs"); + } + public void testMultiValuedTrieP8_fcs() throws Exception { + doTestNoZeros(TRIE_INT_P8_M_VALUED, "fcs"); + } + +} +