hive ip解析
Hive 自定义udf --ip地址解析出归属地
1.问题背景:现在我们的流量表里存有用户的IP地址,有需求需要将ip地址的归属地解析出来。结构是 国家-省份-城市-运营商
2.目前使用的是开源的ip库,调用三方接口不太适合hive udf使用并且都是收费的。
3.开源数据库调研了纯真数据库 发现ip地址解析的结果误差比较大,并且返回的结构不太友好。后来使用的是一个开源项目ip2region 。具体介绍可以看下该项目的gitee地址。ip2region 这个数据库大概有70万条,比纯真的数据库要全面,并且返回结果的结构比较统一 (_城市Id|国家|区域|省份|城市|ISP_)非常有利于我们进行结果的改造。
4.使用该数据库
1.首先将数据库下载下来,在该项目data 目录下ip2region.db ,放到hdfs上
2.编写udf 函数
1.pom中引入
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>2.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.3</version>
<scope>provided</scope>
</dependency>
2.udf
public class Ip2region extends UDF {
private static Configuration configuration;
private static FileSystem fileSystem;
private static InputStream in;
private static byte[] data;
static {
//加载数据
ByteArrayOutputStream out = null;
try {
configuration = new Configuration();
fileSystem = FileSystem.get(URI.create("hdfs:///jars/hive/ip2region.db"), configuration);
in = fileSystem.open(new Path("hdfs:///jars/hive/ip2region.db"));
out = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while (in.read(b) != -1) {
out.write(b);
}
// 提高性能,将ip2region.db一次从hdfs中读取出来,缓存到data字节数组中以重用,
// 避免每来一条数据读取一次ip2region.db
data = out.toByteArray();
out.close();
in.close();
} catch (Exception e){
e.printStackTrace();
}
finally {
try {
if(out != null) {
out.close();
}
if(in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String evaluate(String ip) throws Exception{
DbConfig config = new DbConfig();
DbSearcher searcher = new DbSearcher(config,data);
DataBlock dataBlock = searcher.memorySearch(ip);
String[] split = dataBlock.getRegion().split("\\|");
String addr = convert(split[0])+","+convert(split[2])+","+convert(split[3])+","+convert(split[4]);
return addr;
}
public String convert (String addr) {
return addr.equals("0") ? "" :addr;
}
}
3.打包 需要将ip2region 依赖打入到写的udf中
<build>
<finalName>hive-udf-ip2region</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.3</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<!--打包的插件配置-->
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
5.使用udf函数
将ip库和 udf的jar 都传到hdfs上
进入hive
add jar hdfs:///jars/hive/hive-udf-ip2region-jar-with-dependencies.jar;
create temporary function ip2region as 'com.hive.udf.Ip2region';
select ip2region('124.236.223.17');
6.注意:如果ip库必须传到hdfs 上,否则分布式跑的时候其他节点会加载不到改数据库

浙公网安备 33010602011771号