我有以下类型的数据:
数据被分段为“帧”,每个帧都有一个开始和停止“gpstime”。在每个帧内都有一堆带有“gpstime”值的点。
有一个帧模型有frame_name,start_gps,stop_gps,...
假设我有一个gpstime值列表,并希望为每个值找到相应的frame_name。
我可以做一个循环...
framenames = [frames.objects.filter(start_gps__lte=gpstime[idx],stop_gps__gte=gpstime[idx]).values_list('frame_name',flat=True) for idx in range(len(gpstime))]
这将给我一个'frame_name'列表,每个gpstime一个。这就是我要的。但这很慢。
我想知道的是:是否有更好的方法来预先形成此查找以获取每个gpstime的帧名称,这比迭代列表更有效。这份清单可能会变得非常大。
谢谢!
编辑:框架型号
class frames(models.Model):
frame_id = models.AutoField(primary_key=True)
frame_name = models.CharField(max_length=20)
start_gps = models.FloatField()
stop_gps = models.FloatField()
def __unicode__(self):
return "%s"%(self.frame_name)
答案 0 :(得分:1)
如果我理解正确,gpstime是一个时间列表,你想要为每个gpstime生成一个帧名列表。您当前的这种做法确实非常慢,因为它为每个时间戳进行数据库查询。您需要最小化db命中数。
首先出现在我头上的答案使用了numpy。请注意,我在这里没有做任何额外的假设。如果您的gpstime列表可以排序,即排序无关紧要,那么可以更快地完成。
尝试这样的事情:
from numpy import array
frame_start_times=array(Frame.objects.all().values_list('start_time'))
frame_end_times=array(Frame.objects.all().values_list('end_time'))
frame_names=array(Frame.objects.all().values_list('frame_name'))
frame_names_for_times=[]
for time in gpstime:
frame_inds=frame_start_times[(frame_start_times<time) & (frame_end_times>time)]
frame_names_for_times.append(frame_names[frame_inds].tostring())
编辑:
由于列表已排序,您可以使用.searchsorted()
:
from numpy import array as a
gpstimes=a([151,152,153,190,649,652,920,996])
starts=a([100,600,900,1000])
ends=a([180,650,950,1000])
names=a(['a','b','c','d',])
names_for_times=[]
for time in gpstimes:
start_pos=starts.searchsorted(time)
end_pos=ends.searchsorted(time)
if start_pos-1 == end_pos:
print time, names[end_pos]
else:
print str(time) + ' was not within any frame'
答案 1 :(得分:0)
加快速度的最佳方法是为这些字段添加索引:
start_gps = models.FloatField(db_index=True)
stop_gps = models.FloatField(db_index=True)
然后运行manage.py dbsync
。
答案 2 :(得分:0)
帧表非常大,但我有另一个降低的值 在这种情况下搜索到的帧数低于50.实际上没有 模式,每帧从前一次停止的同一个gpstime开始。
我不太明白你是如何将搜索到的帧数减少到50的,但是如果你只在50 gpstime
中搜索10,000 frames
个值,那么它可能是最简单的将这50帧加载到RAM中,并使用类似于foobarbecue的答案在Python中进行搜索。
但是,如果您在整个表中搜索10 gpstime
个值,例如10,000,000 frames
,那么您可能不希望将所有10,000,000个帧加载到RAM中。
您可以通过添加以下索引来让DB执行类似操作...
ALTER TABLE myapp_frames ADD UNIQUE KEY my_key (start_gps, stop_gps, frame_name);
...然后使用像这样的查询...
(SELECT frame_name FROM myapp_frames
WHERE 2.5 BETWEEN start_gps AND stop_gps LIMIT 1)
UNION ALL
(SELECT frame_name FROM myapp_frames
WHERE 4.5 BETWEEN start_gps AND stop_gps LIMIT 1)
UNION ALL
(SELECT frame_name FROM myapp_frames
WHERE 7.5 BETWEEN start_gps AND stop_gps LIMIT 1);
...返回......
+------------+
| frame_name |
+------------+
| Frame 2 |
| Frame 4 |
| Frame 7 |
+------------+
... EXPLAIN
显示......
+----+--------------+--------------+-------+---------------+--------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+--------------+-------+---------------+--------+---------+------+------+--------------------------+
| 1 | PRIMARY | myapp_frames | range | my_key | my_key | 8 | NULL | 3 | Using where; Using index |
| 2 | UNION | myapp_frames | range | my_key | my_key | 8 | NULL | 5 | Using where; Using index |
| 3 | UNION | myapp_frames | range | my_key | my_key | 8 | NULL | 8 | Using where; Using index |
| NULL | UNION RESULT | <union1,2,3> | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------+--------------+-------+---------------+--------+---------+------+------+--------------------------+
...所以你可以在一个查询中执行所有查找,这些查询会命中该索引,索引应该缓存在RAM中。