Calculer la distance entre les Codes postaux... ET les utilisateurs.
C'est plus une question de quelque chose que j'ai besoin de toute urgence, afin de ne pas passer toute la journée sur les gars.
J'ai construit un site de rencontres (disparu depuis longtemps) en 2000, et l'un des défis était de calcul de la distance entre les utilisateurs, de sorte que nous pourrions présenter votre "correspond" à l'intérieur d'un X mile radius. Simplement d'exposer le problème, compte tenu de la suite de schéma de base de données (environ):
TABLE UTILISATEUR
UserId
Nom d'utilisateur
Code postal
CODE POSTAL DE LA TABLE
Code postal
Latitude
Longitude
Avec l'UTILISATEUR et code POSTAL d'être rejoint sur l'UTILISATEUR.Cp = CP.Code postal.
Quelle approche vous prendre pour répondre à la question suivante: Quels sont les autres utilisateurs vivent dans des Codes postaux qui sont à moins de X km de l'utilisateur du Code Postal.
Nous avons utilisé le Données du recensement de 2000, qui a des tables de codes postaux et de leurs approximative de la latitude et de la longitude.
Nous avons également utilisé la Haversine Formule pour le calcul des distances entre deux points sur une sphère... assez simple math vraiment.
La question, au moins pour nous, être à l'âge de 19 ans, les étudiants du collège nous avons été, est vraiment devenu la façon la plus efficace de calculer et/store distances de tous les membres de tous les autres membres. Une approche (celui que nous avons utilisé) serait d'importer toutes les données et de calculer la distance DE chaque code postal POUR tous les autres code postal. Alors vous feriez stocker et indexer les résultats. Quelque chose comme:
SELECT User.UserId
FROM ZipCode AS MyZipCode
INNER JOIN ZipDistance ON MyZipCode.ZipCode = ZipDistance.MyZipCode
INNER JOIN ZipCode AS TheirZipCode ON ZipDistance.OtherZipCode = TheirZipCode.ZipCode
INNER JOIN User AS User ON TheirZipCode.ZipCode = User.ZipCode
WHERE ( MyZipCode.ZipCode = 75044 )
AND ( ZipDistance.Distance < 50 )
Le problème, bien sûr, est que le ZipDistance table va avoir BEAUCOUP de lignes. Il n'est pas complètement impraticable, mais il est vraiment très grand. Aussi il nécessite de pré-travail sur l'ensemble du jeu de données, qui n'est pas ingérable, mais pas nécessairement souhaitable.
De toute façon, je me demandais ce que l'approche de certains gourous pourrait prendre quelque chose de ce genre. Aussi, je pense que c'est un problème commun des programmeurs s'attaquer de temps en temps, surtout si vous considérez les problèmes qui sont juste avec des algorithmes similaires. Je suis intéressé par une solution complète qui comprend au moins des CONSEILS sur tous les morceaux pour le faire très rapidement en fin de manière efficace. Merci!
Vous devez vous connecter pour publier un commentaire.
Ok, pour commencer, vous n'avez pas vraiment besoin d'utiliser le Haversine formule ici. Pour les grandes distances où une moins précis formule produit une erreur plus grande, vos utilisateurs ne se soucient pas si le match est de plus ou moins quelques miles, et pour rapprocher les distances, l'erreur est très faible. Il y a de plus facile (à calculer) les formules figurant sur la Distance Géographique article de Wikipédia.
Depuis les codes postaux ne sont rien comme uniformément espacés, d'un processus que les partitions de façon uniforme va souffrir puissamment dans les zones où ils sont groupés étroitement (côte est près de DC en étant un bon exemple). Si vous voulez une comparaison visuelle, découvrez http://benfry.com/zipdecode et de comparer le code postal préfixe 89 07.
Une bien meilleure façon de traiter avec l'indexation de cet espace est d'utiliser une structure de données comme un Quadtree ou un R-tree. Cette structure vous permet de faire spatiale et distance des recherches sur des données qui n'est pas uniformément espacés.
Voici ce qu'un Quadtree ressemble:
À la recherche sur elle, vous explorez chaque grande cellule à l'aide de l'indice de petites cellules qui sont en elle. Wikipedia l'explique de manière plus approfondie.
Bien sûr, puisque c'est un assez communs chose à faire, quelqu'un d'autre a déjà fait le plus dur pour vous. Puisque vous n'avez pas spécifié de la base de données que vous utilisez, l'extension PostgreSQL PostGIS servira d'exemple. PostGIS inclut la capacité à mener des travaux de R-tree spatiale des indices qui vous permettent de faire efficace spatiale de l'interrogation.
Une fois que vous avez importé vos données et construit l'index spatial, de l'interrogation à distance est une requête comme:
Je vais vous permettre de travailler à travers le reste du tutoriel vous-même.
Voici quelques autres références pour vous aider à démarrer.
Je serais tout simplement il suffit de créer un zip_code_distances table et de pré-calculer les distances entre tous les 42K zipcodes aux etats-unis qui sont dans un de 20 à 25 km autour de chaque d'autres.
Seulement, y compris zipcodes dans un de 20 à 25 milles de rayon de réduire le nombre de lignes dont vous avez besoin pour stocker dans le tableau des distances de maximum de 1,7 milliard de dollars (42K ^ 2) - 42K à une beaucoup plus gérable 4 millions.
J'ai téléchargé un code postal fichier de données à partir du web qui contient les latitudes et longitudes de tous les officiels NOUS zipcodes au format csv:
J'ai écrit un rapide et sale programme C# pour lire le fichier et de calculer les distances entre chaque code postal, mais seulement de la sortie zipcodes qui relèvent de 25 milles de rayon:
La résultante de sortie de fichier se présente comme suit:
Je voudrais ensuite il suffit de charger ce que les données de distance dans mon zip_code_distances table à l'aide de load data infile et ensuite l'utiliser pour limiter l'espace de recherche de ma demande.
Par exemple, si vous avez un utilisateur dont le code postal est 91210 et ils veulent trouver des gens qui sont dans un rayon de 10 km autour d'eux, puis vous pouvez faire ce qui suit:
Espère que cette aide
EDIT: étendue rayon de 100 miles qui a augmenté le nombre de code postal distances à 32,5 millions de lignes.
rapide contrôle de performance pour code postal 91210 exécution de 0,009 secondes.
Vous pourriez raccourci le calcul, juste en supposant une boîte au lieu d'une circulaire de rayon. Puis lors de la recherche il vous suffit de calculer inférieure/limite supérieure de lat/lon en un point donné+"rayon", et aussi longtemps que vous avez un index sur la lat/lon colonnes vous de pouvoir retirer tous les dossiers qui relèvent de la boîte assez facilement.
Vous pouvez diviser votre espace en régions d'une taille à peu près égale, par exemple, se rapproche de la terre comme un buckyball ou de l'icosaèdre. Les régions peuvent même se chevaucher un peu, si c'est plus facile (par exemple, faire de la circulaire). Enregistrer les région(s) chaque code POSTAL est dans. Ensuite, vous pouvez précalculer la distance maximale possible entre chaque région de la paire, qui a le même O(n^2) problème que le calcul de toutes le code POSTAL de paires, mais pour les plus petites n.
Maintenant, pour chaque code POSTAL, vous pouvez obtenir une liste des régions qui sont certainement au sein de votre gamme donnée, et une liste de régions qui traversent la frontière. Pour les premiers, il suffit de prendre tous les codes postaux. Pour ce dernier, de forage vers le bas dans chaque région de la frontière et de calculer à l'encontre de certains codes postaux.
C'est certainement plus complexe sur le plan mathématique, et en particulier le nombre de régions devrait être choisi pour un bon équilibre entre la taille de la table contre le temps passé à calculer à la volée, mais il réduit la taille de la table précalculée par une bonne marge.
Je voudrais utiliser la latitude et la longitude. Par exemple, si vous avez une latitude de 45 et une longitude de 45 et ont été invités à trouver des correspondances dans les 50 miles, puis vous pouvez le faire en déplaçant 50/69 sat en latitude et 50/69 de sat vers le bas en latitude (1 ° de latitude ~ 69 miles). Sélectionnez les codes postaux avec les latitudes dans cette gamme. Les Longitudes sont un peu différentes, car ils sont plus petits que vous vous déplacez plus près des pôles.
Mais à 45°, 1 longitude ~ 49 miles, de sorte que vous pouvez déplacer 50/49ths gauche en latitude et 50/49ths droit de la latitude, et sélectionnez tous les codes postaux à partir de la latitude avec cette longitude. Cela vous donne tous les codes postaux à l'intérieur d'un carré avec des longueurs de plusieurs centaines de kilomètres. Si vous voulez être vraiment précis, vous pouvez utiliser le Haversine formule de sorcière que vous avez mentionné à éliminer les zips dans les coins de la boîte, pour vous donner une sphère.
Pas chaque paire possible de zip codes vont être utilisés. Je voudrais construire zipdistance comme un "cache" de la table. Pour chaque demande de calculer la distance pour cette paire et de les enregistrer dans la mémoire cache. Lorsqu'une demande pour une distance paire vient, de regarder d'abord dans le cache, puis calculer si il n'est pas disponible.
Je ne connais pas les subtilités de calculs de distance, donc je voudrais aussi vérifier si le calcul à la volée est moins cher que de rechercher (en tenant également compte de la façon dont vous avez souvent à calculer).
Je sais que ce post est TROP vieux, mais en faisant quelques recherches pour un client j'ai trouvé de nouvelles fonctionnalités de l'API Google Maps et c'est tellement simple à mettre en œuvre, vous avez juste besoin de passer à l'url de l'origine et de destination, les codes postaux, et il calcule la distance même avec le trafic, vous pouvez l'utiliser avec n'importe quelle langue:
http://maps.googleapis.com/maps/api/distancematrix/json?origins=90210&destinations=93030&mode=driving&language=en-EN&sensor=false%22
suivant le lien, vous pouvez voir qu'il renvoie un json. Rappelez-vous que vous avez besoin d'une clé API pour l'utiliser sur votre propre hébergement.
source:
http://stanhub.com/find-distance-between-two-postcodes-zipcodes-driving-time-in-current-traffic-using-google-maps-api/
J'ai le problème fonctionne très bien, et à peu près tout le monde la réponse de l'ai utilisé. Je pensais à ce sujet dans les termes de l'ancienne solution au lieu de "recommencer." Babtek obtient le feu vert pour dire dans dans les termes les plus simples.
Je vais passer le code, parce que je vais vous donner les références pour en déduire le besoin de formules, et il y a trop à proprement poster ici.
1) d'Envisager d'Un Point sur une sphère, représentée par la latitude et la longitude. Comprendre Nord, le Sud, l'Est et à l'Ouest les bords de la boîte 2X kilomètres avec Un Point au centre.
2) Sélectionnez tous les points à l'intérieur de la boîte à partir du code Postal de la table. Cela inclut une simple clause where avec les deux Entre les déclarations de limiter par la Lat et Long.
3) Utiliser le haversine formule pour déterminer la partie sphérique de la distance entre Un Point et chaque point de B renvoyé à l'étape 2.
4) Jeter tous les points B où la distance A -> B > X.
5) Sélectionnez où les utilisateurs code Postal est dans le reste de l'ensemble de points B.
C'est assez rapide pour > 100 miles. La plus longue suite a ~ de 0,014 secondes pour calculer le match, et trivial pour exécuter l'instruction select.
Aussi, comme une note de côté, il était nécessaire de mettre en œuvre les mathématiques dans un couple de fonctions et de les appeler dans SQL. Une fois que j'ai passé une certaine distance, le numéro correspondant de ZipCodes était trop gros pour passer à SQL et l'utilisation comme DANS l'énoncé, j'ai donc dû utiliser une table temporaire et rejoindre la résultante ZipCodes à l'Utilisateur sur le code Postal de la colonne.
Je soupçonne que l'utilisation d'un ZipDistance table ne sera pas fournir un rendement à long terme de gain. Le nombre de lignes devient vraiment grand. Si vous de calculer la distance de chaque zip à tous les autres zip code (éventuellement), alors la résultante du nombre de lignes de 40 000 codes postaux serait ~ 1.6 B. Whoah!
En alternance, je suis intéressé par l'utilisation de SQL intégré de type géographie à voir si cela va rendre cela plus facile, mais la bonne vieille int/float types servi amende pour cet échantillon.
Donc... la liste définitive des ressources en ligne que j'ai utilisé, pour votre référence:
1) La Différence maximale, la Latitude et la Longitude.
2) La Formule Haversine.
3) Longue mais complète la discussion de l'ensemble du processus, que j'ai trouvé de Googler trucs dans vos réponses.