From f8025175d5f79715ab00c56548f2a79a287faa5b Mon Sep 17 00:00:00 2001 From: Yonik Seeley Date: Wed, 22 Apr 2015 02:23:09 +0000 Subject: [PATCH] SOLR-7443: Implement range faceting over date fields in facet module git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1675246 13f79535-47bb-0310-9956-ffa450edef68 --- solr/CHANGES.txt | 3 ++ .../apache/solr/search/facet/FacetRange.java | 39 +++++++++++++++++++ .../solr/search/facet/TestJsonFacets.java | 35 ++++++++++++----- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 08fccb28ae1..6124e306cec 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -147,6 +147,9 @@ Bug Fixes * SOLR-7418: Check and raise a SolrException instead of an NPE when an invalid doc id is sent to the MLTQParser. (Anshum Gupta) +* SOLR-7443: Implemented range faceting over date fields in the new facet module + (JSON Facet API). (yonik) + Optimizations ---------------------- diff --git a/solr/core/src/java/org/apache/solr/search/facet/FacetRange.java b/solr/core/src/java/org/apache/solr/search/facet/FacetRange.java index ffeffc26ee2..3a80bbec843 100644 --- a/solr/core/src/java/org/apache/solr/search/facet/FacetRange.java +++ b/solr/core/src/java/org/apache/solr/search/facet/FacetRange.java @@ -19,6 +19,7 @@ package org.apache.solr.search.facet; import java.io.IOException; import java.util.ArrayList; +import java.util.Date; import java.util.EnumSet; import java.util.List; @@ -28,7 +29,9 @@ import org.apache.solr.common.params.FacetParams; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.schema.FieldType; import org.apache.solr.schema.SchemaField; +import org.apache.solr.schema.TrieDateField; import org.apache.solr.schema.TrieField; +import org.apache.solr.util.DateMathParser; public class FacetRange extends FacetRequest { String field; @@ -93,6 +96,9 @@ class FacetRangeProcessor extends FacetProcessor { case LONG: calc = new LongRangeEndpointCalculator(sf); break; + case DATE: + calc = new DateRangeEndpointCalculator(sf, null); + break; default: throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, @@ -371,4 +377,37 @@ class FacetRangeProcessor extends FacetProcessor { return new Long(value.longValue() + Long.valueOf(gap).longValue()); } } + private static class DateRangeEndpointCalculator + extends RangeEndpointCalculator { + private static final String TYPE_ERR_MSG = "SchemaField must use field type extending TrieDateField or DateRangeField"; + private final Date now; + public DateRangeEndpointCalculator(final SchemaField f, + final Date now) { + super(f); + this.now = now; + if (! (field.getType() instanceof TrieDateField) ) { + throw new IllegalArgumentException + (TYPE_ERR_MSG); + } + } + @Override + public String formatValue(Date val) { + return ((TrieDateField)field.getType()).toExternal(val); + } + @Override + protected Date parseVal(String rawval) { + return ((TrieDateField)field.getType()).parseMath(now, rawval); + } + @Override + protected Object parseGap(final String rawval) { + return rawval; + } + @Override + public Date parseAndAddGap(Date value, String gap) throws java.text.ParseException { + final DateMathParser dmp = new DateMathParser(); + dmp.setNow(value); + return dmp.parseMath(gap); + } + } + } diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacets.java b/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacets.java index 40856475814..69624511346 100644 --- a/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacets.java +++ b/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacets.java @@ -258,21 +258,21 @@ public class TestJsonFacets extends SolrTestCaseHS { public void doStats(Client client, ModifiableSolrParams p) throws Exception { // single valued strings - doStatsTemplated(client, params(p, "rows","0", "noexist","noexist_s", "cat_s","cat_s", "where_s","where_s", "num_d","num_d", "num_i","num_i", "super_s","super_s", "val_b","val_b", "sparse_s","sparse_s" ,"multi_ss","multi_ss") ); + doStatsTemplated(client, params(p, "rows","0", "noexist","noexist_s", "cat_s","cat_s", "where_s","where_s", "num_d","num_d", "num_i","num_i", "super_s","super_s", "val_b","val_b", "date","date_dt", "sparse_s","sparse_s" ,"multi_ss","multi_ss") ); // multi-valued strings - doStatsTemplated(client, params(p, "facet","true", "rows","0", "noexist","noexist_ss", "cat_s","cat_ss", "where_s","where_ss", "num_d","num_d", "num_i","num_i", "super_s","super_ss", "val_b","val_b", "sparse_s","sparse_ss", "multi_ss","multi_ss") ); + doStatsTemplated(client, params(p, "facet","true", "rows","0", "noexist","noexist_ss", "cat_s","cat_ss", "where_s","where_ss", "num_d","num_d", "num_i","num_i", "super_s","super_ss", "val_b","val_b", "date","date_dt", "sparse_s","sparse_ss", "multi_ss","multi_ss") ); // single valued docvalues for strings, and single valued numeric doc values for numeric fields - doStatsTemplated(client, params(p, "rows","0", "noexist","noexist_sd", "cat_s","cat_sd", "where_s","where_sd", "num_d","num_dd", "num_i","num_id", "super_s","super_sd", "val_b","val_b", "sparse_s","sparse_sd" ,"multi_ss","multi_sds") ); + doStatsTemplated(client, params(p, "rows","0", "noexist","noexist_sd", "cat_s","cat_sd", "where_s","where_sd", "num_d","num_dd", "num_i","num_id", "super_s","super_sd", "val_b","val_b", "date","date_dt", "sparse_s","sparse_sd" ,"multi_ss","multi_sds") ); // multi-valued docvalues FacetFieldProcessorDV.unwrap_singleValued_multiDv = false; // better multi-valued coverage - doStatsTemplated(client, params(p, "rows","0", "noexist","noexist_sds", "cat_s","cat_sds", "where_s","where_sds", "num_d","num_d", "num_i","num_i", "super_s","super_sds", "val_b","val_b", "sparse_s","sparse_sds" ,"multi_ss","multi_sds") ); + doStatsTemplated(client, params(p, "rows","0", "noexist","noexist_sds", "cat_s","cat_sds", "where_s","where_sds", "num_d","num_d", "num_i","num_i", "super_s","super_sds", "val_b","val_b", "date","date_dt", "sparse_s","sparse_sds" ,"multi_ss","multi_sds") ); // multi-valued docvalues FacetFieldProcessorDV.unwrap_singleValued_multiDv = true; - doStatsTemplated(client, params(p, "rows","0", "noexist","noexist_sds", "cat_s","cat_sds", "where_s","where_sds", "num_d","num_d", "num_i","num_i", "super_s","super_sds", "val_b","val_b", "sparse_s","sparse_sds" ,"multi_ss","multi_sds") ); + doStatsTemplated(client, params(p, "rows","0", "noexist","noexist_sds", "cat_s","cat_sds", "where_s","where_sds", "num_d","num_d", "num_i","num_i", "super_s","super_sds", "val_b","val_b", "date","date_dt", "sparse_s","sparse_sds" ,"multi_ss","multi_sds") ); } public static void doStatsTemplated(Client client, ModifiableSolrParams p) throws Exception { @@ -283,20 +283,21 @@ public class TestJsonFacets extends SolrTestCaseHS { String num_d = m.expand("${num_d}"); String num_i = m.expand("${num_i}"); String val_b = m.expand("${val_b}"); + String date = m.expand("${date}"); String super_s = m.expand("${super_s}"); String sparse_s = m.expand("${sparse_s}"); String multi_ss = m.expand("${multi_ss}"); client.deleteByQuery("*:*", null); - client.add(sdoc("id", "1", cat_s, "A", where_s, "NY", num_d, "4", num_i, "2", super_s, "zodiac", val_b, "true", sparse_s, "one"), null); - client.add(sdoc("id", "2", cat_s, "B", where_s, "NJ", num_d, "-9", num_i, "-5", super_s,"superman", val_b, "false" , multi_ss,"a", multi_ss,"b" ), null); + client.add(sdoc("id", "1", cat_s, "A", where_s, "NY", num_d, "4", num_i, "2", super_s, "zodiac", date,"2001-01-01T01:01:01Z", val_b, "true", sparse_s, "one"), null); + client.add(sdoc("id", "2", cat_s, "B", where_s, "NJ", num_d, "-9", num_i, "-5", super_s,"superman", date,"2002-02-02T02:02:02Z", val_b, "false" , multi_ss,"a", multi_ss,"b" ), null); client.add(sdoc("id", "3"), null); client.commit(); - client.add(sdoc("id", "4", cat_s, "A", where_s, "NJ", num_d, "2", num_i, "3", super_s,"spiderman" , multi_ss, "b"), null); - client.add(sdoc("id", "5", cat_s, "B", where_s, "NJ", num_d, "11", num_i, "7", super_s,"batman" ,sparse_s,"two", multi_ss, "a"), null); + client.add(sdoc("id", "4", cat_s, "A", where_s, "NJ", num_d, "2", num_i, "3", super_s,"spiderman", date,"2003-03-03T03:03:03Z" , multi_ss, "b"), null); + client.add(sdoc("id", "5", cat_s, "B", where_s, "NJ", num_d, "11", num_i, "7", super_s,"batman" , date,"2001-02-03T01:02:03Z" ,sparse_s,"two", multi_ss, "a"), null); client.commit(); - client.add(sdoc("id", "6", cat_s, "B", where_s, "NY", num_d, "-5", num_i, "-5", super_s,"hulk" , multi_ss, "b", multi_ss, "a" ), null); + client.add(sdoc("id", "6", cat_s, "B", where_s, "NY", num_d, "-5", num_i, "-5", super_s,"hulk" , date,"2002-03-01T03:02:01Z" , multi_ss, "b", multi_ss, "a" ), null); client.commit(); @@ -557,6 +558,20 @@ public class TestJsonFacets extends SolrTestCaseHS { , "facets=={count:6, f:{buckets:[ {val:-5.0,count:1}, {val:0.0,count:2}, {val:5.0,count:0} ] } }" ); + // basic range facet on dates + client.testJQ(params(p, "q", "*:*" + , "json.facet", "{f:{type:range, field:${date}, start:'2001-01-01T00:00:00Z', end:'2003-01-01T00:00:00Z', gap:'+1YEAR'}}" + ) + , "facets=={count:6, f:{buckets:[ {val:'2001-01-01T00:00:00Z',count:2}, {val:'2002-01-01T00:00:00Z',count:2}] } }" + ); + + // range facet on dates w/ stats + client.testJQ(params(p, "q", "*:*" + , "json.facet", "{f:{type:range, field:${date}, start:'2002-01-01T00:00:00Z', end:'2005-01-01T00:00:00Z', gap:'+1YEAR', other:all, facet:{ x:'avg(${num_d})' } } }" + ) + , "facets=={count:6, f:{buckets:[ {val:'2002-01-01T00:00:00Z',count:2,x:-7.0}, {val:'2003-01-01T00:00:00Z',count:1,x:2.0}, {val:'2004-01-01T00:00:00Z',count:0}], before:{count:2,x:7.5}, after:{count:0}, between:{count:3,x:-4.0} } }" + ); + // basic range facet with "include" params client.testJQ(params(p, "q", "*:*" , "json.facet", "{f:{range:{field:${num_d}, start:-5, end:10, gap:5, include:upper}}}"