通过距参考点的距离查找全部

时间:2011-05-06 23:24:46

标签: mysql grails distance latitude-longitude

在我的Grails 1.3.7应用程序中,我有一个具有Double纬度和Double经度的Building实体。 我正在实现一个简单的搜索引擎,以便找到具有用户所在点的给定距离的所有Building实例(以十进制度表示的纬度和经度)。 我发现这个http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL很好,因为我使用的是MySQL数据库。边界框近似对我来说非常好,因为我需要执行额外的过滤和计算,我只需要一个查找器来缩小我正在过滤的实例数。 我的问题是:有没有人已经在Grails环境中实现了这种搜索以及如何实现?

1 个答案:

答案 0 :(得分:1)

之前我已经实现了类似要求的东西,并且我使用了HQL查询。这是一段时间以前,我记得我花了很长时间才读起来并弄明白,所以希望能节省你一些时间。

这是基于当前位置(简单的lat长容器对象)和“name”(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。

希望有所帮助, 克里斯。