按距参考点的距离查找所有内容

发布于 2024-11-05 18:02:20 字数 384 浏览 1 评论 0原文

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

In my Grails 1.3.7 application, I have a Building entity with a Double latitude and a Double longitude.
I'm implementing a simple search engine in order to find all the Building instances with a given distance of the point where the user is (latitude and longitude in decimal degrees).
I found this http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL which is good because I'm using a MySQL database. And the bounding box approximation is excellent for me as I need to perform additional filtering and calculations and I just need a finder that narrows down the number of instances I'm filtering.
My question is: has anybody already implemented this kind of search in a Grails environment and how?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你怎么这么可爱啊 2024-11-12 18:02:20

我之前实现过类似需求的东西,并且使用了HQL查询。那是不久前的事,我记得我花了相当长的时间来阅读和弄清楚,所以希望能为您节省一些时间。

这会根据当前位置(一个简单的经纬度容器对象)和“名称”(以开头)进行选择。它选择域对象(地点)以及距当前位置的英里数。它按英里数上升排序。请注意,我添加了“道路因素”来估算道路距离。

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 上应该可以正常工作。

希望有帮助,
克里斯.

I have implemented something with similar requirements before, and I used a HQL query. It was a while ago and I remember it took me quite a while to read up and figure out, so hopefully saves you some time.

This does a select based on a current location (a simple lat long container object), and a "name" (startswith). It selects the domain object (venue) and also the miles away from the current location. It sorts by miles away ascending. Note I added a "road factor" fudge to approximate road distances.

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]
}

This was done on grails version 1.3.4, but pretty sure it should work fine for 1.3.7.

Hope that helps,
Chris.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文