基于ip定位城市的简单实现

来源:互联网 发布:jdbc批量insert数据 编辑:程序博客网 时间:2024/05/16 06:43

               刚来公司报道实习,主管交给我第一个任务是一个统计用户,的注册ip,区分是新疆,西藏,国外,国内其它地区。

      之前有一个做完的工程,就直接给我了。我仔细阅读了一下,我先说一下思路,这个问题我之前电面阿里的时候,被问到过,现在才知道,也是艰难。

               

这是关键的几个资源txt,最后其实也就是靠着扫字典txt,来实现的。首先看一下,ip.txt的内容。

                  

                第一步就是要用buffered reader,来读取,这一整个文件,很大,每一行的第一个跟第三个是ip的前后范围。随之与之对应的是long(由ip转换),最后的的三个字段,第一个是代表城市code,第二个是省份code,后面的运营商。我们来看一下,city.txt,跟province.txt你就明白了。

                 

                下面province.txt

                

               而fip是后来主管,给我的,但是发现是无规则的,而要求必须是由小到大的(原来后面就明白了)。

              下面进入正题

              First:加载ip.txt,跟fip.txt  分别加载成两个arraylist。ip对象到list,ip对象有一个startip,endip属性(数据源我当时是用的线上注册用户表,4000多万,累死,跑了接近两个小时)

              Second: 加载province,city,用两个map来存放,便于后边根据,code来取值。

              3:最关键的一步,我们获得数据源后,得到了ip字符串,我们怎么从ip从list找出来?答案就在startip,endip里,区间的二分查找,比较简单。所以我在第一步的时候,获得了fip(由于txt不是有序的)的list,我直接来了一部排序,看代码。

    Comparator<Ip> comparator = new Comparator<Ip>(){

public int compare(Ip s1, Ip s2) {

//先排年龄

if(s1.getEndIp()-s2.getEndIp()>0){

return 1;

}else{

return -1;

}

}};

Collections.sort(fips,comparator);

       下面附上二分查找的代码

       

 private Ip binarySearch(longipValue) {

    Ip ip = null;

    int size =ips.size();

    int low = 0;

    int high =size - 1;

    while ((low <high) && (low <=size - 1) && (high <=size - 1)) {

      int middle = (low +high) / 2;

      if (ips.get(middle).getStartIp() ==ipValue) {

        ip = ips.get(middle);

        break;

      } else if (ips.get(middle).getStartIp() >ipValue) {

        if (ips.get(middle - 1).getStartIp() ==ipValue) {

          ip = ips.get(middle - 1);

          break;

        } else if (ips.get(middle - 1).getStartIp() <ipValue) {

          if (ipValue <=ips.get(middle - 1).getEndIp()) {

            ip = ips.get(middle - 1);

            break;

          } else {

           

            high = middle - 1;

          }

        } else {

          high = middle - 1;

        }

      } else if (ips.get(middle).getStartIp() <ipValue) {

        if (ips.get(middle + 1).getStartIp() >ipValue) {

          if (ipValue <=ips.get(middle).getEndIp()) {

            ip = ips.get(middle);

            break;

          } else {

            

            high = middle - 1;

          }

        } else if (ips.get(middle + 1).getStartIp() ==ipValue) {

          ip = ips.get(middle + 1);

          break;

        } else {

          low = middle + 1;

        }

      }

    }

    // 位于第一个区间的IP

    if ((low >=high) && (ipValue >=ips.get(0).getStartIp()) && (ipValue <=ips.get(0).getEndIp())) {

      ip = ips.get(0);

    }

    // 位于最后一个区间的IP

    if ((low >=high) && (ipValue >=ips.get(size - 1).getStartIp()) && (ipValue <=ips.get(size - 1).getEndIp())) {

      ip = ips.get(size - 1);

    }

    return ip;

  }


                而基于经纬度定位,其实也就是扫另一个字典。

               

0 0