/** * 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.request; import org.apache.solr.SolrTestCaseJ4; import org.junit.BeforeClass; import org.junit.After; import org.junit.Test; import java.util.ArrayList; import java.util.Collections; import java.util.Random; public class SimpleFacetsTest extends SolrTestCaseJ4 { @BeforeClass public static void beforeClass() throws Exception { initCore("solrconfig.xml","schema.xml"); createIndex(); } static Random rand = new Random(); // TODO: a way to use lucene's newRandom()? static int random_commit_percent = 30; static int random_dupe_percent = 25; // some duplicates in the index to create deleted docs static void randomCommit(int percent_chance) { if (rand.nextInt(100) <= percent_chance) assertU(commit()); } static ArrayList<String[]> pendingDocs = new ArrayList<String[]>(); // committing randomly gives different looking segments each time static void add_doc(String... fieldsAndValues) { do { pendingDocs.add(fieldsAndValues); } while (rand.nextInt(100) <= random_dupe_percent); // assertU(adoc(fieldsAndValues)); // randomCommit(random_commit_percent); } static void createIndex() { indexSimpleFacetCounts(); indexDateFacets(); indexFacetSingleValued(); indexFacetPrefixMultiValued(); indexFacetPrefixSingleValued(); Collections.shuffle(pendingDocs, rand); for (String[] doc : pendingDocs) { assertU(adoc(doc)); randomCommit(random_commit_percent); } assertU(commit()); } static void indexSimpleFacetCounts() { add_doc("id", "42", "range_facet_f", "35.3", "trait_s", "Tool", "trait_s", "Obnoxious", "name", "Zapp Brannigan"); add_doc("id", "43" , "range_facet_f", "28.789", "title", "Democratic Order of Planets"); add_doc("id", "44", "range_facet_f", "15.97", "trait_s", "Tool", "name", "The Zapper"); add_doc("id", "45", "range_facet_f", "30.0", "trait_s", "Chauvinist", "title", "25 star General"); add_doc("id", "46", "range_facet_f", "20.0", "trait_s", "Obnoxious", "subject", "Defeated the pacifists of the Gandhi nebula"); add_doc("id", "47", "range_facet_f", "28.62", "trait_s", "Pig", "text", "line up and fly directly at the enemy death cannons, clogging them with wreckage!"); } @Test public void testSimpleFacetCounts() { 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 multi-select facets with naming", req("q", "id:[42 TO 47]" ,"facet", "true" ,"facet.query", "{!ex=1}trait_s:Obnoxious" ,"facet.query", "{!ex=2 key=foo}id:[42 TO 45]" // tag=2 same as 1 ,"facet.query", "{!ex=3,4 key=bar}id:[43 TO 47]" // tag=3,4 don't exist ,"facet.field", "{!ex=3,1}trait_s" // 3,1 same as 1 ,"fq", "{!tag=1,2}id:47" // tagged as 1 and 2 ) ,"*[count(//doc)=1]" ,"//lst[@name='facet_counts']/lst[@name='facet_queries']" ,"//lst[@name='facet_queries']/int[@name='{!ex=1}trait_s:Obnoxious'][.='2']" ,"//lst[@name='facet_queries']/int[@name='foo'][.='4']" ,"//lst[@name='facet_queries']/int[@name='bar'][.='1']" ,"//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']" ); assertQ("check counts with facet.mincount=1&facet.missing=true using fq", req("q", "id:[42 TO 47]" ,"facet", "true" ,"facet.mincount", "1" ,"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']" ); assertQ("check counts with facet.mincount=2&facet.missing=true using fq", req("q", "id:[42 TO 47]" ,"facet", "true" ,"facet.mincount", "2" ,"f.trait_s.facet.missing", "true" ,"fq", "id:[42 TO 45]" ,"facet.field", "trait_s" ) ,"*[count(//doc)=4]" ,"*[count(//lst[@name='trait_s']/int)=2]" ,"//lst[@name='trait_s']/int[@name='Tool'][.='2']" ,"//lst[@name='trait_s']/int[not(@name)][.='1']" ); assertQ("check sorted paging", req("q", "id:[42 TO 47]" ,"facet", "true" ,"fq", "id:[42 TO 45]" ,"facet.field", "trait_s" ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","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[@name='Pig'][.='0']" ); // check that the default sort is by count assertQ("check sorted paging", req("q", "id:[42 TO 47]" ,"facet", "true" ,"fq", "id:[42 TO 45]" ,"facet.field", "trait_s" ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","3" ) ,"*[count(//lst[@name='trait_s']/int)=3]" ,"//int[1][@name='Tool'][.='2']" ,"//int[2][@name='Chauvinist'][.='1']" ,"//int[3][@name='Obnoxious'][.='1']" ); // // check that legacy facet.sort=true/false works // assertQ(req("q", "id:[42 TO 47]" ,"facet", "true" ,"fq", "id:[42 TO 45]" ,"facet.field", "trait_s" ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","3" ,"facet.sort","true" // true means sort-by-count ) ,"*[count(//lst[@name='trait_s']/int)=3]" ,"//int[1][@name='Tool'][.='2']" ,"//int[2][@name='Chauvinist'][.='1']" ,"//int[3][@name='Obnoxious'][.='1']" ); assertQ(req("q", "id:[42 TO 47]" ,"facet", "true" ,"fq", "id:[42 TO 45]" ,"facet.field", "trait_s" ,"facet.mincount","1" ,"facet.offset","0" ,"facet.limit","3" ,"facet.sort","false" // false means sort by index order ) ,"*[count(//lst[@name='trait_s']/int)=3]" ,"//int[1][@name='Chauvinist'][.='1']" ,"//int[2][@name='Obnoxious'][.='1']" ,"//int[3][@name='Tool'][.='2']" ); } public static void indexDateFacets() { final String i = "id"; final String f = "bday"; final String ff = "a_tdt"; final String ooo = "00:00:00.000Z"; final String xxx = "15:15:15.155Z"; add_doc(i, "201", f, "1976-07-04T12:08:56.235Z", ff, "1900-01-01T"+ooo); add_doc(i, "202", f, "1976-07-05T00:00:00.000Z", ff, "1976-07-01T"+ooo); add_doc(i, "203", f, "1976-07-15T00:07:67.890Z", ff, "1976-07-04T"+ooo); add_doc(i, "204", f, "1976-07-21T00:07:67.890Z", ff, "1976-07-05T"+ooo); add_doc(i, "205", f, "1976-07-13T12:12:25.255Z", ff, "1976-07-05T"+xxx); add_doc(i, "206", f, "1976-07-03T17:01:23.456Z", ff, "1976-07-07T"+ooo); add_doc(i, "207", f, "1976-07-12T12:12:25.255Z", ff, "1976-07-13T"+ooo); add_doc(i, "208", f, "1976-07-15T15:15:15.155Z", ff, "1976-07-13T"+xxx); add_doc(i, "209", f, "1907-07-12T13:13:23.235Z", ff, "1976-07-15T"+xxx); add_doc(i, "2010", f, "1976-07-03T11:02:45.678Z", ff, "2000-01-01T"+ooo); add_doc(i, "2011", f, "1907-07-12T12:12:25.255Z"); add_doc(i, "2012", f, "2007-07-30T07:07:07.070Z"); add_doc(i, "2013", f, "1976-07-30T22:22:22.222Z"); add_doc(i, "2014", f, "1976-07-05T22:22:22.222Z"); } @Test public void testTrieDateFacets() { helpTestDateFacets("bday", false); } @Test public void testDateFacets() { helpTestDateFacets("bday_pdt", false); } @Test public void testTrieDateRangeFacets() { helpTestDateFacets("bday", true); } @Test public void testDateRangeFacets() { helpTestDateFacets("bday_pdt", true); } private void helpTestDateFacets(final String fieldName, final boolean rangeMode) { final String p = rangeMode ? "facet.range" : "facet.date"; final String b = rangeMode ? "facet_ranges" : "facet_dates"; final String f = fieldName; final String c = (rangeMode ? "/lst[@name='counts']" : ""); final String pre = "//lst[@name='"+b+"']/lst[@name='"+f+"']" + c; final String meta = pre + (rangeMode ? "/../" : ""); assertQ("check counts for month of facet by day", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-01T00:00:00.000Z+1MONTH" ,p+".gap", "+1DAY" ,p+".other", "all" ) ,"*[count("+pre+"/int)="+(rangeMode ? 31 : 34)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0' ]" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0' ]" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]" // july4th = 2 because exists doc @ 00:00:00.000 on July5 // (date faceting is inclusive) ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-16T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-17T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-18T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-19T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-21T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-22T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-23T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-24T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-25T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-26T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-27T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-28T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-29T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-30T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-31T00:00:00Z'][.='0']" ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='11']" ); assertQ("check counts for month of facet by day with global mincount = 1", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-01T00:00:00.000Z+1MONTH" ,p+".gap", "+1DAY" ,p+".other", "all" ,"facet.mincount", "1" ) ,"*[count("+pre+"/int)="+(rangeMode ? 8 : 11)+"]" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]" // july4th = 2 because exists doc @ 00:00:00.000 on July5 // (date faceting is inclusive) ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-21T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-30T00:00:00Z'][.='1' ]" ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='11']" ); assertQ("check counts for month of facet by day with field mincount = 1", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-01T00:00:00.000Z+1MONTH" ,p+".gap", "+1DAY" ,p+".other", "all" ,"f." + f + ".facet.mincount", "2" ) ,"*[count("+pre+"/int)="+(rangeMode ? 4 : 7)+"]" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]" // july4th = 2 because exists doc @ 00:00:00.000 on July5 // (date faceting is inclusive) ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='2' ]" ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='11']" ); assertQ("check before is not inclusive of upper bound by default", req("q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-05T00:00:00.000Z" ,p+".end", "1976-07-07T00:00:00.000Z" ,p+".gap", "+1DAY" ,p+".other", "all" ) ,"*[count("+pre+"/int)="+(rangeMode ? 2 : 5)+"]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]" ,meta+"/int[@name='before' ][.='5']" ); assertQ("check after is not inclusive of lower bound by default", req("q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-03T00:00:00.000Z" ,p+".end", "1976-07-05T00:00:00.000Z" ,p+".gap", "+1DAY" ,p+".other", "all" ) ,"*[count("+pre+"/int)="+(rangeMode ? 2 : 5)+"]" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]" ,meta+"/int[@name='after' ][.='8']" ); assertQ("check hardend=false", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-13T00:00:00.000Z" ,p+".gap", "+5DAYS" ,p+".other", "all" ,p+".hardend","false" ) ,"*[count("+pre+"/int)="+(rangeMode ? 3 : 6)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='5' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='4' ]" ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='3']" ,meta+"/int[@name='between'][.='9']" ); assertQ("check hardend=true", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-13T00:00:00.000Z" ,p+".gap", "+5DAYS" ,p+".other", "all" ,p+".hardend","true" ) ,"*[count("+pre+"/int)="+(rangeMode ? 3 : 6)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='5' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='1' ]" ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='6']" ,meta+"/int[@name='between'][.='6']" ); } @Test public void testTrieDateFacetsWithIncludeOption() { helpTestDateFacetsWithIncludeOption("a_tdt", false); } @Test public void testDateFacetsWithIncludeOption() { helpTestDateFacetsWithIncludeOption("a_pdt", false); } @Test public void testTrieDateRangeFacetsWithIncludeOption() { helpTestDateFacetsWithIncludeOption("a_tdt", true); } @Test public void testDateRangeFacetsWithIncludeOption() { helpTestDateFacetsWithIncludeOption("a_pdt", true); } /** similar to helpTestDateFacets, but for differnet fields with test data exactly on on boundary marks */ private void helpTestDateFacetsWithIncludeOption(final String fieldName, final boolean rangeMode) { final String p = rangeMode ? "facet.range" : "facet.date"; final String b = rangeMode ? "facet_ranges" : "facet_dates"; final String f = fieldName; final String c = (rangeMode ? "/lst[@name='counts']" : ""); final String pre = "//lst[@name='"+b+"']/lst[@name='"+f+"']" + c; final String meta = pre + (rangeMode ? "/../" : ""); assertQ("checking counts for lower", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-16T00:00:00.000Z" ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "lower" ) // 15 days + pre+post+inner = 18 ,"*[count("+pre+"/int)="+(rangeMode ? 15 : 18)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]" // ,meta+"/int[@name='before' ][.='1']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='8']" ); assertQ("checking counts for upper", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-16T00:00:00.000Z" ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "upper" ) // 15 days + pre+post+inner = 18 ,"*[count("+pre+"/int)="+(rangeMode ? 15 : 18)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]" // ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='7']" ); assertQ("checking counts for lower & upper", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-16T00:00:00.000Z" ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "lower" ,p+".include", "upper" ) // 15 days + pre+post+inner = 18 ,"*[count("+pre+"/int)="+(rangeMode ? 15 : 18)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]" // ,meta+"/int[@name='before' ][.='1']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='8']" ); assertQ("checking counts for upper & edge", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-16T00:00:00.000Z" ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "upper" ,p+".include", "edge" ) // 15 days + pre+post+inner = 18 ,"*[count("+pre+"/int)="+(rangeMode ? 15 : 18)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]" // ,meta+"/int[@name='before' ][.='1']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='8']" ); assertQ("checking counts for upper & outer", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-13T00:00:00.000Z" // smaller now ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "upper" ,p+".include", "outer" ) // 12 days + pre+post+inner = 15 ,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" // ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='4']" ,meta+"/int[@name='between'][.='5']" ); assertQ("checking counts for lower & edge", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-13T00:00:00.000Z" // smaller now ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "lower" ,p+".include", "edge" ) // 12 days + pre+post+inner = 15 ,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" // ,meta+"/int[@name='before' ][.='1']" ,meta+"/int[@name='after' ][.='3']" ,meta+"/int[@name='between'][.='6']" ); assertQ("checking counts for lower & outer", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-13T00:00:00.000Z" // smaller now ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "lower" ,p+".include", "outer" ) // 12 days + pre+post+inner = 15 ,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='0']" // ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='4']" ,meta+"/int[@name='between'][.='5']" ); assertQ("checking counts for lower & edge & outer", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-13T00:00:00.000Z" // smaller now ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "lower" ,p+".include", "edge" ,p+".include", "outer" ) // 12 days + pre+post+inner = 15 ,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" // ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='4']" ,meta+"/int[@name='between'][.='6']" ); assertQ("checking counts for all", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,p, f ,p+".start", "1976-07-01T00:00:00.000Z" ,p+".end", "1976-07-13T00:00:00.000Z" // smaller now ,p+".gap", "+1DAY" ,p+".other", "all" ,p+".include", "all" ) // 12 days + pre+post+inner = 15 ,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]" ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]" ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1' ]" ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']" ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]" // ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='4']" ,meta+"/int[@name='between'][.='6']" ); } @Test public void testNumericRangeFacetsTrieFloat() { helpTestFractionalNumberRangeFacets("range_facet_f"); } @Test public void testNumericRangeFacetsTrieDouble() { helpTestFractionalNumberRangeFacets("range_facet_d"); } @Test public void testNumericRangeFacetsSortableFloat() { helpTestFractionalNumberRangeFacets("range_facet_sf"); } @Test public void testNumericRangeFacetsSortableDouble() { helpTestFractionalNumberRangeFacets("range_facet_sd"); } private void helpTestFractionalNumberRangeFacets(final String fieldName) { final String f = fieldName; final String pre = "//lst[@name='facet_ranges']/lst[@name='"+f+"']/lst[@name='counts']"; final String meta = pre + "/../"; assertQ(f+": checking counts for lower", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "10" ,"facet.range.end", "50" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.include", "lower" ) ,"*[count("+pre+"/int)=4]" ,pre+"/int[@name='10.0'][.='1' ]" ,pre+"/int[@name='20.0'][.='3' ]" ,pre+"/int[@name='30.0'][.='2' ]" ,pre+"/int[@name='40.0'][.='0' ]" // ,meta+"/int[@name='before' ][.='0']" ,meta+"/int[@name='after' ][.='0']" ,meta+"/int[@name='between'][.='6']" ); assertQ(f + ":checking counts for upper", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "10" ,"facet.range.end", "50" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.include", "upper" ) ,"*[count("+pre+"/int)=4]" ,pre+"/int[@name='10.0'][.='2' ]" ,pre+"/int[@name='20.0'][.='3' ]" ,pre+"/int[@name='30.0'][.='1' ]" ,pre+"/int[@name='40.0'][.='0' ]" // ,meta+"/int[@name='before' ][.='0']" ,meta+"/int[@name='after' ][.='0']" ,meta+"/int[@name='between'][.='6']" ); assertQ(f + ":checking counts for lower & upper", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "10" ,"facet.range.end", "50" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.include", "upper" ,"facet.range.include", "lower" ) ,"*[count("+pre+"/int)=4]" ,pre+"/int[@name='10.0'][.='2' ]" ,pre+"/int[@name='20.0'][.='4' ]" ,pre+"/int[@name='30.0'][.='2' ]" ,pre+"/int[@name='40.0'][.='0' ]" // ,meta+"/int[@name='before' ][.='0']" ,meta+"/int[@name='after' ][.='0']" ,meta+"/int[@name='between'][.='6']" ); assertQ(f + ": checking counts for upper & edge", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "20" ,"facet.range.end", "50" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.include", "upper" ,"facet.range.include", "edge" ) ,"*[count("+pre+"/int)=3]" ,pre+"/int[@name='20.0'][.='4' ]" ,pre+"/int[@name='30.0'][.='1' ]" ,pre+"/int[@name='40.0'][.='0' ]" // ,meta+"/int[@name='before' ][.='1']" ,meta+"/int[@name='after' ][.='0']" ,meta+"/int[@name='between'][.='5']" ); assertQ(f + ": checking counts for upper & outer", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "10" ,"facet.range.end", "30" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.include", "upper" ,"facet.range.include", "outer" ) ,"*[count("+pre+"/int)=2]" ,pre+"/int[@name='10.0'][.='2' ]" ,pre+"/int[@name='20.0'][.='3' ]" // ,meta+"/int[@name='before' ][.='0']" ,meta+"/int[@name='after' ][.='2']" ,meta+"/int[@name='between'][.='5']" ); assertQ(f + ": checking counts for lower & edge", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "10" ,"facet.range.end", "30" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.include", "lower" ,"facet.range.include", "edge" ) ,"*[count("+pre+"/int)=2]" ,pre+"/int[@name='10.0'][.='1' ]" ,pre+"/int[@name='20.0'][.='4' ]" // ,meta+"/int[@name='before' ][.='0']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='5']" ); assertQ(f + ": checking counts for lower & outer", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "20" ,"facet.range.end", "40" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.include", "lower" ,"facet.range.include", "outer" ) ,"*[count("+pre+"/int)=2]" ,pre+"/int[@name='20.0'][.='3' ]" ,pre+"/int[@name='30.0'][.='2' ]" // ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='0']" ,meta+"/int[@name='between'][.='5']" ); assertQ(f + ": checking counts for lower & edge & outer", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "20" ,"facet.range.end", "35.3" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.hardend", "true" ,"facet.range.include", "lower" ,"facet.range.include", "edge" ,"facet.range.include", "outer" ) ,"*[count("+pre+"/int)=2]" ,pre+"/int[@name='20.0'][.='3' ]" ,pre+"/int[@name='30.0'][.='2' ]" // ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='5']" ); assertQ(f + ": checking counts for include all", req( "q", "*:*" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "20" ,"facet.range.end", "35.3" ,"facet.range.gap", "10" ,"facet.range.other", "all" ,"facet.range.hardend", "true" ,"facet.range.include", "all" ) ,"*[count("+pre+"/int)=2]" ,pre+"/int[@name='20.0'][.='4' ]" ,pre+"/int[@name='30.0'][.='2' ]" // ,meta+"/int[@name='before' ][.='2']" ,meta+"/int[@name='after' ][.='1']" ,meta+"/int[@name='between'][.='5']" ); } @Test public void testNumericRangeFacetsTrieInt() { helpTestWholeNumberRangeFacets("id"); } @Test public void testNumericRangeFacetsTrieLong() { helpTestWholeNumberRangeFacets("range_facet_l"); } @Test public void testNumericRangeFacetsSortableInt() { helpTestWholeNumberRangeFacets("range_facet_si"); } @Test public void testNumericRangeFacetsSortableLong() { helpTestWholeNumberRangeFacets("range_facet_sl"); } private void helpTestWholeNumberRangeFacets(final String fieldName) { // the float test covers a lot of the weird edge cases // here we just need some basic sanity checking of the parsing final String f = fieldName; final String pre = "//lst[@name='facet_ranges']/lst[@name='"+f+"']/lst[@name='counts']"; final String meta = pre + "/../"; assertQ(f+": checking counts for lower", req( "q", "id:[30 TO 60]" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "35" ,"facet.range.end", "50" ,"facet.range.gap", "5" ,"facet.range.other", "all" ,"facet.range.include", "lower" ) ,"*[count("+pre+"/int)=3]" ,pre+"/int[@name='35'][.='0' ]" ,pre+"/int[@name='40'][.='3' ]" ,pre+"/int[@name='45'][.='3' ]" // ,meta+"/int[@name='before' ][.='0']" ,meta+"/int[@name='after' ][.='0']" ,meta+"/int[@name='between'][.='6']" ); assertQ(f + ":checking counts for upper", req( "q", "id:[30 TO 60]" ,"rows", "0" ,"facet", "true" ,"facet.range", f ,"facet.range.start", "35" ,"facet.range.end", "50" ,"facet.range.gap", "5" ,"facet.range.other", "all" ,"facet.range.include", "upper" ) ,"*[count("+pre+"/int)=3]" ,pre+"/int[@name='35'][.='0' ]" ,pre+"/int[@name='40'][.='4' ]" ,pre+"/int[@name='45'][.='2' ]" // ,meta+"/int[@name='before' ][.='0']" ,meta+"/int[@name='after' ][.='0']" ,meta+"/int[@name='between'][.='6']" ); } static void indexFacetSingleValued() { indexFacets("40","t_s1"); } @Test public void testFacetSingleValued() { doFacets("t_s1"); } @Test public void testFacetSingleValuedFcs() { doFacets("t_s1","facet.method","fcs"); } static void indexFacets(String idPrefix, String f) { add_doc("id", idPrefix+"1", f, "A"); add_doc("id", idPrefix+"2", f, "B"); add_doc("id", idPrefix+"3", f, "C"); add_doc("id", idPrefix+"4", f, "C"); add_doc("id", idPrefix+"5", f, "D"); add_doc("id", idPrefix+"6", f, "E"); add_doc("id", idPrefix+"7", f, "E"); add_doc("id", idPrefix+"8", f, "E"); add_doc("id", idPrefix+"9", f, "F"); add_doc("id", idPrefix+"10", f, "G"); add_doc("id", idPrefix+"11", f, "G"); add_doc("id", idPrefix+"12", f, "G"); add_doc("id", idPrefix+"13", f, "G"); add_doc("id", idPrefix+"14", f, "G"); } public void doFacets(String f, String... params) { String pre = "//lst[@name='"+f+"']"; String notc = "id:[* TO *] -"+f+":C"; assertQ("check counts for unlimited facet", req(params, "q", "id:[* TO *]", "indent","true" ,"facet", "true" ,"facet.field", f ) ,"*[count(//lst[@name='facet_fields']/lst/int)=7]" ,pre+"/int[@name='G'][.='5']" ,pre+"/int[@name='E'][.='3']" ,pre+"/int[@name='C'][.='2']" ,pre+"/int[@name='A'][.='1']" ,pre+"/int[@name='B'][.='1']" ,pre+"/int[@name='D'][.='1']" ,pre+"/int[@name='F'][.='1']" ); assertQ("check counts for facet with generous limit", req(params, "q", "id:[* TO *]" ,"facet", "true" ,"facet.limit", "100" ,"facet.field", f ) ,"*[count(//lst[@name='facet_fields']/lst/int)=7]" ,pre+"/int[1][@name='G'][.='5']" ,pre+"/int[2][@name='E'][.='3']" ,pre+"/int[3][@name='C'][.='2']" ,pre+"/int[@name='A'][.='1']" ,pre+"/int[@name='B'][.='1']" ,pre+"/int[@name='D'][.='1']" ,pre+"/int[@name='F'][.='1']" ); assertQ("check counts for limited facet", req(params, "q", "id:[* TO *]" ,"facet", "true" ,"facet.limit", "2" ,"facet.field", f ) ,"*[count(//lst[@name='facet_fields']/lst/int)=2]" ,pre+"/int[1][@name='G'][.='5']" ,pre+"/int[2][@name='E'][.='3']" ); assertQ("check offset", req(params, "q", "id:[* TO *]" ,"facet", "true" ,"facet.offset", "1" ,"facet.limit", "1" ,"facet.field", f ) ,"*[count(//lst[@name='facet_fields']/lst/int)=1]" ,pre+"/int[1][@name='E'][.='3']" ); assertQ("test sorted facet paging with zero (don't count in limit)", req(params, "q", "id:[* TO *]" ,"fq",notc ,"facet", "true" ,"facet.field", f ,"facet.mincount","1" ,"facet.offset","0" ,"facet.limit","6" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=6]" ,pre+"/int[1][@name='G'][.='5']" ,pre+"/int[2][@name='E'][.='3']" ,pre+"/int[3][@name='A'][.='1']" ,pre+"/int[4][@name='B'][.='1']" ,pre+"/int[5][@name='D'][.='1']" ,pre+"/int[6][@name='F'][.='1']" ); assertQ("test sorted facet paging with zero (test offset correctness)", req(params, "q", "id:[* TO *]" ,"fq",notc ,"facet", "true" ,"facet.field", f ,"facet.mincount","1" ,"facet.offset","3" ,"facet.limit","2" ,"facet.sort","count" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=2]" ,pre+"/int[1][@name='B'][.='1']" ,pre+"/int[2][@name='D'][.='1']" ); assertQ("test facet unsorted paging", req(params, "q", "id:[* TO *]" ,"fq",notc ,"facet", "true" ,"facet.field", f ,"facet.mincount","1" ,"facet.offset","0" ,"facet.limit","6" ,"facet.sort","index" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=6]" ,pre+"/int[1][@name='A'][.='1']" ,pre+"/int[2][@name='B'][.='1']" ,pre+"/int[3][@name='D'][.='1']" ,pre+"/int[4][@name='E'][.='3']" ,pre+"/int[5][@name='F'][.='1']" ,pre+"/int[6][@name='G'][.='5']" ); assertQ("test facet unsorted paging", req(params, "q", "id:[* TO *]" ,"fq",notc ,"facet", "true" ,"facet.field", f ,"facet.mincount","1" ,"facet.offset","3" ,"facet.limit","2" ,"facet.sort","index" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=2]" ,pre+"/int[1][@name='E'][.='3']" ,pre+"/int[2][@name='F'][.='1']" ); assertQ("test facet unsorted paging, mincount=2", req(params, "q", "id:[* TO *]" ,"fq",notc ,"facet", "true" ,"facet.field", f ,"facet.mincount","2" ,"facet.offset","1" ,"facet.limit","2" ,"facet.sort","index" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=1]" ,pre+"/int[1][@name='G'][.='5']" ); } static void indexFacetPrefixMultiValued() { indexFacetPrefix("50","t_s"); } @Test public void testFacetPrefixMultiValued() { doFacetPrefix("t_s", null, "facet.method","enum"); doFacetPrefix("t_s", null, "facet.method", "enum", "facet.enum.cache.minDf", "3"); doFacetPrefix("t_s", null, "facet.method", "enum", "facet.enum.cache.minDf", "100"); doFacetPrefix("t_s", null, "facet.method", "fc"); } static void indexFacetPrefixSingleValued() { indexFacetPrefix("60","tt_s1"); } @Test public void testFacetPrefixSingleValued() { doFacetPrefix("tt_s1", null); } @Test public void testFacetPrefixSingleValuedFcs() { doFacetPrefix("tt_s1", null, "facet.method","fcs"); doFacetPrefix("tt_s1", "{!threads=0}", "facet.method","fcs"); // direct execution doFacetPrefix("tt_s1", "{!threads=-1}", "facet.method","fcs"); // default / unlimited threads doFacetPrefix("tt_s1", "{!threads=2}", "facet.method","fcs"); // specific number of threads } static void indexFacetPrefix(String idPrefix, String f) { add_doc("id", idPrefix+"1", f, "AAA"); add_doc("id", idPrefix+"2", f, "B"); add_doc("id", idPrefix+"3", f, "BB"); add_doc("id", idPrefix+"4", f, "BB"); add_doc("id", idPrefix+"5", f, "BBB"); add_doc("id", idPrefix+"6", f, "BBB"); add_doc("id", idPrefix+"7", f, "BBB"); add_doc("id", idPrefix+"8", f, "CC"); add_doc("id", idPrefix+"9", f, "CC"); add_doc("id", idPrefix+"10", f, "CCC"); add_doc("id", idPrefix+"11", f, "CCC"); add_doc("id", idPrefix+"12", f, "CCC"); assertU(commit()); } public void doFacetPrefix(String f, String local, String... params) { String indent="on"; String pre = "//lst[@name='"+f+"']"; String notc = "id:[* TO *] -"+f+":C"; String lf = local==null ? f : local+f; assertQ("test facet.prefix middle, exact match first term", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","B" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=3]" ,pre+"/int[1][@name='BBB'][.='3']" ,pre+"/int[2][@name='BB'][.='2']" ,pre+"/int[3][@name='B'][.='1']" ); assertQ("test facet.prefix middle, exact match first term, unsorted", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","index" ,"facet.prefix","B" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=3]" ,pre+"/int[1][@name='B'][.='1']" ,pre+"/int[2][@name='BB'][.='2']" ,pre+"/int[3][@name='BBB'][.='3']" ); assertQ("test facet.prefix middle, exact match first term, unsorted", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","index" ,"facet.prefix","B" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=3]" ,pre+"/int[1][@name='B'][.='1']" ,pre+"/int[2][@name='BB'][.='2']" ,pre+"/int[3][@name='BBB'][.='3']" ); assertQ("test facet.prefix middle, paging", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","1" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","B" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=2]" ,pre+"/int[1][@name='BB'][.='2']" ,pre+"/int[2][@name='B'][.='1']" ); assertQ("test facet.prefix middle, paging", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","1" ,"facet.limit","1" ,"facet.sort","count" ,"facet.prefix","B" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=1]" ,pre+"/int[1][@name='BB'][.='2']" ); assertQ("test facet.prefix middle, paging", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","1" ,"facet.limit","1" ,"facet.sort","count" ,"facet.prefix","B" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=1]" ,pre+"/int[1][@name='BB'][.='2']" ); assertQ("test facet.prefix end, not exact match", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","C" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=2]" ,pre+"/int[1][@name='CCC'][.='3']" ,pre+"/int[2][@name='CC'][.='2']" ); assertQ("test facet.prefix end, exact match", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","CC" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=2]" ,pre+"/int[1][@name='CCC'][.='3']" ,pre+"/int[2][@name='CC'][.='2']" ); assertQ("test facet.prefix past end", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","X" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=0]" ); assertQ("test facet.prefix past end", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","1" ,"facet.limit","-1" ,"facet.sort","count" ,"facet.prefix","X" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=0]" ); assertQ("test facet.prefix at start, exact match", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","AAA" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=1]" ,pre+"/int[1][@name='AAA'][.='1']" ); assertQ("test facet.prefix at Start, not exact match", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","AA" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=1]" ,pre+"/int[1][@name='AAA'][.='1']" ); assertQ("test facet.prefix at Start, not exact match", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","AA" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=1]" ,pre+"/int[1][@name='AAA'][.='1']" ); assertQ("test facet.prefix before start", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","0" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","999" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=0]" ); assertQ("test facet.prefix before start", req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","0" ,"facet.offset","2" ,"facet.limit","100" ,"facet.sort","count" ,"facet.prefix","999" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=0]" ); // test offset beyond what is collected internally in queue assertQ( req(params, "q", "id:[* TO *]" ,"indent",indent ,"facet","true" ,"facet.field", lf ,"facet.mincount","3" ,"facet.offset","5" ,"facet.limit","10" ,"facet.sort","count" ,"facet.prefix","CC" ) ,"*[count(//lst[@name='facet_fields']/lst/int)=0]" ); } }