2015-11-22 19 views
1

我正在努力使用戶所在位置的10英里範圍內的所有事件。我的模型是這個樣子:在一個點的x英里內找到物體

class User(models.Model): 
    location = models.PointField() 
    ... 


class Event(models.Model): 
    location = models.PointField() 
    ... 

在我的測試中,當我檢查用戶和事件之間的距離,我得到的值11.5122663513

from geopy.distance import vincenty 

print vincenty(request.user.location, event.location).miles # 11.5122663513 

然而,當我查詢所有10英里用戶的位置的範圍內活動時,返回的事件:

Event.objects.filter(location__distance_lte=(request.user.location, D(mi=10))).count() # 1 

只有當我把半徑不到4英里,並過濾生效:

Event.objects.filter(location__distance_lte=(request.user.location, D(mi=3))).count() # 0 

我跟着docs' example幾乎到了,所以我不認爲我的查詢是問題。

什麼可能導致這種差異?

回答

1

這非常依賴於您使用的數據庫類型。

因爲笛卡爾數學比地理空間數學快得多,所以查詢可能將座標視爲它們在平面上而不是在球體上。

docs解釋是這樣的:

大多數人都熟悉的地球表面上使用經緯度 參考位置。然而,緯度和經度是角度,而不是距離。換句話說,雖然平面上兩點之間的最短路徑是一條直線,但曲面上兩點之間的最短路徑(如地球上的 )是一個大圓的弧。因此,需要額外的計算 來獲得平面單位的距離(例如,公里和 英里)。使用地理座標系可能會在稍後引入開發人員的併發症 。例如,Spatialite 不具有使用地理座標系(例如,地理座標系)執行幾何之間的距離計算的能力。構建 查詢以查找存儲爲 WGS84的縣邊界5英里範圍內的所有點。

地球表面的某些部分可能投影到二維平面或笛卡爾平面上。投影座標系尤其適用於特定區域的應用,例如,如果您知道您的數據庫將只涵蓋北堪薩斯州的幾何圖形,那麼您可以考慮使用特定於該區域的投影系統。此外,投影座標系以笛卡爾單位(如 米或英尺)定義,從而簡化距離計算。

此外,這可能會受到您的數據庫選擇的影響。如果您使用的是Postgres/PostGIS的,它在文檔下面的註釋:

在PostGIS的,ST_Distance_Sphere不限制幾何類型 地理距離的查詢與執行。但是,這些 查詢可能需要很長時間,因爲對於查詢中的每一行,動態計算的大圓距離必須爲 。這是因爲傳統幾何字段上的空間索引不能使用。

對於WGS84距離查詢的更好性能,請考慮在數據庫中使用 地理列,而不是因爲它們能夠在距離查詢中使用其空間索引 。您可以通過在您的字段 定義中設置geography = True來告訴GeoDjango到 使用地理欄。

您可以通過打印出原始的SQL查詢這個自己:

qs = Event.objects.filter(location__distance_lte=(request.user.location, D(mi=10)) 
print qs.query 

根據您的數據庫類型和數據計劃存儲量,你有幾個選擇:

  • 過濾點第二次在python
  • 嘗試設置geography=True
  • 套裝明確SRID
  • 取一個點,buffer it out into a circle利用指定的半徑,然後使用contains
  • 使用不同的數據庫類型

發現,圓內點如果您共享原始查詢,它會更容易找出發生了什麼事。

+0

我結束了緩衝區出點到一個圓圈選項。對於任何與該選項一起使用的人,請務必將[將半徑轉換爲度數](http://stackoverflow.com/questions/5217348/how-do-i-convert-kilometres-to-degrees-in-geodjango- GEOS)。 – yndolok

相關問題