Problemi nell'ottenere le zip nel raggio tramite MySQL


9

Ho una tabella di codici postali che include il centro lat, lng per ogni codice postale. Lo uso per ottenere un elenco di codici postali entro un determinato raggio di miglio da qualsiasi punto arbitrario.

Mi è appena venuto in mente che, solo perché il punto centrale di una zip non si trova all'interno di un determinato raggio, non significa che la zip stessa non sia all'interno del raggio.

Ho usato le mie abilità artistiche super avanzate per illustrare il punto qui:

inserisci qui la descrizione dell'immagine

  • Le chiazze a strisce verdi rappresentano i codici postali A, B e C.

  • Le macchie rosse sono i centri geografici di ciascun codice postale

  • Il punto fucsia è la posizione target e ..

  • Il cerchio blu grumoso è un raggio di 1 miglio dalla posizione target

Se eseguo una query per tutti i codici postali entro un raggio di 1 miglio dalla sfumatura rosa, verranno restituiti solo i codici postali B e C poiché il punto centrale per la zip A non è compreso nel raggio di un miglio, anche se la macchia rosa stessa è chiaramente nel codice postale A.

SELECT *,
        p.distance_unit
                 * DEGREES(ACOS(COS(RADIANS(p.latpoint))
                 * COS(RADIANS(z.y))
                 * COS(RADIANS(p.longpoint) - RADIANS(z.x))
                 + SIN(RADIANS(p.latpoint))
                 * SIN(RADIANS(z.y)))) AS dist
  FROM standard_zip AS z
  JOIN (   /* these are the query parameters */
        SELECT  $lat  AS latpoint,  $lng AS longpoint,
                $miles AS radius,      69 AS distance_unit
    ) AS p ON 1=1
  WHERE z.y
     BETWEEN p.latpoint  - (p.radius / p.distance_unit)
         AND p.latpoint  + (p.radius / p.distance_unit)
    AND z.x
     BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
         AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
  ORDER BY dist

Come diamine posso scrivere una query che includerà zip A nei risultati?

Ho accesso a spazio / geometria per ogni codice postale che posso aggiungere alla tabella se necessario, ma non ho idea di come lo userei per questo scopo in MySQL.


Modifica : ho trascorso una giornata a leggere i documenti Oracle e MySQL per i dati spaziali e sono riuscito a convertire con successo i miei dati spaziali in MySQL . Come posso scrivere una query simile che utilizza la colonna geometria anziché lat e long? Sto usando i dati 2D .. la geometria è solo poligoni e multipoligoni ..

Penso di averlo capito.

select
  *
from
  (
    select
      MIN(st_distance(geom, POINT(-82.765136, 28.0914015))) * 69 as miles,
      zip
    from
      zip_spatial
    group by
      zip
    order by
      miles asc
  ) d
where
  d.miles < 5

Lascerò la taglia aperta per ora nel caso qualcuno abbia una soluzione migliore, più efficiente.

Risposte:


7

Dall'indicizzazione e l'interrogazione dei dati spaziali in Oracle nella Guida per gli sviluppatori di Oracle® Spatial 11g versione 2 (11.2):

Richiesta di dati spaziali

Spatial utilizza un modello di query a due livelli con operazioni di filtro primario e secondario per risolvere query spaziali e join spaziali. Il termine a due livelli indica che vengono eseguite due operazioni distinte per risolvere le query. Se vengono eseguite entrambe le operazioni, viene restituito il set di risultati esatti.

Non è possibile aggiungere un nome di collegamento al database (dblink) al nome di una tabella spaziale in una query se un indice spaziale è definito su quella tabella.

Query spaziale

