/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2011, Red Hat, Inc. and/or its affiliates or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat, Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.hibernate.search.test.query.facet; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.List; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.search.FullTextQuery; import org.hibernate.search.SearchException; import org.hibernate.search.query.engine.spi.FacetManager; import org.hibernate.search.query.facet.Facet; import org.hibernate.search.query.facet.FacetSortOrder; import org.hibernate.search.query.facet.FacetingRequest; /** * @author Hardy Ferentschik */ public class RangeFacetingTest extends AbstractFacetTest { private static final String indexFieldName = "price"; private static final String priceRange = "priceRange"; public void testRangeQueryForInteger() { FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .from( 0 ).to( 1000 ) .from( 1001 ).to( 1500 ) .from( 1501 ).to( 3000 ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( priceRange ); assertFacetCounts( facets, new int[] { 5, 3, 2 } ); } public void testRangeBelow() { FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .below( 1500 ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( priceRange ); assertFacetCounts( facets, new int[] { 5 } ); } public void testRangeBelowExcludeLimit() { FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .below( 1500 ).excludeLimit() .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( priceRange ); assertFacetCounts( facets, new int[] { 2 } ); } public void testRangeAbove() { FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .above( 1500 ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( priceRange ); assertFacetCounts( facets, new int[] { 8 } ); } public void testRangeAboveExcludeLimit() { FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .above( 1500 ).excludeLimit() .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( priceRange ); assertFacetCounts( facets, new int[] { 5 } ); } public void testRangeAboveBelow() { FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .below( 1500 ) .above( 1500 ).excludeLimit() .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( priceRange ); assertFacetCounts( facets, new int[] { 5, 5 } ); } public void testRangeBelowMiddleAbove() { final String facetingName = "cdPriceFaceting"; FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( facetingName ) .onField( indexFieldName ) .range() .below( 1000 ) .from( 1001 ).to( 1500 ) .above( 1501 ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); query.getFacetManager().enableFaceting( rangeRequest ); List<Facet> facets = query.getFacetManager().getFacets( facetingName ); assertFacetCounts( facets, new int[] { 5, 3, 2 } ); } // HSEARCH-770 public void testRangeBelowWithFacetSelection() { final String facetingName = "truckHorsePowerFaceting"; FacetingRequest rangeRequest = queryBuilder( Truck.class ).facet() .name( facetingName ) .onField( "horsePower" ) .range() .below( 1000 ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Truck.class ); FacetManager facetManager = query.getFacetManager(); query.getFacetManager().enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( facetingName ); // OK facets = facetManager.getFacets( facetingName ); // Still OK assertFacetCounts( facets, new int[] { 4 } ); facetManager.getFacetGroup( facetingName ).selectFacets( facets.get( 0 ) ); //narrow search on facet facets = facetManager.getFacets( facetingName ); // Exception... assertFacetCounts( facets, new int[] { 4 } ); } public void testRangeQueryForDoubleWithZeroCount() { FacetingRequest rangeRequest = queryBuilder( Fruit.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .from( 0.00 ).to( 1.00 ) .from( 1.01 ).to( 1.50 ) .from( 1.51 ).to( 3.00 ) .from( 4.00 ).to( 5.00 ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Fruit.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( priceRange ); assertFacetCounts( facets, new int[] { 5, 3, 2, 0 } ); } public void testRangeQueryForDoubleWithoutZeroCount() { FacetingRequest rangeRequest = queryBuilder( Fruit.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .from( 0.00 ).to( 1.00 ) .from( 1.01 ).to( 1.50 ) .from( 1.51 ).to( 3.00 ) .from( 4.00 ).to( 5.00 ) .includeZeroCounts( false ) .orderedBy( FacetSortOrder.COUNT_ASC ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Fruit.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = query.getFacetManager().getFacets( priceRange ); assertFacetCounts( facets, new int[] { 2, 3, 5 } ); assertEquals( "[0.0, 1.0]", facets.get( 0 ).getValue() ); assertEquals( "[1.01, 1.5]", facets.get( 1 ).getValue() ); assertEquals( "[1.51, 3.0]", facets.get( 2 ).getValue() ); } public void testRangeQueryRangeDefOrderHigherMaxCount() { FacetingRequest rangeRequest = queryBuilder( Fruit.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .from( 0.00 ).to( 1.00 ) .from( 1.01 ).to( 1.50 ) .from( 1.51 ).to( 3.00 ) .from( 4.00 ).to( 5.00 ) .includeZeroCounts( false ) .orderedBy( FacetSortOrder.RANGE_DEFINITION_ODER ) .maxFacetCount(5) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Fruit.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = query.getFacetManager().getFacets( priceRange ); assertFacetCounts( facets, new int[] { 2, 3, 5 } ); assertEquals( "[0.0, 1.0]", facets.get( 0 ).getValue() ); assertEquals( "[1.01, 1.5]", facets.get( 1 ).getValue() ); assertEquals( "[1.51, 3.0]", facets.get( 2 ).getValue() ); } public void testStringRangeFaceting() { final String facetingName = "albumNameFaceting"; final String fieldName = "name_un_analyzed"; FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( facetingName ) .onField( fieldName ) .range() .below( "S" ).excludeLimit() .from( "S" ).to( "U" ) .above( "U" ).excludeLimit() .orderedBy( FacetSortOrder.RANGE_DEFINITION_ODER ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( facetingName ); assertFacetCounts( facets, new int[] { 7, 1, 2 } ); facetManager.getFacetGroup( facetingName ).selectFacets( facets.get( 0 ) ); facets = facetManager.getFacets( facetingName ); assertFacetCounts( facets, new int[] { 7, 0, 0 } ); } public void testDateRangeFaceting() throws Exception { final String facetingName = "albumYearFaceting"; final String fieldName = "releaseYear"; final DateFormat formatter = new SimpleDateFormat( "yyyy" ); FacetingRequest rangeRequest = queryBuilder( Cd.class ).facet() .name( facetingName ) .onField( fieldName ) .range() .below( formatter.parse( "1970" ) ).excludeLimit() .from( formatter.parse( "1970" ) ).to( formatter.parse( "1979" ) ) .from( formatter.parse( "1980" ) ).to( formatter.parse( "1989" ) ) .from( formatter.parse( "1990" ) ).to( formatter.parse( "1999" ) ) .above( formatter.parse( "2000" ) ).excludeLimit() .orderedBy( FacetSortOrder.RANGE_DEFINITION_ODER ) .createFacetingRequest(); FullTextQuery query = createMatchAllQuery( Cd.class ); FacetManager facetManager = query.getFacetManager(); facetManager.enableFaceting( rangeRequest ); List<Facet> facets = facetManager.getFacets( facetingName ); assertFacetCounts( facets, new int[] { 1, 2, 2, 0, 5 } ); facetManager.getFacetGroup( facetingName ).selectFacets( facets.get( 4 ) ); facets = facetManager.getFacets( facetingName ); assertFacetCounts( facets, new int[] { 0, 0, 0, 0, 5 } ); } public void testRangeQueryWithUnsupportedType() { try { queryBuilder( Cd.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .from( new Object() ).to( new Object() ) .createFacetingRequest(); fail( "Unsupported range faceting type" ); } catch ( SearchException e ) { // success } } public void testRangeQueryWithNullToAndFrom() { try { queryBuilder( Cd.class ).facet() .name( priceRange ) .onField( indexFieldName ) .range() .from( null ).to( null ) .createFacetingRequest(); fail( "Unsupported range faceting type" ); } catch ( SearchException e ) { // success } } public void loadTestData(Session session) { Transaction tx = session.beginTransaction(); for ( int i = 0; i < albums.length; i++ ) { Cd cd = new Cd( albums[i], albumPrices[i], releaseDates[i] ); session.save( cd ); } for ( int i = 0; i < fruits.length; i++ ) { Fruit fruit = new Fruit( fruits[i], fruitPrices[i] ); session.save( fruit ); } for ( int i = 0; i < horsePowers.length; i++ ) { Truck truck = new Truck( horsePowers[i] ); session.save( truck ); } tx.commit(); session.clear(); } protected Class<?>[] getAnnotatedClasses() { return new Class[] { Cd.class, Fruit.class, Truck.class }; } }