diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index c32363e3186..5a3971443ac 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -161,6 +161,9 @@ Bug Fixes * SOLR-4406: Fix RawResponseWriter to respect 'base' writer (Steve Davids, hossman) +* SOLR-6024: Fix StatsComponent when using docValues="true" multiValued="true" + (Vitaliy Zhovtyuk & Tomas Fernandez-Lobbe via hossman) + Other Changes --------------------- diff --git a/solr/core/src/test-files/solr/collection1/conf/schema11.xml b/solr/core/src/test-files/solr/collection1/conf/schema11.xml index 19271a496bf..6bf7d6208a5 100755 --- a/solr/core/src/test-files/solr/collection1/conf/schema11.xml +++ b/solr/core/src/test-files/solr/collection1/conf/schema11.xml @@ -317,7 +317,10 @@ valued. --> - + + + + EXAMPLE: name="*_i" will match any field ending in _i (like myid_i, z_i) Longer patterns will be matched first. if equal size patterns both match, the first appearing in the schema will be used. --> - - - - - - - - + + + + + + + + - - - - - + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + diff --git a/solr/core/src/test/org/apache/solr/handler/component/StatsComponentTest.java b/solr/core/src/test/org/apache/solr/handler/component/StatsComponentTest.java index a5bf0ac5c2d..03ee6d8520e 100644 --- a/solr/core/src/test/org/apache/solr/handler/component/StatsComponentTest.java +++ b/solr/core/src/test/org/apache/solr/handler/component/StatsComponentTest.java @@ -18,12 +18,17 @@ package org.apache.solr.handler.component; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.StatsParams; @@ -38,6 +43,7 @@ import org.junit.BeforeClass; /** * Statistics Component Test */ +@LuceneTestCase.SuppressCodecs({"Lucene40", "Lucene41", "Lucene42"}) public class StatsComponentTest extends AbstractSolrTestCase { @BeforeClass @@ -49,24 +55,35 @@ public class StatsComponentTest extends AbstractSolrTestCase { public void setUp() throws Exception { super.setUp(); clearIndex(); + assertU(commit()); lrf = h.getRequestFactory("standard", 0, 20); } public void testStats() throws Exception { for (String f : new String[] { "stats_i","stats_l","stats_f","stats_d", - "stats_ti","stats_tl","stats_tf","stats_td" + "stats_ti","stats_tl","stats_tf","stats_td", + "stats_ti_dv","stats_tl_dv","stats_tf_dv","stats_td_dv" +// , TODO: enable this test after SOLR-6452 is fixed +// "stats_ti_ni_dv","stats_tl_ni_dv","stats_tf_ni_dv","stats_td_ni_dv" }) { doTestFieldStatisticsResult(f); doTestFieldStatisticsMissingResult(f); doTestFacetStatisticsResult(f); doTestFacetStatisticsMissingResult(f); + clearIndex(); + assertU(commit()); } for (String f : new String[] {"stats_ii", - "stats_tis","stats_tfs","stats_tls","stats_tds" // trie fields + "stats_tis","stats_tfs","stats_tls","stats_tds", // trie fields + "stats_tis_dv","stats_tfs_dv","stats_tls_dv","stats_tds_dv" // Doc Values +// , TODO: enable this test after SOLR-6452 is fixed + //"stats_tis_ni_dv","stats_tfs_ni_dv","stats_tls_ni_dv","stats_tds_ni_dv" // Doc Values Not indexed }) { doTestMVFieldStatisticsResult(f); + clearIndex(); + assertU(commit()); } } @@ -86,7 +103,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//long[@name='count'][.='4']" , "//long[@name='missing'][.='0']" , "//long[@name='countDistinct'][.='4']" - , "count(//arr[@name='distinctValues']/*)='4'" + , "count(//arr[@name='distinctValues']/*)=4" , "//double[@name='sumOfSquares'][.='3000.0']" , "//double[@name='mean'][.='-25.0']" , "//double[@name='stddev'][.='12.909944487358056']" @@ -97,6 +114,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { 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(commit()); 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")); @@ -109,7 +127,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//long[@name='count'][.='8']" , "//long[@name='missing'][.='1']" , "//long[@name='countDistinct'][.='8']" - , "count(//arr[@name='distinctValues']/*)='8'" + , "count(//arr[@name='distinctValues']/*)=8" , "//double[@name='sumOfSquares'][.='53101.0']" , "//double[@name='mean'][.='1.125']" , "//double[@name='stddev'][.='87.08852228787508']" @@ -122,7 +140,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//long[@name='count'][.='8']" , "//long[@name='missing'][.='1']" , "//long[@name='countDistinct'][.='8']" - , "count(//lst[@name='" + f + "']/arr[@name='distinctValues']/*)='8'" + , "count(//lst[@name='" + f + "']/arr[@name='distinctValues']/*)=8" , "//double[@name='sumOfSquares'][.='53101.0']" , "//double[@name='mean'][.='1.125']" , "//double[@name='stddev'][.='87.08852228787508']" @@ -135,7 +153,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//lst[@name='true']/long[@name='count'][.='4']" , "//lst[@name='true']/long[@name='missing'][.='0']" , "//lst[@name='true']//long[@name='countDistinct'][.='4']" - , "count(//lst[@name='true']/arr[@name='distinctValues']/*)='4'" + , "count(//lst[@name='true']/arr[@name='distinctValues']/*)=4" , "//lst[@name='true']/double[@name='sumOfSquares'][.='50500.0']" , "//lst[@name='true']/double[@name='mean'][.='17.5']" , "//lst[@name='true']/double[@name='stddev'][.='128.16005617976296']" @@ -148,7 +166,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//lst[@name='false']/long[@name='count'][.='4']" , "//lst[@name='false']/long[@name='missing'][.='1']" , "//lst[@name='true']//long[@name='countDistinct'][.='4']" - , "count(//lst[@name='true']/arr[@name='distinctValues']/*)='4'" + , "count(//lst[@name='true']/arr[@name='distinctValues']/*)=4" , "//lst[@name='false']/double[@name='sumOfSquares'][.='2601.0']" , "//lst[@name='false']/double[@name='mean'][.='-15.25']" , "//lst[@name='false']/double[@name='stddev'][.='23.59908190304586']" @@ -179,7 +197,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { "//long[@name='count'][.='3']", "//long[@name='missing'][.='1']", "//long[@name='countDistinct'][.='3']", - "count(//arr[@name='distinctValues']/str)='3'"); + "count(//arr[@name='distinctValues']/str)=3"); } public void testFieldStatisticsResultsDateField() throws Exception { @@ -210,7 +228,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { "//date[@name='min'][.='1970-01-02T10:17:36Z']", "//date[@name='max'][.='1970-01-12T10:20:54Z']", "//long[@name='countDistinct'][.='2']", - "count(//arr[@name='distinctValues']/date)='2'" + "count(//arr[@name='distinctValues']/date)=2" // "//date[@name='sum'][.='1970-01-13T20:38:30Z']", // sometimes 29.999Z // "//date[@name='mean'][.='1970-01-07T10:19:15Z']" // sometiems 14.999Z ); @@ -232,7 +250,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//long[@name='count'][.='3']" , "//long[@name='missing'][.='1']" , "//long[@name='countDistinct'][.='3']" - , "count(//arr[@name='distinctValues']/*)='3'" + , "count(//arr[@name='distinctValues']/*)=3" , "//double[@name='sumOfSquares'][.='2100.0']" , "//double[@name='mean'][.='-23.333333333333332']" , "//double[@name='stddev'][.='15.275252316519467']" @@ -257,7 +275,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , pre+"/lst[@name='true']/long[@name='count'][.='2']" , pre+"/lst[@name='true']/long[@name='missing'][.='0']" , pre + "/lst[@name='true']/long[@name='countDistinct'][.='2']" - , "count(" + pre + "/lst[@name='true']/arr[@name='distinctValues']/*)='2'" + , "count(" + pre + "/lst[@name='true']/arr[@name='distinctValues']/*)=2" , pre+"/lst[@name='true']/double[@name='sumOfSquares'][.='500.0']" , pre+"/lst[@name='true']/double[@name='mean'][.='15.0']" , pre+"/lst[@name='true']/double[@name='stddev'][.='7.0710678118654755']" @@ -270,7 +288,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , pre+"/lst[@name='false']/long[@name='count'][.='2']" , pre+"/lst[@name='false']/long[@name='missing'][.='0']" , pre + "/lst[@name='true']/long[@name='countDistinct'][.='2']" - , "count(" + pre + "/lst[@name='true']/arr[@name='distinctValues']/*)='2'" + , "count(" + pre + "/lst[@name='true']/arr[@name='distinctValues']/*)=2" , pre+"/lst[@name='false']/double[@name='sumOfSquares'][.='2500.0']" , pre+"/lst[@name='false']/double[@name='mean'][.='35.0']" , pre+"/lst[@name='false']/double[@name='stddev'][.='7.0710678118654755']" @@ -292,7 +310,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//lst[@name='true']/long[@name='count'][.='2']" , "//lst[@name='true']/long[@name='missing'][.='0']" , "//lst[@name='true']/long[@name='countDistinct'][.='2']" - , "count(//lst[@name='true']/arr[@name='distinctValues']/*)='2'" + , "count(//lst[@name='true']/arr[@name='distinctValues']/*)=2" , "//lst[@name='true']/double[@name='sumOfSquares'][.='500.0']" , "//lst[@name='true']/double[@name='mean'][.='15.0']" , "//lst[@name='true']/double[@name='stddev'][.='7.0710678118654755']" @@ -305,7 +323,7 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//lst[@name='false']/long[@name='count'][.='1']" , "//lst[@name='false']/long[@name='missing'][.='1']" , "//lst[@name='false']/long[@name='countDistinct'][.='1']" - , "count(//lst[@name='false']/arr[@name='distinctValues']/*)='1'" + , "count(//lst[@name='false']/arr[@name='distinctValues']/*)=1" , "//lst[@name='false']/double[@name='sumOfSquares'][.='1600.0']" , "//lst[@name='false']/double[@name='mean'][.='40.0']" , "//lst[@name='false']/double[@name='stddev'][.='0.0']" @@ -426,4 +444,186 @@ public class StatsComponentTest extends AbstractSolrTestCase { , "//lst[@name='id2']/double[@name='min'][.='2.0']" , "//lst[@name='id2']/double[@name='max'][.='3.0']"); } + + // SOLR-6024 + public void testFieldStatisticsDocValuesAndMultiValued() throws Exception { + SolrCore core = h.getCore(); + + // precondition for the test + SchemaField catDocValues = core.getLatestSchema().getField("cat_docValues"); + assertTrue("schema no longer satisfies test requirements: cat_docValues no longer multivalued", catDocValues.multiValued()); + assertTrue("schema no longer satisfies test requirements: cat_docValues fieldtype no longer single valued", !catDocValues.getType().isMultiValued()); + assertTrue("schema no longer satisfies test requirements: cat_docValues no longer has docValues", catDocValues.hasDocValues()); + + List types = new ArrayList<>(); + types.add(new FldType("id", ONE_ONE, new SVal('A', 'Z', 4, 4))); + types.add(new FldType("cat_docValues",new IRange(2,2), new SVal('a','z',1, 30))); + Doc d1 = createDoc(types); + d1.getValues("id").set(0, "1"); + d1.getValues("cat_docValues").set(0, "test"); + d1.getValues("cat_docValues").set(1, "testtw"); + updateJ(toJSON(d1), null); + Doc d2 = createDoc(types); + d2.getValues("id").set(0, "2"); + d2.getValues("cat_docValues").set(0, "test"); + d2.getValues("cat_docValues").set(1, "testtt"); + updateJ(toJSON(d2), null); + + assertU(commit()); + + Map args = new HashMap<>(); + args.put(CommonParams.Q, "*:*"); + args.put(StatsParams.STATS, "true"); + args.put(StatsParams.STATS_FIELD, "cat_docValues"); + args.put("indent", "true"); + SolrQueryRequest req = new LocalSolrQueryRequest(core, new MapSolrParams(args)); + + assertQ("test min/max on docValues and multiValued", req + , "//lst[@name='cat_docValues']/str[@name='min'][.='test']" + , "//lst[@name='cat_docValues']/str[@name='max'][.='testtw']"); + + } + + public void testFieldStatisticsDocValuesAndMultiValuedInteger() throws Exception { + SolrCore core = h.getCore(); + String fieldName = "cat_intDocValues"; + // precondition for the test + SchemaField catDocValues = core.getLatestSchema().getField(fieldName); + assertTrue("schema no longer satisfies test requirements: cat_docValues no longer multivalued", catDocValues.multiValued()); + assertTrue("schema no longer satisfies test requirements: cat_docValues fieldtype no longer single valued", !catDocValues.getType().isMultiValued()); + assertTrue("schema no longer satisfies test requirements: cat_docValues no longer has docValues", catDocValues.hasDocValues()); + + List types = new ArrayList<>(); + types.add(new FldType("id", ONE_ONE, new SVal('A', 'Z', 4, 4))); + types.add(new FldType(fieldName, ONE_ONE, new IRange(0, 0))); + + Doc d1 = createDocValuesDocument(types, fieldName, "1", -1, 3, 5); + updateJ(toJSON(d1), null); + + Doc d2 = createDocValuesDocument(types, fieldName, "2", 3, -2, 6); + updateJ(toJSON(d2), null); + + Doc d3 = createDocValuesDocument(types, fieldName, "3", 16, -3, 11); + updateJ(toJSON(d3), null); + + assertU(commit()); + + Map args = new HashMap<>(); + args.put(CommonParams.Q, "*:*"); + args.put(StatsParams.STATS, "true"); + args.put(StatsParams.STATS_FIELD, fieldName); + args.put("indent", "true"); + args.put(StatsParams.STATS_CALC_DISTINCT, "true"); + + SolrQueryRequest req = new LocalSolrQueryRequest(core, new MapSolrParams(args)); + + assertQ("test min/max on docValues and multiValued", req + , "//lst[@name='" + fieldName + "']/double[@name='min'][.='-3.0']" + , "//lst[@name='" + fieldName + "']/double[@name='max'][.='16.0']" + , "//lst[@name='" + fieldName + "']/long[@name='count'][.='12']" + , "//lst[@name='" + fieldName + "']/long[@name='countDistinct'][.='9']" + , "//lst[@name='" + fieldName + "']/double[@name='sum'][.='38.0']" + , "//lst[@name='" + fieldName + "']/double[@name='mean'][.='3.1666666666666665']" + , "//lst[@name='" + fieldName + "']/double[@name='stddev'][.='5.638074031784151']" + , "//lst[@name='" + fieldName + "']/double[@name='sumOfSquares'][.='470.0']" + , "//lst[@name='" + fieldName + "']/long[@name='missing'][.='0']"); + + } + + public void testFieldStatisticsDocValuesAndMultiValuedIntegerFacetStats() throws Exception { + SolrCore core = h.getCore(); + String fieldName = "cat_intDocValues"; + // precondition for the test + SchemaField catDocValues = core.getLatestSchema().getField(fieldName); + assertTrue("schema no longer satisfies test requirements: cat_docValues no longer multivalued", catDocValues.multiValued()); + assertTrue("schema no longer satisfies test requirements: cat_docValues fieldtype no longer single valued", !catDocValues.getType().isMultiValued()); + assertTrue("schema no longer satisfies test requirements: cat_docValues no longer has docValues", catDocValues.hasDocValues()); + + List types = new ArrayList<>(); + types.add(new FldType("id", ONE_ONE, new SVal('A', 'Z', 4, 4))); + types.add(new FldType(fieldName, ONE_ONE, new IRange(0, 0))); + + Doc d1 = createDocValuesDocument(types, fieldName, "1", -1, 3, 5); + updateJ(toJSON(d1), null); + + Doc d2 = createDocValuesDocument(types, fieldName, "2", 3, -2, 6); + updateJ(toJSON(d2), null); + + Doc d3 = createDocValuesDocument(types, fieldName, "3", 16, -3, 11); + updateJ(toJSON(d3), null); + + assertU(commit()); + + Map args = new HashMap<>(); + args.put(CommonParams.Q, "*:*"); + args.put(StatsParams.STATS, "true"); + args.put(StatsParams.STATS_FIELD, fieldName); + args.put(StatsParams.STATS_FACET, fieldName); + args.put("indent", "true"); + args.put(StatsParams.STATS_CALC_DISTINCT, "true"); + + SolrQueryRequest req = new LocalSolrQueryRequest(core, new MapSolrParams(args)); + + assertQEx("can not use FieldCache on multivalued field: cat_intDocValues", req, 400); + + } + + + + public void testFieldStatisticsDocValuesAndMultiValuedDouble() throws Exception { + SolrCore core = h.getCore(); + String fieldName = "cat_floatDocValues"; + // precondition for the test + SchemaField catDocValues = core.getLatestSchema().getField(fieldName); + assertTrue("schema no longer satisfies test requirements: cat_docValues no longer multivalued", catDocValues.multiValued()); + assertTrue("schema no longer satisfies test requirements: cat_docValues fieldtype no longer single valued", !catDocValues.getType().isMultiValued()); + assertTrue("schema no longer satisfies test requirements: cat_docValues no longer has docValues", catDocValues.hasDocValues()); + + List types = new ArrayList<>(); + types.add(new FldType("id", ONE_ONE, new SVal('A', 'Z', 4, 4))); + types.add(new FldType(fieldName, ONE_ONE, new FVal(0, 0))); + + Doc d1 = createDocValuesDocument(types, fieldName, "1", -1, 3, 5); + updateJ(toJSON(d1), null); + + Doc d2 = createDocValuesDocument(types, fieldName, "2", 3, -2, 6); + updateJ(toJSON(d2), null); + + Doc d3 = createDocValuesDocument(types, fieldName, "3", 16, -3, 11); + updateJ(toJSON(d3), null); + + assertU(commit()); + + Map args = new HashMap<>(); + args.put(CommonParams.Q, "*:*"); + args.put(StatsParams.STATS, "true"); + args.put(StatsParams.STATS_FIELD, fieldName); + args.put(StatsParams.STATS_CALC_DISTINCT, "true"); + args.put("indent", "true"); + SolrQueryRequest req = new LocalSolrQueryRequest(core, new MapSolrParams(args)); + + assertQ("test min/max on docValues and multiValued", req + , "//lst[@name='" + fieldName + "']/double[@name='min'][.='-3.0']" + , "//lst[@name='" + fieldName + "']/double[@name='max'][.='16.0']" + , "//lst[@name='" + fieldName + "']/long[@name='count'][.='12']" + , "//lst[@name='" + fieldName + "']/double[@name='sum'][.='38.0']" + , "//lst[@name='" + fieldName + "']/long[@name='countDistinct'][.='9']" + , "//lst[@name='" + fieldName + "']/double[@name='mean'][.='3.1666666666666665']" + , "//lst[@name='" + fieldName + "']/double[@name='stddev'][.='5.638074031784151']" + , "//lst[@name='" + fieldName + "']/double[@name='sumOfSquares'][.='470.0']" + , "//lst[@name='" + fieldName + "']/long[@name='missing'][.='0']"); + + } + + private Doc createDocValuesDocument(List types, String fieldName, String id, Comparable... values) throws Exception { + Doc doc = createDoc(types); + doc.getValues("id").set(0, id); + initMultyValued(doc.getValues(fieldName), values); + return doc; + } + + private List initMultyValued(List cat_docValues, Comparable... comparables) { + Collections.addAll(cat_docValues, comparables); + return cat_docValues; + } }