【问题标题】:Algorithm to look up the date range based on event date根据事件日期查找日期范围的算法
【发布时间】:2009-08-17 23:33:36
【问题描述】:

我正在编写一个 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 年 5 月 2 日,那么我要查找的 shard 是 shard3。如果日期是 2007-08-01,那么它就是 shard1。

实际 PHP 代码的奖励积分,因为应用程序是 PHP。

谢谢。

【问题讨论】:

    标签: php map range lookup


    【解决方案1】:

    我猜你不想希望在日期范围内有漏洞,所以我建议你 只需为每个分片指定一个结束日期,并明确命名一个默认分片 它包含所有太新而无法放入其他碎片之一的东西。

    // 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;
    }
    

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

    【讨论】:

    • 好吧,我不想一直排序和查找,因为那很昂贵。否则,我喜欢你的方法,因为确实没有漏洞。
    • 使用开始日期而不是结束日期将消除对“DEFAULT”的需要。
    • 使用开始日期需要默认捕获任何之前第一个分片。
    • 优化速度,你就赢了!
    【解决方案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
    

    【讨论】:

    • 我明白了,但您的实现仍然受到未优化查找的影响。此外,例如,如果您决定更改分片名称或将长分片范围拆分为 2 个较短的分片,则需要重写整个函数。
    【解决方案3】:

    由于您的分片可以严格排序,因此似乎将它们存储在二叉树中,然后简单地通过该树运行二叉搜索会给您最快的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-09
      • 1970-01-01
      • 2015-10-05
      相关资源
      最近更新 更多