2011-05-06 2 views
0

내 Grails 1.3.7 애플리케이션에는 이중 위도와 이중 경도를 가진 Building 엔티티가 있습니다. 저는 사용자가있는 지점의 주어진 거리 (십진수로 위도와 경도)로 모든 Building 인스턴스를 찾기 위해 간단한 검색 엔진을 구현하고 있습니다. 나는 http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL이 좋은 이유는 MySQL 데이터베이스를 사용하고 있기 때문입니다. 추가 필터링 및 계산을 수행해야하므로 경계 상자 근사값이 뛰어납니다. 필터링하는 인스턴스의 수를 줄이는 파인더가 필요합니다. 제 질문은 이미 Grails 환경에서 이런 종류의 검색을 구현 ​​한 사람이 있습니까?참조 점으로부터 거리로 모두 찾기

+0

MySQL 공간 데이터 지원 (http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html)을 고려해 보셨습니까? 그리고 Criteria와 SqlRestriction (http://grails.org/doc/latest/api/grails/orm/HibernateCriteriaBuilder.html#sqlRestriction(java.lang.String))을 사용할 수 있습니다. –

답변

1

전에 비슷한 요구 사항을 구현했으며 HQL 쿼리를 사용했습니다. 그것은 얼마 전이었으며, 읽는 데 꽤 시간이 걸렸습니다. 그래서 잘하면 시간을 절약 할 수 있습니다.

이것은 현재 위치 (단순 위도가 긴 컨테이너 객체)와 "이름"(startswith)을 기반으로 선택합니다. 도메인 객체 (장소)와 현재 위치에서 멀리 떨어져있는 마일을 선택합니다. 그것은 오름차순 마일 떨어진 정렬합니다. 참고 도로 거리를 대략적으로 나타내는 "도로 팩터"퍼지를 추가했습니다.

def getVenuesInArea(venueName, location, miles, optionsMap) 
{ 
    def max = optionsMap?.max ?: 10 
    def offset = optionsMap?.offset ?: 0 
    if (venueName == null) venueName = "" 
    venueName += '%' 

    double roadFactor = 1.20 // add 20% for the roads, instead of as crow flies... 

    def query 
    def results 

    def countQuery = """ select count(distinct v) 

       from Venue as v 
       WHERE 
       v.name like :venueName AND 
       (acos 
        (
         sin(radians(:lat)) 
         * sin(radians(v.location.latitude)) 
         + cos(radians(:lat)) 
         * cos(radians(v.location.latitude)) 
         * cos(radians(v.location.longitude) - radians(:lon)) 
        ) * 3956.1676 * :roadFactor < :distance 
       ) 

      """ 

    def count = Venue.executeQuery(countQuery, [venueName:venueName, lat:location.latitude, lon:location.longitude, distance:miles, roadFactor:roadFactor])[0] 

    query = """ select distinct v, 

       (
        acos 
        (
         sin(radians(:lat)) 
         * sin(radians(v.location.latitude)) 
         + cos(radians(:lat)) 
         * cos(radians(v.location.latitude)) 
         * cos(radians(v.location.longitude) - radians(:lon)) 
        ) 
        * 3956.1676 * :roadFactor 
       ) as milesAway 

       from Venue as v 
       WHERE 
       v.name like :venueName AND 
       (acos 
        (
         sin(radians(:lat)) 
         * sin(radians(v.location.latitude)) 
         + cos(radians(:lat)) 
         * cos(radians(v.location.latitude)) 
         * cos(radians(v.location.longitude) - radians(:lon)) 
        ) * 3956.1676 * :roadFactor < :distance 
       ) 

       order by 
       (
        acos 
        (
         sin(radians(:lat)) 
         * sin(radians(v.location.latitude)) 
         + cos(radians(:lat)) 
         * cos(radians(v.location.latitude)) 
         * cos(radians(v.location.longitude) - radians(:lon)) 
        ) 
        * 3956.1676 * :roadFactor 
       ) 
       asc, 
       v.name 

      """ 

    results = Venue.executeQuery(query, [venueName:venueName, lat:location.latitude, lon:location.longitude, distance:miles, roadFactor:roadFactor, max:max, offset:offset]) 

    def venues = [] 
    MathContext mc = new MathContext(2) 
    results.each 
    { result -> 
     VenueWithDetails venueDetails = new VenueWithDetails( venue:result[0], milesFrom:new BigDecimal(result[1]).round(mc) ) 
     venues.add(venueDetails) 
    } 
    return [venues:venues, count:count] 
} 

이것은 grails 버전 1.3.4에서 수행되었지만 1.3.7에서는 정상적으로 작동해야합니다.

도움이 되길, 크리스.

관련 문제