Problema ao obter zips no raio via MySQL

9

Eu tenho uma tabela de códigos postais que inclui o centro lat, lng para cada código postal. Eu o uso para obter uma lista de códigos postais dentro de um raio de milha a partir de qualquer ponto arbitrário.

Apenas me ocorreu que, apenas porque o ponto central de um zip não está dentro de um determinado raio, não significa que o próprio zip não esteja dentro do raio.

Eu usei minhas habilidades de arte super avançadas para ilustrar o ponto aqui:

insira a descrição da imagem aqui

  • Os blobs listrados verdes representam os códigos postais A, B e C.

  • As manchas vermelhas são os centros geográficos de cada código postal

  • O ponto fúcsia é o local de destino e ..

  • O círculo azul irregular é um raio de 1,6 km do local de destino

Se eu executar uma consulta para todos os códigos postais dentro de um raio de 1,6 km a partir da mancha rosa, apenas os códigos postais B e C serão retornados como o ponto central do CEP A não estiver dentro do raio de uma milha, mesmo que a própria mancha rosa está claramente no CEP 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

Como diabos eu escrevo uma consulta que incluirá o zip A nos resultados?

Eu tenho acesso a geometria / espacial para cada código postal que eu posso adicionar à tabela, se necessário, mas não tenho idéia de como usá-lo para essa finalidade no MySQL.


Edit : Passei um dia lendo os documentos Oracle e MySQL para dados espaciais e consegui converter meus dados espaciais para MySQL com sucesso . Como escrevo uma consulta semelhante que usa a coluna geometry em vez de lat e long? Estou usando dados 2D .. a geometria é apenas polígonos e multipolígonos ..

Eu acho que meio que descobri isso ..

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

Deixarei a recompensa em aberto por enquanto, caso alguém tenha uma solução melhor e mais eficiente.

Uma vez eu lutei com um urso.
fonte

Respostas:

7

De indexação e consulta de dados espaciais no Oracle no Oracle® Spatial Developer's Guide 11g Release 2 (11.2):

Consultando dados espaciais

O Spatial usa um modelo de consulta de duas camadas com operações de filtro primário e secundário para resolver consultas espaciais e junções espaciais. O termo de duas camadas indica que duas operações distintas são executadas para resolver consultas. Se as duas operações forem executadas, o conjunto de resultados exato será retornado.

Você não pode anexar um nome de link de banco de dados (dblink) ao nome de uma tabela espacial em uma consulta se um índice espacial estiver definido nessa tabela.

Consulta espacial

Em um índice espacial da árvore R, cada geometria é representada por seu retângulo limite mínimo (MBR). Considere a seguinte camada que contém vários objetos na Figura1. Cada objeto é rotulado com seu nome de geometria (geom_1 para a sequência de linhas, geom_2 para o polígono de quatro lados, geom_3 para o polígono triangular e geom_4 para a elipse) e o MBR em torno de cada objeto é representado por uma linha tracejada.

Figura1 Geometrias com MBRs

Descrição de "Figura1 Geometrias com MBRs"

Uma consulta espacial típica é solicitar todos os objetos que estão dentro de uma janela de consulta, ou seja, uma cerca ou janela definida. Uma janela de consulta dinâmica refere-se a uma área retangular que não está definida no banco de dados, mas que deve ser definida antes de ser usada. A Figura 2 mostra as mesmas geometrias da Figura 1, mas adiciona uma janela de consulta representada pela caixa de linhas pontilhadas pesadas.

Figura2 Camada com uma janela de consulta

Descrição da "Figura2 Camada com uma janela de consulta"

Na Figura 2, a janela de consulta cobre partes das geometrias geom_1 e geom_2, bem como parte do MBR para geom_3, mas nenhuma da geometria real geom_3. A janela de consulta não cobre nenhuma parte da geometria geom_4 ou seu MBR.

Operador de filtro primário

O operador SDO_FILTER implementa a parte do filtro primário do processo de duas etapas envolvido no modelo de processamento de consultas do Oracle Spatial. O filtro primário usa os dados do índice para determinar apenas se um conjunto de pares de objetos candidatos pode interagir. Especificamente, o filtro primário verifica se os MBRs dos objetos candidatos interagem, não se os próprios objetos interagem. A sintaxe do operador SDO_FILTER é a seguinte:

SDO_FILTER(geometry1 SDO_GEOMETRY, geometry2 SDO_GEOMETRY, param VARCHAR2)

Na sintaxe anterior:

  • geometry1 é uma coluna do tipo SDO_GEOMETRY em uma tabela. Esta coluna deve ser indexada espacialmente.

  • geometry2 é um objeto do tipo SDO_GEOMETRY. Este objeto pode ou não vir de uma tabela. Se vier de uma tabela, pode ou não ser indexado espacialmente.

  • param é uma sequência opcional do tipo VARCHAR2. Ele pode especificar uma ou ambas as palavras-chave min_resolution e max_resolution.

