Date Usage with Hibernate Search


#1

I have tried to index Date type field of entity with multiple ways and one which worked successfully is

@Temporal(TemporalType.DATE)
@Column(name = "AUTO_REVERSAL_DATE")
@Field(store=Store.NO,index=Index.YES,analyze=Analyze.NO)
@DateBridge(resolution=Resolution.DAY,encoding=EncodingType.NUMERIC)
private Date autoReversalDate;

Now, the problem is that when search is made on the indexed data, it is retrieving date+1 record.

Calendar c1 = Calendar.getInstance();
c1.set(2017, 04, 23); // Trying to search data for 23rd May 2017, but actually returning for 24th May 2017.
Date fromAutoReversalDate = DateTools.round( c1.getTime(), DateTools.Resolution.DAY );
org.apache.lucene.search.Query luceneQuery2 = qb.keyword().onField("autoReversalDate").matching(fromAutoReversalDate).createQuery();
javax.persistence.Query jpaQuery = fullTextEntityManager.createFullTextQuery(luceneQuery2, ReceivableInstructionMain.class);
FullTextQuery a  = (FullTextQuery)jpaQuery;
System.out.println("TOTAL LUCENE RECORDS - "+a.getResultSize()); ---- O/P is 32

From DB, actual result is:

SELECT count(1) FROM RECEIVABLE_INSTRUCTION WHERE AUTO_REVERSAL_DATE = '24-MAY-2017'; --- 32
SELECT count(1) FROM RECEIVABLE_INSTRUCTION WHERE AUTO_REVERSAL_DATE = '23-MAY-2017'; --- 4

How date field should be indexed actually to get correct result?


#2

I’ve had similar issues with the default date bridge when using resolution. It’s a complicated problem, but in essence it has to do with the timezone used to truncate the date to a specific day. If you truncate the same date to the day with two different timezones, you may get different results, since some timezones will be in a different day.

Here, you’re truncating a date created with the default JVM timezone (that’s what Calendar.getInstance() uses), and Hibernate Search will truncate it again when building the query. Which may explain that you’re one day off.

I would suggest to remove the DateTools.round call on your side, and see what happens when you rely on Hibernate Search to get it right.

It’s quite hard to get right, which is why I generally prefer not using the @DateBridge.resolution parameter. An alternative option is for you to use range queries, requesting dates between the day you want at midnight and the next day at midnight. However, it’s not really easy to do with the legacy date/time APIs; it would be much easier with java.time types, such as LocalDate, LocalDateTime or Instant.


#3

When DateTools.round is removed, 0 records are returned.
Calendar c1 = Calendar.getInstance();
c1.set(2017, 04, 23); // Trying to search data for 23rd May 2017, but actually returning for 24th May 2017.
//Date fromAutoReversalDate = DateTools.round( c1.getTime(), DateTools.Resolution.DAY );
org.apache.lucene.search.Query luceneQuery2 = qb.keyword().onField(“autoReversalDate”).matching(c1.getTime()).createQuery();
javax.persistence.Query jpaQuery = fullTextEntityManager.createFullTextQuery(luceneQuery2, ReceivableInstructionMain.class);
FullTextQuery a = (FullTextQuery)jpaQuery;
System.out.println("TOTAL LUCENE RECORDS - "+a.getResultSize()); ---- O/P is 0


#4

I just had a closer look… And indeed, resolution is not taken into account by HSearch when querying, due to implementation issues that cannot be solved in Search 5.

Did you try to remove the resolution option on your @DateBridge? I suspect your dates are already set to midnight on a timezone that is not UTC, causing the DateTools.round to round to a different day.

If that still doesn’t work, do not add the resolution option, but try to create range queries this way:

	private org.apache.lucene.search.Query createDayQuery(QueryBuilder queryBuilder, String fieldName, Date date) {
		ZoneId zone = ZoneId.systemDefault(); // Assuming that's what being used in the rest of the application
		return createDateQuery( queryBuilder, fieldName, date, zone, ChronoUnit.DAYS );
	}

	private org.apache.lucene.search.Query createDateQuery(QueryBuilder queryBuilder, String fieldName, Date date,
			ZoneId zone, TemporalUnit truncationUnit) {
		ZonedDateTime zonedDateTime = date.toInstant().atZone( zone );
		ZonedDateTime start = zonedDateTime.truncatedTo( truncationUnit );
		ZonedDateTime end = start.plus( 1, truncationUnit );
		return queryBuilder.range().onField( fieldName )
				.from( Date.from( start.toInstant() ) )
				.to( Date.from( end.toInstant() ) ).excludeLimit()
				.createQuery();
	}

// Then use it...
 Calendar c1 = Calendar.getInstance();
c1.set(2017, 04, 23); // Trying to search data for 23rd May 2017
Date searchedTime = c1.getTime();
org.apache.lucene.search.Query luceneQuery2 = createDayQuery( qb, “autoReversalDate” searchedTime );
javax.persistence.Query jpaQuery = fullTextEntityManager.createFullTextQuery(luceneQuery2, ReceivableInstructionMain.class);
FullTextQuery a = (FullTextQuery)jpaQuery;
System.out.println("TOTAL LUCENE RECORDS - "+a.getResultSize());

#5

Thanks yrodiere for the solution, it worked with default timezone.
Need to test with multi time zone data and will let you know in case of any further issue.