diff --git a/src/main/java/org/openelisglobal/hibernate/search/massindexer/AutoMassIndexer.java b/src/main/java/org/openelisglobal/hibernate/search/massindexer/AutoMassIndexer.java new file mode 100644 index 0000000000..58b68a51f0 --- /dev/null +++ b/src/main/java/org/openelisglobal/hibernate/search/massindexer/AutoMassIndexer.java @@ -0,0 +1,33 @@ +package org.openelisglobal.hibernate.search.massindexer; + +import org.openelisglobal.common.log.LogEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +@Component +public class AutoMassIndexer implements ApplicationListener { + + @Autowired + MassIndexerService massIndexerService; + + private static boolean alreadyIndexed = false; + + public void onApplicationEvent(ContextRefreshedEvent event) { + if (alreadyIndexed) { + return; + } + try { + LogEvent.logInfo(this.getClass().getSimpleName(), "onApplicationEvent", + "Started Rebuilding Lucene Indexes "); + massIndexerService.reindex(); + alreadyIndexed = true; + LogEvent.logInfo(this.getClass().getSimpleName(), "onApplicationEvent", + "Finished Rebuilding Lucene Indexes "); + } catch (Exception e) { + LogEvent.logDebug(e); + } + + } +} diff --git a/src/main/java/org/openelisglobal/qaevent/controller/rest/ReportNonConformEventsRestController.java b/src/main/java/org/openelisglobal/qaevent/controller/rest/ReportNonConformEventsRestController.java index 6fd6e4e798..01a484a98f 100644 --- a/src/main/java/org/openelisglobal/qaevent/controller/rest/ReportNonConformEventsRestController.java +++ b/src/main/java/org/openelisglobal/qaevent/controller/rest/ReportNonConformEventsRestController.java @@ -84,6 +84,7 @@ public ResponseEntity getNCESampleSearch(@RequestParam(required = false) Stri return ResponseEntity.ok().body(temp); } } catch (Exception e) { + e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("An error occurred while processing the request."); } diff --git a/src/main/java/org/openelisglobal/sample/dao/SearchResultsDAO.java b/src/main/java/org/openelisglobal/sample/dao/SearchResultsDAO.java index 5c29b0c65e..fb3c937c9f 100644 --- a/src/main/java/org/openelisglobal/sample/dao/SearchResultsDAO.java +++ b/src/main/java/org/openelisglobal/sample/dao/SearchResultsDAO.java @@ -21,6 +21,7 @@ public interface SearchResultsDAO { String ID_TYPE_FOR_ST = "stNumberId"; String ID_TYPE_FOR_SUBJECT_NUMBER = "subjectNumberId"; String ID_TYPE_FOR_GUID = "guidId"; + String ID_LIST = "idList"; public List getSearchResults(String lastName, String firstName, String STNumber, String subjectNumber, String nationalID, String externalID, String patientID, String guid, diff --git a/src/main/java/org/openelisglobal/sample/daoimpl/DBSearchResultsDAOImpl.java b/src/main/java/org/openelisglobal/sample/daoimpl/DBSearchResultsDAOImpl.java index a3239052cd..a2419ffd65 100644 --- a/src/main/java/org/openelisglobal/sample/daoimpl/DBSearchResultsDAOImpl.java +++ b/src/main/java/org/openelisglobal/sample/daoimpl/DBSearchResultsDAOImpl.java @@ -30,12 +30,10 @@ import org.openelisglobal.common.util.DateUtil; import org.openelisglobal.patientidentitytype.util.PatientIdentityTypeMap; import org.openelisglobal.sample.dao.SearchResultsDAO; -import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component -@Primary public class DBSearchResultsDAOImpl implements SearchResultsDAO { @PersistenceContext diff --git a/src/main/java/org/openelisglobal/sample/daoimpl/LuceneSearchResultsDAOImpl.java b/src/main/java/org/openelisglobal/sample/daoimpl/LuceneSearchResultsDAOImpl.java index 34db90384d..d146be37f3 100644 --- a/src/main/java/org/openelisglobal/sample/daoimpl/LuceneSearchResultsDAOImpl.java +++ b/src/main/java/org/openelisglobal/sample/daoimpl/LuceneSearchResultsDAOImpl.java @@ -14,12 +14,17 @@ import org.hibernate.search.mapper.orm.session.SearchSession; import org.openelisglobal.common.exception.LIMSRuntimeException; import org.openelisglobal.common.provider.query.PatientSearchResults; +import org.openelisglobal.common.util.ConfigurationProperties; +import org.openelisglobal.common.util.ConfigurationProperties.Property; +import org.openelisglobal.common.util.DateUtil; import org.openelisglobal.patient.valueholder.Patient; import org.openelisglobal.patientidentitytype.util.PatientIdentityTypeMap; import org.openelisglobal.sample.dao.SearchResultsDAO; +import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; @Component +@Primary public class LuceneSearchResultsDAOImpl implements SearchResultsDAO { @PersistenceContext @@ -33,25 +38,43 @@ public List getSearchResults(String lastName, String first SearchSession searchSession = Search.session(entityManager); + boolean queryFirstName = !GenericValidator.isBlankOrNull(firstName); + boolean queryLastName = !GenericValidator.isBlankOrNull(lastName); + boolean queryNationalId = !GenericValidator.isBlankOrNull(nationalID); + boolean querySTNumber = !GenericValidator.isBlankOrNull(STNumber); + boolean querySubjectNumber = !GenericValidator.isBlankOrNull(subjectNumber); + boolean queryExternalId = !GenericValidator.isBlankOrNull(externalID); + boolean queryPatientID = !GenericValidator.isBlankOrNull(patientID); + boolean queryGuid = !GenericValidator.isBlankOrNull(guid); + boolean queryDateOfBirth = !GenericValidator.isBlankOrNull(dateOfBirth); + boolean queryGender = !GenericValidator.isBlankOrNull(gender); + + // fields searched from DB + nationalID = '%' + nationalID + '%'; + STNumber = '%' + STNumber + '%'; + subjectNumber = '%' + subjectNumber + '%'; + externalID = '%' + externalID + '%'; + List hits = searchSession.search(Patient.class).select(f -> f.id(String.class)).where(f -> f.bool(b -> { - if (!GenericValidator.isBlankOrNull(patientID)) { + if (queryPatientID) { b.must(f.match().field("id").matching(patientID)); } - if (!GenericValidator.isBlankOrNull(gender)) { + if (queryGender) { b.must(f.match().field("gender").matching(gender)); } - if (!GenericValidator.isBlankOrNull(dateOfBirth)) { - b.must(f.match().field("birthDateForDisplay").matching(dateOfBirth)); + if (queryDateOfBirth) { + b.must(f.bool().should(f.match().field("birthDateForDisplay").matching(dateOfBirth)) + .should(f.match().field("birthDateForDisplay").matching(getFormatedDOB(dateOfBirth)))); } - if (!GenericValidator.isBlankOrNull(firstName) && !GenericValidator.isBlankOrNull(lastName)) { + if (queryFirstName && queryLastName) { b.must(f.nested().objectField("person") .nest(f.bool().must(f.match().field("person.firstName").matching(firstName).fuzzy()) .must(f.match().field("person.lastName").matching(lastName).fuzzy()))); } else { - if (!GenericValidator.isBlankOrNull(firstName)) { + if (queryFirstName) { b.must(f.match().field("person.firstName").matching(firstName).fuzzy()); } - if (!GenericValidator.isBlankOrNull(lastName)) { + if (queryLastName) { b.must(f.match().field("person.lastName").matching(lastName).fuzzy()); } } @@ -60,8 +83,10 @@ public List getSearchResults(String lastName, String first List longHits = hits.stream().map(Long::parseLong).collect(Collectors.toList()); // 'IN' predicate requires the list to contain at least one value longHits.add(-1L); + int hitsCount = longHits.size(); - String sqlString = buildQueryString(nationalID, externalID, STNumber, subjectNumber, guid); + String sqlString = buildQueryString(queryNationalId, queryExternalId, querySTNumber, querySubjectNumber, + queryGuid, hitsCount); Query query = entityManager.unwrap(Session.class).createNativeQuery(sqlString); query.setParameter(ID_TYPE_FOR_ST, Integer.valueOf(PatientIdentityTypeMap.getInstance().getIDForType("ST"))); query.setParameter(ID_TYPE_FOR_SUBJECT_NUMBER, @@ -69,22 +94,24 @@ public List getSearchResults(String lastName, String first query.setParameter(ID_TYPE_FOR_GUID, Integer.valueOf(PatientIdentityTypeMap.getInstance().getIDForType("GUID"))); - if (!GenericValidator.isBlankOrNull(nationalID)) { + if (queryNationalId) { query.setParameter(NATIONAL_ID_PARAM, nationalID); } - if (!GenericValidator.isBlankOrNull(externalID)) { + if (queryExternalId) { query.setParameter(EXTERNAL_ID_PARAM, nationalID); } - if (!GenericValidator.isBlankOrNull(STNumber)) { + if (querySTNumber) { query.setParameter(ST_NUMBER_PARAM, STNumber); } - if (!GenericValidator.isBlankOrNull(subjectNumber)) { + if (querySubjectNumber) { query.setParameter(SUBJECT_NUMBER_PARAM, subjectNumber); } - if (!GenericValidator.isBlankOrNull(guid)) { + if (queryGuid) { query.setParameter(GUID, guid); } - query.setParameter("idList", longHits); + if (hitsCount > 1) { + query.setParameter(ID_LIST, longHits); + } List queryResults = query.list(); @@ -119,25 +146,37 @@ public List getSearchResultsExact(String lastName, String SearchSession searchSession = Search.session(entityManager); + boolean queryFirstName = !GenericValidator.isBlankOrNull(firstName); + boolean queryLastName = !GenericValidator.isBlankOrNull(lastName); + boolean queryNationalId = !GenericValidator.isBlankOrNull(nationalID); + boolean querySTNumber = !GenericValidator.isBlankOrNull(STNumber); + boolean querySubjectNumber = !GenericValidator.isBlankOrNull(subjectNumber); + boolean queryExternalId = !GenericValidator.isBlankOrNull(externalID); + boolean queryPatientID = !GenericValidator.isBlankOrNull(patientID); + boolean queryGuid = !GenericValidator.isBlankOrNull(guid); + boolean queryDateOfBirth = !GenericValidator.isBlankOrNull(dateOfBirth); + boolean queryGender = !GenericValidator.isBlankOrNull(gender); + List hits = searchSession.search(Patient.class).select(f -> f.id(String.class)).where(f -> f.bool(b -> { - if (!GenericValidator.isBlankOrNull(patientID)) { + if (queryPatientID) { b.must(f.match().field("id").matching(patientID)); } - if (!GenericValidator.isBlankOrNull(gender)) { + if (queryGender) { b.must(f.match().field("gender").matching(gender)); } - if (!GenericValidator.isBlankOrNull(dateOfBirth)) { - b.must(f.match().field("birthDateForDisplay").matching(dateOfBirth)); + if (queryDateOfBirth) { + b.must(f.bool().should(f.match().field("birthDateForDisplay").matching(dateOfBirth)) + .should(f.match().field("birthDateForDisplay").matching(getFormatedDOB(dateOfBirth)))); } - if (!GenericValidator.isBlankOrNull(firstName) && !GenericValidator.isBlankOrNull(lastName)) { + if (queryFirstName && queryLastName) { b.must(f.nested().objectField("person") .nest(f.bool().must(f.match().field("person.firstName").matching(firstName)) .must(f.match().field("person.lastName").matching(lastName)))); } else { - if (!GenericValidator.isBlankOrNull(firstName)) { + if (queryFirstName) { b.must(f.match().field("person.firstName").matching(firstName)); } - if (!GenericValidator.isBlankOrNull(lastName)) { + if (queryLastName) { b.must(f.match().field("person.lastName").matching(lastName)); } } @@ -146,8 +185,10 @@ public List getSearchResultsExact(String lastName, String List longHits = hits.stream().map(Long::parseLong).collect(Collectors.toList()); // 'IN' predicate requires the list to contain at least one value longHits.add(-1L); + int hitsCount = longHits.size(); - String sqlString = buildQueryString(nationalID, externalID, STNumber, subjectNumber, guid); + String sqlString = buildQueryString(queryNationalId, queryExternalId, querySTNumber, querySubjectNumber, + queryGuid, hitsCount); Query query = entityManager.unwrap(Session.class).createNativeQuery(sqlString); query.setParameter(ID_TYPE_FOR_ST, Integer.valueOf(PatientIdentityTypeMap.getInstance().getIDForType("ST"))); query.setParameter(ID_TYPE_FOR_SUBJECT_NUMBER, @@ -155,22 +196,24 @@ public List getSearchResultsExact(String lastName, String query.setParameter(ID_TYPE_FOR_GUID, Integer.valueOf(PatientIdentityTypeMap.getInstance().getIDForType("GUID"))); - if (!GenericValidator.isBlankOrNull(nationalID)) { + if (queryNationalId) { query.setParameter(NATIONAL_ID_PARAM, nationalID); } - if (!GenericValidator.isBlankOrNull(externalID)) { + if (queryExternalId) { query.setParameter(EXTERNAL_ID_PARAM, nationalID); } - if (!GenericValidator.isBlankOrNull(STNumber)) { + if (querySTNumber) { query.setParameter(ST_NUMBER_PARAM, STNumber); } - if (!GenericValidator.isBlankOrNull(subjectNumber)) { + if (querySubjectNumber) { query.setParameter(SUBJECT_NUMBER_PARAM, subjectNumber); } - if (!GenericValidator.isBlankOrNull(guid)) { + if (queryGuid) { query.setParameter(GUID, guid); } - query.setParameter("idList", longHits); + if (hitsCount > 1) { + query.setParameter(ID_LIST, longHits); + } List queryResults = query.list(); @@ -187,8 +230,8 @@ public List getSearchResultsExact(String lastName, String return patientSearchResultsList; } - private String buildQueryString(String nationalID, String externalID, String STNumber, String subjectNumber, - String guid) { + private String buildQueryString(Boolean queryNationalID, Boolean queryExternalID, Boolean querySTNumber, + Boolean querySubjectNumber, Boolean queryGuid, int hitsCount) { StringBuilder queryBuilder = new StringBuilder(); queryBuilder.append("select p.id, pr.first_name, pr.last_name, p.gender, p.entered_birth_date, p.national_id," @@ -205,22 +248,22 @@ private String buildQueryString(String nationalID, String externalID, String STN queryBuilder.append("where "); queryBuilder.append("( false or "); - if (!GenericValidator.isBlankOrNull(subjectNumber)) { + if (querySubjectNumber) { queryBuilder.append("piSN.identity_data ilike :"); queryBuilder.append(SUBJECT_NUMBER_PARAM).append(" or "); } - if (!GenericValidator.isBlankOrNull(nationalID)) { + if (queryNationalID) { queryBuilder.append("p.national_id ilike :"); queryBuilder.append(NATIONAL_ID_PARAM).append(" or "); } - if (!GenericValidator.isBlankOrNull(externalID)) { + if (queryExternalID) { queryBuilder.append("p.external_id ilike :"); queryBuilder.append(EXTERNAL_ID_PARAM).append(" or "); } - if (!GenericValidator.isBlankOrNull(STNumber)) { + if (querySTNumber) { queryBuilder.append("pi.identity_data ilike :"); queryBuilder.append(ST_NUMBER_PARAM).append(" and "); } @@ -237,15 +280,36 @@ private String buildQueryString(String nationalID, String externalID, String STN queryBuilder.append(") or "); } - if (!GenericValidator.isBlankOrNull(guid)) { + if (queryGuid) { queryBuilder.append("piGUID.identity_data = :"); queryBuilder.append(GUID).append(" and "); } // idList contains patient IDs from Lucene search results matching the fields // id, person.firstName, person.lastName, birthDateForDisplay and gender - queryBuilder.append("p.id in :idList"); + if (hitsCount > 1) { + queryBuilder.append("p.id in :"); + queryBuilder.append(ID_LIST).append(" and "); + } + + // No matter which was added last there is one dangling AND to remove. + lastAndIndex = queryBuilder.lastIndexOf("and"); + lastOrIndex = queryBuilder.lastIndexOf("or"); + if (lastAndIndex > lastOrIndex) { + queryBuilder.delete(lastAndIndex, queryBuilder.length()); + } else if (lastOrIndex > lastAndIndex) { + queryBuilder.delete(lastOrIndex, queryBuilder.length()); + } return queryBuilder.toString(); } + + private String getFormatedDOB(String dob) { + String format1 = "dd/MM/yyyy"; + String format2 = "MM/dd/yyyy"; + String dobFormated = ConfigurationProperties.getInstance().getPropertyValue(Property.DEFAULT_DATE_LOCALE) + .equals("fr-FR") ? DateUtil.formatStringDate(dob, format2) : DateUtil.formatStringDate(dob, format1); + + return dobFormated; + } } diff --git a/src/main/java/org/openelisglobal/search/service/DBSearchResultsServiceImpl.java b/src/main/java/org/openelisglobal/search/service/DBSearchResultsServiceImpl.java index a69834de9b..4aa2deb289 100644 --- a/src/main/java/org/openelisglobal/search/service/DBSearchResultsServiceImpl.java +++ b/src/main/java/org/openelisglobal/search/service/DBSearchResultsServiceImpl.java @@ -4,15 +4,15 @@ import org.openelisglobal.common.provider.query.PatientSearchResults; import org.openelisglobal.sample.dao.SearchResultsDAO; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Primary; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service -@Primary public class DBSearchResultsServiceImpl implements SearchResultsService { @Autowired + @Qualifier("DBSearchResultsDAOImpl") SearchResultsDAO searchResultsDAO; @Override diff --git a/src/main/java/org/openelisglobal/search/service/LuceneSearchResultsServiceImpl.java b/src/main/java/org/openelisglobal/search/service/LuceneSearchResultsServiceImpl.java index 3949cbac83..2d8758b186 100644 --- a/src/main/java/org/openelisglobal/search/service/LuceneSearchResultsServiceImpl.java +++ b/src/main/java/org/openelisglobal/search/service/LuceneSearchResultsServiceImpl.java @@ -6,9 +6,11 @@ import org.openelisglobal.sample.dao.SearchResultsDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; @Service +@Primary public class LuceneSearchResultsServiceImpl implements SearchResultsService { @Autowired diff --git a/src/test/java/org/openelisglobal/search/SearchResultsServiceTest.java b/src/test/java/org/openelisglobal/search/SearchResultsServiceTest.java index 1901eceb75..8c44b89708 100644 --- a/src/test/java/org/openelisglobal/search/SearchResultsServiceTest.java +++ b/src/test/java/org/openelisglobal/search/SearchResultsServiceTest.java @@ -38,6 +38,7 @@ public class SearchResultsServiceTest extends BaseWebContextSensitiveTest { PersonService personService; @Autowired + @Qualifier("DBSearchResultsServiceImpl") SearchResultsService DBSearchResultsServiceImpl; @Autowired