我必须实现基于java的呼叫路由引擎,该引擎根据电话号码前缀将呼叫路由到适当的网关。
这里我的表(postgres)包含前缀:
CREATE TABLE call_routing (
prefix character varying(20) PRIMARY KEY NOT NULL,
carrier character varying(50) NOT NULL,
dialstring character varying(50) NOT NULL
)
一些示例数据:
INSERT INTO call_routing values ('02','1','/sofia/gateway/gw1');
INSERT INTO call_routing values ('0221','1','/sofia/gateway/gw2');
INSERT INTO call_routing values ('0228','1','/sofia/gateway/gw3');
例如,电话号码0221123456789应路由到网关“/ sofia / gateway / gw2”,电话号码0211123456789应路由到“/ sofia / gateway / gw1”等。
问题:
答案 0 :(得分:2)
获得更好的索引
直接在前缀上订购,而不是长度(前缀):
SELECT dialstring FROM call_routing
WHERE number like prefix || '%'
ORDER BY prefix DESC
LIMIT 1
为什么?
因为数字abcdef
的选定行将是前缀。所以数字会像:
一 AB ABC ABCD
因此,如果您按字母顺序排序,就足以获得从最长到最短的列表,这就是您想要的。
您还可以使用以下方法获得更强大的过滤器:
prefix between 'a' and 'abcde'
。您的所有前缀将按字母顺序排列>=
最短前缀,按字母顺序排列<=
最长前缀。
所以它可以表达为:
SELECT dialstring FROM call_routing WHERE
prefix between substr(number, 1, 1) and number -- range filter (use index)
AND number like prefix || '%' -- only relevant data (normal filter)
ORDER BY prefix DESC -- index will work
LIMIT 1
当然,索引将在列前缀上。
全部缓存?
是的,拜托。 :)
你有几件物品?如果它不是一个庞大的列表,请将其加载到内存中。
然后你可以有一个TreeMap(如果你想按前缀排序)或HashMap(如果你更喜欢先找到最长的前缀,并且每次都少用一个char)。哪一个会更好?取决于a >> abcde
范围内的前缀数量,与like
条件不匹配(例如abbde
)。
如果没有很多条目
你可以使用一个数组,按前缀desc排序:
be
b
abcde
abbbc
abd
ab
要查找正确的前缀,请执行Arrays.binarySearch(T[], T key, Comparator<T>)
查找您的手机是否在那里(abcde
)。如果是......好的。如果不是你继续前进:
- you find a prefix (OK, this is the winner)
- it doesn't start with the same char (there are no prefix)
这样你就可以遍历范围abcde >> a
并找到第一个前缀(它是最长的前缀)。
好的
正在制作T-R-E-E(我不确定这个名字)。创建一个树,每个节点只包含一个字母(在您的情况下为数字)。
0 // represents 0
->
2 // represents 02
-> 1 // represents 021
-> 3 // represents 023
->
4 // represents 04
因此,当您寻找最长的前缀时,您会尝试在树中尽可能地深入:
Node n = root;
for (char c: number) {
if ((child = n.hasChild(c)) != null)
{
prefix += c;
n = child;
}
else
break;
}
你只需要创建一个
class Node
{
int digit;
Map<Integer, Node> childs = new HashMap<Integer, Node>(); // or a 10 bucket array :)
YourInfo info;
}
创建结构:
findOrCreateNode(prefix).setInfo(info);
其中findOrCreateNode与之前相同,但是当它没有找到节点时......创建它(n.put(c, new Node(c))
)。
答案 1 :(得分:1)
我个人会缓存表格,但您可以按长度排序获得最佳匹配前缀(number
就是您要搜索的内容):
SELECT dialstring FROM call_routing WHERE strpos(number, prefix) = 1 ORDER BY length(prefix) DESC LIMIT 1;
答案 2 :(得分:0)
我想知道这件事。似乎最大的问题是你有垃圾(在你的例子中是gw1)。
SELECT dialstring from call_routing where number like prefix || '%'
ORDER BY length(prefix) DESC
LIMIT 1
索引这将很难,但我想第一个问题是,你跟踪了多少个呼叫前缀?
答案 3 :(得分:0)
您还可以在github上查看这个PostgreSQL模块,该模块专门用于为电话号码提供快速前缀匹配: https://github.com/dimitri/prefix