Django でGeopositionFieldを使用して、ユーザーの座標を保存しています。ここで、現在のユーザーに最も近い 20 人のユーザーのリストを見つけたいと考えています。GeopositionField でその機能を実現できますか? GeoDjangoで簡単に距離を検索できるのは知っていますが、Herokuとpostgresqlを使っているのでコストを抑えたいのと、postgressqlならPostGISをインストールするしかなさそうです。
助言がありますか?
Django でGeopositionFieldを使用して、ユーザーの座標を保存しています。ここで、現在のユーザーに最も近い 20 人のユーザーのリストを見つけたいと考えています。GeopositionField でその機能を実現できますか? GeoDjangoで簡単に距離を検索できるのは知っていますが、Herokuとpostgresqlを使っているのでコストを抑えたいのと、postgressqlならPostGISをインストールするしかなさそうです。
助言がありますか?
2 点間の距離については、Geopy を使用できます。
ドキュメントから:距離.距離の使用例は次のとおりです。
>>> from geopy import distance
>>> _, ne = g.geocode('Newport, RI')
>>> _, cl = g.geocode('Cleveland, OH')
>>> distance.distance(ne, cl).miles
538.37173614757057
これを Django プロジェクトに実装します。models.py で通常のモデルを作成します。
class User(models.Model):
name = models.Charfield()
lat = models.FloatField()
lng = models.FloatField()
少し最適化するには、ユーザー オブジェクトをフィルタリングして、最初に近くのユーザーの概算を取得します。この方法では、データベース内のすべてのユーザーをループする必要はありません。この概算見積もりはオプションです。プロジェクトのすべての要件を満たすには、追加のロジックを作成する必要がある場合があります。
#The location of your user.
lat, lng = 41.512107999999998, -81.607044999999999
min_lat = lat - 1 # You have to calculate this offsets based on the user location.
max_lat = lat + 1 # Because the distance of one degree varies over the planet.
min_lng = lng - 1
max_lng = lng + 1
users = User.objects.filter(lat__gt=min_lat, lat__lt=max__lat, lat__gt=min_lat, lat__lt=max__lat)
# If not 20 fall back to all users.
if users.count() <= 20:
users = User.objects.all()
自分のユーザーと users 内の各ユーザーとの距離を計算し、それらを距離で並べ替えて、最初の 20 を取得します。
results = []
for user in users:
d = distance.distance((lat, lng), (user.lat, user.lng))
results.append( {'distance':d, 'user':user })
results = sorted(results, key=lambda k: k['distance'])
results = results[:20]
ここには2つのオプションがあると思います:
空間インデックス (Postgis および Geodjango で PointField とともに使用) と GeopositionField を使用せずに効率的な方法はありません。この問題に対処するために私が見つけた唯一の方法は次のとおりです。
GeopositionField は座標をテキストとして格納しますが、フィールド.latitude
で およびlongitude
を使用して取得できます。
Postgresql 9.1+ ( http://wiki.postgresql.org/images/4/46/Knn.pdf ) では K-Nearest-Neighbors 問題がサポートされているようです。ただし、ポイントを格納するためにテーブルに別の列を追加するか ( http://www.postgresql.org/docs/9.2/static/datatype-geometric.html )、GeopositionField の距離関数を実装する必要があると思います。
開発のためだけに Heroku の基本的なセットアップを使用していて、より高いプランに変更する予定がある場合は、他の heroku プランが Postgis をサポートしているため、最初のアプローチを使用することをお勧めします。このアプローチは簡単に実装でき、後で単純な Postgis に変更できます。関数呼び出し。
ただし、これが空間データを扱う唯一のケースである場合は、Point フィールドと KNN サポートを使用することをお勧めします。したがって、将来、postgis のサポートは必要ありません。
ソース コードをGeopositionField
ざっと見てみると、 は座標をプレーン テキスト ( <latitude>,<longitude>
) として格納しているだけなので、データベースから適切なデータを効率的に抽出する方法はありません。効率的なデータベース クエリが必要な場合は、GeoDjango または PostGIS を使用する必要があります (または、空間データ検索を提供する別の方法を見つけます)。