电话号码前缀查找

时间:2012-08-31 09:04:12

标签: java postgresql jdbc lookup prefix

我必须实现基于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”等。

问题:

  1. 使用java / jdbc查询最佳匹配前缀的最快方法是什么。
  2. 将应用程序启动时的表读取到java对象中是一种更好的方法,并且在每次调用时都没有db访问权限的情况下执行java中的所有操作吗?

4 个答案:

答案 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