You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by tf...@apache.org on 2014/08/08 01:27:20 UTC

svn commit: r1616628 - in /lucene/dev/trunk/solr: ./ core/src/test/org/apache/solr/ solrj/src/java/org/apache/solr/client/solrj/ solrj/src/java/org/apache/solr/client/solrj/response/ solrj/src/test-files/solrj/ solrj/src/test/org/apache/solr/client/sol...

Author: tflobbe
Date: Thu Aug  7 23:27:19 2014
New Revision: 1616628

URL: http://svn.apache.org/r1616628
Log:
SOLR-6283: Add support for Interval Faceting in SolrJ

Added:
    lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/IntervalFacet.java   (with props)
    lucene/dev/trunk/solr/solrj/src/test-files/solrj/sampleIntervalFacetsResponse.xml   (with props)
Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/DistributedIntervalFacetingTest.java
    lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/SolrQuery.java
    lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/QueryResponse.java
    lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrQueryTest.java
    lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/response/QueryResponseTest.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1616628&r1=1616627&r2=1616628&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Thu Aug  7 23:27:19 2014
@@ -173,6 +173,7 @@ New Features
 * SOLR-6318: New "terms" QParser for efficiently filtering documents by a list of values. For
   many values, it's more appropriate than a boolean query. (David Smiley)
 
+* SOLR-6283: Add support for Interval Faceting in SolrJ. (Tomás Fernández Löbbe)
 
 Bug Fixes
 ----------------------

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/DistributedIntervalFacetingTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/DistributedIntervalFacetingTest.java?rev=1616628&r1=1616627&r2=1616628&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/DistributedIntervalFacetingTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/DistributedIntervalFacetingTest.java Thu Aug  7 23:27:19 2014
@@ -2,9 +2,13 @@ package org.apache.solr;
 
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
 
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util.LuceneTestCase.Slow;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.response.IntervalFacet.Count;
+import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.junit.BeforeClass;
 
@@ -40,6 +44,61 @@ public class DistributedIntervalFaceting
     del("*:*");
     commit();
     testRandom();
