【问题标题】:mapping ipaddress range to country codes (data-structure hashmaps or trees?)将 IP 地址范围映射到国家代码(数据结构哈希图或树?)
【发布时间】:2009-08-09 02:19:26
【问题描述】:

试图解决我在这里找到的一个难题: http://zcasper.blogspot.com/2005/10/google-phone-interview.html

目标是在内存中重新呈现 IP 地址范围到国家/地区代码查找表,并使用此数据结构处理 ipaddress 的 zilloin 行以识别国家/地区代码。

所以我一开始就想到了使用 HashTable 哈希表效果很好;如果我们有一个国家代码来进行范围查找,因为我们映射到 IP 地址范围的国家名称较少?

但不确定;我如何使用 ipaddress 到国家/地区代码。有什么想法吗? 或者我可以使用树数据结构吗?

【问题讨论】:

    标签: java tree hashtable


    【解决方案1】:

    输入文件提供了一系列 IP 地址(不是 1:1 映射),因此您需要某种有序的映射结构。

    // Assuming IPv4, and the inputs are valid (start before end) 
    // and no overlapping ranges. 
    public class CountyCodeToIPMap {
        private final TreeMap<Long, CountryCodeEntry> ipMap = 
                new TreeMap<Long, CountryCodeEntry>();
    
        public void addIpRange(long startIp, long endIp, String countryCode) {
            ipMap.put(startIp, new CountryCodeEntry(endIp, countryCode);
        }
    
        public String getCountryCode(long ip) {
            Map.Entry<Long, CountryCodeEntry> entry = ipMap.floorEntry(ip);
            if (entry != null && ip <= entry.getValue().endIpAddress) {
                return entry.getValue().countryCode;
            } else {
                return null;
            }
        }
    }
    
    public class CountryCodeEntry {
        public final long endIpAddress;
        public final String countryCode;
        public CountryCodeEntry (long endIpAddress, String countryCode) {
            this.endIpAddress = endIpAdddress;
            this.countryCode = countryCode;
        }
    }
    

    【讨论】:

    • 尝试了 20 万条记录;它很快:-),顺便说一句,Java Collections 中是否有任何编程 api 来了解诸如“深度”或“高度”之类的树数据结构属性?
    • 我不知道。 JDK中的TreeMap是红黑树,所以会大致平衡,JDK中的另一个选项是ConcurrentSkipList,如果提前对导入数据进行排序会更好地平衡。除了您需要在 Java 集合库之外查看一些更专业的结构。
    【解决方案2】:

    您没有机会存储所有 IP 地址。 您可以做的是将间隔开始-结束存储在 IP 地址范围所在的位置。

    有一个专门的数据结构,叫做Interval Tree,它允许你查询这个。

    【讨论】:

    • 存储范围不正是 OP 所说的那样吗?
    【解决方案3】:

    如果您正在考虑使用 sql 解决方案:

    如果您可以为数据集添加一些约束,您可能会使用非常简单的 sql。你甚至可以使用简单的索引。 - 当您使用GeoCityLite 数据集时就是这种情况

    如果您的 ip 块不重叠,您可以将它们作为 unsigned 32 位数字插入数据库中的“块”表中,然后像使用休眠一样查询它们:

         (GeoipBlocks) getSession()
                .createQuery("select  gb" +
                        " from GeoipBlocks gb" +
                        " where gb.startIpNum <= :ipnumeric " +
                        " order by gb.startIpNum desc").
                        setMaxResults(1)
                .setParameter("ipnumeric", ipInLongValue)
                .uniqueResult()
    

    我是用 hql 语法写的,因为不是所有的数据库都使用相同的 offset + limit 语法

    发出最佳匹配查询,假设所有块不重叠。 - 你甚至不需要结束 ip,这是由后继者自动确定的。

    避免这样查询!:

        select * from blocks where ipstart <= ip and ipend >= ip 
    

    我的数据库无法充分利用它们的索引,并进行了大量的表扫描。

    【讨论】:

      【解决方案4】:

      由于 Internet 路由的工作方式,您的算法需要处理最长前缀匹配,并且您希望存储 CIDR blocks,而不是地址。

      我开发了一种算法来处理此问题,但无法在此处发布。开源中最接近的是Linux中的路由表处理代码。

      您还可以查看Patricia Trie or Radix Tree 算法。这些可以用来解决这个问题。

      【讨论】:

        猜你喜欢
        • 2014-12-04
        • 2014-10-21
        • 2017-12-28
        • 1970-01-01
        • 2013-07-02
        • 1970-01-01
        • 2013-11-11
        • 2015-01-16
        • 1970-01-01
        相关资源
        最近更新 更多