主要考察的是广播变量的使用:

1、将要广播的数据 IP 规则数据存放在HDFS上,(广播出去的内容一旦广播出去产就不能改变了,如果需要实时改变的规则,可以将规则放到Redis中)

2、在Spark中转成RDD,然后收集到Driver端,

3、把 IP 规则数据广播到Executor中。Driver端广播变量的引用是怎样跑到 Executor中的呢?  Task在Driver端生成的,广播变量的引用是伴随着Task被发送到Executor中的,广播变量的引用也被发送到Executor中,恰好指向HDFS

4、Executor执行分配到的 Task时,从Executor中获取 IP 规则数据做计算。

  1. package com.rz.spark.base
  2.  
  3. import java.sql.{Connection, DriverManager, PreparedStatement}
  4.  
  5. import org.apache.spark.broadcast.Broadcast
  6. import org.apache.spark.rdd.RDD
  7. import org.apache.spark.{SparkConf, SparkContext}
  8.  
  9. object IpLocation2 {
  10. def main(args: Array[String]): Unit = {
  11. val conf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[2]")
  12. val sc = new SparkContext(conf)
  13.  
  14. // 取到HDFS中的 ip规则
  15. val rulesLine: RDD[String] = sc.textFile(args())
  16.  
  17. // 整理ip规则数据
  18. val ipRulesRDD: RDD[(Long, Long, String)] = rulesLine.map(line => {
  19. val fields = line.split("[|]")
  20. val startNum = fields().toLong
  21. val endNum = fields().toLong
  22. val province = fields()
  23. (startNum, endNum, province)
  24. })
  25. // 将分散在多个Executor中的部分IP规则数据收集到Driver端
  26. val rulesInDriver: Array[(Long, Long, String)] = ipRulesRDD.collect()
  27.  
  28. // 将Driver端的数据广播到Executor中
  29. // 调用sc上的广播方法
  30. // 广播变量的引用(还在Driver端中)
  31. val broadcastRef: Broadcast[Array[(Long, Long, String)]] = sc.broadcast(rulesInDriver)
  32.  
  33. // 创建RDD,读取访问日志
  34. val accessLines: RDD[String] = sc.textFile(args())
  35.  
  36. // 整理数据
  37. val provinceAndOne: RDD[(String, Int)] = accessLines.map(log => {
  38. // 将log日志的第一行进行切分
  39. val fields = log.split("[|]")
  40. val ip = fields()
  41. // 将ip转换成10进制
  42. val ipNum = MyUtils.ip2Long(ip)
  43. // 进行二分法查找,通过Driver端的引用获取到Executor中的广播变量
  44. // (该函数中的代码是在Executor中被调用执行的,通过广播变量的引用,就可以拿到当前Executor中的广播的ip二人规则)
  45. // Driver端广播变量的引用是怎样跑到 Executor中的呢?
  46. // Task在Driver端生成的,广播变量的引用是伴随着Task被发送到Executor中的,广播变量的引用也被发送到Executor中,恰好指向HDFS
  47. val rulesInExecutor: Array[(Long, Long, String)] = broadcastRef.value
  48. // 查找
  49. var province = "末知"
  50. val index = MyUtils.binarySearch(rulesInExecutor, ipNum)
  51. if (index != -) {
  52. province = rulesInExecutor(index)._3
  53. }
  54. (province, )
  55. })
  56. // 聚合
  57. val reduced: RDD[(String, Int)] = provinceAndOne.reduceByKey(_+_)
  58. // 将结果打印
  59. // val result = reduced.collect()
  60. // println(result.toBuffer)
  61.  
  62. // 将结果写入到MySQL中
  63. // 一次拿一个分区的每一条数据
  64. reduced.foreachPartition(it=>{
  65. val conn: Connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata?characterEncoding=utf-8","root","root")
  66. val pstm: PreparedStatement = conn.prepareStatement("insert into access_log values(?,?)")
  67.  
  68. it.foreach(tp=>{
  69. pstm.setString(, tp._1)
  70. pstm.setInt(,tp._2)
  71. pstm.executeUpdate()
  72. })
  73. pstm.close()
  74. conn.close()
  75. })
  76.  
  77. sc.stop()
  78. }
  79. }

