我有一个Django/PostgreSQL应用程序,它显示哪些用户离特定用户最近。它使用ORDER子句中的PostGIS 2.0KNN (K最近邻) <->操作符列出用户,最接近的是第一位。我在最初的数据集中发现的是,两个搜索结果是无序的(所有的距离都是从洛杉矶(CA)测量的):
Member, City, State, Distance (miles)
user1, North Las Vegas, NV, 239
user2, Phoenix, AZ, 365
user3, Provo, UT, 568
user4, Twin Falls, ID, 630
user5, Albuquerque, NM, 673
user6, Portland, OR, 828
user7, Bozeman, MT, 896
user8, Seattle, WA, 962
user9, Boulder, CO, 834 <- Out of order!
user10, Laramie, WY, 862 <- Out of order!
user11, Naperville, IL, 1756成员名只是Django的contrib.auth.models用户类中的username列。包含几何信息的UserAccount类定义如下:
class UserAccount(models.Model):
user = models.OneToOneField(User, primary_key=True, unique=True)
address_line_1 = models.CharField(max_length=30)
address_line_2 = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30)
region = models.CharField(max_length=30, blank=True)
postal_code = models.CharField(max_length=10, blank=True)
country = models.ForeignKey('Country')
measurement_sys = models.CharField(max_length=5) # US or Metric
# User's home (default) and current longitude and latitude
home_lon = models.FloatField(default=0.0)
home_lat = models.FloatField(default=0.0)
current_lon = models.FloatField(default=0.0)
current_lat = models.FloatField(default=0.0)
# GeoDjango-specific fields
home_point = models.PointField(srid=4326)
current_point = models.PointField(srid=4326)
objects = models.GeoManager()以下是我的Django视图中的查询:
def members(request, template):
"""View all members of the website."""
uid = request.session['uid'] # PK from User table
# Get the current user's lon/lat and measurement system
try:
ua = UserAccount.objects.get(user_id=uid)
lon = ua.current_lon
lat = ua.current_lat
measurement_sys = ua.measurement_sys
except UserAccount.DoesNotExist as e:
return HttpResponseRedirect(reverse('unable-to-display-members'))
# Define the proximity query.
if measurement_sys == 'US':
multiplier = 0.000621371 # Convert to miles
else:
multiplier = 0.001 # Convert to kilometers
query = "SELECT \
ua.user_id, \
au.username, \
ua.city, \
ua.region, \
ST_Distance( \
ua.current_point::geography, \
ST_GeographyFromText( \
'SRID=4326;POINT(" \
+ str(lon) \
+ " " \
+ str(lat) + \
")' \
) \
)*" + str(multiplier) + " AS distance \
FROM \
user_account ua \
INNER JOIN \
auth_user au \
ON (ua.user_id = au.id) \
WHERE ua.user_id != %s \
ORDER BY \
ua.current_point::geometry \
<-> \
'SRID=4326;POINT(" + str(lon) + " " + str(lat) + ")'::geometry \
LIMIT 250;"
# Run the proximity query
raw_queryset = UserAccount.objects.raw(query, [uid])
# Paginate results
user_list = [user for user in raw_queryset]
list_size = len(list(user_list))
paginator = Paginator(user_list, 10, 4)
paginator._count = list_size
page = request.GET.get('page')
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
return render(request, template, {'users': users})我的问题做错了吗?KNN算子有时会“打嗝”并返回一些无序的结果吗?我问这个问题是因为当我尝试从我的表中取出两条无序记录时,然后为那些地址更远的用户添加更多的记录(例如,在IL、LA、MI、NC、PA、NY和ME中),所有结果都是正确的。
顺便说一下,我的输入位于这里。
谢谢!
发布于 2014-05-30 19:37:25
最新答复:
Postgis有两种近似解决方案,用于kNN邻居功能,因为2011年9月
你的问题是,两者都是近似的,所以它们并不完美。因此,如果您想获得最好的250个结果,您可以使用它们中的任何一个来检索(例如,最好的1000个结果),然后通过ST_DISTANCE命令相同的结果,并限制250个从这些大约1000个结果中得到最好的250个结果。
示例:
SELECT * FROM
(SELECT *,ST_DISTANCE(current_point::geography, 'SRID=4326;POINT(" + str(lon) + " " + str(lat) + ")'::geography ) AS st_dist
FROM ua
ORDER BY current_point::geometry <-> 'SRID=4326;POINT(" + str(lon) + " " + str(lat) + ")'::geometry
LIMIT 1000) AS s
ORDER BY st_dist LIMIT 250;https://stackoverflow.com/questions/23941425
复制相似问题