2

我有以下类型的数据:

数据被分割成“帧”,每个帧都有一个开始和停止“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)
4

3 回答 3

1

如果我理解正确,gpstime 是一个时间列表,并且您想生成一个帧名列表,其中每个 gpstime 都有一个。您当前执行此操作的方式确实非常慢,因为它会为每个时间戳进行数据库查询。您需要最小化数据库命中的数量。

首先出现在我脑海中的答案是使用 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'
于 2013-06-11T19:37:04.940 回答
0

加快速度的最佳方法是向这些字段添加索引:

start_gps = models.FloatField(db_index=True)
stop_gps = models.FloatField(db_index=True)

然后运行manage.py dbsync

于 2013-06-11T22:22:22.970 回答
0

帧表非常大,但我有另一个值可以将在这种情况下搜索到的帧降低到 50 以下。实际上并没有模式,每一帧都以与前一站相同的 gpstime 开始。

我不太明白您如何将搜索帧数降低到 50,但是如果您gpstime仅在 50 中搜索 10,000 个值frames,那么将这 50 个帧加载到 RAM 中并在Python,使用类似于 foobarbecue 的答案。

但是,如果您在gpstime整个表中搜索 10 个值,例如 10,000,000 frames,那么您可能不想将所有 10,000,000 帧加载到 RAM 中。

您可以通过添加以下索引来让数据库执行类似的操作...

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 中。

于 2013-06-12T14:09:29.543 回答