在语音应用程序中,我必须找到国际电话号码上前缀的最长匹配。我有一个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);
}
}
答案 0 :(得分:2)
好吧,如果您编写自己的 stripos ,可能会推迟200-300秒秒,因为您只需要执行前缀匹配,而不是尝试匹配前缀任何职位。
虽然,这是我的建议:
1)抛弃CSV格式并开始使用体面的关系数据库,MySQL很好。 Ps声明“db太慢/太重”没有任何意义。如果你正确设置了所有内容,那么通过数据库匹配前缀将需要 0秒(是的,你读得正确,几毫秒)。 SQL支持带前缀的全文扫描。存储每个电话号码的长度,并将其编入索引。
2)开始缓存请求。
对于您的CSV解决方案,如果您将电话号码存储为 prefixTree.csv ,则可以获得良好的性能提升,之后,您可以快速获得以特定前缀开头的所有电话号码。 Ps,当你收到请求时,不要每次都加载csv文件到内存。那太慢了!将其缓存为静态(PHP有静态吗?)