捕获postgis st_clip的错误,并修复“无法从工作栅格中获取波段”

时间:2017-02-12 04:15:16

标签: postgresql postgis postgis-raster

我有数百万个多边形,还有一个更大的栅格表(平铺)。我想st_clip(栅格,多边形),然后在剪切的栅格上应用st_summarystatsagg()。代码如下所示。

with pieces as (
select d.pid,
       st_clip(r.rast, d.geom) as rast
       from tbl_raster as r
       inner join tbl_poly as d
       on st_intersects(r.rast, d.geom)
)
insert into tbl_out(pid, val1, val2, val3)
select pid,
       (stats1).mean as v1,
       (stats2).mean as v2,
       (stats3).mean as v3
from (
     select p.pid,
            st_summarystatsagg(p.rast, 1, true) as stats1,
            st_summarystatsagg(p.rast, 2, true) as stats2,
            st_summarystatsagg(p.rast, 3, true) as stats3
     from pieces as p
     group by p.pid
);

该代码适用于小的多边形子集(数千),但是当我传递数百万时,它会返回错误

ERROR:  RASTER_clip: Could not get band from working raster
CONTEXT:  PL/pgSQL function st_clip(raster,integer[],geometry,double precision[],boolean) line 8 at RETURN

我希望获得更多多边形导致此问题的诊断信息。有没有办法做try-catch块类型的东西然后我将从那里转储一些信息。或者让它给出一些空值或其他东西并使查询完成,然后我查看问题的输出。

postgresql的版本是9.6.1,postgis是2.3.1,gdal 2.1.2,并使用psql -f在Linux上运行。

谢谢!

修改

按照@Eelke的建议,我在PL / pgSQL中使用了循环,并确定了问题所在。

如果多边形触摸没有共享内部点的栅格,则ST_Clip似乎失败,如果请求多个频带计算。如下面的测试代码所示,如​​果我计算ST_Intersects与多边形的光栅联合,它似乎按预期工作(由我)。但事实证明这是昂贵的。我希望找到ST_Intersects的替代品,如果没有共享内部点,它就不会选择。但我找不到这样做的功能,无法弄清楚表达......有这样的表达吗?

以下是我提出的可重现的结果:

--DROP SCHEMA IF EXISTS test_rast;
--CREATE SCHEMA test_rast;

SET search_path TO test_rast, public;

-- Create raster catalog of 3 bands
DROP TABLE IF EXISTS dummy_rast_3band;
CREATE TABLE dummy_rast_3band(rid int, rast raster);
INSERT INTO dummy_rast_3band(rid, rast)
VALUES
(1, ST_AddBand(
                ST_MakeEmptyRaster(240, 240, 82,   59.6, 6./3600., 6./3600., 0, 0, 4326),
                ARRAY[
                ROW(1, '8BUI'::text, 0, 255),
                ROW(2, '8BUI'::text, 0, 255),
                ROW(3, '8BUI'::text, 0, 255)
                ]::addbandarg[]
        )
),
(2, ST_AddBand(
                ST_MakeEmptyRaster(240, 240, 82.4, 59.6, 6./3600., 6./3600., 0, 0, 4326),
                ARRAY[
                ROW(1, '8BUI'::text, 0, 255),
                ROW(2, '8BUI'::text, 0, 255),
                ROW(3, '8BUI'::text, 0, 255)
                ]::addbandarg[]
        )
) ;

-- Almost identical raster catalogue, the only difference being there is only one  band
DROP TABLE IF EXISTS dummy_rast_1band;
CREATE TABLE dummy_rast_1band(rid int, rast raster);
INSERT INTO dummy_rast_1band(rid, rast)
VALUES
(1, ST_AddBand(
                ST_MakeEmptyRaster(240, 240, 82,   59.6, 6./3600., 6./3600., 0, 0, 4326),
                '8BUI'::text, 0, NULL
        )
),
(2, ST_AddBand(
                ST_MakeEmptyRaster(240, 240, 82.4, 59.6, 6./3600., 6./3600., 0, 0, 4326),
                '8BUI'::text, 0, NULL
        )
) ;

-- Prepare polygon which touches one raster
DROP TABLE IF EXISTS dummy_poly;
CREATE TABLE dummy_poly(pid int, geom geometry);
INSERT INTO dummy_poly(pid, geom)
VALUES
(1, ST_GeomFromText( 'MULTIPOLYGON(((82.4180000000001 59.8655000000001,82.4 59.8655000000001,82.4 59.8745000000001,82.4180000000001 59.8745000000001,82.4180000000001 59.8655000000001)))', 4326));

-- Four tests with ST_Clip()
-- This works, with 1-band raster
SELECT ST_Summary(ST_Clip(r.rast, d.geom))
FROM dummy_rast_1band AS r INNER JOIN dummy_poly AS d
ON ST_Intersects(r.rast, d.geom);

-- This fails with
--   RASTER_clip: Could not get band from working raster
--   CONTEXT:  PL/pgSQL function st_clip(raster,integer[],geometry,double precision[],boolean)
--             line 8 at RETURN
SELECT ST_Summary(ST_Clip(r.rast, d.geom))
FROM dummy_rast_3band AS r INNER JOIN dummy_poly AS d
ON ST_Intersects(r.rast, d.geom);

-- If ask for one band, that works
SELECT ST_Summary(ST_Clip(r.rast, 2, d.geom, true))
FROM dummy_rast_3band AS r INNER JOIN dummy_poly AS d
ON ST_Intersects(r.rast, d.geom);

-- If I union raster into bigger piece, it works
SELECT ST_Summary(ST_Clip(ST_Union(r.rast), d.geom))
FROM dummy_rast_3band AS r INNER JOIN dummy_poly AS d
ON ST_Intersects(r.rast, d.geom)
GROUP BY d.geom;

1 个答案:

答案 0 :(得分:0)

正如我在上面的编辑中所说,我认为问题来自ST_Clip在特定条件下的意外行为:(1)栅格具有多频带,(2)多边形触摸栅格而没有共享内部。我的解决方法是分别操作每个乐队。它似乎比原来运行稍慢,但它并不是一场灾难。

with pieces as (
select d.pid,
       st_clip(r.rast, 1, d.geom) as rast1
       st_clip(r.rast, 2, d.geom) as rast2
       st_clip(r.rast, 3, d.geom) as rast3
       from tbl_raster as r
       inner join tbl_poly as d
       on st_intersects(r.rast, d.geom)
)
insert into tbl_out(pid, val1, val2, val3)
select pid,
       (stats1).mean as v1,
       (stats2).mean as v2,
       (stats3).mean as v3
from (
     select p.pid,
            st_summarystatsagg(p.rast1, 1, true) as stats1,
            st_summarystatsagg(p.rast2, 1, true) as stats2,
            st_summarystatsagg(p.rast3, 1, true) as stats3
     from pieces as p
     group by p.pid
);