Python GeoDjango触摸功能运行缓慢
首先,这是我的设置:Python GeoDjango触摸功能运行缓慢,python,django,postgresql,postgis,geodjango,Python,Django,Postgresql,Postgis,Geodjango,首先,这是我的设置: Python 2.7.6 Django 1.6 PostgreSQL 9.3.1 PostGIS 2.1.1 我已将自然地球和数据集加载到PostGIS中。以下是我使用的Django模型: class Location(models.Model): name = models.CharField(max_length=255) imported_from = models.CharField(max_length=255) admin_level
- Python 2.7.6
- Django 1.6
- PostgreSQL 9.3.1
- PostGIS 2.1.1
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)}
这个查询在某些地方(如安哥拉)运行得很好,但在其他一些地方(如美国)运行得非常慢。我确实在几何体上创建了一个要点索引,但我没有看到我预期的速度。当我为美国运行查询时,django调试工具栏告诉我查询()需要106260.14毫秒才能完成,这显然是不可接受的
整个位置表只有4865个条目,那么发生了什么?我发出这个查询对吗?是的,我希望它会很慢,因为您链接到的几何体非常大:
[[ MULTIPOLYGON - 346 elements, 36054 pts ]]
要点索引也不会有帮助,因为CPU会消耗大量时间来确定该点是否在这个特定的详细多边形内,而不是确定它是否在包含数千行数据的边界框(bbox)内。请注意,这是几何图形和一个重叠在几个大陆上的bbox:
由于bbox在带有+ve经度的日期线上弯曲,它覆盖了欧洲。这意味着,如果在欧洲查询一个点,它将与美国的bbox相交,PostGIS可能需要检查这个大型几何体,以查看它是否与多边形接触。请参阅以了解GiST索引的工作原理,以及为什么重叠较少的较小框查询速度最快
最好的解决方案是使用较小的几何图形,这些几何图形本身具有较少的元素/点,并且通常具有较小的BBox以帮助编制GiST索引。您提到的“状态”数据集更理想,因为它们的地理范围有限,顶点可能更少(有助于详细的空间关系查询)。除了自然地球之外,确定全球行政边界的一个非常好的数据集是:
这两个选项都会移动边界并改变“接触”的含义,因为边界不同,这会对“接触”产生巨大的影响。请注意,还有几个更常见的运算符,它们表示不同的内容,例如“相交”、“包含”和“内部”;请看这是一个非常好的解释,完全不是我所期望的。另一个解决方案是,我们可以简单地修剪夏威夷/阿拉斯加的外部点,使bbox更小。如果我们去美国的数据集,这个问题实际上不会得到解决,因为夏威夷/阿拉斯加的bbox仍然会环绕。