calcul du pourcentage d'aire d'intersection dans la clause where

15

J'ai un tableau de polygones (groupes de blocs de recensement) en postgres. Je veux marquer chaque groupe de blocs avec la ville (une autre table polygonale) dans laquelle il réside principalement. Est-ce possible? Je pense que je devrais essentiellement créer quelque chose comme:

select b.*,t.name  
from blockgroups b, towns t  
where (st_area(st_intersection(b.wkb_geometry, t.wkb_geometry))/st_area(b.wkb_geometry)) > .5  

mais cette requête prend une éternité (j'ai environ 5000 groupes de blocs et 375 villes ...). Des suggestions sur la façon de faire fonctionner cette requête soit si elle est incorrecte, soit plus rapide si elle est correcte?

eirvin
la source
On dirait que vous voulez marquer les groupes de blocs en fonction du chevauchement maximal? Si oui, voyez cette réponse . Si vos «villes» sont également des géographies de recensement (MCD ou lieux, par exemple), il n'est probablement pas nécessaire de calculer le pourcentage de chevauchement.
dbaston

Réponses:

23

La façon dont vous le faites fonctionnera mais cela prendra trop de temps, car postgis essaie de créer la géométrie de l'intersection de chaque combinaison "groupe de blocs vs ville", même quand ils ne se touchent même pas.

Ajoutez une autre vérification de condition à votre clause WHERE pour vérifier si les deux géométries interceptent et placez-la avant celle existante:

select b.*,t.name
from blockgroups b, towns t
where st_intersects(b.wkb_geometry, t.wkb_geometry) and    
    (st_area(st_intersection(b.wkb_geometry, t.wkb_geometry))/st_area(b.wkb_geometry)) > .5

En SQL, si vous avez une liste de conditions dans la clause WHERE, elles sont testées par l'ordre dans lequel elles sont écrites. Si un FAUX est retourné dans l'une des premières opérations, la requête sautera simplement les autres conditions de vérification, car le résultat sera toujours FAUX.

Assurez-vous également d'avoir des index spatiaux sur blockgroups.wkb_geometry et towns.wkb_geometry.

Alexandre Neto
la source
1
L'ajout ST_Intersectsest la bonne façon de procéder ici, mais le planificateur peut ou non exécuter les conditions dans l'ordre où elles sont écrites. Consultez la documentation Postgres pour plus de détails à ce sujet. ST_Intersectset ST_Intersectionont le même coût sur mon installation (100), donc pour être honnête, je ne suis pas sûr de ce que fait le planificateur, mais il semble toujours faire la bonne chose ici.
dbaston
Ahh ... J'ai supposé que les conditions seraient vérifiées comme dans d'autres langues. Mais je suppose que cela donne au planificateur une autre option.
Alexandre Neto
10

Pour ajouter à la réponse très utile d'Alexandre, si certaines de vos unités de recensement peuvent s'étendre sur trois de vos villes (et donc vous ne pouvez garantir plus de 50% de chutes dans n'importe quelle ville), vous pouvez le faire:

select distinct on (b.id)
b.*,t.name,
(st_area(st_intersection(b.wkb_geometry, t.wkb_geometry))/st_area(b.wkb_geometry)) as proportion
from blockgroups b, towns t
where st_intersects(b.wkb_geometry, t.wkb_geometry) 
order by b.id, proportion desc;

Cela protège essentiellement contre la situation suivante - dans laquelle les zones en bleu disparaîtraient: entrez la description de l'image ici

RobinL
la source
1
Je l'adore absolument lorsque le tout premier problème que je rencontre avec une réponse SO est résolu par la toute prochaine réponse. À la vôtre, @RobinL!
wfgeo