天天看點

MaxCompute中實作IPv4和IPv6位址歸屬地轉換

一、需求場景

大資料平台的成熟使得更多種類的非結構化、半結構化的資料分析成為可能,其中應用非常廣泛的一種場景就是把IP位址轉換為歸屬地又是極為常見的一種場景。那麼利用MaxCompute如何實作IPv4和IPv6位址向歸屬地的轉換呢?

本文通過MaxCompute UDF方式來實作IPv4和IPv6位址轉換。首先,要實作IPv4和IPv6位址與歸屬地的轉換必須要有IP位址庫。沒錯,我們首先要把IPv4和IPv6位址庫下載下傳到本地,分别命名為ipv4.txt和ipv6.txt。

二、實作思路

1、将ipv4.txt和ipv6.txt位址庫中IPv4和IPv6分别轉換為數值和數值字元串做排序。 

2、采用二分查找找到ip所屬的範圍,根據ipv4.txt和ipv6.txt庫輸出對應範圍所歸屬的省份和城市資訊。

三、UDF編寫

MaxCompute如何實作UDF可以參考官方文檔:

MaxCompute UDF

實作UDF需要繼承

com.aliyun.odps.udf.UDF

類,并實作

evaluate

方法。

1、實作setup方法加載IP位址庫資料,并做初始化

代碼片段如下:

public void setup(ExecutionContext ctx) throws UDFException, IOException {
        //IPV4
        if(ipV4ObjsArray==null)
        {
            BufferedInputStream bufferedInputStream = ctx.readResourceFileAsStream("ipv4.txt");

            BufferedReader br = new BufferedReader(new InputStreamReader(bufferedInputStream));
            ArrayList<IpV4Obj> ipV4ObjArrayList=new ArrayList<>();
            String line = null;
            while ((line = br.readLine()) != null) {
                String[] f = line.split("\\|", -1);
                if(f.length>=5)
                {
                    long startIp = IpUtils.StringToLong(f[0]);
                    long endIp = IpUtils.StringToLong(f[1]);
                    String city=f[3];
                    String province=f[4];
                    IpV4Obj ipV4Obj = new IpV4Obj(startIp, endIp, city, province);
                    ipV4ObjArrayList.add(ipV4Obj);
                }
            }
            br.close();
            List<IpV4Obj> collect = ipV4ObjArrayList.stream().sorted(Comparator.comparing(IpV4Obj::getStartIp)).collect(Collectors.toList());
            ArrayList<IpV4Obj> basicIpV4DataList=(ArrayList)collect;
            IpV4Obj[] ipV4Objs = new IpV4Obj[basicIpV4DataList.size()];
            ipV4ObjsArray = basicIpV4DataList.toArray(ipV4Objs);
        }

        //IPV6
        if(ipV6ObjsArray==null)
        {
            BufferedInputStream bufferedInputStream = ctx.readResourceFileAsStream("ipv6.txt");
            BufferedReader br = new BufferedReader(new InputStreamReader(bufferedInputStream));
            ArrayList<IpV6Obj> ipV6ObjArrayList=new ArrayList<>();
            String line = null;
            while ((line = br.readLine()) != null) {
                String[] f = line.split("\\|", -1);
                if(f.length>=5)
                {
                    String startIp = IpUtils.StringToBigIntString(f[0]);
                    String endIp = IpUtils.StringToBigIntString(f[1]);
                    String city=f[3];
                    String province=f[4];
                    IpV6Obj ipV6Obj = new IpV6Obj(startIp, endIp, city, province);
                    ipV6ObjArrayList.add(ipV6Obj);
                }
            }
            br.close();
            List<IpV6Obj> collect = ipV6ObjArrayList.stream().sorted(Comparator.comparing(IpV6Obj::getStartIp)).collect(Collectors.toList());
            ArrayList<IpV6Obj> basicIpV6DataList=(ArrayList)collect;
            IpV6Obj[] ipV6Objs = new IpV6Obj[basicIpV6DataList.size()];
            ipV6ObjsArray = basicIpV6DataList.toArray(ipV6Objs);
        }

    }      

2、實作evaluate方法,完成使用者資料IP位址到歸屬地的轉換邏輯

public String evaluate(String ip){
        if(ip==null||ip.trim().isEmpty()||!(ip.contains(".")||ip.contains(":")))
        {
            return null;
        }
        int ipV4OrV6=0;
        try {
            ipV4OrV6= IpUtils.isIpV4OrV6(ip);
        } catch (Exception e) {
            return null;
        }
        //如果是IPV4
        if(ipV4OrV6==4)
        {
            int i = binarySearch(ipV4ObjsArray, IpUtils.StringToLong(ip));
            if(i>=0)
            {
                IpV4Obj ipV4Obj = ipV4ObjsArray[i];
                return ipV4Obj.city+","+ipV4Obj.province;
            }else{
                return null;
            }
        }else if(ipV4OrV6==6)//如果是IPV6
        {
            int i = binarySearchIPV6(ipV6ObjsArray, IpUtils.StringToBigIntString(ip));
            if(i>=0)
            {
                IpV6Obj ipV6Obj = ipV6ObjsArray[i];
                return ipV6Obj.city+","+ipV6Obj.province;
            }else{
                return null;
            }
        }else{//如果不符合IPV4或IPV6格式
            return null;
        }

    }      

四、UDF函數注冊

MaxCompute UDF函數操作可以參考官方文檔:

MaxCompute函數操作

這裡通過兩種方式注冊MaxCompute UDF函數

1、通過odpscmd

odpscmd用戶端下載下傳安裝以及使用請參考:

用戶端
--上次資源:
add file ipv4.txt -f;
add file ipv6.txt -f;
add jar ipv4_ipv6_aton.jar;

--注冊函數:
--類名:com.aliyun.odps.udf.udfFunction.IpLocation
create function function_name as 'com.aliyun.odps.udf.udfFunction.IpLocation' using 'ipv4_ipv6_aton.jar, ipv4.txt, ipv6.txt';
      
MaxCompute中實作IPv4和IPv6位址歸屬地轉換

2、DataWorks

DataWorks注冊MaxCompute函數請參考文檔:

DataWorks注冊MaxCompute函數

(1)上傳MaxCompute資源

這裡需要上傳的資源清單:ipv4_ipv6_aton.jar, ipv4.txt, ipv6.txt

參考上述文檔上傳資源截圖如下:

       其中ipv4_ipv6_aton.jar選擇 MaxCompute-->JAR

ipv4.txt, ipv6.txt選擇MaxCompute-->File

MaxCompute中實作IPv4和IPv6位址歸屬地轉換
MaxCompute中實作IPv4和IPv6位址歸屬地轉換

(2)注冊函數

MaxCompute中實作IPv4和IPv6位址歸屬地轉換
MaxCompute中實作IPv4和IPv6位址歸屬地轉換

五、UDF函數測試

MaxCompute中實作IPv4和IPv6位址歸屬地轉換

六、函數源碼

MaxCompute IPv4-IPv6位址轉換UDF源碼請點選下載下傳:

IPv4-IPv6 UDF源碼 IPv4-IPv6位址庫

七、參考文檔

MaxCompute IP位址轉換曆史參考文檔:

1、

【大資料技巧】MaxCompute中實作IP位址歸屬地轉換

八、MaxCompute開發者社群交流群

歡迎加入“MaxCompute開發者社群2群”,點選連結

MaxCompute開發者社群2群

申請申請加入或掃描以下二維碼加入。

MaxCompute中實作IPv4和IPv6位址歸屬地轉換