如何有效地计算Java中间隔列表中的点列表的命中数?

时间:2016-02-02 19:29:37

标签: java mysql algorithm performance intervals

我有一个大约50,000点在0到250,000,000之间的列表和一个大约10,000,000个间隔的列表。间隔存储在12个表中的MySQL数据库中。

我想计算每个点周围有多少个间隔。我尝试了几种方法来做到这一点,但我总是遇到问题。如果我想构建一个间隔树,它需要很多内存,只需要在列表上迭代需要很长时间。

我得到一个点列表后大约10秒内我需要结果。另外,准备数据库或创建数据结构不是问题。因此,如果只需要进行一次这种准备就可以花费更多的时间,那就没关系了。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

I would do this with files.

  1. Create a file with 20 million records listing locations of endpoints, and whether going from left to right you have +1 interval (start of interval), or -1 interval (end of interval)
  2. Sort this file by location.
  3. Run through the file ONCE, and emit for each location a record with the location, how many endpoints to its left, and how many if you are at that point.
  4. Put the contents of that file in the database, with a BTREE index.

Now for each point you can use the index to find the record with the last location larger than or equal to your point. And then access the correct field depending on that.

If you can't coax MySQL to do this in time, you can use BerkeleyDB to implement the BTREE and just do that. Or heck, you can probably just sort your points then scan that file in parallel with the 20 million point file. (I'd try BerkeleyDB first.)

答案 1 :(得分:0)

没有简单的解决方案。有(我相信)没有直接的方法来执行查询而不扫描每个表的至少一半。 “half”来自INDEX(Start), INDEX(End),希望优化器能够动态选择更好的索引。这是“订单(N)”。

<强>吊桶即可。通过发明“桶”并确定哪个区间位于哪个桶(或桶)中,您可以通过询问它所在的单个桶来搜索点,然后在该桶内扫描Start..End。 INDEX(bucket, start), INDEX(bucket, end)。但是,它确实需要复制某些行(因为间隔可能跨越多个存储区)。它是对性能的部分改进,并且在插入和选择方面涉及一些复杂性。桶的数量成为速度和空间之间的权衡。

<强>非重叠即可。如果你可以把它变成非重叠的间隔,那么有一个更好的方法,就是Order(1)。 Reference。它确实涉及插入和选择的复杂性,但存储例程可以隐藏这样的。

第13张表。如果您使用存储桶或不重叠,那么可能更好地拥有第13个搜索表,从而将复杂性限制在该表中而不会弄乱现有的12个。