【问题标题】:Ruby Rails Postgis - Finding all the points in a polygonRuby Rails Postgis - 查找多边形中的所有点
【发布时间】:2012-02-18 18:52:37
【问题描述】:

我想要一些关于构建 sql 查询以在带有 activerecord-postgis-adapter 的 Rails 中使用的帮助。我已经做了很多阅读,但现在有点卡住了,任何帮助将不胜感激。

我有两个模型事件和区域:

事件有一个点类型的“几何”列

class Event < ActiveRecord::Base
  self.rgeo_factory_generator = RGeo::Geos.factory_generator    
end

t.spatial  "geometry", :limit => {:srid=>4326, :type=>"polygon", :geographic=>true}

区域有一个多边形类型的“几何”列

class Area < ActiveRecord::Base 
  self.rgeo_factory_generator = RGeo::Geos.factory_generator
end

t.spatial  "geometry", :limit => {:srid=>4326, :type=>"point", :geographic=>true}

我可以在谷歌地图上创建和绘制事件和区域,并通过单击地图并保存到数据库来创建区域。

我希望能够执行以下 2 个查询:

  1. @area.events - 显示区域内的所有事件
  2. @event.areas - 显示单个事件所在的所有区域

我知道我在这里可能会问一些问题,但我们将不胜感激任何帮助

非常感谢

【问题讨论】:

  • 只是为了澄清...您是在寻找执行此操作的 SQL 脚本还是 ruby​​ 答案?用于此的 Postgres SQL 脚本相对简单(使用 ST_contains),如果您提供这两个表的架构以及它们之间的关系,我可以为您提供完整的脚本。
  • 您好第十二... 我想在 Rails 中实现它,但不知道该怎么做,我想我想要一个 Areas 和 Events AreasEvents 之间的连接表,例如,因为我希望能够查看给定区域中的事件,并给定事件查看它所在的所有区域,但我看不到如何使用标准 Rails 关联来实现这一点。我需要快速解决方案,因为会有大量事件,所以我认为我需要使用 ST_contains。我还没有实现表之间的任何关系。剂量这个帮助?

标签: sql ruby-on-rails ruby postgis


【解决方案1】:

这里有一个快速的方法来做到这一点。这些只会返回 ActiveRecord 对象的数组。

class Area
  def events
    Event.joins("INNER JOIN areas ON areas.id=#{id} AND st_contains(areas.geometry, events.geometry)").all
  end
end

class Event
  def areas
    Area.joins("INNER JOIN events ON events.id=#{id} AND st_contains(areas.geometry, events.geometry)").all
  end
end

您可能应该记住(缓存结果),这样您就不会在每次调用该方法时都查询数据库。那应该是直截了当的;我把它作为练习留给读者。

可能可以变得复杂,并将其封装在真正的 Rails 关联代理中(这样您就可以获得所有 Rails 关联的好东西)。我还没有调查过这个。在任何情况下,它都不是标准的 Rails 关联,因为您没有存储 ID。

第十二条是正确的:您应该为两个表创建空间索引。 Activerecord-postgis-adapter 应该让您在迁移中轻松完成这些工作。

change_table :events do |t|
  t.index :geometry, :spatial => true
end

change_table :areas do |t|
  t.index :geometry, :spatial => true
end

如果您在安装 postgis 时遇到问题,我最近写了一堆关于此内容的博客文章。查看http://www.daniel-azuma.com/blog/archives/category/tech/georails。我自己也是 rgeo 和 activerecord-postgis-adapter 的作者,所以如果您遇到困难,我很乐意为您提供帮助。

【讨论】:

  • 谢谢丹尼尔,这真的很好,是的,我正确安装了 postgis,由于认为我的列应该是地理的,所以我遇到的错误......顺便说一句,你的宝石很棒,非常感谢感谢您为他们付出的所有努力。
  • 嗨丹尼尔,这是我找到的最佳答案。你有没有考虑让这个与关联代理一起工作?顺便说一句,很棒的博客系列,感谢所有 rgeo 的帮助 :)
【解决方案2】:

这个答案对你来说是一项正在进行的工作。我对 ruby​​ on rails 很弱,但我应该能够帮助您完成 DB 部分。

您有两个表,Area 包含一个多边形,Event 将事件保存为一个点(如果事件也是一个区域并且您试图挑选重叠区域的...如果事件是单点,这是可行的)。

Select *
from area a inner join event e on 1=1

这将创建一个加入每个事件的每个区域的列表...如果您有 500 个事件和 20 个区域,则查询将返回 10'000 行。现在您要过滤此事件,以便仅在他们已加入的区域内的事件。我们可以使用 st_contains 作为 st_contains(polygon,point):

where st_contains(a.polygon,e.point) = 't'

如果您运行它,它应该为您提供区域内所有事件的 a.,e.。现在只需计算您想要计算的内容即可。

select a.id, count(1)
from area a inner join event e on 1=1
where st_contains(a.polygon,e.point) = 't'
group by 1

这将为您提供所有区域的列表(按 id)以及其中的事件计数。用 e.id 切换 a.id 将给出事件 id 的列表以及它们所在的数字区域。

不幸的是,我不知道如何在 Ruby 中表达这些查询,但是您需要的数据库概念在这里...

出于速度考虑,您应该查看 Postgres 的 GIStree 索引...索引多边形的性能呈指数级增长。

编辑:

PostGIS 是 Postgres 附带的一个 contrib 文件,但在标准安装中不存在...您需要找到这个 contrib 文件。这些将在您的数据库中安装一系列 GIS 功能,包括 ST_Contains。 (函数驻留在数据库中,因此请确保将函数安装在正在使用的数据库中)

PostGIS contrib 文件安装的第二个东西是几何数据类型所需的 template_postGIS 数据库(geom 作为数据类型在安装之前不存在)。

【讨论】:

  • 您总是可以在Area.find_by_sql('select a.* from area a ...') 中包装那种 SQL 以从 ActiveRecord 中取出对象。顺便说一句,很抱歉破坏了酷炫的 666 代表,但有人必须这样做。
  • 呵呵,谢谢...我只需要随机投票 10 项即可将其取回;)
  • 谢谢,太好了... 2 个问题,1,我收到以下错误 gist.github.com/1685908 我认为我所有的数据都在 SRID 中,所以是因为我的数据库没有 postgis 功能? 2.你提到GIStree我做了快速搜索,没有找到任何东西,你能给我一个链接吗?非常感谢,这是一个真正的帮助。
  • 啊,抱歉...假设您已经安装了 contrib 文件。 Postgres 有一系列'contrib' 文件,它们是 Postgres 数据库的功能附加组件(通常作为一堆函数完成)... DBlink 提供调用不同数据库的能力,但标准安装中没有。 PostGIS 也是一个贡献文件...阅读答案上的编辑,我会将这些信息放在那里
  • 第二个问题的答案:postgresql.org/docs/8.1/static/gist.html 我认为它在技术上是一个 btree_gist 索引...我相信与 Oracle 中的 r-tree 概念相同。
猜你喜欢
  • 2015-03-06
  • 2010-12-24
  • 2018-02-28
  • 2019-11-07
  • 2015-01-08
  • 2018-11-12
  • 1970-01-01
  • 1970-01-01
  • 2019-12-10
相关资源
最近更新 更多