Skip to content

Commit

Permalink
Merge pull request #528 from egovernments/dev
Browse files Browse the repository at this point in the history
dev -> master:proximity based search
  • Loading branch information
kavi-egov authored Oct 19, 2023
2 parents 351fdf3 + eeca8a8 commit d0943ed
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega
Set<String> finalBucketKeys = new LinkedHashSet<>();

// For multi aggr, find all plot keys first
// enrichBucketKeys(aggrNodes, finalBucketKeys, interval);
enrichBucketKeys(aggrNodes, finalBucketKeys, interval, startDate, isPredictionEnabled);
initializeMultiAggrPlotMap(multiAggrPlotMap, finalBucketKeys);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,3 @@ private static boolean doesTextExistInArrayNode(ArrayNode arrayNode, String sear
return false;
}
}

8 changes: 7 additions & 1 deletion health-services/household/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
All notable changes to this module will be documented in this file.

## 1.1.1-beta

- Added proximity based search support

## 1.1.0


## 1.0.0

- Base version

## 1.1.0
4 changes: 2 additions & 2 deletions health-services/household/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<artifactId>household</artifactId>
<packaging>jar</packaging>
<name>household</name>
<version>1.1.0</version>
<version>1.1.1-beta</version>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
Expand Down Expand Up @@ -49,7 +49,7 @@
<dependency>
<groupId>org.egov.common</groupId>
<artifactId>health-services-models</artifactId>
<version>1.0.7-SNAPSHOT</version>
<version>1.0.9-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
@Slf4j
public class HouseholdRepository extends GenericRepository<Household> {

private final String searchCriteriaWaypointQuery = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))\n";
private final String calculateDistanceFromTwoWaypointsFormulaQuery = "( 6371.4 * acos (LEAST (GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) ) + sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance ";
@Autowired
protected HouseholdRepository(Producer producer,
NamedParameterJdbcTemplate namedParameterJdbcTemplate,
Expand Down Expand Up @@ -88,4 +90,41 @@ public List<Household> find(HouseholdSearch searchObject, Integer limit, Integer
paramsMap.put("offset", offset);
return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper);
}