工具类

  1. package com.rz.spark.base
  2.  
  3. import java.sql
  4. import java.sql.{DriverManager, PreparedStatement}
  5.  
  6. import scala.io.{BufferedSource, Source}
  7.  
  8. object MyUtils {
  9.  
  10. def ip2Long(ip: String): Long = {
  11. val fragments = ip.split("[.]")
  12. var ipNum = 0L
  13. for (i <- until fragments.length){
  14. ipNum = fragments(i).toLong | ipNum << 8L
  15. }
  16. ipNum
  17. }
  18.  
  19. def readRules(path: String): Array[(Long, Long, String)] = {
  20. //读取ip规则
  21. val bf: BufferedSource = Source.fromFile(path)
  22. val lines: Iterator[String] = bf.getLines()
  23. //对ip规则进行整理,并放入到内存
  24. val rules: Array[(Long, Long, String)] = lines.map(line => {
  25. val fileds = line.split("[|]")
  26. val startNum = fileds().toLong
  27. val endNum = fileds().toLong
  28. val province = fileds()
  29. (startNum, endNum, province)
  30. }).toArray
  31. rules
  32. }
  33.  
  34. def binarySearch(lines: Array[(Long, Long, String)], ip: Long) : Int = {
  35. var low =
  36. var high = lines.length -
  37. while (low <= high) {
  38. val middle = (low + high) /
  39. if ((ip >= lines(middle)._1) && (ip <= lines(middle)._2))
  40. return middle
  41. if (ip < lines(middle)._1)
  42. high = middle -
  43. else {
  44. low = middle +
  45. }
  46. }
  47. -
  48. }
  49.  
  50. def data2MySQL(it: Iterator[(String, Int)]): Unit = {
  51. //一个迭代器代表一个分区,分区中有多条数据
  52. //先获得一个JDBC连接
  53. val conn: sql.Connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata?characterEncoding=UTF-8", "root", "")
  54. //将数据通过Connection写入到数据库
  55. val pstm: PreparedStatement = conn.prepareStatement("INSERT INTO access_log VALUES (?, ?)")
  56. //将分区中的数据一条一条写入到MySQL中
  57. it.foreach(tp => {
  58. pstm.setString(, tp._1)
  59. pstm.setInt(, tp._2)
  60. pstm.executeUpdate()
  61. })
  62. //将分区中的数据全部写完之后,在关闭连接
  63. if(pstm != null) {
  64. pstm.close()
  65. }
  66. if (conn != null) {
  67. conn.close()
  68. }
  69. }
  70. }

