mirror of https://github.com/apache/lucene.git
SOLR-13417: handle stats on date/str fields in solrj's JSON facet resp
* Except for min/max aggregation in all other cases values woudl be number. As for same data/string field, value can vary based on aggregation used, capture response in Map<String, Object>
This commit is contained in:
parent
9586396dba
commit
b7ce53d0bf
|
@ -183,6 +183,9 @@ Bug Fixes
|
||||||
|
|
||||||
* SOLR-13180: Fix ClassCastException in Json Request API (Johannes Kloos, Jan Høydahl, Munendra S N)
|
* SOLR-13180: Fix ClassCastException in Json Request API (Johannes Kloos, Jan Høydahl, Munendra S N)
|
||||||
|
|
||||||
|
* SOLR-13417: Handle stats aggregation on date and string fields in SolrJ's JSON facet response processing
|
||||||
|
(Jason Gerlowski, Munendra S N)
|
||||||
|
|
||||||
Other Changes
|
Other Changes
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.apache.solr.client.solrj.response.json;
|
package org.apache.solr.client.solrj.response.json;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -36,6 +37,7 @@ public class NestableJsonFacet {
|
||||||
private final Map<String, NestableJsonFacet> queryFacetsByName;
|
private final Map<String, NestableJsonFacet> queryFacetsByName;
|
||||||
private final Map<String, BucketBasedJsonFacet> bucketBasedFacetByName;
|
private final Map<String, BucketBasedJsonFacet> bucketBasedFacetByName;
|
||||||
private final Map<String, Number> statFacetsByName;
|
private final Map<String, Number> statFacetsByName;
|
||||||
|
private final Map<String, Object> statsByName;
|
||||||
private final Map<String, HeatmapJsonFacet> heatmapFacetsByName;
|
private final Map<String, HeatmapJsonFacet> heatmapFacetsByName;
|
||||||
|
|
||||||
public NestableJsonFacet(NamedList<Object> facetNL) {
|
public NestableJsonFacet(NamedList<Object> facetNL) {
|
||||||
|
@ -43,6 +45,7 @@ public class NestableJsonFacet {
|
||||||
bucketBasedFacetByName = new HashMap<>();
|
bucketBasedFacetByName = new HashMap<>();
|
||||||
statFacetsByName = new HashMap<>();
|
statFacetsByName = new HashMap<>();
|
||||||
heatmapFacetsByName = new HashMap<>();
|
heatmapFacetsByName = new HashMap<>();
|
||||||
|
statsByName = new HashMap<>();
|
||||||
|
|
||||||
for (Map.Entry<String, Object> entry : facetNL) {
|
for (Map.Entry<String, Object> entry : facetNL) {
|
||||||
final String key = entry.getKey();
|
final String key = entry.getKey();
|
||||||
|
@ -52,6 +55,9 @@ public class NestableJsonFacet {
|
||||||
domainCount = ((Number) entry.getValue()).longValue();
|
domainCount = ((Number) entry.getValue()).longValue();
|
||||||
} else if(entry.getValue() instanceof Number) { // Stat/agg facet value
|
} else if(entry.getValue() instanceof Number) { // Stat/agg facet value
|
||||||
statFacetsByName.put(key, (Number)entry.getValue());
|
statFacetsByName.put(key, (Number)entry.getValue());
|
||||||
|
statsByName.put(key, (Number) entry.getValue());
|
||||||
|
} else if (entry.getValue() instanceof String || entry.getValue() instanceof Date) {
|
||||||
|
statsByName.put(key, entry.getValue());
|
||||||
} else if(entry.getValue() instanceof NamedList) { // Either heatmap/query/range/terms facet
|
} else if(entry.getValue() instanceof NamedList) { // Either heatmap/query/range/terms facet
|
||||||
final NamedList<Object> facet = (NamedList<Object>) entry.getValue();
|
final NamedList<Object> facet = (NamedList<Object>) entry.getValue();
|
||||||
final boolean isBucketBased = facet.get("buckets") != null;
|
final boolean isBucketBased = facet.get("buckets") != null;
|
||||||
|
@ -104,18 +110,34 @@ public class NestableJsonFacet {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the value for a stat or agg facet with the provided name
|
* Retrieve the value for a stat or agg facet with the provided name
|
||||||
|
* @deprecated this method works only for numeric value stats, instead use {@link #getStatValue(String)}
|
||||||
*/
|
*/
|
||||||
public Number getStatFacetValue(String name) {
|
public Number getStatFacetValue(String name) {
|
||||||
return statFacetsByName.get(name);
|
return statFacetsByName.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the value for a stat or agg with the provided name
|
||||||
|
*/
|
||||||
|
public Object getStatValue(String name) {
|
||||||
|
return statsByName.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the names of any stat or agg facets that are direct descendants of this facet
|
* @return the names of any stat or agg facets that are direct descendants of this facet
|
||||||
|
* @deprecated this method returns only stats names with numeric value, instead use {@link #getStatNames()}
|
||||||
*/
|
*/
|
||||||
public Set<String> getStatFacetNames() {
|
public Set<String> getStatFacetNames() {
|
||||||
return statFacetsByName.keySet();
|
return statFacetsByName.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the names of any stat or agg that are direct descendants of this facet
|
||||||
|
*/
|
||||||
|
public Set<String> getStatNames() {
|
||||||
|
return statsByName.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a "heatmap" facet by its name
|
* Retrieve a "heatmap" facet by its name
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.solr.client.ref_guide_examples;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -34,10 +35,10 @@ import org.apache.solr.client.solrj.request.json.JsonQueryRequest;
|
||||||
import org.apache.solr.client.solrj.request.json.QueryFacetMap;
|
import org.apache.solr.client.solrj.request.json.QueryFacetMap;
|
||||||
import org.apache.solr.client.solrj.request.json.RangeFacetMap;
|
import org.apache.solr.client.solrj.request.json.RangeFacetMap;
|
||||||
import org.apache.solr.client.solrj.request.json.TermsFacetMap;
|
import org.apache.solr.client.solrj.request.json.TermsFacetMap;
|
||||||
import org.apache.solr.client.solrj.response.json.BucketJsonFacet;
|
|
||||||
import org.apache.solr.client.solrj.response.json.NestableJsonFacet;
|
|
||||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||||
import org.apache.solr.client.solrj.response.UpdateResponse;
|
import org.apache.solr.client.solrj.response.UpdateResponse;
|
||||||
|
import org.apache.solr.client.solrj.response.json.BucketJsonFacet;
|
||||||
|
import org.apache.solr.client.solrj.response.json.NestableJsonFacet;
|
||||||
import org.apache.solr.cloud.SolrCloudTestCase;
|
import org.apache.solr.cloud.SolrCloudTestCase;
|
||||||
import org.apache.solr.common.SolrDocument;
|
import org.apache.solr.common.SolrDocument;
|
||||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||||
|
@ -455,6 +456,7 @@ public class JsonRequestApiTest extends SolrCloudTestCase {
|
||||||
.setQuery("memory")
|
.setQuery("memory")
|
||||||
.withFilter("inStock:true")
|
.withFilter("inStock:true")
|
||||||
.withStatFacet("avg_price", "avg(price)")
|
.withStatFacet("avg_price", "avg(price)")
|
||||||
|
.withStatFacet("min_manufacturedate_dt", "min(manufacturedate_dt)")
|
||||||
.withStatFacet("num_suppliers", "unique(manu_exact)")
|
.withStatFacet("num_suppliers", "unique(manu_exact)")
|
||||||
.withStatFacet("median_weight", "percentile(weight,50)");
|
.withStatFacet("median_weight", "percentile(weight,50)");
|
||||||
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
|
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
|
||||||
|
@ -464,9 +466,13 @@ public class JsonRequestApiTest extends SolrCloudTestCase {
|
||||||
assertEquals(4, queryResponse.getResults().getNumFound());
|
assertEquals(4, queryResponse.getResults().getNumFound());
|
||||||
assertEquals(4, queryResponse.getResults().size());
|
assertEquals(4, queryResponse.getResults().size());
|
||||||
final NestableJsonFacet topLevelFacetingData = queryResponse.getJsonFacetingResponse();
|
final NestableJsonFacet topLevelFacetingData = queryResponse.getJsonFacetingResponse();
|
||||||
assertEquals(146.66, (double) topLevelFacetingData.getStatFacetValue("avg_price"), 0.5);
|
assertEquals(146.66, (double) topLevelFacetingData.getStatValue("avg_price"), 0.5);
|
||||||
assertEquals(3, topLevelFacetingData.getStatFacetValue("num_suppliers"));
|
assertEquals(3, topLevelFacetingData.getStatValue("num_suppliers"));
|
||||||
assertEquals(352.0, (double) topLevelFacetingData.getStatFacetValue("median_weight"), 0.5);
|
assertEquals(352.0, (double) topLevelFacetingData.getStatValue("median_weight"), 0.5);
|
||||||
|
|
||||||
|
Object val = topLevelFacetingData.getStatValue("min_manufacturedate_dt");
|
||||||
|
assertTrue(val instanceof Date);
|
||||||
|
assertEquals("2006-02-13T15:26:37Z", ((Date)val).toInstant().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -478,6 +484,7 @@ public class JsonRequestApiTest extends SolrCloudTestCase {
|
||||||
.setQuery("*:*")
|
.setQuery("*:*")
|
||||||
.withFilter("price:[1.0 TO *]")
|
.withFilter("price:[1.0 TO *]")
|
||||||
.withFilter("popularity:[0 TO 10]")
|
.withFilter("popularity:[0 TO 10]")
|
||||||
|
.withStatFacet("min_manu_id_s", "min(manu_id_s)")
|
||||||
.withStatFacet("avg_value", "avg(div(popularity,price))");
|
.withStatFacet("avg_value", "avg(div(popularity,price))");
|
||||||
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
|
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
|
||||||
//end::solrj-json-metrics-facet-simple[]
|
//end::solrj-json-metrics-facet-simple[]
|
||||||
|
@ -486,7 +493,10 @@ public class JsonRequestApiTest extends SolrCloudTestCase {
|
||||||
assertEquals(13, queryResponse.getResults().getNumFound());
|
assertEquals(13, queryResponse.getResults().getNumFound());
|
||||||
assertEquals(10, queryResponse.getResults().size());
|
assertEquals(10, queryResponse.getResults().size());
|
||||||
final NestableJsonFacet topLevelFacetingData = queryResponse.getJsonFacetingResponse();
|
final NestableJsonFacet topLevelFacetingData = queryResponse.getJsonFacetingResponse();
|
||||||
assertEquals(0.036, (double) topLevelFacetingData.getStatFacetValue("avg_value"), 0.1);
|
assertEquals(0.036, (double) topLevelFacetingData.getStatValue("avg_value"), 0.1);
|
||||||
|
Object val = topLevelFacetingData.getStatValue("min_manu_id_s");
|
||||||
|
assertTrue(val instanceof String);
|
||||||
|
assertEquals("apple", val.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -511,7 +521,7 @@ public class JsonRequestApiTest extends SolrCloudTestCase {
|
||||||
assertEquals(13, queryResponse.getResults().getNumFound());
|
assertEquals(13, queryResponse.getResults().getNumFound());
|
||||||
assertEquals(10, queryResponse.getResults().size());
|
assertEquals(10, queryResponse.getResults().size());
|
||||||
final NestableJsonFacet topLevelFacetingData = queryResponse.getJsonFacetingResponse();
|
final NestableJsonFacet topLevelFacetingData = queryResponse.getJsonFacetingResponse();
|
||||||
assertEquals(0.108, (double) topLevelFacetingData.getStatFacetValue("avg_value"), 0.1);
|
assertEquals(0.108, (double) topLevelFacetingData.getStatValue("avg_value"), 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -551,7 +561,7 @@ public class JsonRequestApiTest extends SolrCloudTestCase {
|
||||||
assertEquals(10, queryResponse.getResults().size());
|
assertEquals(10, queryResponse.getResults().size());
|
||||||
final NestableJsonFacet topLevelFacetingData = queryResponse.getJsonFacetingResponse();
|
final NestableJsonFacet topLevelFacetingData = queryResponse.getJsonFacetingResponse();
|
||||||
assertEquals(2, topLevelFacetingData.getQueryFacet("high_popularity").getCount());
|
assertEquals(2, topLevelFacetingData.getQueryFacet("high_popularity").getCount());
|
||||||
assertEquals(199.5, topLevelFacetingData.getQueryFacet("high_popularity").getStatFacetValue("average_price"));
|
assertEquals(199.5, topLevelFacetingData.getQueryFacet("high_popularity").getStatValue("average_price"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -545,8 +545,8 @@ public class DirectJsonQueryRequestFacetingIntegrationTest extends SolrCloudTest
|
||||||
|
|
||||||
private void assertHasStatFacetWithValue(NestableJsonFacet response, String expectedFacetName, Double expectedStatValue) {
|
private void assertHasStatFacetWithValue(NestableJsonFacet response, String expectedFacetName, Double expectedStatValue) {
|
||||||
assertTrue("Expected response to have stat facet named '" + expectedFacetName + "'",
|
assertTrue("Expected response to have stat facet named '" + expectedFacetName + "'",
|
||||||
response.getStatFacetValue(expectedFacetName) != null);
|
response.getStatValue(expectedFacetName) != null);
|
||||||
assertEquals(expectedStatValue, response.getStatFacetValue(expectedFacetName));
|
assertEquals(expectedStatValue, response.getStatValue(expectedFacetName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertExpectedDocumentsFoundAndReturned(QueryResponse response, int expectedNumFound, int expectedReturned) {
|
private void assertExpectedDocumentsFoundAndReturned(QueryResponse response, int expectedNumFound, int expectedReturned) {
|
||||||
|
|
|
@ -571,8 +571,8 @@ public class JsonQueryRequestFacetingIntegrationTest extends SolrCloudTestCase {
|
||||||
|
|
||||||
private void assertHasStatFacetWithValue(NestableJsonFacet response, String expectedFacetName, Double expectedStatValue) {
|
private void assertHasStatFacetWithValue(NestableJsonFacet response, String expectedFacetName, Double expectedStatValue) {
|
||||||
assertTrue("Expected response to have stat facet named '" + expectedFacetName + "'",
|
assertTrue("Expected response to have stat facet named '" + expectedFacetName + "'",
|
||||||
response.getStatFacetValue(expectedFacetName) != null);
|
response.getStatValue(expectedFacetName) != null);
|
||||||
assertEquals(expectedStatValue, response.getStatFacetValue(expectedFacetName));
|
assertEquals(expectedStatValue, response.getStatValue(expectedFacetName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertExpectedDocumentsFoundAndReturned(QueryResponse response, int expectedNumFound, int expectedReturned) {
|
private void assertExpectedDocumentsFoundAndReturned(QueryResponse response, int expectedNumFound, int expectedReturned) {
|
||||||
|
|
Loading…
Reference in New Issue