PostGIS: attribuer l'ID du point de la couche A au point le plus proche de la couche B

15

Cela aurait dû être un précurseur évident (que je n'ai pas posé) à mon autre question: comment créer des diagrammes d'araignée (lignes de moyeu) dans PostGIS?

Si je ne connais pas la relation entre un point de la couche A (magasins) et un point de la couche B (clients), je voudrais généralement dire «le client 1 est desservi par le magasin le plus proche». Bien que je réalise que ce fait n'est peut-être pas vrai, il peut être un substitut décent.

À l'aide de PostGIS, quelle est la manière la plus efficace d'attribuer l'ID du point le plus proche dans la couche A (magasins) à chaque point dans la couche B (clients). La sortie que je recherche est quelque chose comme ci-dessous.

Customer | Store
    1    |   A
    2    |   A
    3    |   B
    4    |   C
RyanKDalton
la source

Réponses:

6

également:

sélectionnez A.ID comme CUST_ID, (sélectionnez B.ID de B ordre par st_distance (A.geom, B.geom) limit 1) comme STORE_ID de A

eprand
la source
C'était le meilleur moyen d'accomplir la tâche. Voir ma note ci-dessous pour le code réel que j'ai utilisé.
RyanKDalton
8

Il semble que si vous avez beaucoup plus de clients que de magasins, il pourrait être plus efficace de créer une couche de polygones voronoi pour les magasins, puis de faire une jointure spatiale des clients par rapport aux polygones du magasin.

Kirk Kuykendall
la source
1
J'aime cette approche!
underdark
Quelle approche serait la plus simple pour créer des polys voronoi? Y a-t-il d'autres options que ce qui est noté ici: bostongis.com/… bostongis.com/…
RyanKDalton
Je pense que le Delaunay Triangulation and Dirichlet Package dans le deuxième tutoriel serait approprié, je ne sais pas si c'est le plus simple.
Kirk Kuykendall
5

Sur http://www.bostongis.com/?content_name=postgis_nearest_neighbors :

Si vous avez besoin d'obtenir le voisin le plus proche pour tous les enregistrements d'une table, mais que vous n'avez besoin que du premier voisin le plus proche pour chacun, vous pouvez utiliser la syntaxe DISTINCT ON distincte de PostgreSQL. Ce qui ressemblerait à quelque chose comme ceci:

SELECT DISTINCT ON(g1.gid)  g1.gid As gref_gid, 
       g1.description As gref_description, 
       g2.gid As gnn_gid, 
       g2.description As gnn_description  
FROM sometable As g1, sometable As g2   
WHERE g1.gid <> g2.gid 
      AND ST_DWithin(g1.the_geom, g2.the_geom, 300)   
ORDER BY g1.gid, ST_Distance(g1.the_geom,g2.the_geom) 

Cela permettra de trouver des distances minimales jusqu'à 300 unités. Donc, vous devez d'abord vérifier vos données et savoir quelle sera l'ampleur de vos distances minimales.

obscur
la source
3

Merci pour la contribution de tout le monde. J'ai finalement opté pour une combinaison de suggestions d'eprand et d'Underdark. Le code final que j'ai utilisé était:

CREATE TABLE closest_point as
SELECT DISTINCT ON (A.GID) A.GID AS CUST_ID, 
      (SELECT B.GID FROM "STORES" as B 
       ORDER BY ST_Distance(A.the_geom, B.the_geom) limit 1) as STORE_ID, 
       A.the_geom 
FROM "CUSTOMERS" as A, "STORES" as B;

J'ai ensuite créé un diagramme voronoi sur la couche magasins pour confirmer que les résultats ont fonctionné correctement, ce qui bien sûr, ils l'ont fait. Merci pour votre excellent travail!

RyanKDalton
la source