2011-05-06 57 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应该可以正常工作。

希望有帮助, 克里斯。