/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, 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.engine;
import java.math.BigDecimal;
import java.util.List;
import junit.framework.Assert;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.ProjectionConstants;
import org.hibernate.search.Search;
import org.hibernate.search.SearchFactory;
import org.hibernate.search.bridge.util.impl.NumericFieldUtils;
import org.hibernate.search.test.SearchTestCase;
import org.hibernate.search.test.util.TestForIssue;
public class NumericFieldTest extends SearchTestCase {
FullTextSession fullTextSession;
public void setUp() throws Exception {
super.setUp();
Session session = openSession();
fullTextSession = Search.getFullTextSession( session );
prepareData();
}
public void tearDown() throws Exception {
cleanData();
assertTrue(indexIsEmpty());
super.tearDown();
}
public void testIndexAndSearchNumericField() {
Transaction tx = fullTextSession.beginTransaction();
// Range Queries including lower and upper bounds
assertEquals("Query id ", 3, numericQueryFor("overriddenFieldName", 1, 3).size());
assertEquals("Query by double range", 3, numericQueryFor( "latitude", -10d, 10d ).size() );
assertEquals("Query by integer range", 4, numericQueryFor( "ranking", 1 ,2 ).size() );
assertEquals("Query by long range", 3, numericQueryFor( "myCounter", 1L, 3L ).size() );
assertEquals("Query by multi-fields", 2, numericQueryFor( "strMultiple", 0.7d, 0.9d).size() );
assertEquals("Query on custom bridge by range", 4, numericQueryFor("visibleStars", -100L, 500L).size() );
// Range Queries different bounds
assertEquals("Query by id excluding upper", 2, numericQueryFor("overriddenFieldName", 1, 3, true, false).size() );
assertEquals("Query by id excluding upper and lower", 1, numericQueryFor("overriddenFieldName", 1, 3, false, false).size() );
// Range Query for embedded entities
assertEquals("Range Query for indexed embedded", 2, numericQueryFor("country.idh", 0.9, 1d).size() );
// Range Query across entities
assertEquals("Range Query across entities", 1, numericQueryFor("pinPoints.stars", 4, 5).size() );
// Exact Matching Queries
assertEquals("Query id exact", 1, doExactQuery("overriddenFieldName", 1).getId());
assertEquals("Query double exact", 2, doExactQuery( "latitude", -10d).getId() );
assertEquals("Query integer exact", 3, doExactQuery("longitude", -20d).getId() );
assertEquals("Query long exact", 4, doExactQuery("myCounter",4L).getId() );
assertEquals("Query multifield exact", 5, doExactQuery("strMultiple",0.1d).getId() );
assertEquals("Query on custom bridge exact", 3, doExactQuery("visibleStars", 1000L).getId() );
tx.commit();
fullTextSession.clear();
// Delete operation on Numeric Id with overriden field name:
tx = fullTextSession.beginTransaction();
List allLocations = fullTextSession.createCriteria( Location.class ).list();
for (Object location : allLocations) {
fullTextSession.delete( location );
}
tx.commit();
fullTextSession.clear();
tx = fullTextSession.beginTransaction();
assertEquals("Check for deletion on Query", 0, numericQueryFor("overriddenFieldName", 1, 6).size());
// and now check also for the real index contents:
Query query = NumericFieldUtils.createNumericRangeQuery("overriddenFieldName", 1, 6, true, true);
FullTextQuery fullTextQuery = fullTextSession
.createFullTextQuery( query, Location.class )
.setProjection( ProjectionConstants.DOCUMENT );
assertEquals("Check for deletion on index projection", 0, fullTextQuery.list().size() );
tx.commit();
}
@TestForIssue( jiraKey = "HSEARCH-1193")
public void testNumericFieldProjections() {
Transaction tx = fullTextSession.beginTransaction();
try {
Query latitudeQuery = NumericFieldUtils.createNumericRangeQuery( "latitude", -20d, -20d, true, true );
List list = fullTextSession.createFullTextQuery(latitudeQuery, Location.class)
.setProjection( "latitude" )
.list();
Assert.assertEquals( 1, list.size() );
Object[] firstProjection = (Object[]) list.get( 0 );
Assert.assertEquals( 1, firstProjection.length );
Assert.assertEquals( Double.valueOf( -20d ), firstProjection[0] );
List listAgain = fullTextSession.createFullTextQuery(latitudeQuery, Location.class)
.setProjection( "coordinatePair_x", "coordinatePair_y" )
.list();
Assert.assertEquals( 1, listAgain.size() );
Object[] secondProjection = (Object[]) listAgain.get( 0 );
Assert.assertEquals( 2, secondProjection.length );
Assert.assertEquals( Double.valueOf( 1d ), secondProjection[0] );
Assert.assertEquals( Double.valueOf( 2d ), secondProjection[1] );
}
finally {
tx.commit();
}
}
private boolean indexIsEmpty() {
int numDocsLocation = countSizeForType( Location.class );
int numDocsPinPoint = countSizeForType( PinPoint.class );
return numDocsLocation==0 && numDocsPinPoint==0;
}
private int countSizeForType(Class<?> type) {
SearchFactory searchFactory = fullTextSession.getSearchFactory();
int numDocs = -1; //to have it fail in case of errors
IndexReader locationIndexReader = searchFactory.getIndexReaderAccessor().open( type );
try {
numDocs = locationIndexReader.numDocs();
}
finally {
searchFactory.getIndexReaderAccessor().close( locationIndexReader );
}
return numDocs;
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { PinPoint.class, Location.class };
}
private Location doExactQuery(String fieldName, Object value) {
Query matchQuery = NumericFieldUtils.createExactMatchQuery(fieldName, value);
return (Location) fullTextSession.createFullTextQuery(matchQuery, Location.class).list().get(0);
}
private List numericQueryFor(String fieldName, Object from, Object to) {
Query query = NumericFieldUtils.createNumericRangeQuery(fieldName, from, to, true, true);
return fullTextSession.createFullTextQuery(query, Location.class).list();
}
private List numericQueryFor(String fieldName, Object from, Object to, boolean includeLower, boolean includeUpper) {
Query query = NumericFieldUtils.createNumericRangeQuery( fieldName, from, to, includeLower, includeUpper );
return fullTextSession.createFullTextQuery(query, Location.class).list();
}
private void prepareData() {
Transaction tx = fullTextSession.beginTransaction();
Location loc1 = new Location(1, 1L, -20d, -40d, 1, "Random text", 1.5d, countryFor("England", 0.947), BigDecimal.ONE );
loc1.addPinPoints(new PinPoint( 1, 4, loc1), new PinPoint( 2, 5, loc1 ) );
Location loc2 = new Location(2, 2L, -10d, -30d, 1, "Some text", 0.786d, countryFor("Italy", 0.951), BigDecimal.ONE );
loc2.addPinPoints(new PinPoint( 3, 1, loc2), new PinPoint( 4, 2, loc2 ) );
Location loc3 = new Location(3, 3L, 0d, -20d, 1, "A text", 0.86d, countryFor("Brazil", 0.813), BigDecimal.TEN );
Location loc4 = new Location(4, 4L, 10d, 0d, 2, "Any text", 0.99d, countryFor("France", 0.872), BigDecimal.ONE );
Location loc5 = new Location(5, 5L, 20d, 20d, 3, "Random text", 0.1d, countryFor("India", 0.612), BigDecimal.ONE );
fullTextSession.save(loc1);
fullTextSession.save(loc2);
fullTextSession.save(loc3);
fullTextSession.save(loc4);
fullTextSession.save(loc5);
tx.commit();
fullTextSession.clear();
}
private Country countryFor(String name, double idh) {
return new Country( name, idh );
}
private void cleanData() {
Transaction tx = fullTextSession.beginTransaction();
List<Location> locations = fullTextSession.createCriteria(Location.class).list();
for(Location location: locations) {
fullTextSession.delete( location );
}
tx.commit();
fullTextSession.close();
}
}