内容简介:实现 IP 转地理位置,期间遇到的各种问题也一并记录于此。大数据的朋友有个需求,需要把查了下
摘要
在hive
中,要实现某些功能写 SQL
不方便实现时, UDF
(User-Defined Function 用户自定义函数) 就出现了。本文主要使用 Python
实现 IP 转地理位置,期间遇到的各种问题也一并记录于此。
前言
大数据的朋友有个需求,需要把 hive
存储的 IP
地址转换成地理位置,便于后期对于用户行为的分析。由于我之前有使用 golang
写过一个给自己的服务: grpc + REST api
方式提供 IP
转地理位置,所以我接下了这个需求。
开始
查了下 hive
可以使用 Java
、 Python
,就愉快地选择了 Python
。
本文的所有代码在 github
中: udf-ip2region
此功能是借用开源库 ip2region
提供 Python
连接类,及数据文件。
本示例在 hive 1.1.0
中测试通过。
UDF 源码分析
上面的开源库已经可以实现使用 python
来转换 IP
为地理位置了,只需要写个 python
脚本来调用,并封装成 hive
的 UDF
。
下面是我写的一个转换脚本:
# -*- coding:utf-8 -*- """ " Hive python udf " ip 地址转地理位置 " " Author: Mo<zhoujiangangcom@gmail.com> " Date : 2019-01-17 11:57:32 " " 用法: " ## 添加脚本到 hive " add file path/to/ip2region.db path/to/ip2Region.py path/to/p2area.py; " ## 使用脚本 " select TRANSFORM(ip) USING "python ip2area.py" as (ip,country,province,city,isp) from " ( select '127.0.222.1' as ip ) t; " """ import os import re import sys sys.path.append(os.getcwd()) import ip2Region def check_ip(ip_addr): compile_ip = re.compile( '^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$') if compile_ip.match(ip_addr): return True else: return False if __name__ == '__main__': searcher = ip2Region.Ip2Region("ip2region.db") for line in sys.stdin: line = line.strip() # 检查 ip 是否合法 if not check_ip(line): print(line) continue try: # 可替换的查询方式:memorySearch, btreeSearch, binarySearch # 速度: # memorySearch > btreeSearch > binarySearch data = searcher.btreeSearch(line) # region = data["region"].decode("utf8").split('|') region = data["region"].split('|') # region[1] 为区域,如有需要,可加入到最后 # a.append(region[1]) del region[1] region.insert(0, line) # hive 中使用制表符(\t)来分隔字段,可返回多个字段供 hive 使用。 print('\t'.join(region)) except Exception as e: print(line)
其中有一些注意点:
-
在这个脚本里,在引入
ip2Region
之前,先执行了sys.path.append(os.getcwd())
,在hive
中加载非标准库时并不会去检查当前目录。在没加载当前文件时,调用的时候会一直报错,并且没有报错日志,很是头疼。 -
python
写的udf
使用时,hive
是把值传给python
的标准输入的(python ip2area.py
),并且会有多行传入。 -
在脚本中尽量捕获所有异常,异常被抛出时,会导致
hive
执行失败。 -
hive
中使用制表符(\t
)对python
返回的值进行分割,返回多个值时可以使用此分割。使用时可以这么用:as (ip,country,province,city,isp)
这里的 check_ip
这个方法,可以去掉,这里 ip2Region
其实已经会对 ip
进行验证,失败时会抛出异常,只要捕获这个异常就可以了。
hive 中使用此自定义函数
$ git clone --depth 1 https://github.com/ynt/udf-ip2region $ cd udf-ip2region $ pwd
把下面出现的 /path/to
都替换为上面命令 pwd
的输出。
$ hive hive> add file path/to/ip2region.db path/to/ip2Region.py path/to/p2area.py; hive> select TRANSFORM(ip) USING "python ip2area.py" as (ip,country,province,city,isp) from ( select '218.26.55.199' as ip ) t;
可以看到如下输出:
... Total MapReduce CPU Time Spent: 2 seconds 600 msec OK 218.26.55.199 中国 山西省 太原市 联通 Time taken: 19.57 seconds, Fetched: 1 row(s)
看到此输出说明脚本使用成功了,当然你如果不需要显示市和 isp
信息, 修改 as
后面的语句为 as (ip,country,province)
即可, python
脚本的输出对于 hive
来说是向后可缺省的。换句话说, python
返回多个字段,你不必在 hive
中全部使用 as
接收, 未被接收的字段,将被丢弃。
小结
Hive
调用 python
写的自定义脚本时,会出现各种报错。这些报错在本地跑时完全没有问题,而且 hive
都不显示这些错误输出,要调试这类代码时,只能在 python
脚本只动手脚,一个大的 try ... except
把所有代码包起来,在 except
块中 print(error)
来实现调试。
这些各种的问题,我猜想是由于 hive
可能自带了 python
的版本,当然没有研究他们带的版本,使用相同版本可能会更好开发自定义脚本。
总的来说,一个小脚本,实现的功能还不简单,期间种种宛如烟云。
以上所述就是小编给大家介绍的《Hive Udf:Python 实现 IP 转地理位置》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Java 根据 IP 获取地理位置
- Android Q 地理位置权限变更
- 基于Elasticsearch的地理位置简单搜索
- Java 根据经纬度获取地理位置
- MySQL中地理位置数据扩展geometry的使用心得
- WinSrv2019使用DNS构建基于地理位置感知的应用负载均衡
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。