2 votos

Vecinos a poca distancia de cada fila

Tengo un proyecto de investigación de 180.000 entradas y necesito calcular el número de vecinos (puntos de la misma tabla) que existen en un radio de 300 metros para cada punto. Mi método es muy lento y pregunto si hay una forma mejor.

Mi idea inicial era unir la tabla con la izquierda, luego calcular ST_Distance_Sphere para cada fila de la tabla de resultados, y luego contar de forma agregada el número de entradas que están a menos de 300 metros - pero esto está resultando ser extremadamente lento. El JOIN inicial, en particular, está tardando más de una hora en completarse (todavía se está ejecutando).

SELECT source_id as id, sum(case when dist_meters < 305 THEN 1 ELSE 0 END) as neighbors_within_distance FROM
(SELECT 
    a.id as source_id,
    a.biz_lat as source_lat,
    a.biz_lon as source_lon,
    b.id as match_id, 
    b.biz_lat,
    b.biz_lon,
    ST_Distance_Sphere(ST_MakePoint(a.biz_lon, a.biz_lat), ST_MakePoint(b.biz_lon,b.biz_lat)) as dist_meters
FROM a LEFT JOIN a as b ON 1=1) as processed group by source_id

Actualmente no tengo ningún índice, y las columnas lat/lon se almacenan como flotantes. Podría realizar primero un análisis KNN para seleccionar los 500 puntos más cercanos, y luego filtrar el conjunto de datos más pequeño hasta llegar sólo a los vecinos que cumplen el criterio de los 300 metros - pero no estoy seguro de cómo hacerlo rápidamente.

¿Hay una forma mejor de resolver este problema?

EDIT : Aquí están mis consultas de configuración y las filas de datos de ejemplo

DROP TABLE IF EXISTS a;
CREATE TABLE a (
    id              integer,
    name            text,
    street_address  text,
    city            text,
    state           text,
    zip             text,
    county          text,
    telephone       text,
    fax             text,
    email           text,
    web             text,
    type            text,
    num_employees   text,
    sic_1           text,
    sic_2           text,
    headquarters    text,
    revenue         text,
    biz_lat         float,
    biz_lon         float,
    class           text,
    encoding_type   text,
    bbox1           float,
    bbox2           float,
    bbox3           float,
    bbox4           float,
    display         text,
    source          text
);

Una fila de ejemplo del conjunto de datos

 ID Company Name    Street Address  City    State/Province  Postal Code County  Telephone Number    Fax Number  Company Email Address   URL/Web Address Company Type    No. of Employees    Primary SIC Code 1  Primary SIC Code 2  Headquarters    Sales/Revenue   lat lon class   type    bbox1   bbox2   bbox3   bbox4   display source
54776   26430. bizname  123 fake    Seguin  Texas   78155   El Paso (830) 555-3910              PRIVATE - PARENT    6   7359    Equipment rental & leasin, nec  Headquarters    1,098,000 (USD) 29.56570181 -97.94911784     place   house  29.56565181 29.56575181 -97.94916784    -97.94906784     123 Fake Seguin Guadalupe County  Texas 78155  United States of America

0voto

evojacking Puntos 21
  1. Realmente creo que unirse a 1 = 1 no es una buena idea...
  2. Intente reducir su declaración de selección utilizando ST_DWithin(geom1, geom2, 300) que es definitivamente más rápido que ST_Distance_Sphere()
  3. ¡Construya índices!
  4. ¿Puede compartir los datos? Una parte al menos.

ACTUALIZACIÓN:

Supongo que sería útil acotar la unión con la condición de distancia antes de la propia unión. ¿Qué tal `JOIN table ON 1=1 distance < 300? ¿Funcionaría?

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X