/**
* @param searchObject
* @param limit
* @param offset
* @param tenantId
* @param includeDeleted
* @return
* @throws QueryBuilderException
*
* Fetch all the household which falls under the radius provided using longitude and latitude provided.
*/
public List<Household> findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException {
String query = searchCriteriaWaypointQuery +
"SELECT * FROM (SELECT h.*, a.*, " + calculateDistanceFromTwoWaypointsFormulaQuery + " \n" +
"FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw ";
Map<String, Object> paramsMap = new HashMap<>();
List<String> whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap);
query = GenericQueryBuilder.generateQuery(query, whereFields).toString();
query = query.replace("id IN (:id)", "h.id IN (:id)");
query = query.replace("clientReferenceId IN (:clientReferenceId)", "h.clientReferenceId IN (:clientReferenceId)");
query = query + " and h.tenantId=:tenantId ";
if (Boolean.FALSE.equals(includeDeleted)) {
query = query + "and isDeleted=:isDeleted ";
}
query = query + " ) AS rt ";
query = query + " WHERE distance < :distance ";
query = query + " ORDER BY distance ASC LIMIT :limit OFFSET :offset ";
paramsMap.put("s_latitude", searchObject.getLatitude());
paramsMap.put("s_longitude", searchObject.getLongitude());
paramsMap.put("tenantId", tenantId);
paramsMap.put("isDeleted", includeDeleted);
paramsMap.put("distance", searchObject.getSearchRadius());
paramsMap.put("limit", limit);
paramsMap.put("offset", offset);
return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ public List<Household> search(HouseholdSearch householdSearch, Integer limit, In
log.info("households found for search by id, size: {}", households.size());
return households;
}
if(isProximityBasedSearch(householdSearch)) {
try {
List<Household> households = householdRepository.findByRadius(householdSearch, limit, offset, tenantId, includeDeleted);
log.info("households found for search, size: {}", households.size());
return households;
} catch (QueryBuilderException e) {
log.error("error occurred while searching households", e);
throw new CustomException("ERROR_IN_QUERY", e.getMessage());
}
}
try {
List<Household> households = householdRepository.find(householdSearch, limit, offset,
tenantId, lastChangedSince, includeDeleted);
Expand Down Expand Up @@ -231,4 +241,7 @@ private Tuple<List<Household>, Map<Household, ErrorDetails>> validate(List<Valid
return new Tuple<>(validHouseholds, errorDetailsMap);
}

private Boolean isProximityBasedSearch(HouseholdSearch householdSearch) {
return householdSearch.getLatitude() != null && householdSearch.getLongitude() != null && householdSearch.getSearchRadius() != null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.egov.common.data.query.annotations.Exclude;
import org.egov.common.data.query.annotations.Table;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import java.util.List;

/**
Expand Down Expand Up @@ -38,5 +41,25 @@ public class HouseholdSearch {

@JsonProperty("boundaryCode")
private String localityCode = null;

@Exclude
@JsonProperty("latitude")
@DecimalMin("-90")
@DecimalMax("90")
private Double latitude = null;

@Exclude
@JsonProperty("longitude")
@DecimalMin("-180")
@DecimalMax("180")
private Double longitude = null;

/*
* @value unit of measurement in Kilometer
* */
@Exclude
@JsonProperty("searchRadius")
@DecimalMin("0")
private Double searchRadius = null;
}

8 changes: 7 additions & 1 deletion health-services/individual/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
All notable changes to this module will be documented in this file.

## 1.1.2-beta

- Added proximity based search support

## 1.1.0


## 1.0.0

- Base version

## 1.1.0
4 changes: 2 additions & 2 deletions health-services/individual/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<artifactId>individual</artifactId>
<packaging>jar</packaging>
<name>individual</name>
<version>1.1.1</version>
<version>1.1.2-beta</version>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
Expand Down Expand Up @@ -49,7 +49,7 @@
<dependency>
<groupId>org.egov.common</groupId>
<artifactId>health-services-models</artifactId>
<version>1.0.7-SNAPSHOT</version>
<version>1.0.9-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
Expand All @@ -38,6 +39,9 @@
@Slf4j
public class IndividualRepository extends GenericRepository<Individual> {

private final String cteQuery = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))";
private final String calculateDistanceFromTwoWaypointsFormulaQuery = "( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance ";

