首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PostGIS最近邻搜索结果混乱?

PostGIS最近邻搜索结果混乱?
EN

Stack Overflow用户
提问于 2014-05-29 19:28:15
回答 1查看 696关注 0票数 3

我有一个Django/PostgreSQL应用程序,它显示哪些用户离特定用户最近。它使用ORDER子句中的PostGIS 2.0KNN (K最近邻) <->操作符列出用户,最接近的是第一位。我在最初的数据集中发现的是,两个搜索结果是无序的(所有的距离都是从洛杉矶(CA)测量的):

代码语言:javascript
复制
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类定义如下:

代码语言:javascript
复制
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视图中的查询:

代码语言:javascript
复制
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中),所有结果都是正确的。

顺便说一下,我的输入位于这里

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-05-30 19:37:25

最新答复:

Postgis有两种近似解决方案,用于kNN邻居功能,因为2011年9月

  • 使用<->操作符,您可以使用包围框的中心来计算对象间的距离,从而得到最近的邻居。
  • 使用<#>运算符,您可以使用边界框本身来计算对象间的距离,从而得到最近的邻居。

你的问题是,两者都是近似的,所以它们并不完美。因此,如果您想获得最好的250个结果,您可以使用它们中的任何一个来检索(例如,最好的1000个结果),然后通过ST_DISTANCE命令相同的结果,并限制250个从这些大约1000个结果中得到最好的250个结果。

示例:

代码语言:javascript
复制
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;
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23941425

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档