pom文件

  1. <properties>
  2. <maven.compiler.source>1.8</maven.compiler.source>
  3. <maven.compiler.target>1.8</maven.compiler.target>
  4. <scala.version>2.11.</scala.version>
  5. <spark.version>2.2.</spark.version>
  6. <hadoop.version>2.6.</hadoop.version>
  7. <encoding>UTF-</encoding>
  8. </properties>
  9.  
  10. <dependencies>
  11. <!-- 导入scala的依赖 -->
  12. <dependency>
  13. <groupId>org.scala-lang</groupId>
  14. <artifactId>scala-library</artifactId>
  15. <version>${scala.version}</version>
  16. </dependency>
  17.  
  18. <!-- 导入spark的依赖 -->
  19. <dependency>
  20. <groupId>org.apache.spark</groupId>
  21. <artifactId>spark-core_2.</artifactId>
  22. <version>${spark.version}</version>
  23. </dependency>
  24.  
  25. <!-- 指定hadoop-client API的版本 -->
  26. <dependency>
  27. <groupId>org.apache.hadoop</groupId>
  28. <artifactId>hadoop-client</artifactId>
  29. <version>${hadoop.version}</version>
  30. </dependency>
  31.  
  32. </dependencies>
  33.  
  34. <build>
  35. <pluginManagement>
  36. <plugins>
  37. <!-- 编译scala的插件 -->
  38. <plugin>
  39. <groupId>net.alchim31.maven</groupId>
  40. <artifactId>scala-maven-plugin</artifactId>
  41. <version>3.2.</version>
  42. </plugin>
  43. <!-- 编译java的插件 -->
  44. <plugin>
  45. <groupId>org.apache.maven.plugins</groupId>
  46. <artifactId>maven-compiler-plugin</artifactId>
  47. <version>3.5.</version>
  48. </plugin>
  49. </plugins>
  50. </pluginManagement>
  51. <plugins>
  52. <plugin>
  53. <groupId>net.alchim31.maven</groupId>
  54. <artifactId>scala-maven-plugin</artifactId>
  55. <executions>
  56. <execution>
  57. <id>scala-compile-first</id>
  58. <phase>process-resources</phase>
  59. <goals>
  60. <goal>add-source</goal>
  61. <goal>compile</goal>
  62. </goals>
  63. </execution>
  64. <execution>
  65. <id>scala-test-compile</id>
  66. <phase>process-test-resources</phase>
  67. <goals>
  68. <goal>testCompile</goal>
  69. </goals>
  70. </execution>
  71. </executions>
  72. </plugin>
  73.  
  74. <plugin>
  75. <groupId>org.apache.maven.plugins</groupId>
  76. <artifactId>maven-compiler-plugin</artifactId>
  77. <executions>
  78. <execution>
  79. <phase>compile</phase>
  80. <goals>
  81. <goal>compile</goal>
  82. </goals>
  83. </execution>
  84. </executions>
  85. </plugin>
  86.  
  87. <!-- 打jar插件 -->
  88. <plugin>
  89. <groupId>org.apache.maven.plugins</groupId>
  90. <artifactId>maven-shade-plugin</artifactId>
  91. <version>2.4.</version>
  92. <executions>
  93. <execution>
  94. <phase>package</phase>
  95. <goals>
  96. <goal>shade</goal>
  97. </goals>
  98. <configuration>
  99. <filters>
  100. <filter>
  101. <artifact>*:*</artifact>
  102. <excludes>
  103. <exclude>META-INF/*.SF</exclude>
  104. <exclude>META-INF/*.DSA</exclude>
  105. <exclude>META-INF/*.RSA</exclude>
  106. </excludes>
  107. </filter>
  108. </filters>
  109. </configuration>
  110. </execution>
  111. </executions>
  112. </plugin>
  113. </plugins>
  114. </build>

Spark- 根据ip地址计算归属地的更多相关文章

  1. spark练习---ip匹配以及广播的特性

    今天,我们还是在介绍spark的小练习,这次的小练习还是基于IP相关的操作,我们可以先看一下今天的需求,我们有两个文件, 第一个文件,是IP的字典,也就是我们上一篇介绍过的,就是表明了所有IP字段所属 ...

  2. IP和归属地

    ip: http://www.ip.cn/index.php?ip=10.132.98.143 归属地: http://www.ip138.com:8080/search.asp?action=mob ...

  3. 【Spark】如何用Spark查询IP地址?

    文章目录 需求 思路 ip地址转换为Long类型的两种方法 ip地址转换数字地址的原理 第一种方法 第二种方法 步骤 一.在mysql创建数据库表 二.开发代码 需求 日常生活中,当我们打开地图时,会 ...

  4. IP地址计算和划分

    一.      B类地址 范围从128-191(第一串8位二进制10000000~10111111),如172.168.1.1,第一和第二段号码为网络号码,剩下的2段号码为本地计算机的号码.转换为2进 ...

  5. 查询ip地址归属地

    查询ip地址归属地方法: curl ip.cn/$ip 如果没有返回,试试地址写全: curl https://www.ip.cn/$ip 如:

  6. python查询IP地址所属地

    1.linux命令行版 #!/usr/bin/python #-*- coding: utf-8 -*- import json import urllib import sys def get_da ...

  7. python 查找IP地址归属地

    #!/usr/bin/env python # -*- coding: utf-8 -*- #查找IP地址归属地 #writer by keery_log #Create time:2013-10-3 ...

  8. ip地址计算

    1.多少个子网? 2x个,其中x为被遮盖(取值为1)的位数.例如,在11000000(这个值是子网掩码的最后几位,例如,mask=18)中,取值为1的位数为2,因此子网数位22=4个: 2.每个子网包 ...

  9. 【java】获取客户端访问的公网ip和归属地

    import com.alibaba.druid.support.json.JSONUtils; import org.thymeleaf.util.StringUtils; import javax ...

随机推荐

  1. 巨蟒python全栈开发数据库攻略2:基础攻略2

    1.存储引擎表类型 2.整数类型和sql_mode 3.浮点类&字符串类型&日期类型&集合类型&枚举类型 4.数值类型补充 5.完整性约束

  2. Java 语言基础之函数

    函数的定义: 函数就是定义在类中的具有特定功能的一段独立小程序 函数也称为方法 函数定义格式: 修饰符 返回值类型 函数名(参数类型 形式参数1, 参数类型 形式参数2,...) { 执行语句; re ...

  3. python进程锁

    import time import threading import multiprocessing lock = multiprocessing.RLock() def task(arg): pr ...

  4. JSP--JSP语法--指令--include(动态包含/静态包含)--九大隐式对象--四大域对象--JSP内置标签--JavaBean的动作元素--MVC三层架构

    一.JSP 原理:JSP其实就是一个servlet. Servlet负责业务逻辑处理,JSP只负责显示.开发中,JSP中不能有一行JAVA代码 二.JSP语法 1.    JSP模板元素:JSP中HT ...

  5. Codeforces Round #302 (Div. 2)

    A. Set of Strings 题意:能否把一个字符串划分为n段,且每段第一个字母都不相同? 思路:判断字符串中出现的字符种数,然后划分即可. #include<iostream> # ...

  6. 把RedisWatcher安装为windows服务

    安装完成后, 到安装目录下修改watcher.conf.注意,任何路径都不可包含空格,中文,特殊字符,且全部使用绝对路径配置文件中文注释exepath --> redis-server.exe的 ...

  7. ArcGIS COM Exception 0x80040228

    问题:  string shpDir = Path.GetDirectoryName(shpfile);             string shpfilename = Path.GetFileNa ...

  8. Python 字符串连接问题归结

    一.概述 Python 字符串连接场景较为普遍.由于编者对 Java 等语言较为熟悉,常常将两者语法混淆. 加之,Python 语法较为灵活.例如,单单实现字符串连接,就有数种方法.在此,一并归结! ...

  9. CentOS中nginx负载均衡和反向代理的搭建

    1: 修改centos命令行启动(减少内存占用): vim /etc/inittab :initdefault: --> 修改5为3 若要界面启动使用 startx 2:安装jdk )解压:jd ...

  10. Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined) C - Table Tennis Game 2

    地址:http://codeforces.com/contest/765/problem/C 题目: C. Table Tennis Game 2 time limit per test 2 seco ...