使用PostGIS从点数据

时间:2017-07-24 18:39:51

标签: database postgresql gis postgis heatmap

我有一个巨大的表(gps_points),其中几何列存储了2D点。我想要完成的是运行输出类似

的查询
 id | freq
-------------
  1 | 365
  2 | 1092
  3 | 97
...

其中" id"是我的总边界框内的一个小矩形的唯一标识符," freq"是指特定矩形内的点数。

所以我将PostGIS表定义为:

create table sub_rects (
id int,
geom geometry)

然后我在外部运行一个脚本,在那里我生成1000x1000个这样的矩形并创建它们的多边形,所以我得到一百万行像这样:

insert into sub_rects values(1,ST_GeomFromText('POLYGON((1.1 1.2, 1.1 1.4, 1.5 1.4, 1.5 1.2, 1.1 1.2))'));

除了当然每个多边形都有一组新的坐标,以便在我的gps数据的边界框坐标上匹配1000x1000网格中的实际位置,并且每个元组的ID都会更新。

然后我在这个表上生成一个空间索引和一个主键索引。

最后,我可以使用

运行此表和原始数据表(gps_points)
select id, count(*) from sub_rects r join gps_points g on r.geom && g.geom group by id;

这给了我寻求的输出。问题是加载所有的小多边形需要永远,每次我想生成一个具有不同数量的矩形的地图或在具有不同底层坐标的数据集上运行时,我必须删除sub_rects并生成和重新加载它。

有更好的方法吗?我不需要图形输出。我只需要生成数据。不必在外部生成支持表(sub_rects)将是非常好的,我怀疑有一些计算成本较低的方法来完成相同的事情。我更不希望安装任何其他软件。

ETA:根据评论中的请求,这里是查询计划(在我的家庭计算机上,所以较小的数据集和其他表名,但是相同的计划):

gisdb=# explain analyse select g.id id, count(*) from gridrect g join broadcast b on g.geom && b.wkb_geometry group by g.id;

    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
 GroupAggregate  (cost=0.57..177993.58 rows=10101 width=12) (actual time=14.740..3528.600 rows=1962 loops=1)
   Group Key: g.id
   ->  Nested Loop  (cost=0.57..144786.36 rows=6621242 width=4) (actual time=13.948..3050.741 rows=1366376 loops=1)
         ->  Index Scan using gridrect_id_idx on gridrect g  (cost=0.29..485.30 rows=10201 width=124) (actual time=0.079..6.582 rows=10201 loops=1)
         ->  Index Scan using broadcast_wkb_geometry_geom_idx on broadcast b  (cost=0.29..12.78 rows=137 width=32) (actual time=0.011..0.217 rows=134 loops=10201)
               Index Cond: (g.geom && wkb_geometry)
 Planning time: 0.591 ms
 Execution time: 3529.320 ms
(8 rows)

ETA 2:

根据答案中的建议,我修改了那里建议的代码:

(SELECT row_number() OVER (ORDER BY geom) id, geom
 FROM (SELECT st_geomfromtext(
                  concat('Polygon((', x || ' ' || y, ',', x + xstep || ' ' || y, ',', x + xstep || ' ' || y + ystep,
                         ',', x || ' ' || y + ystep, ',', x || ' ' || y, '))')) geom
       FROM (SELECT x, y
             FROM (SELECT generate_series(xmin, xmin + xdelta, xstep) x) x,
                  (SELECT generate_series(ymin, ymin + ydelta, ystep) y) y) foo) bar);

其中xmin,ymin,xdelta,ydelta,xstep和ystep都是由外部脚本计算的,但如果你在函数调用中包装上面的内容,也可以计算为Postgres函数的一部分。从中生成一个临时表并对其运行查询比我最初做的快两个数量级。

2 个答案:

答案 0 :(得分:0)

两件事。 首先在sql级别创建表(从pg_admin为exmaple)。

    function name(){
        var response = document.getElementById("name").value;
        if(response.length == 0){
            document.getElementById("msg1").style.color = "Red";
            document.getElementById("msg1").innerHTML = " You did not provide name";
        }
        else{
            document.getElementById("msg1").style.color = "Green";
            document.getElementById("msg1").innerHTML = "<strong> Valid</strong>";
        }
    }
    function phone(){
        var response = document.getElementById("phone").value;
        var pattern = /^d{3}-d{3}-d{4}$/;
        if(pattern.test(response)){
            document.getElementById("msg2").style.color = "Red";
            document.getElementById("msg2").innerHTML = " Provide number in xxx-xxx-xxxx format";
        }
        else{
            document.getElementById("msg2").style.color = "Green";
            document.getElementById("msg2").innerHTML = "<strong> Valid</strong>";
        }
    }
    function id(){
        var response = document.getElementById("id").value;
        if(response.length == 0){
             document.getElementById("msg3").style.color = "Red";
             document.getElementById("msg3").innerHTML = " You did not provide a seven-digit id";
    }
    else{
        document.getElementById("msg3").style.color = "Green";
        document.getElementById("msg3").innerHTML = "<strong> Valid</strong>";
    }
}
function email(){
    var emailInput = document.getElementById("email").value;
    var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (emailPattern.test(emailInput)){
        document.getElementById("msg4").style.color = "Green";
        document.getElementById("msg4").innerHTML = "<strong> Valid</strong>";
        return (true);
    }
    else{
        document.getElementById("msg4").style.color = "Red";
        document.getElementById("msg4").innerHTML = " Invalid Email";
        return (false);
    }
}
function room(){
    var response = document.getElementById("room").value;
    var pattern = /^d{3}-s{1}$/;
    if(patttern.test(response)){
        document.getElementById("msg5").style.color = "Red";
        document.getElementById("msg5").innerHTML = " You did not provide accurate room information";
        return(true);
    }
    else{
        document.getElementById("msg5").style.color = "Green";
        document.getElementById("msg5").innerHTML = "<strong> Valid</strong>";
        return(false);
    }
}
function result(){
    document.getElementById("end").innerHTML = "<center>Your request has been recorded. Please stay patient as the maintenance team prepares to work on it. Thanks.</center>";
} 

创建索引

使用gist(geom)创建多边形索引;

然后使用您的查询或此查询。在你的情况下检查哪一个会更快

create table polygons as
select st_geomfromtext(concat('Polygon((',x||' '||y,',',x||' 
'||y+0.2,',',x+0.4||' '||y+0.2,',',x+0.4||' '||y,',',x||' '||y,'))')) geom
  FROM (select generate_series(0,199.9,0.2) x) x,
       (select generate_series(0,199.9,0.4) y) y

按ID分组;

答案 1 :(得分:0)

以下是从边界框生成网格的示例:

https://gis.stackexchange.com/questions/16374/how-to-create-a-regular-polygon-grid-in-postgis

要生成密度数据,请尝试先创建包含所有数据的临时表,然后获取计数。根据我的经验,下面比将所有内容组合到单个查询中要快一些:

create temp table rect_points as 
select r.id as rect_id, p.id as point_id 
from sub_rects r, gps_points p
where p.geom && r.geom;

create index idx on rect_points (rect_id);

select rect_id, count(*) from rect_points group by rect_id;