Dictionary 缓存复杂数据的最佳方法

Dictionary 缓存复杂数据的最佳方法,dictionary,go,Dictionary,Go,我有一个根据号码前缀存储语音通话成本的表: Prefix ratio 44 0.01597 447 0.04958 447530 0.03 447531 0.048 447532 0.04950 1 0.1 97 0.1 在表中查找数字的前缀有点复杂,因为需要最大匹配前缀。 例如 4475122112的前缀是447 4475302112的前缀是447530 我希望将表缓存在内存中,通过减少数据库交互来提高性能。 由于要获取数字的前缀(然后是其速

我有一个根据号码前缀存储语音通话成本的表:

Prefix  ratio 
44      0.01597
447     0.04958
447530  0.03
447531  0.048
447532  0.04950
1       0.1
97      0.1
在表中查找数字的前缀有点复杂,因为需要最大匹配前缀。 例如
4475122112的前缀是447
4475302112的前缀是447530

我希望将表缓存在内存中,通过减少数据库交互来提高性能。 由于要获取数字的前缀(然后是其速率),需要在缓存上进行某种搜索

我找到了两种方法:

  • 将它们存储在纯映射中。在地图上搜索可以简单到扫描所有地图(可能是懒惰的)
  • 将链表结构创建为树。短前缀靠近根,最长前缀靠近叶
    现在,缓存此类数据的最佳方式是什么?或者有其他机制吗?

    将它们存储在地图中,然后尝试您要查找的费用号码。如果号码(键)不在地图中,请剪掉其最后一个数字并重复。通过这种方式,如果您找到匹配项,则保证该前缀最长

    下面是一个查找函数示例:

    var prefixCostMap = map[uint64]float64{
        44:     0.01597,
        447:    0.04958,
        447530: 0.03,
        447531: 0.048,
        447532: 0.04950,
        1:      0.1,
        97:     0.1,
    }
    
    func lookup(num uint64) (longestPrefix uint64, cost float64, ok bool) {
        longestPrefix = num
    
        for longestPrefix > 0 {
            cost, ok = prefixCostMap[longestPrefix]
            if ok {
                break
            }
            longestPrefix = longestPrefix / 10 // Cut off last digit
        }
    
        return
    }
    
    测试它:

    fmt.Println(lookup(4475122112))
    fmt.Println(lookup(4475302112))
    fmt.Println(lookup(999))
    
    fmt.Println(lookup("4475122112"))
    fmt.Println(lookup("4475302112"))
    fmt.Println(lookup("999"))
    fmt.Println(lookup("0123456"))
    
    输出(在上尝试):

    注意:这不支持以0开头的数字。如果您还需要处理这个问题,您可以将数字存储为字符串值,这样初始
    0
    数字将被保留

    这是
    字符串
    版本的外观:

    var prefixCostMap = map[string]float64{
        "44":     0.01597,
        "447":    0.04958,
        "447530": 0.03,
        "447531": 0.048,
        "447532": 0.04950,
        "1":      0.1,
        "97":     0.1,
        "0123":   0.05,
    }
    
    func lookup(num string) (longestPrefix string, cost float64, ok bool) {
        longestPrefix = num
    
        for longestPrefix != "" {
            cost, ok = prefixCostMap[longestPrefix]
            if ok {
                break
            }
            longestPrefix = longestPrefix[:len(longestPrefix)-1] // Cut off last digit
        }
    
        return
    }
    
    测试它:

    fmt.Println(lookup(4475122112))
    fmt.Println(lookup(4475302112))
    fmt.Println(lookup(999))
    
    fmt.Println(lookup("4475122112"))
    fmt.Println(lookup("4475302112"))
    fmt.Println(lookup("999"))
    fmt.Println(lookup("0123456"))
    
    输出(在上尝试):


    一个映射可以被一些哈希代码用于直接查找;不需要扫描。您显示的表经过了很好的预计算,似乎可以用于直接查找前缀。这个链接在过去帮助我使用地图:@Zimano。条目是数字。例如,4475302112。我一开始不知道前缀。要找到它的相关前缀,需要进行某种搜索。这张桌子可能有上千条记录,非常像@icza。回答得很好。在查找(4475122112)中,要查找前缀(447),需要访问映射七次。它在拥有10000条记录的大型映射中是否存在性能问题?@irmorteza索引(散列)映射的速度很快,其复杂性是
    O(1)
    (平均)。它不取决于地图中元素的数量。因此,您可以在同一时间检查/查找地图中的值,无论它是包含10个元素还是1000万个元素。