In un indice spaziale R-tree, ogni geometria è rappresentata dal suo rettangolo di delimitazione minimo (MBR). Considera il seguente livello contenente diversi oggetti in Figura 1. Ogni oggetto è etichettato con il suo nome di geometria (geom_1 per la stringa di linea, geom_2 per il poligono a quattro facce, geom_3 per il poligono triangolare e geom_4 per l'ellisse) e l'MBR attorno a ciascun oggetto è rappresentato da una linea tratteggiata.

Figure1 Geometrie con MBR

Descrizione di "Figure1 Geometrie con MBR"

Una tipica query spaziale è richiedere tutti gli oggetti che si trovano all'interno di una finestra di query, ovvero una recinzione o una finestra definita. Una finestra di query dinamica fa riferimento a un'area rettangolare che non è definita nel database, ma che deve essere definita prima di essere utilizzata. La Figura 2 mostra le stesse geometrie della Figura 1, ma aggiunge una finestra di query rappresentata dal riquadro a linea tratteggiata.

Figura 2 livelli con una finestra di query

Descrizione di "Figure2 Layer con una finestra di query"

Nella Figura 2, la finestra della query copre parti delle geometrie geom_1 e geom_2, nonché parte dell'MBR per geom_3 ma nessuna della geometria geom_3 effettiva. La finestra della query non copre alcuna parte della geometria geom_4 o il suo MBR.

Operatore filtro primario

L'operatore SDO_FILTER implementa la parte di filtro principale del processo in due passaggi coinvolto nel modello di elaborazione delle query di Oracle Spatial. Il filtro primario utilizza i dati dell'indice per determinare solo se un insieme di coppie di oggetti candidati può interagire. In particolare, il filtro primario controlla se gli MBR degli oggetti candidati interagiscono, non se gli oggetti stessi interagiscono. La sintassi dell'operatore SDO_FILTER è la seguente:

SDO_FILTER(geometry1 SDO_GEOMETRY, geometry2 SDO_GEOMETRY, param VARCHAR2)

Nella sintassi precedente:

  • geometria1 è una colonna di tipo SDO_GEOMETRY in una tabella. Questa colonna deve essere indicizzata spazialmente.

  • geometry2 è un oggetto di tipo SDO_GEOMETRY. Questo oggetto può o non può provenire da una tabella. Se proviene da una tabella, può essere o non può essere indicizzato spazialmente.

  • param è una stringa opzionale di tipo VARCHAR2. Può specificare una o entrambe le parole chiave min_resolution e max_resolution.

I seguenti esempi eseguono solo un'operazione di filtro primario (senza operazione di filtro secondario). Restituiranno tutte le geometrie mostrate in Figura2 che hanno un MBR che interagisce con la finestra della query. Il risultato dei seguenti esempi sono le geometrie geom_1, geom_2 e geom_3.

Esempio1 esegue un'operazione di filtro principale senza inserire la finestra della query in una tabella. La finestra verrà indicizzata in memoria e le prestazioni saranno molto buone.

Esempio 1 Filtro primario con una finestra di query temporanea

SELECT A.Feature_ID FROM TARGET A  WHERE sdo_filter(A.shape, SDO_geometry(2003,NULL,NULL,
                                       SDO_elem_info_array(1,1003,3),
                                       SDO_ordinate_array(x1,y1, x2,y2))
                           ) = 'TRUE';   

Nell'esempio 1, (x1, y1) e (x2, y2) sono gli angoli in basso a sinistra e in alto a destra della finestra della query.


1
Fantastico .. Quindi dovrei creare la geometria del cerchio per rappresentare il raggio e poi vedere quali poligoni si intersecano .. interessante .. grazie per le informazioni
ho lottato con un orso una volta.

Sì ... dai ... Spero che funzioni bene per te.
l.lijith,

5

Qualsiasi tentativo di includere A includerà probabilmente D, E, F, G. Il problema non può essere risolto senza avere un percorso esatto che definisce ciascuna area di codice postale.

Trova un tale database, quindi crea un SPATIALindice usando tali poligoni arbitrari.


So che ho bisogno di dati spaziali (e ce l'ho, ma è in una tabella Oracle e non sto trovando molte informazioni su come convertirli) .. Il problema è capire come interrogare i dati.
ho lottato con un orso.

Se sei soddisfatto delle prestazioni del nuovo codice, questo è probabilmente il migliore. Nota: la query elenca la distanza da ogni zip, quindi probabilmente non esiste un potenziale di ottimizzazione. (Sarò piacevolmente sorpreso se otterrai un codice migliore.)
Rick James,

è una specie di cosa sto pensando anch'io. Ti darò la generosità prima che scada e tu ne ricevi la metà comunque .. voglio solo vedere quali altre risposte potrei ottenere prima.
ho lottato con un orso.

3

Lo stai facendo male. Innanzitutto, se possibile, utilizzare PostGIS, che è il principale RDMBS con soluzione spaziale.

Quindi si desidera seguire questi passaggi.

  1. Abbassa lo ZCTA (aree di tabulazione del codice postale) dal set di dati TIGER del censimento . I codici postali non sono in realtà noti per certo. Ufficialmente, i codici postali sono solo per uso interno da USPS. Poiché tutti li usano, incluso il governo, la seconda fonte più autorevole è diventata lo shapefile ZCTA.
  2. Importa questi shapefile nel tuo database, con PostgreSQL puoi usarlo facilmente shp2pgsql
  3. Indicizza la geometria che hai importato.

    CREATE INDEX ON census_zcta USING gist (geog);
    ANALYZE census_zcta;
    
  4. Eseguire una query POI (Point of Interest) contro gli shapefile. Il punto di interesse nel tuo caso sono i cavi di input, questo sarà simile a questo,

    SELECT *
    FROM census_zcta AS zcta
      WHERE ST_Intersects( zcta, ST_MakePoint(long,lat)::geog );
    

ℹ 1609.344 Metri = 1 Miglio

MySQL

Con MySQL avrai

  1. Usa ogr2ogr per generare istruzioni di inserimento MySQL per il Census Shapefile.
  2. Utilizzare MBRIntersectsper utilizzare l'indice spaziale. L'interrogazione finale dovrebbe assomigliare a qualcosa

    SELECT *
    FROM zcta
    WHERE MBRIntersects( geom, Point(long,lat) )
      AND ST_Intersects ( geom, Point(long,lat) );
    

3
1) So di aver sbagliato. ecco perché l'ho chiesto. 2) la società per cui lavoro ha pagato l'accesso ai limiti interni del codice postale usps. abbiamo lavorato direttamente con gli usps per questo progetto e 3) in generale, suggerendo che OP utilizza un set di strumenti completamente diverso non è una risposta corretta.
ho lottato con un orso.

