根据事件日期查找日期范围的算法

时间:2009-08-17 23:33:36

标签: php map range lookup

我正在编写一个PHP函数,根据我的日期戳,使用一个表来查找应用程序应该去哪个DB分片。

分片配置是这样的(伪代码):第一列是我正在寻找的事件的日期,第二列是事件所在的分片。

pre-2008 -> shard1
2008-2009 -> shard2
2009_01-2009_06 -> shard3
2009_07 -> shard4
2009_08 -> shard5
2009_09 and up -> shard6

正如您所看到的,我想要的配置非常灵活 - 它可以占用任何日期范围,无论大小,都可以映射到分片。

我正在寻找基于给定日期进行查找的最快方法。

例如,如果我的日期是2009-05-02,那么我所追踪的碎片是shard3。如果日期是2007-08-01,那么它是shard1。

实际PHP代码的加分点,因为应用程序是用PHP格式的。

谢谢。

3 个答案:

答案 0 :(得分:2)

<?php

function get_shard($datetime)
{
    $timestamp = strtotime($datetime);

    $shards = array(array('start' => null, 'end' => '2007-12-31'),
                    array('start' => '2008-01-01', 'end' => '2008-12-31'),
                    array('start' => '2009-01-01', 'end' => '2009-06-30'),
                    array('start' => '2009-07-01', 'end' => '2009-07-31'),
                    array('start' => '2009-08-01', 'end' => '2009-08-31'),
                    array('start' => '2009-09-01', 'end' => null),
                    );
    foreach ($shards as $key => $range) {
        $start = strtotime($range['start']);
        $end = strtotime($range['end']);
        if ($timestamp >= $start && $timestamp <= $end) {
            return $key + 1;
        }
        if ($timestamp >= $start && $end === false) {
            return $key + 1;
        }
    }
}


$datetime = '2007-08-01';
echo 'shard' . get_shard($datetime) . "\n";

$datetime = '2009-05-02';
echo 'shard' . get_shard($datetime) . "\n";

$datetime = '2010-01-01';
echo 'shard' . get_shard($datetime) . "\n";

?>

输出:

shard1
shard3
shard6

答案 1 :(得分:2)

我猜你想要在日期范围内打洞,所以我建议你 只需为每个分片指定结束日期,并明确命名一个默认分片 它包含了一些太新而无法容纳其他碎片的东西。

// configure shards
$SHARDS = array(
        // <end date>   => <shard number>
        '2007-12-31'    => 'shard1', // shard1 - up to end of 2007
        '2008-12-31'    => 'shard2', // shard2 - up to end of 2008
        '2009-06-30'    => 'shard3', // shard3 - up to end of June 09
        '2009-07-31'    => 'shard4', // shard4 - up to end of July 2009
        '2009-08-31'    => 'shard5', // shard4 - up to end of August 2009
        'DEFAULT'       => 'shard6', // everything else in shard 6
        );

这样可以很容易地获得正确的日期,并且基于日期查找分片的代码很简单:

function findShardByDate($date) {
    static $default = false;
    static $sorted = false;
    if($sorted === false) {
        // copy of global $SHARDS
        $SHARDS = $GLOBALS['SHARDS'];
        $default = $SHARDS['DEFAULT'];
        unset($SHARDS['DEFAULT']);
        // make sure $SHARDS is sorted
        ksort($SHARDS);
        $sorted = $SHARDS;
        unset($SHARDS);
    }
    // find the first shard which would contain that date
    foreach($sorted as $endDate => $shardName)
        if($endDate >= $date)
            return $shardName;
    // no shard found - use the default shard
    return $default;
}

编辑:使用静态变量,以便只进行一次排序。

答案 2 :(得分:0)

由于您的分片可以严格排序,似乎将它们存储在二叉树中,然后只需通过该树运行二进制搜索就可以获得最快的结果。