You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2014/11/05 00:09:42 UTC
svn commit: r1636772 [2/2] - in /lucene/dev/trunk/solr: ./
core/src/java/org/apache/solr/handler/component/
core/src/java/org/apache/solr/util/ core/src/test/org/apache/solr/cloud/
core/src/test/org/apache/solr/handler/component/ solrj/src/java/org/apa...
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/component/DistributedFacetPivotWhiteBoxTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/component/DistributedFacetPivotWhiteBoxTest.java?rev=1636772&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/component/DistributedFacetPivotWhiteBoxTest.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/component/DistributedFacetPivotWhiteBoxTest.java Tue Nov 4 23:09:41 2014
@@ -0,0 +1,138 @@
+package org.apache.solr.handler.component;
+
+/*
+ * 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.
+ */
+
+import org.apache.solr.BaseDistributedSearchTestCase;
+import org.apache.solr.client.solrj.response.PivotField;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+
+import java.util.List;
+
+public class DistributedFacetPivotWhiteBoxTest extends BaseDistributedSearchTestCase {
+
+ public DistributedFacetPivotWhiteBoxTest() {
+ this.fixShardCount = true;
+ this.shardCount = 4;
+ }
+
+ @Override
+ public void doTest() throws Exception {
+
+ del("*:*");
+
+ // NOTE: we use the literal (4 character) string "null" as a company name
+ // to help ensure there isn't any bugs where the literal string is treated as if it
+ // were a true NULL value.
+ index(id, 19, "place_t", "cardiff dublin", "company_t", "microsoft polecat", "price_ti", "15");
+ index(id, 20, "place_t", "dublin", "company_t", "polecat microsoft null", "price_ti", "19",
+ // this is the only doc to have solo_* fields, therefore only 1 shard has them
+ // TODO: add enum field - blocked by SOLR-6682
+ "solo_i", 42, "solo_s", "lonely", "solo_dt", "1976-03-06T01:23:45Z");
+ index(id, 21, "place_t", "krakow london la dublin", "company_t",
+ "microsoft fujitsu null polecat", "price_ti", "29");
+ index(id, 22, "place_t", "krakow london cardiff", "company_t",
+ "polecat null bbc", "price_ti", "39");
+ index(id, 23, "place_t", "krakow london", "company_t", "", "price_ti", "29");
+ index(id, 24, "place_t", "krakow la", "company_t", "");
+ index(id, 25, "company_t", "microsoft polecat null fujitsu null bbc", "price_ti", "59");
+ index(id, 26, "place_t", "krakow", "company_t", "null");
+ index(id, 27, "place_t", "krakow cardiff dublin london la",
+ "company_t", "null microsoft polecat bbc fujitsu");
+ index(id, 28, "place_t", "krakow cork", "company_t", "fujitsu rte");
+ commit();
+
+ handle.clear();
+ handle.put("QTime", SKIPVAL);
+ handle.put("timestamp", SKIPVAL);
+ handle.put("maxScore", SKIPVAL);
+
+ doShardTestTopStats();
+ doTestRefinementRequest();
+ }
+
+ /**
+ * recreates the initial request to a shard in a distributed query
+ * confirming that both top level stats, and per-pivot stats are returned.
+ */
+ private void doShardTestTopStats() throws Exception {
+
+ SolrParams params = params("facet", "true",
+ "q", "*:*",
+ // "wt", "javabin",
+ "facet.pivot", "{!stats=s1}place_t,company_t",
+ // "version", "2",
+ "start", "0", "rows", "0",
+ "fsv", "true",
+ "fl", "id,score",
+ "stats", "true",
+ "stats.field", "{!key=avg_price tag=s1}price_ti",
+ "f.place_t.facet.limit", "160",
+ "f.place_t.facet.pivot.mincount", "0",
+ "f.company_t.facet.limit", "160",
+ "f.company_t.facet.pivot.mincount", "0",
+ "isShard", "true", "distrib", "false");
+ QueryResponse rsp = queryServer(new ModifiableSolrParams(params));
+
+ assertNotNull("initial shard request should include non-null top level stats",
+ rsp.getFieldStatsInfo());
+ assertFalse("initial shard request should include top level stats",
+ rsp.getFieldStatsInfo().isEmpty());
+
+ List<PivotField> placePivots = rsp.getFacetPivot().get("place_t,company_t");
+ for (PivotField pivotField : placePivots) {
+ assertFalse("pivot stats should not be empty in initial request",
+ pivotField.getFieldStatsInfo().isEmpty());
+ }
+ }
+
+ /**
+ * recreates a pivot refinement request to a shard in a distributed query
+ * confirming that the per-pivot stats are returned, but not the top level stats
+ * because they shouldn't be overcounted.
+ */
+ private void doTestRefinementRequest() throws Exception {
+ SolrParams params = params("facet.missing", "true",
+ "facet", "true",
+ "facet.limit", "4",
+ "distrib", "false",
+ // "wt", "javabin",
+ // "version", "2",
+ "rows", "0",
+ "facet.sort", "index",
+ "fpt0", "~krakow",
+ "facet.pivot.mincount", "-1",
+ "isShard", "true",
+ "facet.pivot", "{!fpt=0 stats=st1}place_t,company_t",
+ "stats", "false",
+ "stats.field", "{!key=sk1 tag=st1,st2}price_ti");
+ QueryResponse rsp = clients.get(0).query(new ModifiableSolrParams(params));
+
+ assertNull("pivot refine request should *NOT* include top level stats",
+ rsp.getFieldStatsInfo());
+
+ List<PivotField> placePivots = rsp.getFacetPivot().get("place_t,company_t");
+
+ assertEquals("asked to refine exactly one place",
+ 1, placePivots.size());
+ assertFalse("pivot stats should not be empty in refinement request",
+ placePivots.get(0).getFieldStatsInfo().isEmpty());
+
+ }
+}
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/component/FacetPivotSmallTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/component/FacetPivotSmallTest.java?rev=1636772&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/component/FacetPivotSmallTest.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/component/FacetPivotSmallTest.java Tue Nov 4 23:09:41 2014
@@ -0,0 +1,504 @@
+package org.apache.solr.handler.component;
+
+/*
+ * 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.
+ */
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.params.FacetParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.SolrQueryRequest;
+import org.junit.BeforeClass;
+
+/**
+ * Single node testing of pivot facets
+ */
+public class FacetPivotSmallTest extends SolrTestCaseJ4 {
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ initCore("solrconfig.xml", "schema11.xml");
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ clearIndex();
+ assertU(commit());
+ lrf = h.getRequestFactory("standard", 0, 20);
+ }
+
+ /**
+ * we don't support comma's in the "stats" local param ... yet: SOLR-6663
+ */
+ public void testStatsTagHasComma() throws Exception {
+
+ if (random().nextBoolean()) {
+ // behavior should be same either way
+ index();
+ }
+
+ assertQEx("Can't use multiple tags in stats local param until SOLR-6663 is decided",
+ req("q","*:*", "facet", "true",
+ "stats", "true",
+ "stats.field", "{!tag=foo}price_ti",
+ "stats.field", "{!tag=bar}id",
+ "facet.pivot", "{!stats=foo,bar}place_t,company_t"),
+ 400);
+ }
+
+ /**
+ * if bogus stats are requested, the pivots should still work
+ */
+ public void testBogusStatsTag() throws Exception {
+ index();
+
+ assertQ(req("q","*:*", "facet", "true",
+ "facet.pivot", "{!stats=bogus}place_t,company_t")
+ // check we still get pivots...
+ , "//arr[@name='place_t,company_t']/lst[str[@name='value'][.='dublin']]"
+ // .. but sanity check we don't have any stats
+ , "count(//arr[@name='place_t,company_t']/lst[str[@name='value'][.='dublin']]/lst[@name='stats'])=0");
+ }
+
+ public void testPivotFacetUnsorted() throws Exception {
+ index();
+
+ final ModifiableSolrParams params = new ModifiableSolrParams();
+ params.add("q", "*:*");
+ params.add("facet", "true");
+ params.add("facet.pivot", "place_t,company_t");
+
+ SolrQueryRequest req = req(params);
+ final String facetPivotPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='place_t,company_t']/lst";
+ assertQ(req, facetPivotPrefix + "/str[@name='field'][.='place_t']",
+ // dublin
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=4]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=4]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]",
+ // london
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=2]",
+ // cardiff
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]",
+ // krakow
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=1]",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]",
+
+ // la
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]",
+ // cork
+ facetPivotPrefix + "[str[@name='value'][.='cork']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='cork']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=1]",
+ facetPivotPrefix + "[str[@name='value'][.='cork']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='rte']",
+ facetPivotPrefix + "[str[@name='value'][.='cork']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=1]"
+ );
+ }
+
+ public void testPivotFacetStatsUnsortedTagged() throws Exception {
+ index();
+
+ final ModifiableSolrParams params = new ModifiableSolrParams();
+ params.add("q", "*:*");
+ params.add("facet", "true");
+ params.add("facet.pivot", "{!stats=s1}place_t,company_t");
+ params.add("stats", "true");
+ params.add("stats.field", "{!key=avg_price tag=s1 mean=true}price_ti");
+
+ SolrQueryRequest req = req(params);
+ final String statsPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='place_t,company_t']/lst";
+ String dublinMicrosoftStats = statsPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[str[@name='value'][.='microsoft']]/lst[@name='stats']/lst[@name='stats_fields']/lst[@name='avg_price']";
+ String cardiffPolecatStats = statsPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[str[@name='value'][.='polecat']]/lst[@name='stats']/lst[@name='stats_fields']/lst[@name='avg_price']";
+ String krakowFujitsuStats = statsPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[str[@name='value'][.='fujitsu']]/lst[@name='stats']/lst[@name='stats_fields']/lst[@name='avg_price']";
+ assertQ(req,
+ dublinMicrosoftStats + "/double[@name='min'][.=15.0]",
+ dublinMicrosoftStats + "/double[@name='max'][.=29.0]",
+ dublinMicrosoftStats + "/long[@name='count'][.=3]",
+ dublinMicrosoftStats + "/long[@name='missing'][.=1]",
+ dublinMicrosoftStats + "/double[@name='sum'][.=63.0]",
+ dublinMicrosoftStats + "/double[@name='sumOfSquares'][.=1427.0]",
+ dublinMicrosoftStats + "/double[@name='mean'][.=21.0]",
+ dublinMicrosoftStats + "/double[@name='stddev'][.=7.211102550927978]",
+
+ cardiffPolecatStats + "/double[@name='min'][.=15.0]",
+ cardiffPolecatStats + "/double[@name='max'][.=39.0]",
+ cardiffPolecatStats + "/long[@name='count'][.=2]",
+ cardiffPolecatStats + "/long[@name='missing'][.=1]",
+ cardiffPolecatStats + "/double[@name='sum'][.=54.0]",
+ cardiffPolecatStats + "/double[@name='sumOfSquares'][.=1746.0]",
+ cardiffPolecatStats + "/double[@name='mean'][.=27.0]",
+ cardiffPolecatStats + "/double[@name='stddev'][.=16.97056274847714]",
+
+ krakowFujitsuStats + "/null[@name='min']",
+ krakowFujitsuStats + "/null[@name='max']",
+ krakowFujitsuStats + "/long[@name='count'][.=0]",
+ krakowFujitsuStats + "/long[@name='missing'][.=1]",
+ krakowFujitsuStats + "/double[@name='sum'][.=0.0]",
+ krakowFujitsuStats + "/double[@name='sumOfSquares'][.=0.0]",
+ krakowFujitsuStats + "/double[@name='mean'][.='NaN']",
+ krakowFujitsuStats + "/double[@name='stddev'][.=0.0]"
+ );
+ }
+
+
+ public void testPivotFacetSortedCount() throws Exception {
+ index();
+
+ final ModifiableSolrParams params = new ModifiableSolrParams();
+ params.add("q", "*:*");
+ params.add("facet", "true");
+ params.add("facet.pivot", "place_t,company_t");
+
+ // Test sorting by count
+ //TODO clarify why facet count active by default
+ // The default is count if facet.limit is greater than 0, index otherwise, but facet.limit was not defined
+ params.set(FacetParams.FACET_SORT, FacetParams.FACET_SORT_COUNT);
+ final String facetPivotPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='place_t,company_t']/lst";
+ SolrQueryRequest req = req(params);
+ assertQ(req, facetPivotPrefix + "/str[@name='field'][.='place_t']",
+ // dublin
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=4]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=4]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]",
+ // london
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=2]",
+ // cardiff
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='cardiff']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]",
+ // krakow
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=1]",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='krakow']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]",
+
+ // la
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[5]/str[@name='value'][.='bbc']",
+ facetPivotPrefix + "[str[@name='value'][.='la']]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]",
+ // cork
+ facetPivotPrefix + "[str[@name='value'][.='cork']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='cork']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=1]",
+ facetPivotPrefix + "[str[@name='value'][.='cork']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='rte']",
+ facetPivotPrefix + "[str[@name='value'][.='cork']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=1]"
+ );
+
+
+ }
+
+
+ public void testPivotFacetLimit() throws Exception {
+ index();
+
+ final ModifiableSolrParams params = new ModifiableSolrParams();
+ params.add("q", "*:*");
+ params.add("facet", "true");
+ params.add("facet.pivot", "place_t,company_t");
+
+ params.set(FacetParams.FACET_SORT, FacetParams.FACET_SORT_COUNT);
+ params.set(FacetParams.FACET_LIMIT, 2);
+
+ final String facetPivotPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='place_t,company_t']/lst";
+ SolrQueryRequest req = req(params);
+ assertQ(req, facetPivotPrefix + "/str[@name='field'][.='place_t']",
+ // dublin
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=4]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=4]",
+ // london
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='london']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=3]"
+ );
+ }
+
+ public void testPivotIndividualFacetLimit() throws Exception {
+ index();
+
+ final ModifiableSolrParams params = new ModifiableSolrParams();
+ params.add("q", "*:*");
+ params.add("facet", "true");
+ params.add("facet.pivot", "place_t,company_t");
+
+ params.set(FacetParams.FACET_SORT, FacetParams.FACET_SORT_COUNT);
+ params.set("f.place_t." + FacetParams.FACET_LIMIT, 1);
+ params.set("f.company_t." + FacetParams.FACET_LIMIT, 4);
+
+ final String facetPivotPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='place_t,company_t']/lst";
+ SolrQueryRequest req = req(params);
+ assertQ(req, facetPivotPrefix + "/str[@name='field'][.='place_t']",
+ // dublin
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[1]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[1]/int[@name='count'][.=4]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[2]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[2]/int[@name='count'][.=4]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[3]/str[@name='value'][.='null']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[3]/int[@name='count'][.=3]",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[4]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "[str[@name='value'][.='dublin']]/arr[@name='pivot']/lst[4]/int[@name='count'][.=2]"
+ );
+ }
+
+ public void testPivotFacetMissing() throws Exception {
+ // Test facet.missing=true with diff sorts
+ index();
+ indexMissing();
+
+ SolrParams missingA = params("q", "*:*",
+ "rows", "0",
+ "facet", "true",
+ "facet.pivot", "place_t,company_t",
+ // default facet.sort
+ FacetParams.FACET_MISSING, "true");
+
+ final String facetPivotPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='place_t,company_t']/lst";
+ SolrQueryRequest req = req(missingA);
+ assertQ(req, facetPivotPrefix + "/arr[@name='pivot'][count(.) > 0]", // not enough values for pivot
+ facetPivotPrefix + "[7]/null[@name='value'][.='']", // not the missing place value
+ facetPivotPrefix + "[7]/int[@name='count'][.=2]", // wrong missing place count
+ facetPivotPrefix + "[7]/arr[@name='pivot'][count(.) > 0]", // not enough sub-pivots for missing place
+ facetPivotPrefix + "[7]/arr[@name='pivot']/lst[6]/null[@name='value'][.='']", // not the missing company value
+ facetPivotPrefix + "[7]/arr[@name='pivot']/lst[6]/int[@name='count'][.=1]", // wrong missing company count
+ facetPivotPrefix + "[7]/arr[@name='pivot']/lst[6][not(arr[@name='pivot'])]" // company shouldn't have sub-pivots
+ );
+
+ SolrParams missingB = SolrParams.wrapDefaults(missingA,
+ params(FacetParams.FACET_LIMIT, "4",
+ "facet.sort", "index"));
+
+
+ req = req(missingB);
+ assertQ(req, facetPivotPrefix + "/arr[@name='pivot'][count(.) > 0]", // not enough values for pivot
+ facetPivotPrefix + "[5]/null[@name='value'][.='']", // not the missing place value
+ facetPivotPrefix + "[5]/int[@name='count'][.=2]", // wrong missing place count
+ facetPivotPrefix + "[5]/arr[@name='pivot'][count(.) > 0]", // not enough sub-pivots for missing place
+ facetPivotPrefix + "[5]/arr[@name='pivot']/lst[5]/null[@name='value'][.='']", // not the missing company value
+ facetPivotPrefix + "[5]/arr[@name='pivot']/lst[5]/int[@name='count'][.=1]", // wrong missing company count
+ facetPivotPrefix + "[5]/arr[@name='pivot']/lst[5][not(arr[@name='pivot'])]" // company shouldn't have sub-pivots
+ );
+ }
+
+ public void testPivotFacetIndexSortMincountAndLimit() throws Exception {
+ // sort=index + mincount + limit
+ index();
+ indexMissing();
+
+ for (SolrParams variableParams : new SolrParams[]{
+ // we should get the same results regardless of overrequest
+ params(),
+ params()}) {
+ SolrParams p = SolrParams.wrapDefaults(params("q", "*:*",
+ "rows", "0",
+ "facet", "true",
+ "facet.pivot", "company_t",
+ "facet.sort", "index",
+ "facet.pivot.mincount", "4",
+ "facet.limit", "4"),
+ variableParams);
+ final String facetPivotPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='company_t']";
+ SolrQueryRequest req = req(p);
+ assertQ(req, facetPivotPrefix + "[count(./lst) = 4]", // not enough values for pivot
+ facetPivotPrefix + "/lst[1]/str[@name='value'][.='fujitsu']",
+ facetPivotPrefix + "/lst[1]/int[@name='count'][.=4]",
+ facetPivotPrefix + "/lst[2]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "/lst[2]/int[@name='count'][.=5]",
+ facetPivotPrefix + "/lst[3]/str[@name='value'][.='null']",
+ facetPivotPrefix + "/lst[3]/int[@name='count'][.=6]",
+ facetPivotPrefix + "/lst[4]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "/lst[4]/int[@name='count'][.=6]"
+ );
+ }
+ }
+
+ public void testPivotFacetIndexSortMincountLimitAndOffset() throws Exception {
+ // sort=index + mincount + limit + offset
+ index();
+ indexMissing();
+
+ for (SolrParams variableParams : new SolrParams[]{
+ // we should get the same results regardless of overrequest
+ params(),
+ params()}) {
+ SolrParams p = SolrParams.wrapDefaults(params("q", "*:*",
+ "rows", "0",
+ "facet", "true",
+ "facet.pivot", "company_t",
+ "facet.sort", "index",
+ "facet.pivot.mincount", "4",
+ "facet.offset", "1",
+ "facet.limit", "4"),
+ variableParams);
+ final String facetPivotPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='company_t']";
+ SolrQueryRequest req = req(p);
+ assertQ(req, facetPivotPrefix + "[count(./lst) = 3]", // asked for 4, but not enough meet the mincount
+ facetPivotPrefix + "/lst[1]/str[@name='value'][.='microsoft']",
+ facetPivotPrefix + "/lst[1]/int[@name='count'][.=5]",
+ facetPivotPrefix + "/lst[2]/str[@name='value'][.='null']",
+ facetPivotPrefix + "/lst[2]/int[@name='count'][.=6]",
+ facetPivotPrefix + "/lst[3]/str[@name='value'][.='polecat']",
+ facetPivotPrefix + "/lst[3]/int[@name='count'][.=6]"
+ );
+ }
+ }
+
+
+ public void testPivotFacetIndexSortMincountLimitAndOffsetPermutations() throws Exception {
+ // sort=index + mincount + limit + offset (more permutations)
+ index();
+ indexMissing();
+
+ for (SolrParams variableParams : new SolrParams[]{
+ // all of these combinations should result in the same first value
+ params("facet.pivot.mincount", "4",
+ "facet.offset", "2"),
+ params("facet.pivot.mincount", "5",
+ "facet.offset", "1"),
+ params("facet.pivot.mincount", "6",
+ "facet.offset", "0")}) {
+ SolrParams p = SolrParams.wrapDefaults(params("q", "*:*",
+ "rows", "0",
+ "facet", "true",
+ "facet.limit", "1",
+ "facet.sort", "index",
+ "facet.overrequest.ratio", "0",
+ "facet.pivot", "company_t"),
+ variableParams);
+ final String facetPivotPrefix = "//lst[@name='facet_counts']/lst[@name='facet_pivot']/arr[@name='company_t']";
+ SolrQueryRequest req = req(p);
+ assertQ(req, facetPivotPrefix + "[count(./lst) = 1]", // asked for 4, but not enough meet the mincount
+ facetPivotPrefix + "/lst[1]/str[@name='value'][.='null']",
+ facetPivotPrefix + "/lst[1]/int[@name='count'][.=6]"
+ );
+ }
+ }
+
+ private void indexMissing() {
+ String[] missingDoc = {"id", "777"};
+ assertU(adoc(missingDoc));
+ assertU(commit());
+ }
+
+ private void index() {
+ // NOTE: we use the literal (4 character) string "null" as a company name
+ // to help ensure there isn't any bugs where the literal string is treated as if it
+ // were a true NULL value.
+ String[] doc = {"id", "19", "place_t", "cardiff dublin", "company_t", "microsoft polecat", "price_ti", "15"};
+ assertU(adoc(doc));
+ String[] doc1 = {"id", "20", "place_t", "dublin", "company_t", "polecat microsoft null", "price_ti", "19"};
+ assertU(adoc(doc1));
+ String[] doc2 = {"id", "21", "place_t", "london la dublin", "company_t",
+ "microsoft fujitsu null polecat", "price_ti", "29"};
+ assertU(adoc(doc2));
+ String[] doc3 = {"id", "22", "place_t", "krakow london cardiff", "company_t",
+ "polecat null bbc", "price_ti", "39"};
+ assertU(adoc(doc3));
+ String[] doc4 = {"id", "23", "place_t", "london", "company_t", "", "price_ti", "29"};
+ assertU(adoc(doc4));
+ String[] doc5 = {"id", "24", "place_t", "la", "company_t", ""};
+ assertU(adoc(doc5));
+ String[] doc6 = {"id", "25", "company_t", "microsoft polecat null fujitsu null bbc", "price_ti", "59"};
+ assertU(adoc(doc6));
+ String[] doc7 = {"id", "26", "place_t", "krakow", "company_t", "null"};
+ assertU(adoc(doc7));
+ String[] doc8 = {"id", "27", "place_t", "krakow cardiff dublin london la", "company_t",
+ "null microsoft polecat bbc fujitsu"};
+ assertU(adoc(doc8));
+ String[] doc9 = {"id", "28", "place_t", "cork", "company_t",
+ "fujitsu rte"};
+ assertU(adoc(doc9));
+ assertU(commit());
+ }
+}
Modified: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/SolrQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/SolrQuery.java?rev=1636772&r1=1636771&r2=1636772&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/SolrQuery.java (original)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/SolrQuery.java Tue Nov 4 23:09:41 2014
@@ -806,6 +806,13 @@ public class SolrQuery extends Modifiabl
this.add( StatsParams.STATS_FIELD, field );
}
+
+ public void addGetFieldStatistics( String ... field )
+ {
+ this.set( StatsParams.STATS, true );
+ this.add( StatsParams.STATS_FIELD, field );
+ }
+
public void addStatsFieldFacets( String field, String ... facets )
{
if( field == null ) {
Modified: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/FieldStatsInfo.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/FieldStatsInfo.java?rev=1636772&r1=1636771&r2=1636772&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/FieldStatsInfo.java (original)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/FieldStatsInfo.java Tue Nov 4 23:09:41 2014
@@ -180,6 +180,10 @@ public class FieldStatsInfo implements S
return stddev;
}
+ public Double getSumOfSquares() {
+ return sumOfSquares;
+ }
+
public Map<String, List<FieldStatsInfo>> getFacets() {
return facets;
}
Modified: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/PivotField.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/PivotField.java?rev=1636772&r1=1636771&r2=1636772&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/PivotField.java (original)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/PivotField.java Tue Nov 4 23:09:41 2014
@@ -20,6 +20,7 @@ package org.apache.solr.client.solrj.res
import java.io.PrintStream;
import java.io.Serializable;
import java.util.List;
+import java.util.Map;
public class PivotField implements Serializable
{
@@ -27,13 +28,23 @@ public class PivotField implements Seria
final Object _value;
final int _count;
final List<PivotField> _pivot;
-
- public PivotField( String f, Object v, int count, List<PivotField> pivot )
+ final Map<String,FieldStatsInfo> _statsInfo;
+
+ /**
+ * @deprecated Use {@link #PivotField(String,Object,int,List,Map)} with a null <code>statsInfo</code>
+ */
+ @Deprecated
+ public PivotField( String f, Object v, int count, List<PivotField> pivot) {
+ this(f, v, count, pivot, null);
+ }
+
+ public PivotField( String f, Object v, int count, List<PivotField> pivot, Map<String,FieldStatsInfo> statsInfo)
{
_field = f;
_value = v;
_count = count;
_pivot = pivot;
+ _statsInfo = statsInfo;
}
public String getField() {
@@ -52,6 +63,10 @@ public class PivotField implements Seria
return _pivot;
}
+ public Map<String,FieldStatsInfo> getFieldStatsInfo() {
+ return _statsInfo;
+ }
+
@Override
public String toString()
{
@@ -63,7 +78,16 @@ public class PivotField implements Seria
for( int i=0; i<indent; i++ ) {
out.print( " " );
}
- out.println( _field + "=" + _value + " ("+_count+")" );
+ out.print( _field + "=" + _value + " ("+_count+")" );
+ if (null != _statsInfo) {
+ out.print( "->stats:[" );
+ for( FieldStatsInfo fieldStatsInfo : _statsInfo.values() ) {
+ out.print(fieldStatsInfo.toString());
+ out.print(",");
+ }
+ out.print("]");
+ }
+ out.println();
if( _pivot != null ) {
for( PivotField p : _pivot ) {
p.write( out, indent+1 );
Modified: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/QueryResponse.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/QueryResponse.java?rev=1636772&r1=1636771&r2=1636772&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/QueryResponse.java (original)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/QueryResponse.java Tue Nov 4 23:09:41 2014
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.beans.DocumentObjectBinder;
@@ -163,19 +164,25 @@ public class QueryResponse extends SolrR
}
private void extractStatsInfo(NamedList<Object> info) {
+ _fieldStatsInfo = extractFieldStatsInfo(info);
+ }
+
+ private Map<String, FieldStatsInfo> extractFieldStatsInfo(NamedList<Object> info) {
if( info != null ) {
- _fieldStatsInfo = new HashMap<>();
+ Map<String, FieldStatsInfo> fieldStatsInfoMap = new TreeMap<>();
NamedList<NamedList<Object>> ff = (NamedList<NamedList<Object>>) info.get( "stats_fields" );
if( ff != null ) {
for( Map.Entry<String,NamedList<Object>> entry : ff ) {
NamedList<Object> v = entry.getValue();
if( v != null ) {
- _fieldStatsInfo.put( entry.getKey(),
+ fieldStatsInfoMap.put( entry.getKey(),
new FieldStatsInfo( v, entry.getKey() ) );
}
}
}
+ return fieldStatsInfoMap;
}
+ return null;
}
private void extractDebugInfo( NamedList<Object> debug )
@@ -396,14 +403,38 @@ public class QueryResponse extends SolrR
Object v = nl.getVal( 1 );
assert "count".equals(nl.getName(2));
int cnt = ((Integer)nl.getVal( 2 )).intValue();
- List<PivotField> p = null;
+
+ List<PivotField> subPivots = null;
+ Map<String,FieldStatsInfo> fieldStatsInfos = null;
+
if (4 <= nl.size()) {
- assert "pivot".equals(nl.getName(3));
- Object subPiv = nl.getVal(3);
- assert null != subPiv : "Server sent back 'null' for sub pivots?";
- p = readPivots( (List<NamedList>) subPiv );
+ for(int index = 3; index < nl.size(); index++) {
+ final String key = nl.getName(index);
+ final Object val = nl.getVal(index);
+ switch (key) {
+
+ case "pivot": {
+ assert null != val : "Server sent back 'null' for sub pivots?";
+ assert val instanceof List : "Server sent non-List for sub pivots?";
+
+ subPivots = readPivots( (List<NamedList>) val );
+ break;
+ }
+ case "stats": {
+ assert null != val : "Server sent back 'null' for stats?";
+ assert val instanceof NamedList : "Server sent non-NamedList for stats?";
+
+ fieldStatsInfos = extractFieldStatsInfo((NamedList<Object>) val);
+ break;
+ }
+ default:
+ throw new RuntimeException( "unknown key in pivot: "+ key+ " ["+val+"]");
+
+ }
+ }
}
- values.add( new PivotField( f, v, cnt, p ) );
+
+ values.add( new PivotField( f, v, cnt, subPivots, fieldStatsInfos ) );
}
return values;
}
Modified: lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java?rev=1636772&r1=1636771&r2=1636772&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java (original)
+++ lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java Tue Nov 4 23:09:41 2014
@@ -57,12 +57,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
-import java.util.Set;
/**
* This should include tests against the example solr config
@@ -814,6 +811,197 @@ abstract public class SolrExampleTests e
doPivotFacetTest(false);
}
+ @Test
+ public void testPivotFacetsStats() throws Exception {
+ SolrServer server = getSolrServer();
+
+ // Empty the database...
+ server.deleteByQuery("*:*");// delete everything!
+ server.commit();
+ assertNumFound("*:*", 0); // make sure it got in
+
+ int id = 1;
+ ArrayList<SolrInputDocument> docs = new ArrayList<>();
+ docs.add(makeTestDoc("id", id++, "features", "aaa", "manu", "apple", "cat", "a", "inStock", true, "popularity", 12, "price", .017));
+ docs.add(makeTestDoc("id", id++, "features", "aaa", "manu", "lg", "cat", "a", "inStock", false, "popularity", 13, "price", 16.04));
+ docs.add(makeTestDoc("id", id++, "features", "aaa", "manu", "samsung", "cat", "a", "inStock", true, "popularity", 14, "price", 12.34));
+ docs.add(makeTestDoc("id", id++, "features", "aaa", "manu", "lg", "cat", "b", "inStock", false, "popularity", 24, "price", 51.39));
+ docs.add(makeTestDoc("id", id++, "features", "aaa", "manu", "nokia", "cat", "b", "inStock", true, "popularity", 28, "price", 131.39));
+ docs.add(makeTestDoc("id", id++, "features", "bbb", "manu", "ztc", "cat", "a", "inStock", false, "popularity", 32));
+ docs.add(makeTestDoc("id", id++, "features", "bbb", "manu", "htc", "cat", "a", "inStock", true, "popularity", 31, "price", 131.39));
+ docs.add(makeTestDoc("id", id++, "features", "bbb", "manu", "apple", "cat", "b", "inStock", false, "popularity", 36));
+ docs.add(makeTestDoc("id", id++, "features", "bbb", "manu", "lg", "cat", "b", "inStock", true, "popularity", 37, "price", 1.39));
+ docs.add(makeTestDoc("id", id++, "features", "bbb", "manu", "ztc", "cat", "b", "inStock", false, "popularity", 38, "price", 47.98));
+ docs.add(makeTestDoc("id", id++, "features", "bbb", "manu", "ztc", "cat", "b", "inStock", true, "popularity", -38));
+ docs.add(makeTestDoc("id", id++, "cat", "b")); // something not matching all fields
+ server.add(docs);
+ server.commit();
+
+ for (String pivot : new String[] { "{!key=pivot_key stats=s1}features,manu",
+ "{!key=pivot_key stats=s1}features,manu,cat",
+ "{!key=pivot_key stats=s1}features,manu,cat,inStock"
+ }) {
+
+ // for any of these pivot params, the assertions we check should be teh same
+ // (we stop asserting at the "manu" level)
+
+ SolrQuery query = new SolrQuery("*:*");
+ query.addFacetPivotField(pivot);
+ query.setFacetLimit(1);
+ query.addGetFieldStatistics("{!key=foo_price tag=s1}price", "{!tag=s1}popularity");
+ query.setFacetMinCount(0);
+ query.setRows(0);
+
+ QueryResponse rsp = server.query(query);
+
+ // check top (ie: non-pivot) stats
+ Map<String, FieldStatsInfo> map = rsp.getFieldStatsInfo();
+ FieldStatsInfo intValueStatsInfo = map.get("popularity");
+ assertEquals(-38.0d, intValueStatsInfo.getMin());
+ assertEquals(38.0d, intValueStatsInfo.getMax());
+ assertEquals(11l, intValueStatsInfo.getCount().longValue());
+ assertEquals(1l, intValueStatsInfo.getMissing().longValue());
+ assertEquals(227.0d, intValueStatsInfo.getSum());
+ assertEquals(20.636363636363637d, intValueStatsInfo.getMean());
+
+ FieldStatsInfo doubleValueStatsInfo = map.get("foo_price");
+ assertEquals(.017d, (double) doubleValueStatsInfo.getMin(), .01d);
+ assertEquals(131.39d, (double) doubleValueStatsInfo.getMax(), .01d);
+ assertEquals(8l, doubleValueStatsInfo.getCount().longValue());
+ assertEquals(4l, doubleValueStatsInfo.getMissing().longValue());
+ assertEquals(391.93d, (double) doubleValueStatsInfo.getSum(), .01d);
+ assertEquals(48.99d, (double) doubleValueStatsInfo.getMean(), .01d);
+
+ // now get deeper and look at the pivots...
+
+ NamedList<List<PivotField>> pivots = rsp.getFacetPivot();
+ assertTrue( ! pivots.get("pivot_key").isEmpty() );
+
+ List<PivotField> list = pivots.get("pivot_key");
+ PivotField featuresBBBPivot = list.get(0);
+ assertEquals("features", featuresBBBPivot.getField());
+ assertEquals("bbb", featuresBBBPivot.getValue());
+ assertNotNull(featuresBBBPivot.getFieldStatsInfo());
+ assertEquals(2, featuresBBBPivot.getFieldStatsInfo().size());
+
+ FieldStatsInfo featuresBBBPivotStats1 = featuresBBBPivot.getFieldStatsInfo().get("foo_price");
+ assertEquals("foo_price", featuresBBBPivotStats1.getName());
+ assertEquals(131.39d, (double) featuresBBBPivotStats1.getMax(), .01d);
+ assertEquals(1.38d, (double) featuresBBBPivotStats1.getMin(), .01d);
+ assertEquals(180.75d, (double) featuresBBBPivotStats1.getSum(), .01d);
+ assertEquals(3, (long) featuresBBBPivotStats1.getCount());
+ assertEquals(3, (long) featuresBBBPivotStats1.getMissing());
+ assertEquals(60.25d, (double) featuresBBBPivotStats1.getMean(), .01d);
+ assertEquals(65.86d, featuresBBBPivotStats1.getStddev(), .01d);
+ assertEquals(19567.34d, featuresBBBPivotStats1.getSumOfSquares(), .01d);
+
+ FieldStatsInfo featuresBBBPivotStats2 = featuresBBBPivot.getFieldStatsInfo().get("popularity");
+ assertEquals("popularity", featuresBBBPivotStats2.getName());
+ assertEquals(38.0d, (double) featuresBBBPivotStats2.getMax(), .01d);
+ assertEquals(-38.0d, (double) featuresBBBPivotStats2.getMin(), .01d);
+ assertEquals(136.0d, (double) featuresBBBPivotStats2.getSum(), .01d);
+ assertEquals(6, (long) featuresBBBPivotStats2.getCount());
+ assertEquals(0, (long) featuresBBBPivotStats2.getMissing());
+ assertEquals(22.66d, (double) featuresBBBPivotStats2.getMean(), .01d);
+ assertEquals(29.85d, featuresBBBPivotStats2.getStddev(), .01d);
+ assertEquals(7538.0d, featuresBBBPivotStats2.getSumOfSquares(), .01d);
+
+ List<PivotField> nestedPivotList = featuresBBBPivot.getPivot();
+ PivotField featuresBBBPivotPivot = nestedPivotList.get(0);
+ assertEquals("manu", featuresBBBPivotPivot.getField());
+ assertEquals("ztc", featuresBBBPivotPivot.getValue());
+ assertNotNull(featuresBBBPivotPivot.getFieldStatsInfo());
+ assertEquals(2, featuresBBBPivotPivot.getFieldStatsInfo().size());
+
+ FieldStatsInfo featuresBBBManuZtcPivotStats1 = featuresBBBPivotPivot.getFieldStatsInfo().get("foo_price");
+ assertEquals("foo_price", featuresBBBManuZtcPivotStats1.getName());
+ assertEquals(47.97d, (double) featuresBBBManuZtcPivotStats1.getMax(), .01d);
+ assertEquals(47.97d, (double) featuresBBBManuZtcPivotStats1.getMin(), .01d);
+ assertEquals(47.97d, (double) featuresBBBManuZtcPivotStats1.getSum(), .01d);
+ assertEquals(1, (long) featuresBBBManuZtcPivotStats1.getCount());
+ assertEquals(2, (long) featuresBBBManuZtcPivotStats1.getMissing());
+ assertEquals(47.97d, (double) featuresBBBManuZtcPivotStats1.getMean(), .01d);
+ assertEquals(0.0d, featuresBBBManuZtcPivotStats1.getStddev(), .01d);
+ assertEquals(2302.08d, featuresBBBManuZtcPivotStats1.getSumOfSquares(), .01d);
+
+
+ FieldStatsInfo featuresBBBManuZtcPivotStats2 = featuresBBBPivotPivot.getFieldStatsInfo().get("popularity");
+ assertEquals("popularity", featuresBBBManuZtcPivotStats2.getName());
+ assertEquals(38.0d, (double) featuresBBBManuZtcPivotStats2.getMax(), .01d);
+ assertEquals(-38.0d, (double) featuresBBBManuZtcPivotStats2.getMin(), .01d);
+ assertEquals(32.0, (double) featuresBBBManuZtcPivotStats2.getSum(), .01d);
+ assertEquals(3, (long) featuresBBBManuZtcPivotStats2.getCount());
+ assertEquals(0, (long) featuresBBBManuZtcPivotStats2.getMissing());
+ assertEquals(10.66d, (double) featuresBBBManuZtcPivotStats2.getMean(), .01d);
+ assertEquals(42.25d, featuresBBBManuZtcPivotStats2.getStddev(), .01d);
+ assertEquals(3912.0d, featuresBBBManuZtcPivotStats2.getSumOfSquares(), .01d);
+ }
+ }
+
+ @Test
+ public void testPivotFacetsStatsNotSupported() throws Exception {
+ SolrServer server = getSolrServer();
+
+ // Empty the database...
+ server.deleteByQuery("*:*");// delete everything!
+ server.commit();
+ assertNumFound("*:*", 0); // make sure it got in
+
+ // results of this test should be the same regardless of wether any docs in index
+ if (random().nextBoolean()) {
+ server.add(makeTestDoc("id", 1, "features", "aaa", "cat", "a", "inStock", true, "popularity", 12, "price", .017));
+ server.commit();
+ }
+
+ ignoreException("is not currently supported");
+
+ // boolean field
+ SolrQuery query = new SolrQuery("*:*");
+ query.addFacetPivotField("{!stats=s1}features,manu");
+ query.addGetFieldStatistics("{!key=inStock_val tag=s1}inStock");
+ try {
+ server.query(query);
+ fail("SolrException should be thrown on query");
+ } catch (SolrException e) {
+ assertEquals("Pivot facet on boolean is not currently supported, bad request returned", 400, e.code());
+ assertTrue(e.getMessage().contains("is not currently supported"));
+ assertTrue(e.getMessage().contains("boolean"));
+ }
+
+ // asking for multiple stat tags -- see SOLR-6663
+ query = new SolrQuery("*:*");
+ query.addFacetPivotField("{!stats=tag1,tag2}features,manu");
+ query.addGetFieldStatistics("{!tag=tag1}price", "{!tag=tag2}popularity");
+ query.setFacetMinCount(0);
+ query.setRows(0);
+ try {
+ server.query(query);
+ fail("SolrException should be thrown on query");
+ } catch (SolrException e) {
+ assertEquals(400, e.code());
+ assertTrue(e.getMessage().contains("stats"));
+ assertTrue(e.getMessage().contains("comma"));
+ assertTrue(e.getMessage().contains("tag"));
+ }
+
+ // text field
+ query = new SolrQuery("*:*");
+ query.addFacetPivotField("{!stats=s1}features,manu");
+ query.addGetFieldStatistics("{!tag=s1}features");
+ query.setFacetMinCount(0);
+ query.setRows(0);
+ try {
+ server.query(query);
+ fail("SolrException should be thrown on query");
+ } catch (SolrException e) {
+ assertEquals("Pivot facet on string is not currently supported, bad request returned", 400, e.code());
+ assertTrue(e.getMessage().contains("is not currently supported"));
+ assertTrue(e.getMessage().contains("text_general"));
+ }
+
+
+ }
+
public void testPivotFacetsMissing() throws Exception {
doPivotFacetTest(true);
}