+    del("*:*");
+    commit();
+    testSolrJ();
+  }
+
+  private void testSolrJ() throws Exception {
+    indexr("id", "0", "test_i_dv", "0", "test_s_dv", "AAA");
+    indexr("id", "1", "test_i_dv", "1", "test_s_dv", "BBB");
+    indexr("id", "2", "test_i_dv", "2", "test_s_dv", "AAA");
+    indexr("id", "3", "test_i_dv", "3", "test_s_dv", "CCC");
+    commit();
+    
+    QueryResponse response = controlClient.query(new SolrQuery("*:*"));
+    assertEquals(4, response.getResults().getNumFound());
+    
+    SolrQuery q = new SolrQuery("*:*");
+    String[] intervals =  new String[]{"[0,1)","[1,2)", "[2,3)", "[3,*)"};
+    q.addIntervalFacets("test_i_dv", intervals);
+    response = controlClient.query(q);
+    assertEquals(1, response.getIntervalFacets().size());
+    assertEquals("test_i_dv", response.getIntervalFacets().get(0).getField());
+    assertEquals(4, response.getIntervalFacets().get(0).getIntervals().size());
+    for (int i = 0; i < response.getIntervalFacets().get(0).getIntervals().size(); i++) {
+      Count count = response.getIntervalFacets().get(0).getIntervals().get(i);
+      assertEquals(intervals[i], count.getKey());
+      assertEquals(1, count.getCount());
+    }
+    
+    q = new SolrQuery("*:*");
+    q.addIntervalFacets("test_i_dv", intervals);
+    q.addIntervalFacets("test_s_dv", new String[]{"{!key='AAA'}[AAA,AAA]", "{!key='BBB'}[BBB,BBB]", "{!key='CCC'}[CCC,CCC]"});
+    response = controlClient.query(q);
+    assertEquals(2, response.getIntervalFacets().size());
+    
+    int stringIntervalIndex = "test_s_dv".equals(response.getIntervalFacets().get(0).getField())?0:1;
+        
+    assertEquals("test_i_dv", response.getIntervalFacets().get(1-stringIntervalIndex).getField());
+    assertEquals("test_s_dv", response.getIntervalFacets().get(stringIntervalIndex).getField());
+    
+    for (int i = 0; i < response.getIntervalFacets().get(1-stringIntervalIndex).getIntervals().size(); i++) {
+      Count count = response.getIntervalFacets().get(1-stringIntervalIndex).getIntervals().get(i);
+      assertEquals(intervals[i], count.getKey());
+      assertEquals(1, count.getCount());
+    }
+    
+    List<Count> stringIntervals = response.getIntervalFacets().get(stringIntervalIndex).getIntervals();
+    assertEquals(3, stringIntervals.size());
+    assertEquals("AAA", stringIntervals.get(0).getKey());
+    assertEquals(2, stringIntervals.get(0).getCount());
+    
+    assertEquals("BBB", stringIntervals.get(1).getKey());
+    assertEquals(1, stringIntervals.get(1).getCount());
+    
+    assertEquals("CCC", stringIntervals.get(2).getKey());
+    assertEquals(1, stringIntervals.get(2).getCount());
   }
 
   private void testRandom() throws Exception {

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=1616628&r1=1616627&r2=1616628&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 Thu Aug  7 23:27:19 2014
@@ -17,6 +17,13 @@
 
 package org.apache.solr.client.solrj;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Pattern;
+
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.FacetParams;
 import org.apache.solr.common.params.HighlightParams;
@@ -25,13 +32,6 @@ import org.apache.solr.common.params.Sta
 import org.apache.solr.common.params.TermsParams;
 import org.apache.solr.common.util.DateUtil;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.regex.Pattern;
-
 
 /**
  * This is an augmented SolrParams with get/set/add fields for common fields used
@@ -273,7 +273,40 @@ public class SolrQuery extends Modifiabl
     this.set(FacetParams.FACET, true);
     return this;
   }
-
+  
+  /**
+   * Add Interval Faceting on a field. All intervals for the same field should be included
+   * in the same call to this method.
+   * For syntax documentation see <a href="https://wiki.apache.org/solr/SimpleFacetParameters#Interval_Faceting">Solr wiki</a>
+   * 
+   * @param field the field to add facet intervals
+   * @param intervals Intervals to be used for faceting. It can be an empty array, but it can't 
+   * be <code>null</code>
+   * @return this
+   */
+  public SolrQuery addIntervalFacets(String field, String[] intervals) {
+    if (intervals == null) {
+      throw new IllegalArgumentException("Can't add null intervals");
+    }
+    set(FacetParams.FACET, true);
+    add(FacetParams.FACET_INTERVAL, field);
+    for (String interval:intervals) {
+      add(String.format(Locale.ROOT, "f.%s.facet.interval.set", field), interval);
+    }
+    return this;
+  }
+  
+  /**
+   * Remove all Interval Facets on a field
+   * 
+   * @param field the field to remove from facet intervals
+   * @return Array of current intervals for <code>field</code>
+   */
+  public String[] removeIntervalFacets(String field) {
+    while(remove(FacetParams.FACET_INTERVAL, field)){};
+    return remove(String.format(Locale.ROOT, "f.%s.facet.interval.set", field));
+  }
+  
   /** get the facet fields
    * 
    * @return string array of facet fields or null if not set/empty
@@ -317,6 +350,7 @@ public class SolrQuery extends Modifiabl
       this.remove(FacetParams.FACET_SORT);
       this.remove(FacetParams.FACET_ZEROS);
       this.remove(FacetParams.FACET_PREFIX); // does not include the individual fields...
+      this.remove(FacetParams.FACET_INTERVAL); // does not remove interval parameters
     }
     return this;
   }

Added: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/IntervalFacet.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/IntervalFacet.java?rev=1616628&view=auto
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/IntervalFacet.java (added)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/response/IntervalFacet.java Thu Aug  7 23:27:19 2014
@@ -0,0 +1,85 @@
+package org.apache.solr.client.solrj.response;
+
+import java.util.List;
+
+/*
+ * 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.
+ */
+/**
+ * Objects of this class will contain the result of all the intervals defined
+ * for a specific field. 
+ */
+public class IntervalFacet {
+ 
+  /**
+   * The field for which interval facets where calculated
+   */
+  private final String field;
+
+  /**
+   * The list of interval facets calculated for {@link #field}
+   */
+  private final List<Count> intervals;
+  
+  IntervalFacet(String field, List<Count> values) {
+    this.field = field;
+    this.intervals = values;
+  }
+  
+  /**
+   * @return The field for which interval facets where calculated
+   */
+  public String getField() {
+    return field;
+  }
+
+  /**
+   * @return The list of interval facets calculated for {@link #field}
+   */
+  public List<Count> getIntervals() {
+    return intervals;
+  }
+  
+  /**
+   * Holds counts for facet intervals defined in a field
+   */
+  public static class Count {
+    /**
+     * The key of this interval. This is the original 
+     * interval string or the value of the "key" local
+     * param
+     */
+    private final String key;
+    /**
+     * The count of this interval
+     */
+    private final int count;
+    
+    Count(String key, int count) {
+      super();
+      this.key = key;
+      this.count = count;
+    }
+    
+    public String getKey() {
+      return key;
+    }
+
+    public int getCount() {
+      return count;
+    }
+  }
+}

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=1616628&r1=1616627&r2=1616628&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 Thu Aug  7 23:27:19 2014
@@ -17,14 +17,19 @@
 
 package org.apache.solr.client.solrj.response;
 
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.solr.client.solrj.SolrServer;
 import org.apache.solr.client.solrj.beans.DocumentObjectBinder;
 import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.params.CursorMarkParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.common.params.CursorMarkParams;
-
-import java.util.*;
 
 /**
  * 
@@ -60,6 +65,7 @@ public class QueryResponse extends SolrR
   private List<FacetField> _facetDates = null;
   private List<RangeFacet> _facetRanges = null;
   private NamedList<List<PivotField>> _facetPivot = null;
+  private List<IntervalFacet> _intervalFacets = null;
 
   // Highlight Info
   private Map<String,Map<String,List<String>>> _highlighting = null;
@@ -363,6 +369,20 @@ public class QueryResponse extends SolrR
         _facetPivot.add( pf.getName(i), readPivots( (List<NamedList>)pf.getVal(i) ) );
       }
     }
+    
+    //Parse interval facets
+    NamedList<NamedList<Object>> intervalsNL = (NamedList<NamedList<Object>>) info.get("facet_intervals");
+    if (intervalsNL != null) {
+      _intervalFacets = new ArrayList<>(intervalsNL.size());
+      for (Map.Entry<String, NamedList<Object>> intervalField : intervalsNL) {
+        String field = intervalField.getKey();
+        List<IntervalFacet.Count> counts = new ArrayList<IntervalFacet.Count>(intervalField.getValue().size());
+        for (Map.Entry<String, Object> interval : intervalField.getValue()) {
+          counts.add(new IntervalFacet.Count(interval.getKey(), (Integer)interval.getValue()));
+        }
+        _intervalFacets.add(new IntervalFacet(field, counts));
+      }
+    }
   }
   
   protected List<PivotField> readPivots( List<NamedList> list )
@@ -466,6 +486,10 @@ public class QueryResponse extends SolrR
     return _facetPivot;
   }
   
+  public List<IntervalFacet> getIntervalFacets() {
+    return _intervalFacets;
+  }
+  
   /** get
    * 
    * @param name the name of the

Added: lucene/dev/trunk/solr/solrj/src/test-files/solrj/sampleIntervalFacetsResponse.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/test-files/solrj/sampleIntervalFacetsResponse.xml?rev=1616628&view=auto
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/test-files/solrj/sampleIntervalFacetsResponse.xml (added)
+++ lucene/dev/trunk/solr/solrj/src/test-files/solrj/sampleIntervalFacetsResponse.xml Thu Aug  7 23:27:19 2014
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+
+<response>
+
+<lst name="responseHeader">
+  <int name="status">0</int>
+  <int name="QTime">3</int>
+  <lst name="params">
+    <arr name="f.price.facet.interval.set">
+      <str>[0,10]</str>
+      <str>(10,100]</str>
+      <str>(100,*]</str>
+    </arr>
+    <str name="facet">true</str>
+    <str name="indent">true</str>
+    <arr name="f.popularity.facet.interval.set">
+      <str>{!key=bad}[0,4]</str>
+      <str>{!key=average}(4,7]</str>
+      <str>{!key=good}(7,*]</str>
+    </arr>
+    <arr name="facet.interval">
+      <str>price</str>
+      <str>popularity</str>
+    </arr>
+    <str name="q">*:*</str>
+    <str name="wt">xml</str>
+  </lst>
+</lst>
+<result name="response" numFound="32" start="0">
+  <doc>
+    <str name="id">GB18030TEST</str>
+    <str name="name">Test with some GB18030 encoded characters</str>
+    <arr name="features">
+      <str>No accents here</str>
+      <str>这是一个功能</str>
+      <str>This is a feature (translated)</str>
+      <str>这份文件是很有光泽</str>
+      <str>This document is very shiny (translated)</str>
+    </arr>
+    <float name="price">0.0</float>
+    <str name="price_c">0,USD</str>
+    <bool name="inStock">true</bool>
+    <long name="_version_">1475377182535581696</long></doc>
+  <doc>
+    <str name="id">SP2514N</str>
+    <str name="name">Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133</str>
+    <str name="manu">Samsung Electronics Co. Ltd.</str>
+    <str name="manu_id_s">samsung</str>
+    <arr name="cat">
+      <str>electronics</str>
+      <str>hard drive</str>
+    </arr>
+    <arr name="features">
+      <str>7200RPM, 8MB cache, IDE Ultra ATA-133</str>
+      <str>NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor</str>
+    </arr>
+    <float name="price">92.0</float>
+    <str name="price_c">92,USD</str>
+    <int name="popularity">6</int>
+    <bool name="inStock">true</bool>
+    <date name="manufacturedate_dt">2006-02-13T15:26:37Z</date>
+    <str name="store">35.0752,-97.032</str>
+    <long name="_version_">1475377182576476160</long></doc>
+  <doc>
+    <str name="id">6H500F0</str>
+    <str name="name">Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300</str>
+    <str name="manu">Maxtor Corp.</str>
+    <str name="manu_id_s">maxtor</str>
+    <arr name="cat">
+      <str>electronics</str>
+      <str>hard drive</str>
+    </arr>
+    <arr name="features">
+      <str>SATA 3.0Gb/s, NCQ</str>
+      <str>8.5ms seek</str>
+      <str>16MB cache</str>
+    </arr>
+    <float name="price">350.0</float>
+    <str name="price_c">350,USD</str>
+    <int name="popularity">6</int>
+    <bool name="inStock">true</bool>
+    <str name="store">45.17614,-93.87341</str>
+    <date name="manufacturedate_dt">2006-02-13T15:26:37Z</date>
+    <long name="_version_">1475377182582767616</long></doc>
+  <doc>
+    <str name="id">F8V7067-APL-KIT</str>
+    <str name="name">Belkin Mobile Power Cord for iPod w/ Dock</str>
+    <str name="manu">Belkin</str>
+    <str name="manu_id_s">belkin</str>
+    <arr name="cat">
+      <str>electronics</str>
+      <str>connector</str>
+    </arr>
+    <arr name="features">
+      <str>car power adapter, white</str>
+    </arr>
+    <float name="weight">4.0</float>
+    <float name="price">19.95</float>
+    <str name="price_c">19.95,USD</str>
+    <int name="popularity">1</int>
+    <bool name="inStock">false</bool>
+    <str name="store">45.18014,-93.87741</str>
+    <date name="manufacturedate_dt">2005-08-01T16:30:25Z</date>
+    <long name="_version_">1475377182589059072</long></doc>
+  <doc>
+    <str name="id">IW-02</str>
+    <str name="name">iPod &amp; iPod Mini USB 2.0 Cable</str>
+    <str name="manu">Belkin</str>
+    <str name="manu_id_s">belkin</str>
+    <arr name="cat">
+      <str>electronics</str>
+      <str>connector</str>
+    </arr>
+    <arr name="features">
+      <str>car power adapter for iPod, white</str>
+    </arr>
+    <float name="weight">2.0</float>
+    <float name="price">11.5</float>
+    <str name="price_c">11.50,USD</str>
+    <int name="popularity">1</int>
+    <bool name="inStock">false</bool>
+    <str name="store">37.7752,-122.4232</str>
+    <date name="manufacturedate_dt">2006-02-14T23:55:59Z</date>
+    <long name="_version_">1475377182591156224</long></doc>
+  <doc>
+    <str name="id">MA147LL/A</str>
+    <str name="name">Apple 60 GB iPod with Video Playback Black</str>
+    <str name="manu">Apple Computer Inc.</str>
+    <str name="manu_id_s">apple</str>
+    <arr name="cat">
+      <str>electronics</str>
+      <str>music</str>
+    </arr>
+    <arr name="features">
+      <str>iTunes, Podcasts, Audiobooks</str>
+      <str>Stores up to 15,000 songs, 25,000 photos, or 150 hours of video</str>
+      <str>2.5-inch, 320x240 color TFT LCD display with LED backlight</str>
+      <str>Up to 20 hours of battery life</str>
+      <str>Plays AAC, MP3, WAV, AIFF, Audible, Apple Lossless, H.264 video</str>
+      <str>Notes, Calendar, Phone book, Hold button, Date display, Photo wallet, Built-in games, JPEG photo playback, Upgradeable firmware, USB 2.0 compatibility, Playback speed control, Rechargeable capability, Battery level indication</str>
+    </arr>
+    <str name="includes">earbud headphones, USB cable</str>
+    <float name="weight">5.5</float>
+    <float name="price">399.0</float>
+    <str name="price_c">399.00,USD</str>
+    <int name="popularity">10</int>
+    <bool name="inStock">true</bool>
+    <str name="store">37.7752,-100.0232</str>
+    <date name="manufacturedate_dt">2005-10-12T08:00:00Z</date>
+    <long name="_version_">1475377182597447680</long></doc>
+  <doc>
+    <str name="id">adata</str>
+    <str name="compName_s">A-Data Technology</str>
+    <str name="address_s">46221 Landing Parkway Fremont, CA 94538</str>
+    <long name="_version_">1475377182608982016</long></doc>
+  <doc>
+    <str name="id">apple</str>
+    <str name="compName_s">Apple</str>
+    <str name="address_s">1 Infinite Way, Cupertino CA</str>
+    <long name="_version_">1475377182608982017</long></doc>
+  <doc>
+    <str name="id">asus</str>
+    <str name="compName_s">ASUS Computer</str>
+    <str name="address_s">800 Corporate Way Fremont, CA 94539</str>
+    <long name="_version_">1475377182610030592</long></doc>
+  <doc>
+    <str name="id">ati</str>
+    <str name="compName_s">ATI Technologies</str>
+    <str name="address_s">33 Commerce Valley Drive East Thornhill, ON L3T 7N6 Canada</str>
+    <long name="_version_">1475377182610030593</long></doc>
+</result>
+<lst name="facet_counts">
+  <lst name="facet_queries"/>
+  <lst name="facet_fields"/>
+  <lst name="facet_dates"/>
+  <lst name="facet_ranges"/>
+  <lst name="facet_intervals">
+    <lst name="price">
+      <int name="[0,10]">3</int>
+      <int name="(10,100]">4</int>
+      <int name="(100,*]">9</int>
+    </lst>
+    <lst name="popularity">
+      <int name="bad">3</int>
+      <int name="average">10</int>
+      <int name="good">2</int>
+    </lst>
+  </lst>
+</lst>
+</response>

Modified: lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrQueryTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrQueryTest.java?rev=1616628&r1=1616627&r2=1616628&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrQueryTest.java (original)
+++ lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/SolrQueryTest.java Thu Aug  7 23:27:19 2014
@@ -417,4 +417,36 @@ public class SolrQueryTest extends Lucen
     solrQuery.addFacetQuery("field:value");
     assertTrue("Adding a Facet Query should enable facets", solrQuery.getBool(FacetParams.FACET));
   }
+  
+  public void testFacetInterval() {
+    SolrQuery solrQuery = new SolrQuery();
+    solrQuery.addIntervalFacets("field1", new String[]{});
+    assertTrue(solrQuery.getBool(FacetParams.FACET));
+    assertEquals("field1", solrQuery.get(FacetParams.FACET_INTERVAL));
+    
+    solrQuery.addIntervalFacets("field2", new String[]{"[1,10]"});
+    assertArrayEquals(new String[]{"field1", "field2"}, solrQuery.getParams(FacetParams.FACET_INTERVAL));
+    assertEquals("[1,10]", solrQuery.get("f.field2.facet.interval.set"));
+    
+    solrQuery.addIntervalFacets("field3", new String[]{"[1,10]", "(10,100]", "(100,1000]", "(1000,*]"});
+    assertArrayEquals(new String[]{"field1", "field2", "field3"}, solrQuery.getParams(FacetParams.FACET_INTERVAL));
+    assertArrayEquals(new String[]{"[1,10]", "(10,100]", "(100,1000]", "(1000,*]"}, solrQuery.getParams("f.field3.facet.interval.set"));
+    
+    //Validate adding more intervals for an existing field
+    solrQuery.addIntervalFacets("field2", new String[]{"[10,100]"});
+    assertArrayEquals(new String[]{"[1,10]", "[10,100]"}, solrQuery.getParams("f.field2.facet.interval.set"));
+    
+    assertNull(solrQuery.removeIntervalFacets("field1"));
+    assertArrayEquals(new String[]{"field2", "field3", "field2"}, solrQuery.getParams(FacetParams.FACET_INTERVAL));
+    assertNull(solrQuery.getParams("f.field1.facet.interval.set"));
+    
+    assertArrayEquals(new String[]{"[1,10]", "[10,100]"}, solrQuery.removeIntervalFacets("field2"));
+    assertArrayEquals(new String[]{"field3"}, solrQuery.getParams(FacetParams.FACET_INTERVAL));
+    assertNull(solrQuery.getParams("f.field2.facet.interval.set"));
+    
+    assertArrayEquals(new String[]{"[1,10]", "(10,100]", "(100,1000]", "(1000,*]"}, solrQuery.removeIntervalFacets("field3"));
+    assertNull(solrQuery.getParams(FacetParams.FACET_INTERVAL));
+    assertNull(solrQuery.getParams("f.field3.facet.interval.set"));
+    
+  }
 }

Modified: lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/response/QueryResponseTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/response/QueryResponseTest.java?rev=1616628&r1=1616627&r2=1616628&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/response/QueryResponseTest.java (original)
+++ lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/response/QueryResponseTest.java Thu Aug  7 23:27:19 2014
@@ -262,5 +262,49 @@ public class QueryResponseTest extends L
     assertEquals("708_AR", documents.get(8).getFieldValue("acco_id"));
     assertEquals("708_HI", documents.get(9).getFieldValue("acco_id"));
   }
+  
+  
+  public void testIntervalFacetsResponse() throws Exception {
+    XMLResponseParser parser = new XMLResponseParser();
+    try(SolrResourceLoader loader = new SolrResourceLoader(null, null)) {
+      InputStream is = loader.openResource("solrj/sampleIntervalFacetsResponse.xml");
+      assertNotNull(is);
+      Reader in = new InputStreamReader(is, StandardCharsets.UTF_8);
+      NamedList<Object> response = parser.processResponse(in);
+      in.close();
+      
+      QueryResponse qr = new QueryResponse(response, null);
+      assertNotNull(qr);
+      assertNotNull(qr.getIntervalFacets());
+      assertEquals(2, qr.getIntervalFacets().size());
+      
+      IntervalFacet facet = qr.getIntervalFacets().get(0);
+      assertEquals("price", facet.getField());
+      assertEquals(3, facet.getIntervals().size());
+      
+      assertEquals("[0,10]", facet.getIntervals().get(0).getKey());
+      assertEquals("(10,100]", facet.getIntervals().get(1).getKey());
+      assertEquals("(100,*]", facet.getIntervals().get(2).getKey());
+      
+      assertEquals(3, facet.getIntervals().get(0).getCount());
+      assertEquals(4, facet.getIntervals().get(1).getCount());
+      assertEquals(9, facet.getIntervals().get(2).getCount());
+      
+      
+      facet = qr.getIntervalFacets().get(1);
+      assertEquals("popularity", facet.getField());
+      assertEquals(3, facet.getIntervals().size());
+      
+      assertEquals("bad", facet.getIntervals().get(0).getKey());
+      assertEquals("average", facet.getIntervals().get(1).getKey());
+      assertEquals("good", facet.getIntervals().get(2).getKey());
+      
+      assertEquals(3, facet.getIntervals().get(0).getCount());
+      assertEquals(10, facet.getIntervals().get(1).getCount());
+      assertEquals(2, facet.getIntervals().get(2).getCount());
+      
+    }
+    
+  }
 
 }