/*
* 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 java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import org.hibernate.Session;
import org.hibernate.Transaction;
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.testutil.JsonHelper;
import org.hibernate.search.elasticsearch.testutil.TestElasticsearchClient;
import org.hibernate.search.elasticsearch.testutil.junit.SkipOnElasticsearch2;
import org.hibernate.search.elasticsearch.util.impl.ElasticsearchDateHelper;
import org.hibernate.search.query.engine.spi.QueryDescriptor;
import org.hibernate.search.test.SearchTestBase;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* @author Gunnar Morling
*/
@Category(SkipOnElasticsearch2.class)
public class Elasticsearch5IndexMappingIT extends SearchTestBase {
@Rule
public TestElasticsearchClient elasticsearchClient = new TestElasticsearchClient();
@Before
public void setupTestData() {
Session s = openSession();
Transaction tx = s.beginTransaction();
Calendar dob = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ), Locale.ENGLISH );
dob.set( 1958, 3, 7, 0, 0, 0 );
dob.set( Calendar.MILLISECOND, 0 );
Calendar subscriptionEndDate = GregorianCalendar.getInstance( TimeZone.getTimeZone( "Europe/Paris" ), Locale.FRENCH );
subscriptionEndDate.set( 2016, 5, 7, 4, 4, 4 );
GolfPlayer hergesheimer = new GolfPlayer.Builder()
.firstName( "Klaus" )
.lastName( "Hergesheimer" )
.active( true )
.dateOfBirth( dob.getTime() )
.subscriptionEndDate( subscriptionEndDate )
.handicap( 3.4 )
.puttingStrength( 2.5 )
.driveWidth( 285 )
.strength( "precision" )
.strength( "willingness" )
.strength( "stamina" )
.build();
s.persist( hergesheimer );
GolfPlayer galore = new GolfPlayer.Builder()
.lastName( "Galore" )
.ranking( 311 )
.build();
s.persist( galore );
GolfPlayer kidd = new GolfPlayer.Builder()
.lastName( "Kidd" )
.build();
s.persist( kidd );
GolfCourse purbeck = new GolfCourse(
"Purbeck",
127.3,
new Hole( 433, (byte) 4 ), new Hole( 163, (byte) 3 )
);
s.persist( purbeck );
GolfCourse mountMaja = new GolfCourse(
"Mount Maja",
111.9,
new Hole( 512, (byte) 5 ), new Hole( 113, (byte) 3 )
);
s.persist( mountMaja );
GolfPlayer brand = new GolfPlayer.Builder()
.lastName( "Brand" )
.playedCourses( purbeck, mountMaja )
.wonCourses( purbeck, mountMaja )
.build();
s.persist( brand );
purbeck.getPlayedBy().add( brand );
mountMaja.getPlayedBy().add( brand );
s.persist( brand );
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 testMapping() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
// Check the generated mapping
JsonHelper.assertJsonEquals(
"{" +
"'dynamic':'strict'," +
"'properties':{" +
"'active':{" +
"'type':'boolean'," +
"'null_value':false" +
"}," +
"'age':{" +
"'type':'integer'" +
"}," +
"'dateOfBirth':{" +
"'type':'date'," +
"'null_value': '" + toElasticsearchDateHelperDateString("1970-01-01+00:00") + "'" +
"}," +
"'driveWidth':{" +
"'type':'integer'," +
"'null_value':-1" +
"}," +
"'firstName':{" +
"'type':'text'" +
"}," +
"'fullName':{" +
"'type':'text'" +
"}," +
"'fullNameStored':{" +
"'type':'keyword'," +
"'index':false," +
"'store':true" +
"}," +
"'handicap':{" +
"'type':'double'" +
"}," +
"'id':{" +
"'type':'keyword'," +
"'store':true" +
"}," +
"'lastName':{" +
"'type':'text'" +
"}," +
"'playedCourses':{" +
"'properties':{" +
"'holes':{" +
"'properties':{" +
"'length':{" +
"'type':'integer'" +
"}," +
"'par':{" +
"'type':'integer'" +
"}" +
"}" +
"}," +
"'name':{" +
"'type':'text'" +
"}," +
"'rating':{" +
"'type':'double'" +
"}" +
"}" +
"}," +
"'puttingStrength':{" +
"'type':'text'" +
"}," +
"'ranking':{" +
"'properties':{" +
"'value':{" +
"'type':'text'" +
"}" +
"}" +
"}," +
"'strengths':{" +
"'type':'text'" +
"}," +
"'subscriptionEndDate':{" +
"'type':'date'," +
"'null_value': '" + toElasticsearchDateHelperDateString("1970-01-01+00:00") + "'" +
"}," +
"'won_holes':{" +
"'properties':{" +
"'length':{" +
"'type':'integer'" +
"}," +
"'par':{" +
"'type':'integer'" +
"}" +
"}" +
"}," +
"'won_name':{" +
"'type':'text'" +
"}," +
"'won_rating':{" +
"'type':'double'" +
"}" +
"}" +
"}",
elasticsearchClient.index( "golfplayer" ).type( GolfPlayer.class.getName() ).getMapping()
);
// Check we send correctly formatted data when indexing
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'lastName' : 'Hergesheimer' } } }" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection( ElasticsearchProjectionConstants.SOURCE )
.list();
String source = (String) ( (Object[]) result.iterator().next() )[0];
JsonHelper.assertJsonEqualsIgnoringUnknownFields(
"{" +
"\"active\": true," +
"\"dateOfBirth\": \"1958-04-07T00:00:00Z\"," +
"\"subscriptionEndDate\": \"2016-06-07T02:00:00+02:00\"," +
"\"driveWidth\": 285," +
"\"firstName\": \"Klaus\"," +
"\"handicap\": 3.4," +
"\"lastName\": \"Hergesheimer\"," +
"\"fullName\": \"Klaus Hergesheimer\"," +
"\"age\": 34," +
"\"puttingStrength\": \"2.5\"" +
"}",
source
);
tx.commit();
s.close();
}
/*
* Allows generating a date exactly as it would be outputed by the Elasticsearch date Helper.
* This helper internally uses the JVM's timezone to format dates, so the actual output
* depends on the platform and cannot be stored as a constant string.
*/
private String toElasticsearchDateHelperDateString(String string) {
Date date = ElasticsearchDateHelper.stringToDate( string );
return ElasticsearchDateHelper.dateToString( date );
}
@Test
public void testEmbeddedMapping() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'lastName' : 'Galore' } } }" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection( ElasticsearchProjectionConstants.SOURCE )
.list();
String source = (String) ( (Object[]) result.iterator().next() )[0];
JsonHelper.assertJsonEqualsIgnoringUnknownFields(
"{" +
"\"lastName\": \"Galore\"," +
"\"ranking\": {" +
"\"value\": \"311\"" +
"}" +
"}",
source
);
tx.commit();
s.close();
}
@Test
public void testElementCollectionOfBasicTypeMapping() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'lastName' : 'Hergesheimer' } } }" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection( ElasticsearchProjectionConstants.SOURCE )
.list();
String source = (String) ( (Object[]) result.iterator().next() )[0];
JsonHelper.assertJsonEqualsIgnoringUnknownFields(
"{" +
"\"lastName\": \"Hergesheimer\"," +
"\"strengths\": [" +
"\"willingness\", \"precision\", \"stamina\"" +
"]" +
"}",
source
);
tx.commit();
s.close();
}
@Test
public void testEmbeddedListOfEntityMapping() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'lastName' : 'Brand' } } }" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection( ElasticsearchProjectionConstants.SOURCE )
.list();
String source = (String) ( (Object[]) result.iterator().next() )[0];
JsonHelper.assertJsonEqualsIgnoringUnknownFields(
"{" +
"'lastName' : 'Brand'," +
"'playedCourses': [" +
"{" +
"'name' : 'Purbeck'," +
"'rating' : 127.3, " +
"'holes': [" +
"{ 'par' : 4, 'length' : 433 }," +
"{ 'par' : 3, 'length' : 163 }" +
"]" +
"}," +
"{" +
"'name' : 'Mount Maja'," +
"'rating' : 111.9, " +
"'holes': [" +
"{ 'par' : 5, 'length' : 512 }," +
"{ 'par' : 3, 'length' : 113 }" +
"]" +
"}" +
"]," +
"'won_name': ['Purbeck', 'Mount Maja']," +
"'won_rating': [127.3, 111.9]," +
"'won_holes': [" +
"[" +
"{ 'par' : 4, 'length' : 433 }," +
"{ 'par' : 3, 'length' : 163 }" +
"], [" +
"{ 'par' : 5, 'length' : 512 }," +
"{ 'par' : 3, 'length' : 113 }" +
"]" +
"]" +
"}",
source
);
tx.commit();
s.close();
}
@Test
public void testEmbeddedListOfEntityWithPrefixMapping() throws Exception {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromJson( "{ 'query': { 'match' : { 'lastName' : 'Brand' } } }" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection( ElasticsearchProjectionConstants.SOURCE )
.list();
String source = (String) ( (Object[]) result.iterator().next() )[0];
JsonHelper.assertJsonEqualsIgnoringUnknownFields(
"{" +
"'lastName' : 'Brand'," +
"'playedCourses': [" +
"{" +
"'name' : 'Purbeck'," +
"'rating' : 127.3, " +
"'holes': [" +
"{ 'par' : 4, 'length' : 433 }," +
"{ 'par' : 3, 'length' : 163 }" +
"]" +
"}," +
"{" +
"'name' : 'Mount Maja'," +
"'rating' : 111.9, " +
"'holes': [" +
"{ 'par' : 5, 'length' : 512 }," +
"{ 'par' : 3, 'length' : 113 }" +
"]" +
"}" +
"]" +
"}",
source
);
tx.commit();
s.close();
}
@Test
public void testNullTokenMapping() {
Session s = openSession();
FullTextSession session = Search.getFullTextSession( s );
Transaction tx = s.beginTransaction();
QueryDescriptor query = ElasticsearchQueries.fromQueryString( "lastName:Kidd" );
List<?> result = session.createFullTextQuery( query, GolfPlayer.class )
.setProjection( ElasticsearchProjectionConstants.SOURCE )
.list();
String source = (String) ( (Object[]) result.iterator().next() )[0];
JsonHelper.assertJsonEquals(
"{" +
"\"active\": null," +
"\"dateOfBirth\": null," +
"\"subscriptionEndDate\":null," +
"\"driveWidth\": null," +
"\"firstName\": <NULL>," +
"\"handicap\": 0.0," + // not nullable
"\"id\": '3'," +
"\"puttingStrength\": \"0.0\"," + // not nullable
"\"lastName\": \"Kidd\"," +
"\"fullName\": \"Kidd\"," +
"\"fullNameStored\": \"Kidd\"" +
// ranking.value is null but indexNullAs() has not been given, so it's
// not present in the index at all
// "\"ranking\": {" +
// "\"value\": ..." +
// "}" +
"}",
source
);
tx.commit();
s.close();
}
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class[] { GolfPlayer.class, GolfCourse.class, Hole.class };
}
}