/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.elasticsearch.test;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.hibernate.search.elasticsearch.ElasticsearchProjectionConstants;
import org.hibernate.search.elasticsearch.ElasticsearchQueries;
import org.hibernate.search.elasticsearch.test.model.Address;
import org.hibernate.search.elasticsearch.test.model.Country;
import org.hibernate.search.elasticsearch.test.model.Owner;
import org.hibernate.search.elasticsearch.test.model.Person;
import org.hibernate.search.elasticsearch.test.model.State;
import org.hibernate.search.elasticsearch.test.model.StateCandidate;
import org.hibernate.search.elasticsearch.test.model.Tower;
import org.hibernate.search.query.engine.spi.QueryDescriptor;
import org.hibernate.search.test.SearchTestBase;
import org.hibernate.search.testsupport.TestForIssue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* @author Gunnar Morling
*/
public class ElasticsearchIT extends SearchTestBase {
@Before
public void setupTestData() {
Session s = openSession();
Transaction tx = s.beginTransaction();
ScientificArticle article1 = new ScientificArticle(
"ORM for dummies",
"Object/relational mapping with Hibernate",
"blah blah blah", 7
);
s.persist( article1 );
ScientificArticle article2 = new ScientificArticle(
"Latest in ORM",
"Object/relational mapping with Hibernate - The latest news",
"blah blah blah", 8
);
s.persist( article2 );
ScientificArticle article3 = new ScientificArticle(
"ORM for beginners",
"Object/relational mapping with an unknown tool",
"blah blah blah", 9
);
s.persist( article3 );
ScientificArticle article4 = new ScientificArticle(
"High-performance ORM",
"Tuning persistence with Hibernate",
"blah blah blah", 10
);
s.persist( article4 );
ScientificArticle article5 = new ScientificArticle(
"ORM modelling",
"Modelling your domain model with Hibernate",
"blah blah blah", 11
);
s.persist( article5 );
ResearchPaper paper1 = new ResearchPaper(
"Very important research on Hibernate",
"Latest research on Hibernate",
"blah blah blah", 7
);
s.persist( paper1 );
ResearchPaper paper2 = new ResearchPaper(
"Some research",
"Important Hibernate research",
"blah blah blah", 7
);
s.persist( paper2 );
BachelorThesis bachelorThesis = new BachelorThesis(
"Latest findings",
"blah blah blah"
);
s.persist( bachelorThesis );
MasterThesis masterThesis = new MasterThesis(
"Great findings",
"blah blah blah"
);
s.persist( masterThesis );
Calendar dob = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ), Locale.ENGLISH );
dob.set( 1958, 3, 7, 0, 0, 0 );
dob.set( Calendar.MILLISECOND, 0 );
GolfPlayer hergesheimer = new GolfPlayer.Builder()
.firstName( "Klaus" )
.lastName( "Hergesheimer" )
.active( true )
.dateOfBirth( dob.getTime() )
.handicap( 3.4 )
.puttingStrength( 2.5 )
.driveWidth( 285 )
.ranking( 311 )
.strength( "precision" )
.strength( "willingness" )
.strength( "stamina" )
.build();
s.persist( hergesheimer );
tx.commit();
s.close();
}
@After
public void deleteTestData() {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match_all' : {} } }" );
List<?> result = session.createFullTextQuery( query ).list();
for ( Object entity : result ) {
session.delete( entity );
}
tx.commit();
s.close();
}
@Test
public void testFields() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'abstract' : 'Hibernate' } } }" );
List<?> result = session.createFullTextQuery( query, ScientificArticle.class ).list();
assertThat( result ).onProperty( "title" ).containsOnly(
"Latest in ORM",
"ORM for dummies",
"High-performance ORM",
"ORM modelling"
);
tx.commit();
s.close();
}
@Test
public void testNumericFieldQuery() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'range' : { 'wordCount' : { 'gte' : 8, 'lt' : 10 } } } }" );
List<?> result = session.createFullTextQuery( query ).list();
assertThat( result ).onProperty( "title" ).containsOnly( "Latest in ORM", "ORM for beginners" );
tx.commit();
s.close();
}
@Test
@TestForIssue(jiraKey = "HSEARCH-2467")
public void testDateFieldRangeQuery() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
Query query = NumericRangeQuery.newLongRange( "dateOfBirth", -373078800000L, null, true, true );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setSort( new Sort( new SortField( "id", SortField.Type.STRING ) ) )
.list();
assertThat( result ).onProperty( "firstName" ).containsOnly( "Klaus" );
tx.commit();
s.close();
}
@Test
public void testEmbeddedIndexing() throws Exception {
Tower tower = new Tower();
tower.setName( "JBoss tower" );
Address a = new Address();
a.setStreet( "Tower place" );
a.getTowers().add( tower );
tower.setAddress( a );
Person o = new Owner();
o.setName( "Atlanta Renting corp" );
a.setOwnedBy( o );
o.setAddress( a );
Country c = new Country();
c.setName( "France" );
a.setCountry( c );
Session s = openSession();
Transaction tx = s.beginTransaction();
s.persist( tower );
tx.commit();
FullTextSession session = Search.getFullTextSession( s );
QueryDescriptor query;
List<?> result;
query = ElasticsearchQueries.fromJson(
"{" +
"'query' : { " +
"'match' : { " +
"'address.street' : 'place'" +
" }" +
" }" +
" }"
);
result = session.createFullTextQuery( query, Tower.class ).list();
assertEquals( "unable to find property in embedded", 1, result.size() );
query = ElasticsearchQueries.fromJson(
"{" +
"'query' : { " +
"'match' : { " +
"'address.ownedBy.name' : 'renting'" +
" }" +
" }" +
" }"
);
result = session.createFullTextQuery( query, Tower.class ).list();
assertEquals( "unable to find property in embedded", 1, result.size() );
query = ElasticsearchQueries.fromJson(
"{" +
"'query' : { " +
"'match' : { " +
"'address.id' : " + a.getId() +
" }" +
" }" +
" }"
);
result = session.createFullTextQuery( query, Tower.class ).list();
assertEquals( "unable to find property by id of embedded", 1, result.size() );
query = ElasticsearchQueries.fromJson(
"{" +
"'query' : { " +
"'match' : { " +
"'address.country.name' : 'France'" +
" }" +
" }" +
" }"
);
result = session.createFullTextQuery( query, Tower.class ).list();
assertEquals( "unable to find property with 2 levels of embedded", 1, result.size() );
s.clear();
tx = s.beginTransaction();
Address address = s.get( Address.class, a.getId() );
address.getOwnedBy().setName( "Buckhead community" );
tx.commit();
s.clear();
session = Search.getFullTextSession( s );
query = ElasticsearchQueries.fromJson(
"{" +
"'query' : { " +
"'match' : { " +
"'address.ownedBy.name' : 'buckhead'" +
" }" +
" }" +
" }"
);
result = session.createFullTextQuery( query, Tower.class ).list();
assertEquals( "change in embedded not reflected in root index", 1, result.size() );
s.clear();
tx = s.beginTransaction();
s.delete( s.get( Tower.class, tower.getId() ) );
tx.commit();
s.close();
}
@Test
public void testEmbeddedIndexingOfElementCollection() throws Exception {
Session s = openSession();
Transaction tx = s.beginTransaction();
FullTextSession session = Search.getFullTextSession( s );
QueryDescriptor query;
List<?> result;
query = ElasticsearchQueries.fromJson(
"{" +
"'query' : { " +
"'match' : { " +
"'strengths' : 'willingness'" +
" }" +
" }" +
" }"
);
result = session.createFullTextQuery( query, GolfPlayer.class ).list();
assertEquals( "unable to find property in embedded element collection", 1, result.size() );
tx.commit();
s.close();
}
@Test
public void testIndexSharing() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'title' : 'findings' } } }" );
List<?> result = session.createFullTextQuery( query, MasterThesis.class, BachelorThesis.class ).list();
assertThat( result ).onProperty( "title" ).containsOnly( "Great findings", "Latest findings" );
tx.commit();
s.close();
}
@Test
public void testRestrictionByType() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'abstract' : 'Hibernate' } } }" );
List<?> result = session.createFullTextQuery( query, ResearchPaper.class ).list();
assertThat( result ).onProperty( "title" ).containsOnly( "Very important research on Hibernate", "Some research" );
tx.commit();
s.close();
}
@Test
public void testFirstResultAndMaxResults() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'abstract' : 'Hibernate' } } }" );
List<?> result = session.createFullTextQuery( query, ScientificArticle.class )
.setFirstResult( 1 )
.setMaxResults( 2 )
.setSort( new Sort( new SortField( "id", SortField.Type.STRING, false ) ) )
.list();
assertThat( result ).onProperty( "title" ).containsOnly( "Latest in ORM", "High-performance ORM" );
tx.commit();
s.close();
}
@Test
public void testGetResultSize() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'abstract' : 'Hibernate' } } }" );
FullTextQuery fullTextQuery = session.createFullTextQuery( query, ScientificArticle.class );
assertThat( fullTextQuery.getResultSize() ).isEqualTo( 4 );
tx.commit();
s.close();
}
@Test
public void testScroll() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'abstract' : 'Hibernate' } } }" );
FullTextQuery fullTextQuery = session.createFullTextQuery( query, ScientificArticle.class )
.setSort( new Sort( new SortField( "id", SortField.Type.STRING, false ) ) );
ScrollableResults scrollableResults = fullTextQuery.scroll();
assertEquals( -1, scrollableResults.getRowNumber() );
assertTrue( scrollableResults.last() );
assertEquals( 3, scrollableResults.getRowNumber() );
scrollableResults.beforeFirst();
List<ScientificArticle> articles = new ArrayList<>();
while ( scrollableResults.next() ) {
articles.add( (ScientificArticle) scrollableResults.get()[0] );
}
scrollableResults.close();
assertThat( articles ).onProperty( "title" ).containsExactly(
"ORM for dummies",
"Latest in ORM",
"High-performance ORM",
"ORM modelling"
);
fullTextQuery = session.createFullTextQuery( query, ScientificArticle.class )
.setSort( new Sort( new SortField( "id", SortField.Type.STRING, false ) ) );
scrollableResults = fullTextQuery
.setFirstResult( 1 )
.setMaxResults( 2 )
.scroll();
assertEquals( -1, scrollableResults.getRowNumber() );
assertTrue( scrollableResults.last() );
assertEquals( 1, scrollableResults.getRowNumber() );
scrollableResults.beforeFirst();
articles = new ArrayList<>();
while ( scrollableResults.next() ) {
articles.add( (ScientificArticle) scrollableResults.get()[0] );
}
scrollableResults.close();
assertThat( articles ).onProperty( "title" ).containsExactly(
"Latest in ORM",
"High-performance ORM"
);
tx.commit();
s.close();
}
@Test
@TestForIssue(jiraKey = "HSEARCH-2253")
public void testSort() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'abstract' : 'Hibernate' } } }" );
// by title, ascending
List<?> result = session.createFullTextQuery( query, ScientificArticle.class )
.setSort( new Sort( new SortField( "title", SortField.Type.STRING, false ) ) )
.list();
assertThat( result ).onProperty( "title" ).containsExactly(
"High-performance ORM",
"Latest in ORM",
"ORM for dummies",
"ORM modelling"
);
// By id, descending
result = session.createFullTextQuery( query, ScientificArticle.class )
.setSort( new Sort( new SortField( "id", SortField.Type.STRING, true ) ) )
.list();
assertThat( result ).onProperty( "id" ).containsExactly(
5L,
4L,
2L,
1L
);
tx.commit();
s.close();
}
@Test
public void testFieldBoost() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson(
"{" +
"'query': {" +
"'bool' : {" +
"'should' : [" +
"{ 'match' : { 'abstract' : 'important' } }," +
"{ 'match' : { 'title' : 'important' } }" +
"]" +
"}" +
"}" +
"}"
);
List<?> result = session.createFullTextQuery( query, ResearchPaper.class ).list();
assertThat( result ).onProperty( "title" ).containsExactly(
"Very important research on Hibernate",
"Some research"
);
tx.commit();
s.close();
}
@Test
public void testQueryStringQuery() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromQueryString( "abstract:Hibernate" );
List<?> result = session.createFullTextQuery( query, ScientificArticle.class ).list();
assertThat( result ).onProperty( "title" ).containsOnly(
"Latest in ORM",
"ORM for dummies",
"High-performance ORM",
"ORM modelling"
);
query = ElasticsearchQueries.fromQueryString( "abstract:important OR title:important" );
result = session.createFullTextQuery( query, ResearchPaper.class ).list();
assertThat( result ).onProperty( "title" ).containsOnly(
"Very important research on Hibernate",
"Some research"
);
query = ElasticsearchQueries.fromQueryString( "wordCount:[8 TO 10}" );
result = session.createFullTextQuery( query, ScientificArticle.class ).list();
assertThat( result ).onProperty( "title" ).containsOnly( "Latest in ORM", "ORM for beginners" );
tx.commit();
s.close();
}
@Test
public void testProjection() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromQueryString( "lastName:Hergesheimer" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection(
ElasticsearchProjectionConstants.ID,
ElasticsearchProjectionConstants.OBJECT_CLASS,
ElasticsearchProjectionConstants.SCORE,
ElasticsearchProjectionConstants.THIS,
"firstName",
"lastName",
"active",
"dateOfBirth",
"handicap",
"driveWidth",
"ranking.value",
ElasticsearchProjectionConstants.TOOK,
ElasticsearchProjectionConstants.TIMED_OUT
)
.list();
assertThat( result ).hasSize( 1 );
Calendar dob = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ), Locale.ENGLISH );
dob.set( 1958, 3, 7, 0, 0, 0 );
dob.set( Calendar.MILLISECOND, 0 );
Object[] projection = (Object[]) result.iterator().next();
assertThat( projection[0] ).describedAs( "id" ).isEqualTo( 1L );
assertThat( projection[1] ).describedAs( "object class" ).isEqualTo( GolfPlayer.class );
assertThat( projection[2] ).describedAs( "score" ).isInstanceOf( Float.class );
assertThat( projection[3] ).describedAs( "this" ).isInstanceOf( GolfPlayer.class );
assertThat( ( (GolfPlayer) projection[3] ).getId() ).isEqualTo( 1L );
assertThat( projection[4] ).describedAs( "firstName" ).isEqualTo( "Klaus" );
assertThat( projection[5] ).describedAs( "lastName" ).isEqualTo( "Hergesheimer" );
assertThat( projection[6] ).describedAs( "active" ).isEqualTo( true );
assertThat( projection[7] ).describedAs( "dateOfBirth" ).isEqualTo( dob.getTime() );
assertThat( projection[8] ).describedAs( "handicap" ).isEqualTo( 3.4D );
assertThat( projection[9] ).describedAs( "driveWidth" ).isEqualTo( 285 );
assertThat( projection[10] ).describedAs( "ranking value" ).isEqualTo( BigInteger.valueOf( 311 ) );
assertThat( projection[11] ).describedAs( "took" ).isInstanceOf( Integer.class );
assertThat( (Integer) projection[11] ).describedAs( "took" ).isGreaterThanOrEqualTo( 0 );
assertThat( projection[12] ).describedAs( "timeout" ).isEqualTo( Boolean.FALSE );
tx.commit();
s.close();
}
@Test
public void testQueryById() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson(
"{" +
"'query': {" +
"'ids' : {" +
"'values' : ['1', '3']" +
"}" +
"}" +
"}"
);
List<?> result = session.createFullTextQuery( query, ScientificArticle.class ).list();
assertThat( result ).onProperty( "title" ).containsOnly(
"ORM for dummies",
"ORM for beginners"
);
query = ElasticsearchQueries.fromQueryString( "_id:1 OR _id:3" );
result = session.createFullTextQuery( query, ScientificArticle.class ).list();
assertThat( result ).onProperty( "title" ).containsOnly(
"ORM for dummies",
"ORM for beginners"
);
tx.commit();
s.close();
}
@Test
public void testStringMappedNumericProperty() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'puttingStrength' : '2.5' } } }" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection( ElasticsearchProjectionConstants.ID, "puttingStrength" )
.list();
assertThat( result ).hasSize( 1 );
Object[] projection = (Object[]) result.iterator().next();
assertThat( projection[0] ).isEqualTo( 1L );
assertThat( projection[1] ).isEqualTo( 2.5D );
tx.commit();
s.close();
}
@Test
public void testBooleanProperty() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'term' : { 'active' : 'true' } } }" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection( ElasticsearchProjectionConstants.ID )
.list();
assertThat( result ).hasSize( 1 );
Object[] projection = (Object[]) result.iterator().next();
assertThat( projection[0] ).isEqualTo( 1L );
tx.commit();
s.close();
}
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class[] { ScientificArticle.class, Tower.class, Address.class, Country.class, State.class, StateCandidate.class, ResearchPaper.class,
BachelorThesis.class, MasterThesis.class, GolfPlayer.class, GolfCourse.class, Hole.class };
}
}