在PHP中使用50K行CSV文件找到最长匹配的最快方法

时间:2014-08-23 12:43:42

标签: php algorithm csv longest-prefix

在语音应用程序中,我必须找到国际电话号码上前缀的最长匹配。我有一个50K行的费率表,存储在CSV文件中,定期更新新费率(CSV列标题包含前缀,国家/地区费率等)。该应用程序使用REST API向用户显示基于他们输入的电话呼叫目的地的费用。不能使用简单的KVS,因为有多个匹配并需要最长的前缀匹配。 API被命中ALOT所以直接使用DB太慢/太重(在这里使用APC但似乎没有那么大的区别)。我能想出的最好的算法如下所示,但在体面的机器上完成仍需要近1秒。任何PHP算法专家都有更好的方法吗?

    function getRate($phoneNumber) { 

        if (!apc_fetch('ALL_RATES')){

            $all_rates = array_map('str_getcsv', file('/var/billing/rates.csv'));
            apc_store('ALL_RATES', $all_rates);

        } else {

            $all_rates = apc_fetch('ALL_RATES');
        } 

        $noOfCountries = sizeof($all_rates);    
        $bestMatch = 0;


        for ($n=1;$n<$noOfCountries;$n++) {

            $country = $all_rates[$n];
            $country_prefix = $country[0];

            $match = stripos($phoneNumber, $country_prefix);

            if ($match===0){

                if (strlen($country_prefix) > $bestMatch) {

                    $bestMatch = strlen($country_prefix);
                    $matchedCountry = $n;

                }

            }

        }

        $prefix = $all_rates[$matchedCountry][0];
        $country = $all_rates[$matchedCountry][1];
        $rate = $all_rates[$matchedCountry][2];

        return array($country,$prefix,$rate);

    }
}

1 个答案:

答案 0 :(得分:2)

好吧,如果您编写自己的 stripos ,可能会推迟200-300秒秒,因为您只需要执行前缀匹配,而不是尝试匹配前缀任何职位。

虽然,这是我的建议:

1)抛弃CSV格式并开始使用体面的关系数据库,MySQL很好。 Ps声明“db太慢/太重”没有任何意义。如果你正确设置了所有内容,那么通过数据库匹配前缀将需要 0秒(是的,你读得正确,几毫秒)。 SQL支持带前缀的全文扫描。存储每个电话号码的长度,并将其编入索引。

2)开始缓存请求。

对于您的CSV解决方案,如果您将电话号码存储为 prefixTree.csv ,则可以获得良好的性能提升,之后,您可以快速获得以特定前缀开头的所有电话号码。 Ps,当你收到请求时,不要每次都加载csv文件到内存。那太慢了!将其缓存为静态(PHP有静态吗?)

更多信息:http://phpir.com/tries-and-wildcards/