5

ユーザーが選択した特定の場所からnの都市/町までの距離を表示できる必要があります。これは、地図をクリックして100マイル以内のすべての目的地を取得するようなものですが、地図ではなくWebページ上のリンクになります。

州内から国へ、そして潜在的にグローバルにスケールアップするソリューションを選択する必要があります。つまり、数千から数十万の場所にスケールアップする必要があります。

CITY1_ID、CITY2_ID、およびDISTANCEをリレーショナルDBテーブルに格納することは考えていますが、Webアプリケーション(数百万行)に適しているかどうかは疑問です。

これは、NoSQLデータベースまたはグラフDBを使用してより効率的に実行できますか?または、RDBMSは、適切な設計でこの問題を解決するのに十分ですか?

追加:DBに保存しない場合、次のようになります。サンノゼから100マイル以内のすべての都市を取得しますか?

4

7 に答える 7

4

都市ごとに 1 つ保存city_id, latitude, longitudeし、実行時の入力に基づいて距離を計算する必要があります。

于 2012-10-02T20:20:09.160 に答える
2

2 つの都市間の距離を計算する代わりに、100 マイルの境界ボックスを計算すると、データベースにプラグインする 4 つの float 変数があります。float 比較は、データベース内の距離計算よりもはるかに高速です。欠点は、コーナーでの距離が少し長くなることです。

境界ボックスを計算する PHP 関数

function getBoundingBox($lat_degrees,$lon_degrees,$distance_in_miles)
{
       $半径 = 3963.1; //地球のマイル

        // ベアリング
        $due_north = 0;
        $due_south = 180;
        $due_east = 90;
        $当然_西= 270;

        // 緯度と経度をラジアンに変換
        $lat_r = deg2rad($lat_degrees);
        $lon_r = deg2rad($lon_degrees);

        // $distance_in_miles 離れた最北端、最南端、最東端、最西端の角を見つける
        //元の式から
        // http://www.movable-type.co.uk/scripts/latlong.html

        $northmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_north));
        $southmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_south));

        $eastmost = $lon_r + atan2(sin($due_east)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r)) ;
        $westmost = $lon_r + atan2(sin($due_west)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r)) ;

        $northmost = rad2deg($northmost);
        $southmost = rad2deg($southmost);
        $eastmost = rad2deg($eastmost);
        $westmost = rad2deg($westmost);

        //NWコーナーとSEコーナーの2点を返す
        配列を返します($northmost,$westmost,$southmost,$eastmost);
}

あなたのSQLは

SELECT * FROM table WHERE latitude <= $northmost AND longitude >= $westmost AND latitude >= $southmost AND longitude <= $eastmost

于 2012-10-06T07:09:42.670 に答える
1

私が複数回使用した(ただしmysqlでは使用しない)簡単な解決策は、距離を返す4つのパラメーター、、を使用してユーザー定義関数を作成し、その距離関数some_distance_functionに対してlatitude1すべてlongitude1をテストして、すべてのアイテムを確認することです。距離が指定された値以下です。数千の場所しかない場合、これは非常に問題なく効率的です。latitude2longitude2

数百万のレコードに対してこのクエリを実行する必要がある場合は、(少なくとも検索能力の点で)永続的なデータ構造が優れているため、選択したデータベースで使用できるGIS(地理情報システム)拡張機能を確認することをお勧めします。膨大な数の場所を検索するため。

編集:Microsoftがそれを行う方法の例を示すには、 http://technet.microsoft.com/en-us/library/bb964712( v = sql.105 ).aspxを参照してください。

MySQLは一般的に空間拡張をサポートしているようです。

http://dev.mysql.com/doc/refman/5.0/en/gis-introduction.html
http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html

編集II:

この質問も役立つかもしれません。

MYSQLで2点間の距離を見つけます。(ポイントデータ型を使用)

于 2012-10-02T20:54:11.247 に答える
1

これはRDBMSを使用したソリューションです。2 つのテーブルを保持する

  • CityByLat { latitude, city_id } と緯度のクラスタ化インデックス
  • CityByLng { logitude, city_id } 経度のクラスター化インデックス付き

特定の緯度と経度から特定の半径内にある都市を検索する必要がある場合、2 つのテーブルに対して効率的な範囲クエリを実行して、特定の緯度と経度の範囲内にある都市を取得できます。このようにして取得した都市のみから実際の距離を計算できます。

于 2012-10-06T06:49:26.260 に答える
0

保存せず、実行時に経度と緯度で計算します。都市間のすべての距離を節約するのとは対照的に、非常にスケーラブルです。

基準点 (サンノゼ) があり、すべての都市レコードをループして実行時に計算します (レコードが多い場合は、この計算をクライアントで、おそらく JavaScript などを使用して実行します。サーバーに実行させる場合は、すぐに通行料がかかります)。JavaScript は次のようになります。

var R = 6371; // Radius of the earth in km
var dLat = (lat2-lat1).toRad();  // Javascript functions in radians
var dLon = (lon2-lon1).toRad(); 
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * 
        Math.sin(dLon/2) * Math.sin(dLon/2); 
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
var d = R * c; // Distance in km

上記のコードはhereから来ています

注: 私はオランダ人なのでメートル法を使用しているため、キロメートル単位です。

于 2012-10-02T20:23:31.810 に答える
0

私はNeo4Jを似たようなものに使用しています.Neo4Jは、グラフとして表現できるあらゆるタイプのデータに対して非常にうまくスケーリングします.

于 2012-10-02T20:34:08.727 に答える
0

他の人が指摘したように、各エントリの緯度/経度座標を保存し、実行時に次のようなものを使用して距離を計算すると、km/miles の距離出力が得られます。

function distance($lat1, $lng1, $lat2, $lng2, $miles = true)
{
        $pi80 = M_PI / 180;
        $lat1 *= $pi80;
        $lng1 *= $pi80;
        $lat2 *= $pi80;
        $lng2 *= $pi80;

        $r = 6372.797; // mean radius of Earth in km
        $dlat = $lat2 - $lat1;
        $dlng = $lng2 - $lng1;
        $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
        $km = $r * $c;

        return ($miles ? ($km * 0.621371192) : $km);
}

編集: これは、半径検索内のn 個の一致には適していません。特定の半径内の町/都市の密度を考えると、距離計算を SQL に移動する方がはるかに高速であり、 x km/マイル内の都市と一致させることができます。

于 2012-10-02T20:46:08.560 に答える