2009-08-17 90 views
1

我正在编写一个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。

谢谢。

回答

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

编辑:使用的静态变量,这样排序只是做一旦。

+0

嗯,我不想整理和查找所有的时间,因为这很贵。否则,我喜欢你的方法,因为确实没有漏洞。 – 2009-08-18 00:54:43

+0

使用开始日期而不是结束日期将消除对'默认'的需要。 – 2009-08-18 03:23:51

+0

使用开始日期将需要一个默认值来捕捉*第一个分片之前的任何内容*。 – 2009-08-18 04:01:56

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 
+0

我明白了,但您的实现仍然受到未优化查找的影响。另外,例如,如果您决定更改碎片名称或将长碎片范围拆分为2个较短的碎片范围,则需要重写整个函数。 – 2009-08-18 00:56:27