首先,这是我的设置:
我已将自然地球countries和states数据集加载到PostGIS中。这是我正在使用的Django模型:
class Location(models.Model):
name = models.CharField(max_length=255)
imported_from = models.CharField(max_length=255)
admin_level = models.CharField(max_length=255, blank=True)
geometry = models.MultiPolygonField(blank=True, default=None, null=True)
objects = models.GeoManager() #override the default manager with a GeoManager instance
parent = models.ForeignKey('self', blank=True, default=None, null=True)
def __unicode__(self):
return self.name
@staticmethod
def get_countries(continent):
return Location.objects.filter(parent=continent).order_by('name')
@staticmethod
def get_continents():
return Location.objects.filter(parent=None).order_by('name')
@staticmethod
def get_states(country):
return Location.objects.filter(parent=country).order_by('name')
这应该是相当不言自明的,但需要注意的一点是,这允许一个地点的层次结构(例如,德克萨斯州在美国,在北美)。
我需要获得一组触及其他位置的位置。以下是我在视图中执行此操作的方式:
touching_locations = {x for x in Location.objects.filter(geometry__touches=Location.objects.get(name='LOCATION_NAME').geometry).values_list('name', flat=True)}
这个查询对于某些地方(如安哥拉)来说效果很好,但对于其他一些地方(如美国)来说,它的速度非常慢。我做在geometry
上创建了一个GiST索引,但我没有看到我预期的速度。当我运行美国的查询时,django-debug-toolbar告诉我查询(https://gist.github.com/gfairchild/7476754)需要106260.14毫秒才能完成,这显然是不可接受的。
整个地点表只有4865个条目,所以发生了什么?我是否正确发出此查询?
答案 0 :(得分:2)
是的,我预计它会很慢,因为你链接的几何体是巨大的:
[[ MULTIPOLYGON - 346 elements, 36054 pts ]]
GiST索引也无济于事,因为CPU会烧掉以确定该点是否在此特定详细多边形内,而不是确定它是否在数千行数据的边界框(bbox)内。请注意,这里是几何和一个重叠几个大洲的bbox:
由于bbox以+ ve经度扭转了日期线,因此它覆盖了欧洲。这意味着如果您要查询欧洲的一个点,它将与美国的bbox相交,而PostGIS可能需要检查这个大的几何体以查看它是否接触到多边形。请参阅R-Tree以了解GiST索引的工作原理,以及为什么具有较少重叠的较小框查询速度最快。
最佳解决方案是使用较小的几何图形,这些几何图形本身具有较少的元素/点,并且通常具有较小的bbox以帮助GiST索引。您提到的“状态”数据集更为理想,因为它们具有有限的地理范围和可能更少的顶点(有助于详细的空间关系查询)。除了自然地球之外,世界范围内确定行政边界的一个非常好的数据集是:http://www.gadm.org
这两个选项都会移动边界并改变“触摸”的含义,因为边界不同,这对“触摸”产生了巨大的影响。请注意,还有其他几个更常见且意味着不同的运算符,例如“intersects”,“contains”和“within”;见https://en.wikipedia.org/wiki/DE-9IM