protected IndividualRepository(@Qualifier("individualProducer") Producer producer,
NamedParameterJdbcTemplate namedParameterJdbcTemplate,
RedisTemplate<String, Object> redisTemplate,
Expand Down Expand Up @@ -79,6 +83,10 @@ public List<Individual> find(IndividualSearch searchObject, Integer limit, Integ
Map<String, Object> paramsMap = new HashMap<>();
String query = getQueryForIndividual(searchObject, limit, offset, tenantId, lastChangedSince,
includeDeleted, paramsMap);
if (isProximityBasedSearch(searchObject)) {
List<Individual> individuals = findByRadius(query, searchObject, includeDeleted, paramsMap);
return individuals;
}
if (searchObject.getIdentifier() == null) {
List<Individual> individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper);
if (!individuals.isEmpty()) {
Expand Down Expand Up @@ -113,6 +121,77 @@ public List<Individual> find(IndividualSearch searchObject, Integer limit, Integ
}
}

/**
* @param query
* @param searchObject
* @param includeDeleted
* @param paramsMap
* @return
*
* Fetch all the household which falls under the radius provided using longitude and latitude provided.
*/
public List<Individual> findByRadius(String query, IndividualSearch searchObject, Boolean includeDeleted, Map<String, Object> paramsMap) {
query = query.replace("LIMIT :limit OFFSET :offset", "");
paramsMap.put("s_latitude", searchObject.getLatitude());
paramsMap.put("s_longitude", searchObject.getLongitude());
if (searchObject.getIdentifier() != null) {
Map<String, Object> identifierParamMap = new HashMap<>();
String identifierQuery = getIdentifierQuery(searchObject.getIdentifier(), identifierParamMap);
identifierParamMap.put("isDeleted", includeDeleted);
List<Identifier> identifiers = this.namedParameterJdbcTemplate
.query(identifierQuery, identifierParamMap, new IdentifierRowMapper());
if (CollectionUtils.isEmpty(identifiers)) {
query = query.replace(" tenantId=:tenantId ", " tenantId=:tenantId AND id=:individualId ");
paramsMap.put("individualId", identifiers.stream().findAny().get().getIndividualId());
query = cteQuery + ", cte_individual AS (" + query + ")";
query = query + "SELECT * FROM (SELECT cte_i.*, " + calculateDistanceFromTwoWaypointsFormulaQuery
+" FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt ";
if(searchObject.getSearchRadius() != null) {
query = query + " WHERE rt.distance < :distance ";
}
query = query + " ORDER BY distance ASC ";
query = query + "LIMIT :limit OFFSET :offset";
paramsMap.put("distance", searchObject.getSearchRadius());
List<Individual> individuals = this.namedParameterJdbcTemplate.query(query,
paramsMap, this.rowMapper);
if (!individuals.isEmpty()) {
individuals.forEach(individual -> {
individual.setIdentifiers(identifiers);
List<Address> addresses = getAddressForIndividual(individual.getId(), includeDeleted);
individual.setAddress(addresses);
Map<String, Object> indServerGenIdParamMap = new HashMap<>();
indServerGenIdParamMap.put("individualId", individual.getId());
indServerGenIdParamMap.put("isDeleted", includeDeleted);
enrichSkills(includeDeleted, individual, indServerGenIdParamMap);
});
}
return individuals;
}
} else {
query = cteQuery + ", cte_individual AS (" + query + ")";
query = query + "SELECT * FROM (SELECT cte_i.*, "+ calculateDistanceFromTwoWaypointsFormulaQuery
+" FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt ";
if(searchObject.getSearchRadius() != null) {
query = query + " WHERE rt.distance < :distance ";
}
query = query + " ORDER BY distance ASC ";
query = query + "LIMIT :limit OFFSET :offset";
paramsMap.put("distance", searchObject.getSearchRadius());
List<Individual> individuals = this.namedParameterJdbcTemplate.query(query,
paramsMap, this.rowMapper);
if (!individuals.isEmpty()) {
enrichIndividuals(individuals, includeDeleted);
}
return individuals;
}
return Collections.emptyList();
}


private Boolean isProximityBasedSearch(IndividualSearch searchObject) {
return searchObject.getLatitude() != null && searchObject.getLongitude() != null && searchObject.getSearchRadius() != null;
}

private void enrichSkills(Boolean includeDeleted, Individual individual, Map<String, Object> indServerGenIdParamMap) {
String individualSkillQuery = getQuery("SELECT * FROM individual_skill WHERE individualId =:individualId",
includeDeleted);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
Expand Down Expand Up @@ -96,5 +98,26 @@ public class IndividualSearch {
@Exclude
@JsonProperty("userId")
private Long userId;

@Exclude
@JsonProperty("latitude")
@DecimalMin("-90")
@DecimalMax("90")
private Double latitude;

@Exclude
@JsonProperty("longitude")
@DecimalMin("-180")
@DecimalMax("180")
private Double longitude;

/*
* @value unit of measurement in Kilometer
* */
@Exclude
@JsonProperty("searchRadius")
@DecimalMin("0")
private Double searchRadius;

}

0 comments on commit d0943ed

Please sign in to comment.