2011-05-06 103 views
0

在我的Grails 1.3.7應用程序中,我有一個具有Double緯度和Double經度的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)。 – 2011-05-07 20:37:16

回答

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應該可以正常工作。

希望有幫助, 克里斯。