From fc8d8f5540d1a95de76cfecf3183147b0e5cf3a5 Mon Sep 17 00:00:00 2001 From: Jian Date: Fri, 27 Apr 2018 18:36:24 +0200 Subject: [PATCH] Jian | BAH-460 | search patient by name and gender using lucen search --- .../module/bahmnicore/dao/PatientDao.java | 7 ++ .../bahmnicore/dao/impl/PatientDaoImpl.java | 65 +++++++++++++++++++ .../service/BahmniPatientService.java | 2 +- .../impl/BahmniPatientServiceImpl.java | 30 +++++---- .../impl/BahmniPatientDaoImplLuceneIT.java | 31 +++++++++ .../impl/BahmniPatientServiceImplTest.java | 20 ------ .../search/BahmniPatientSearchController.java | 3 +- 7 files changed, 121 insertions(+), 37 deletions(-) diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/PatientDao.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/PatientDao.java index 0516349ff7..21ccafec6d 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/PatientDao.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/PatientDao.java @@ -3,6 +3,7 @@ import org.bahmni.module.bahmnicore.contract.patient.response.PatientResponse; import org.openmrs.Patient; import org.openmrs.RelationshipType; +import org.openmrs.module.emrapi.patient.PatientProfile; import java.util.List; @@ -19,6 +20,12 @@ List getPatientsUsingLuceneSearch(String identifier, String nam String programAttributeFieldName, String[] addressSearchResultFields, String[] patientSearchResultFields, String loginLocationUuid, Boolean filterPatientsByLocation, Boolean filterOnAllIdentifiers); + List getSimilarPatientsUsingLuceneSearch(String identifer, String name, String gender, String customAttribute, + String addressFieldName, String addressFieldValue, Integer length, + Integer offset, String[] customAttributeFields, String programAttributeFieldValue, + String programAttributeFieldName, String[] addressSearchResultFields, + String[] patientSearchResultFields, String loginLocationUuid, Boolean filterPatientsByLocation, Boolean filterOnAllIdentifiers); + public Patient getPatient(String identifier); public List getPatients(String partialIdentifier, boolean shouldMatchExactPatientId); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/PatientDaoImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/PatientDaoImpl.java index f147768b4c..59b1d249be 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/PatientDaoImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/PatientDaoImpl.java @@ -22,8 +22,13 @@ import org.openmrs.Patient; import org.openmrs.PatientIdentifier; import org.openmrs.PatientIdentifierType; +import org.openmrs.Person; +import org.openmrs.PersonName; import org.openmrs.RelationshipType; import org.openmrs.api.context.Context; +import org.openmrs.api.db.hibernate.HibernatePatientDAO; +import org.openmrs.api.db.hibernate.PersonLuceneQuery; +import org.openmrs.api.db.hibernate.search.LuceneQuery; import org.openmrs.module.bahmniemrapi.visitlocation.BahmniVisitLocationServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -100,6 +105,66 @@ public List getPatientsUsingLuceneSearch(String identifier, Str return patientResponses; } + @Override + public List getSimilarPatientsUsingLuceneSearch(String identifier, String name, String gender, String customAttribute, + String addressFieldName, String addressFieldValue, Integer length, + Integer offset, String[] customAttributeFields, String programAttributeFieldValue, + String programAttributeFieldName, String[] addressSearchResultFields, + String[] patientSearchResultFields, String loginLocationUuid, + Boolean filterPatientsByLocation, Boolean filterOnAllIdentifiers) { + + validateSearchParams(customAttributeFields, programAttributeFieldName, addressFieldName); + PatientResponseMapper patientResponseMapper = new PatientResponseMapper(Context.getVisitService(),new BahmniVisitLocationServiceImpl(Context.getLocationService())); + + List patients = getPatientsByNameAndGender(name, gender, length); + List patientIds = patients.stream().map(patient -> patient.getPatientId()).collect(toList()); + Map programAttributes = Context.getService(BahmniProgramWorkflowService.class).getPatientProgramAttributeByAttributeName(patientIds, programAttributeFieldName); + Set uniquePatientIds = new HashSet<>(); + List patientResponses = patients.stream() + .map(patient -> { + if(!uniquePatientIds.contains(patient.getPatientId())) { + PatientResponse patientResponse = patientResponseMapper.map(patient, loginLocationUuid, patientSearchResultFields, addressSearchResultFields, + programAttributes.get(patient.getPatientId())); + uniquePatientIds.add(patient.getPatientId()); + return patientResponse; + }else + return null; + }).filter(Objects::nonNull) + .collect(toList()); + return patientResponses; + } + + + private List getPatientsByNameAndGender(String name, String gender, Integer length) { + HibernatePatientDAO patientDAO = new HibernatePatientDAO(); + patientDAO.setSessionFactory(sessionFactory); + List patients = new ArrayList(); + String query = LuceneQuery.escapeQuery(name); + PersonLuceneQuery personLuceneQuery = new PersonLuceneQuery(sessionFactory); + LuceneQuery nameQuery = personLuceneQuery.getPatientNameQueryWithOrParser(query, false); + /* person.gender does not work somehow in LuceneQuery, so the dirty way is to filter result with person's gender */ + // if(gender != null && !gender.isEmpty()){ + // nameQuery.include("person.gender", gender); + // } + List persons = nameQuery.list().stream() + .filter( + personName -> + personName.getPreferred() + && checkGender(personName.getPerson(), gender) + ).collect(toList()); + persons = persons.subList(0, Math.min(length, persons.size())); + persons.forEach(person -> patients.add(patientDAO.getPatient(person.getPerson().getPersonId()))); + return patients; + } + + private Boolean checkGender(Person person, String gender) { + if(gender != null && !gender.isEmpty()){ + return gender.equals(person.getGender()); + } else { + return true; + } + } + private List getPatientIdentifiers(String identifier, Boolean filterOnAllIdentifiers, Integer offset, Integer length) { FullTextSession fullTextSession = Search.getFullTextSession(sessionFactory.getCurrentSession()); QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(PatientIdentifier.class).get(); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/BahmniPatientService.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/BahmniPatientService.java index dc17ca3b6c..eb598e582b 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/BahmniPatientService.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/BahmniPatientService.java @@ -17,7 +17,7 @@ public interface BahmniPatientService { List luceneSearch(PatientSearchParameters searchParameters); - List searchSimilarPatients(PatientSearchParameters searchParameters, PatientResponseMapper patientResponseMapper); + List searchSimilarPatients(PatientSearchParameters searchParameters); public List get(String partialIdentifier, boolean shouldMatchExactPatientId); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImpl.java index ad2eb52a0a..a2539d3eb9 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImpl.java @@ -90,20 +90,22 @@ public List luceneSearch(PatientSearchParameters searchParamete } @Override - public List searchSimilarPatients(PatientSearchParameters searchParameters, PatientResponseMapper patientResponseMapper) { - List patients = new ArrayList(); - Set persons = personService.getSimilarPeople(searchParameters.getName(), null, searchParameters.getGender()); - for (Person person : persons) { - Patient patient = new Patient(person); - PatientResponse patientResponse = patientResponseMapper.map( - patient, - searchParameters.getLoginLocationUuid(), - searchParameters.getPatientSearchResultFields(), - searchParameters.getAddressSearchResultFields(), - patient.getPatientId()); - patients.add(patientResponse); - } - return patients; + public List searchSimilarPatients(PatientSearchParameters searchParameters) { + return patientDao.getSimilarPatientsUsingLuceneSearch(searchParameters.getIdentifier(), + searchParameters.getName(), + searchParameters.getGender(), + searchParameters.getCustomAttribute(), + searchParameters.getAddressFieldName(), + searchParameters.getAddressFieldValue(), + searchParameters.getLength(), + searchParameters.getStart(), + searchParameters.getPatientAttributes(), + searchParameters.getProgramAttributeFieldValue(), + searchParameters.getProgramAttributeFieldName(), + searchParameters.getAddressSearchResultFields(), + searchParameters.getPatientSearchResultFields(), + searchParameters.getLoginLocationUuid(), + searchParameters.getFilterPatientsByLocation(), searchParameters.getFilterOnAllIdentifiers()); } @Override diff --git a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/dao/impl/BahmniPatientDaoImplLuceneIT.java b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/dao/impl/BahmniPatientDaoImplLuceneIT.java index c02cfc7bc0..1977901fbc 100644 --- a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/dao/impl/BahmniPatientDaoImplLuceneIT.java +++ b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/dao/impl/BahmniPatientDaoImplLuceneIT.java @@ -213,4 +213,35 @@ public void shouldNotReturnDuplicatePatientsEvenIfTwoIdentifiersMatches() { assertTrue(patient.getExtraIdentifiers().contains("200006")); } + @Test + public void shouldSearchSimilarPatientByPatientName() { + String[] addressResultFields = {"city_village"}; + List patients = patientDao.getSimilarPatientsUsingLuceneSearch("", "Peet", "", null, "city_village", "", 100, 0, null,"",null,addressResultFields,null, "c36006e5-9fbb-4f20-866b-0ece245615a1", false, false); + PatientResponse patient1 = patients.get(0); + PatientResponse patient2 = patients.get(1); + + assertEquals(2, patients.size()); + assertEquals(patient1.getGivenName(), "Horatio"); + assertEquals(patient1.getMiddleName(), "Peeter"); + assertEquals(patient1.getFamilyName(), "Sinha"); + assertEquals(patient2.getGivenName(), "John"); + assertEquals(patient2.getMiddleName(), "Peeter"); + assertEquals(patient2.getFamilyName(), "Sinha"); + } + + @Test + public void shouldSearchSimilarPatientByPatientNameAndGender() { + String[] addressResultFields = {"city_village"}; + List patients = patientDao.getSimilarPatientsUsingLuceneSearch("", "Peet", "F", null, "city_village", "", 100, 0, null,"",null,addressResultFields,null, "c36006e5-9fbb-4f20-866b-0ece245615a1", false, false); + PatientResponse patient1 = patients.get(0); + + for(PatientResponse response: patients) { + System.out.println(response.getGivenName() + " " + response.getMiddleName() + " " + response.getFamilyName()); + } + assertEquals(1, patients.size()); + assertEquals(patient1.getGivenName(), "John"); + assertEquals(patient1.getMiddleName(), "Peeter"); + assertEquals(patient1.getFamilyName(), "Sinha"); + } + } diff --git a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImplTest.java b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImplTest.java index 84d45a10ac..4b71241115 100644 --- a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImplTest.java +++ b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImplTest.java @@ -3,21 +3,17 @@ import org.bahmni.module.bahmnicore.contract.patient.PatientSearchParameters; import org.bahmni.module.bahmnicore.contract.patient.mapper.PatientResponseMapper; import org.bahmni.module.bahmnicore.contract.patient.response.PatientConfigResponse; -import org.bahmni.module.bahmnicore.contract.patient.response.PatientResponse; import org.bahmni.module.bahmnicore.dao.PatientDao; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.openmrs.Concept; -import org.openmrs.Person; import org.openmrs.PersonAttributeType; import org.openmrs.api.ConceptService; import org.openmrs.api.PersonService; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import static junit.framework.Assert.assertEquals; import static org.mockito.Mockito.anyInt; @@ -32,10 +28,6 @@ public class BahmniPatientServiceImplTest { private ConceptService conceptService; @Mock private PatientDao patientDao; - @Mock - private PatientSearchParameters searchParameters; - @Mock - private PatientResponseMapper patientResponseMapper; private BahmniPatientServiceImpl bahmniPatientService; @@ -78,16 +70,4 @@ public void shouldGetPatientByPartialIdentifier() throws Exception { verify(patientDao).getPatients("partial_identifier", shouldMatchExactPatientId); } - @Test - public void shouldGetSimiliarPatientResponseFromPersonSet() throws Exception { - Set persons = new HashSet(); - persons.add(new Person()); - persons.add(new Person()); - when(personService.getSimilarPeople(searchParameters.getName(), null, searchParameters.getGender())).thenReturn(persons); - - List response = bahmniPatientService.searchSimilarPatients(searchParameters, patientResponseMapper); - - assertEquals(response.size(), 2); - - } } diff --git a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/search/BahmniPatientSearchController.java b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/search/BahmniPatientSearchController.java index ab443f7b25..6e5b0ba76f 100644 --- a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/search/BahmniPatientSearchController.java +++ b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/search/BahmniPatientSearchController.java @@ -81,8 +81,7 @@ public ResponseEntity> searchSimilarPerson(HttpSer RequestContext requestContext = RestUtil.getRequestContext(request, response); PatientSearchParameters searchParameters = new PatientSearchParameters(requestContext); try { - PatientResponseMapper patientResponseMapper = new PatientResponseMapper(Context.getVisitService(),new BahmniVisitLocationServiceImpl(Context.getLocationService())); - List patients = bahmniPatientService.searchSimilarPatients(searchParameters, patientResponseMapper); + List patients = bahmniPatientService.searchSimilarPatients(searchParameters); AlreadyPaged alreadyPaged = new AlreadyPaged(requestContext, patients, false); return new ResponseEntity(alreadyPaged, HttpStatus.OK); }catch (IllegalArgumentException e){