Os exemplos a seguir executam apenas uma operação de filtro primário (sem operação de filtro secundário). Eles retornarão todas as geometrias mostradas na Figura 2 que possuem um MBR que interage com a janela de consulta. O resultado dos exemplos a seguir são geometrias geom_1, geom_2 e geom_3.

O Exemplo1 executa uma operação de filtro primário sem inserir a janela de consulta em uma tabela. A janela será indexada na memória e o desempenho será muito bom.

Exemplo1 Filtro primário com uma janela de consulta temporária

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';   

No Exemplo1, (x1, y1) e (x2, y2) são os cantos inferior esquerdo e superior direito da janela de consulta.

l.lijith
fonte
11
Legal .. Então, eu deveria criar a geometria do círculo para representar o raio e depois ver quais polígonos se cruzam .. interessante .. thx pela informação
lutei com um urso uma vez.
Sim ... vamos lá ... Espero que funcione bem para você.
31517
5

Qualquer tentativa de inclusão de A provavelmente incluirá D, E, F, G. O problema não pode ser resolvido sem um caminho exato definindo cada área do código postal.

Encontre esse banco de dados e crie um SPATIALíndice usando polígonos arbitrários.

Rick James
fonte
Eu sei que preciso de dados espaciais (e eu os tenho, mas estão em uma tabela Oracle e não estou encontrando muita informação sobre como convertê-los) .. o problema é descobrir como consultar os dados.
Lutei com um urso uma vez.
Se você está satisfeito com o desempenho do novo código, provavelmente é o melhor. Nota: A consulta lista a distância para cada zip, portanto, provavelmente não há potencial de otimização. (I vai ser agradavelmente surpreendido se você obter o código melhor.)
Rick James
isso também é o que estou pensando. Eu lhe darei a recompensa antes que ela atinja o tempo limite e você receba metade dela de qualquer maneira .. só quero ver que outras respostas eu poderia receber primeiro.
Lutei com um urso uma vez.
3

Você está fazendo isso errado. Primeiro, se possível, use o PostGIS - que é o principal RDMBS com solução espacial.

Então você deseja seguir estas etapas.

  1. Puxe para baixo o ZCTA (áreas de tabulação de código postal) do conjunto de dados TIGER do censo . Os códigos postais não são realmente conhecidos com certeza. Oficialmente, os códigos postais são para uso interno apenas pelo USPS. Como todos os usam, incluindo o governo, a segunda fonte mais autorizada se tornou os shapefiles do ZCTA.
  2. Importe esses shapefiles para o seu banco de dados, com o PostgreSQL você pode usar facilmente shp2pgsql
  3. Indexar a geometria que você importou.

    CREATE INDEX ON census_zcta USING gist (geog);
    ANALYZE census_zcta;
  4. Execute uma consulta de ponto de interesse (POI) nos shapefiles. O ponto de interesse no seu caso são os cabos de entrada, que serão assim,

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

ℹ 1609.344 metros = 1 milha

MySQL

Com o MySQL você terá

  1. Use ogr2ogr para gerar instruções de inserção do MySQL para o Census Shapefile.
  2. Use MBRIntersectspara utilizar o índice espacial. A consulta final deve ser algo como

    SELECT *
    FROM zcta
    WHERE MBRIntersects( geom, Point(long,lat) )
      AND ST_Intersects ( geom, Point(long,lat) );
Evan Carroll
fonte
3
1) eu sei que estava fazendo errado. foi por isso que perguntei. 2) a empresa em que trabalho pagou o acesso aos limites internos do código postal do usps. trabalhamos diretamente com os usuários do projeto e 3) geralmente, sugerir que o OP usa um conjunto de ferramentas totalmente diferente não é uma resposta adequada.
Lutei com um urso uma vez.
11
@iwrestledabearonce Você pode fazer todas essas coisas com o MySQL 8 e apenas substituir o ST_DWithinporMBRIntersects
Evan Carroll
11
"acesso pago aos limites internos do CEP" , você sabe o nome desse produto? AFAIK não existe. (embora USPS faz oferta de 2 produtos de dados e algumas APIs para decodificação de endereço)
Evan Carroll
11
obrigado por adicionar as informações sobre o mysql. +1. a API não é pública e não está listada em nenhum site, de fato, o URL do endpoint nem sequer possui um nome de domínio, solicitamos diretamente no endereço IP. no entanto, apenas para provar que a API existe, ela está listada neste documento (as três que se referem ao EDDM são as que eu estou me referindo) usps.com/business/web-tools-apis/archive/…
um urso uma vez.
11
Na verdade, isso parece legítimo se você estiver executando o terminal EDDM / SelectZIP. Isso não é anunciado para esse fim, mas parabéns por encontrar esse ponto final.
Evan Carroll
1

Confira este conjunto de dados em GreatData.com (observe que este não é de código aberto, mas um serviço pago).

Eles usam densidade populacional em vez do centro do zip.

E como usar o tipo de dados espaciais do servidor sql para obter resultados corretos rapidamente.

Espero que isto ajude.

Matt McDonald
fonte
Esse conjunto de dados está disponível para o MySQL ou apenas para o SQL Server?
precisa saber é o seguinte