0

在语音应用程序中,我必须找到国际电话号码前缀的最长匹配。我有一个 50K 行的费率表,存储在 CSV 文件中,该文件会定期更新为新费率(CSV 列标题包含前缀、国家/地区费率等)。该应用程序使用 REST API 来根据用户输入的电话向用户显示呼叫目的地的费用。不能使用简单的 KVS,因为有多个匹配项并且需要最长的前缀匹配项。API 受到很多打击,因此直接使用数据库太慢/太重(在此处使用 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);

    }
}
4

1 回答 1

2

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

不过,这是我推荐的:

1) 抛弃 CSV 格式,开始使用像样的关系数据库,MySQL 很好。Ps 声明“db 太慢/太重”没有意义。如果您设置正确,通过数据库匹配前缀将花费0 秒(是的,您没看错,几毫秒)。SQL 支持带前缀的全文扫描。存储每个电话号码的长度,并对其进行索引。

2) 开始缓存请求。

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

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

于 2014-08-23T13:44:03.860 回答