Geoalchemy2查询所有距离X米以内的用户。

9
我有一个应用程序,接受地址字符串,将其发送到谷歌地图API并获取经纬度坐标,然后我想显示所有距离该点X米的用户(其经纬度存储在我的数据库中),然后我想过滤结果只显示拥有特定宠物的用户。
首先,我有我的模型。
class User(UserMixin, Base):
    first_name = Column(Unicode)

    address = Column(Unicode)
    location = Column(Geometry('POINT'))

    pets = relationship('Pet', secondary=user_pets, backref='pets') 

class Pet(Base):
    __tablename__ = 'pets'   
    id = Column(Integer, primary_key=True)
    name = Column(Unicode)

user_pets = Table('user_pets', Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id')),
    Column('pet_id', Integer, ForeignKey('pets.id'))
)

我从Google API获取我的纬度/经度并将其存储在我的数据库中,因此从地址字符串“伦敦英格兰”中获取:

POINT (-0.1198244000000000 51.5112138999999871)

这将保存在我的数据库中,类似于:
0101000000544843D7CFACBEBF5AE102756FC14940

现在所有的工作都很顺利,但是我在阅读Geoalchemy2文档时似乎找不到一个解决我的问题的示例查询。我想传递另一组经纬度坐标给Geoalchemy2,然后返回最近的10个用户。在查询过程中,我还将过滤只有特定宠物的用户(这对我的查询并非必要,但我想展示整个查询实际上会做什么)。我不太喜欢回答没有提供示例查询的问题,但我真的不知道应该使用哪些函数来实现我的要求结果。我猜我需要使用“ST_DWithin”或“ST_DFullyWithin”,但我找不到任何一个函数的完整示例。谢谢。所以我知道现在有一个工作查询。
distance = 10
address_string = "London, England"
results = Geocoder.geocode(address_string)
# load long[1], lat[0] into shapely
center_point = Point(results.coordinates[1], results.coordinates[0])
print center_point
# 'POINT (-0.1198244000000000 51.5112138999999871)'
wkb_element = from_shape(center_point)
users = DBSession.query(User).\
    filter(func.ST_DWithin(User.location,  wkb_element, distance)).all()

生成以下SQL语句

2013-12-30 15:12:06,445 INFO  [sqlalchemy.engine.base.Engine][Dummy-2] SELECT users.first_name AS users_first_name, users.last_name AS users_last_name, users.phone AS users_phone, users.address AS users_address, users.about AS users_about, ST_AsBinary(users.location) AS users_location, users.profile_image_id AS users_profile_image_id, users.searchable AS users_searchable, users.user_password AS users_user_password, users.registered_date AS users_registered_date, users.id AS users_id, users.last_login_date AS users_last_login_date, users.status AS users_status, users.user_name AS users_user_name, users.email AS users_email, users.security_code AS users_security_code 
FROM users 
WHERE ST_DWithin(users.location, ST_GeomFromWKB(%(ST_GeomFromWKB_1)s, %(ST_GeomFromWKB_2)s), %(param_1)s)
2013-12-30 15:12:06,445 INFO  [sqlalchemy.engine.base.Engine][Dummy-2] {'ST_GeomFromWKB_1': <read-only buffer for 0x7f7d10258f70, size -1, offset 0 at 0x7f7d10258db0>, 'param_1': 10, 'ST_GeomFromWKB_2': -1}

现在无论距离变量是什么,它总是返回所有用户,所以我猜测有些地方不太对,但我想不出原因。
2个回答

10

答案:

单位是以度为半径,所以我需要将英里转换成度数来得到最佳的(粗略)估计值。它不需要非常准确:

d = 90
distance = d * 0.014472
#1 mile = 0.014472 degrees  

r1 = -0.1198244
r2 = 51.5112139

# load long[1], lat[0] into shapely
center_point = Point(r1, r2)
# 'POINT (-0.1198244000000000 51.5112138999999871)'

wkb_element = from_shape(center_point)

users = DBSession.query(User).\
    filter(func.ST_DFullyWithin(User.location,  wkb_element, distance)).all()

2

经纬度数据并不适合距离计算。

每一纬度大约相隔69英里(111公里)。由于地球略微呈椭圆形,这个范围会有所变化。赤道上的距离为68.703英里(110.567公里),两极则为69.407英里(111.699公里)。这是很方便的,因为每一分钟(1/60度)大约相当于一英里。

经线在赤道最宽,为69.172英里(111.321公里),向两极逐渐缩小到零。在北纬或南纬40度处,经度之间的距离为53英里(85公里)。

您可以使用ST_Transform将您的坐标转换为使用米或英里的不同投影。由于这些投影是将地球的球面投影到栅格化平面,因此往往是局部的。英国国家网格(SRID 27700)可能适合您的需求。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接