1
@iwrestledabearonce Si può fare tutte queste cose con MySQL 8 anche solo sostituire il ST_DWithinconMBRIntersects
Evan Carroll

1
"accesso a pagamento ai limiti interni del codice postale usps" ti capita di conoscere il nome di quel prodotto? AFAIK non esiste nulla del genere. (sebbene USPS offra 2 prodotti dati e alcune API per l'indirizzo di decodifica)
Evan Carroll

1
grazie per aver aggiunto le informazioni su mysql. +1. l'API non è pubblico e non è elencato su nessun sito web, infatti l'URL dell'endpoint non ha nemmeno un nome di dominio, lo richiediamo direttamente dall'indirizzo IP. tuttavia, solo per dimostrare che l'API esiste, è elencata in questo documento (i 3 che si riferiscono a EDDM sono quelli a cui mi riferisco) usps.com/business/web-tools-apis/archive/…
Ho lottato con un orso una volta.

1
In realtà sembra legittimo se si sta eseguendo l'endpoint EDDM / SelectZIP. Non è pubblicizzato a tale scopo, ma complimenti per trovare quel punto finale.
Evan Carroll, il

1

Dai un'occhiata a questo set di dati da GreatData.com ( tieni presente che questo non è open source ma un servizio a pagamento).

Usano la densità di popolazione anziché il centro della zip.

E come utilizzare il tipo di dati spaziali del server sql per ottenere rapidamente risultati corretti.

Spero che sia di aiuto.


Questo set di dati è disponibile per MySQL o è solo per SQL Server?
ypercubeᵀᴹ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.