SqlAlchemy / Sqlite距离计算

时间:2011-03-05 21:06:45

标签: python sqlite sqlalchemy geospatial

我正在使用sqlAlchemy ORM,并且想要计算并返回给定点和存储点的距离。

class Event(Base):

    __tablename__ = 'events'
    # Schema
    id = Column(Integer, primary_key=True)
    title = Column(String(150))
    description = Column(Text)
    url = Column(String(800))
    lat = Column(Float)
    lng = Column(Float)

....和我的疑问:

    nearest = """SELECT *, ((lat - '-41.288889') * (lat - '-41.288889')
 + (lng  - 174.777222) * (lng  - 174.777222)) AS distance FROM events 
ORDER BY distance ASC """

e = Event.query.from_statement(nearest)

这似乎以正确的顺序返回对象,但我无法访问distance属性。如何获取此值 - 或者实现此目的的最佳实践方法是什么?

3 个答案:

答案 0 :(得分:2)

问题1:纬度和经度具有不同的长度......在赤道处相同(假设地球是球体)但在极点处经度是零长度。

更新要举例说明问题的严重性:

向北或向南行驶一度纬度将覆盖大约111.2公里(假设地球是一个球体)。向东或向西经过一度经度将在赤道上覆盖约111.2公里的。在-41.3度的纬度,它将只覆盖83.5公里。

从(-41.3,174.8)到东至(-41.3,174.92)是10.0公里。您的计算方法将其视为13.3 km远 - 错误率为33%

你可以通过一个相当简单的近似来达到4米误差:

from math import pi, sqrt, radians, cos
Earth_radius_km = 6371.009
km_per_deg_lat = 2 * pi * Earth_radius_km / 360.0

# what your SQL query is in effect doing
def approx_dist_1(lat1, lon1, lat2, lon2):
    return km_per_deg_lat * sqrt((lat1 - lat2) ** 2 + (lon1 - lon2) ** 2)

# better version    
def approx_dist_2(lat1, lon1, lat2, lon2):
    # calculate km_per_deg_lon for your central station in Python and 
    # embed it in your query
    km_per_deg_lon = km_per_deg_lat * cos(radians(lat1))
    return sqrt((km_per_deg_lat *(lat1 - lat2)) ** 2 + (km_per_deg_lon * (lon1 - lon2)) ** 2)

这个近似距离足以“找到最近的披萨店”应用程序,并且具有可以在像SQLite这样不支持sin / cos / tan和它们的反转的基本环境中使用的优点。盒子。

问题2:SQLite是宽容的,但你不应该养成使用引号的习惯,如(lat - '-41.288889')

问题3:我无法在SQLlite级别重现您的问题:

sqlite> create table foo (lat float, lon float);
sqlite> insert into foo values(99.9, -170.1);
sqlite> select * from foo;
99.9|-170.1
sqlite> SELECT *, ((lat - '-41.288889') * (lat - '-41.288889')
   ...>  + (lon  - 174.777222) * (lon  - 174.777222)) AS distance from foo;
99.9|-170.1|138874.600631492
sqlite>

也许你应该详细说明“这似乎以正确的顺序返回对象,但我无法访问距离属性”......内省e告诉你什么?

答案 1 :(得分:0)

您可以在此处找到一些帮助:SQLAlchemy custom query column

答案 2 :(得分:0)

正如John Machin指出的那样,你的距离算法有点奇怪,如果你的点数大约相差100公里,将会导致错误的结果。

您需要转换为米(或英尺等)以获得合理的结果。寻找Haversine或Vincenty算法。更好,看看SQLAlchemy是否有一些对你有用的东西。