欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

GeoHash编码原理和代码演示

程序员文章站 2024-03-15 14:23:41
...

GeoHash编码原理和代码演示

1. 背景

1.1 概述

  1. 在大数据领域中,时常需要进行海量数据的映射检索,其中GPS转换为地理位置以及IP地址转换为地理位置就是一种很常见需求。
  2. 由于数据量很大,如何进行快速查询就需要使用到各种算法。
  3. 在大数据领域,常见的快速匹配如布隆过滤器,bitmap算法,hyperloglog算法这些是位图算法。
  4. 今天要说的geohash算法,则是二分法结合编码的一种地理位置信息算法。

1.2 原理

  1. 经度范围是东经180到西经180,纬度范围是南纬90到北纬90,我们设定西经为负,南纬为负,所以地球上的经度范围就是[-180, 180],纬度范围就是[-90,90]。如果以本初子午线、赤道为界,地球可以分成4个部分
  2. 纬度范围[-90°, 0°)用二进制0代表,(0°, 90°]用二进制1代表,经度范围[-180°, 0°)用二进制0代表,(0°, 180°]用二进制1代表,那么地球可以分成如下4个部分
    GeoHash编码原理和代码演示
  3. 更小范围二分划分
    GeoHash编码原理和代码演示
  4. 转换计算方法步骤
  • 将经纬度变成二进制。
    GeoHash编码原理和代码演示
    GeoHash编码原理和代码演示
  • 将经纬度合并
    GeoHash编码原理和代码演示
  • 按照Base32进行编码
    GeoHash编码原理和代码演示

参考自:https://www.jianshu.com/p/2fd0cf12e5ba

2. 案例

  1. 环境
  • idea 2020
  • jdk 1.8
  • maven 3.6.3
  • pom文件
<dependencies>

        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.11</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-hive_2.11</artifactId>
        </dependency>

        <dependency>
            <groupId>ch.hsr</groupId>
            <artifactId>geohash</artifactId>
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>

        <dependency>
            <groupId>org.lionsoul</groupId>
            <artifactId>ip2region</artifactId>
            <version>1.7.2</version>
        </dependency>



    </dependencies>


    <build>
        <plugins>
            <!--  把依赖jar中的用到的类,提取到自己的jar中 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass></mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <!--下面是为了使用 mvn package命令,如果不加则使用mvn assembly-->
                <executions>
                    <execution>
                        <id>make-assemble</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
  1. 代码
object GeoHashDict {
  def main(args: Array[String]): Unit = {

    val spark = SparkSession.builder()
      .config("spark.sql.shuffle.partitions","2")
      .appName("地理位置知识库加工")
      .master("local")
      .getOrCreate()
    import spark.implicits._
    import org.apache.spark.sql.functions._

    // 加载mysql中的原始表数据,里面包含省市区和经纬度信息
    val props = new Properties()
    props.load(GeoHashDict.getClass.getClassLoader.getResourceAsStream("db.properties"))

    val df = spark.read.jdbc("jdbc:mysql://localhost:3306/realtimedw?useUnicode=true&characterEncoding=utf8","t_md_areas",props)

    // 扁平化操作
    df.createTempView("df")
    val df2 = spark.sql(
      """
        |
        |select
        |province.areaname as province,
        |city.areaname as city,
        |region.areaname as region,
        |region.bd09_lng  as lng,
        |region.bd09_lat  as lat
        |
        |from df region join df city on region.parentid = city.id and region.level=3
        |               join df province on city.parentid=province.id
        |""".stripMargin)

    df2.show(20,false)

	// 自定义函数
    val gps2geo: UserDefinedFunction = udf((lat:Double, lng:Double)=>{
    	// 5是geohash精度,越长,地理位置精度越高
      GeoHash.geoHashStringWithCharacterPrecision(lat,lng,5)
    })

    val res = df2.select('province,'city,'region,gps2geo('lat,'lng) as "geohash")


    res.write.parquet("dataware/data/geodict")


    spark.close()
  }

}
  1. 注意使用的maven中jar包是这个
    GeoHash编码原理和代码演示