当前位置: 首页 > news >正文

Spark轨迹大数据高效处理_计算两经纬度点间的距离_使用Haversine formula公式

开发背景

        接上文我求的两经纬度点之间的方位角,我的需求里还提到了要计算距离,当然这个距离也是为后面的需求做铺垫的,因此需要求两个经纬度电之间的距离。

        不要妄想用勾股定理求出来,实际上距离的计算还是稍微复杂些。这里使用的是Haversine公式,用于在给定两个地理坐标点的情况下计算它们之间的球面距离,我直接将这个公式的数学计算实现为一个方法,然后再代码中调用。

生产环境使用(球面短距离计算)

        Haversine公式的数学理论基于球面三角学和三角恒等式的推导,通过近似计算大圆航线距离,适用于小距离的球面距离计算。这基本符合我的需求,因为我的计算都是基本是短距离计算的,基本不会跨省,实际效果也不错,如果你是超远距离计算,比如跨国,跨洲了,可以先试试,然后再考虑使用。

                        来源 https://wikipredia.net/zh/Haversine_formula#Formulation

说完理论部分,我就要开始上代码了,基本上你配置完spark环境,直接把我的代码扔上去就能看到输出结果,因为我是做了很多遍验证的。

spark代码

这个你可以转成python,反正算法基本都一样,不过换了一种写法

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._/*** 增加了多对多的方位角计算以及计算对应距离模型计算方法* 代码实现了计算多个点位对多个点位的方位角计算以及对应的距离计算,基本算是final版本* 基本实现了角度计算和距离计算* 在实际生产中,会出现噪音点,以及点位null值等,还是提前清洗一下数据为好* 2024年8月6日写,几个月前就搞好了,一直没空发博客。。。今天又闲下来了,干就完了,有问题及时联系* @email matrix70@163.com* @author lixh*/
object Angle_MoreToMore_Distance {/*** @author lixh* @param lon1* @param lat1* @param lon2* @param lat2* @return*/// 计算两个经纬度坐标之间的方位角def calculateAzimuth(lon1: Double, lat1: Double, lon2: Double, lat2: Double): Double = {val dx = lon2 - lon1val dy = lat2 - lat1val azimuth = math.atan2(dx, dy) * 180 / math.Pi(azimuth + 360) % 360}//距离算法 Haversine @author lixhdef haversineDistance(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double = {val toRadians = Math.toRadians(_: Double)val dLat = toRadians(lat2 - lat1)val dLon = toRadians(lon2 - lon1)val a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *Math.sin(dLon / 2) * Math.sin(dLon / 2)val c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))val EARTH_RADIUS_KM = 6371.0val distance = EARTH_RADIUS_KM * cdistance}def main(args: Array[String]): Unit = {val spark = SparkSession.builder().appName("Azimuth Calculation") // 设置应用程序名称.master("local[*]") // 运行模式,这里使用本地模式.getOrCreate()import spark.implicits._// DF A 包含地点信息和经纬度信息 @author https://blog.csdn.net/qq_52128187?type=blog    val A = Seq((101, "北京", 39.9042, 116.4074),(102, "广州", 23.16, 113.23)).toDF("id1", "name1", "latitudeA", "longitudeA")// DF C 包含地点信息和经纬度信息val C = Seq((101, "吉林", 43.8171, 125.3235),(101, "黑龙江", 45.8023, 126.5350),(102, "江苏", 32.0603, 118.7969),(102, "浙江", 30.2875, 120.1536),(101,"新疆", 43.77, 87.68),(102, "台湾省", 25.05, 121.50)).toDF("id2", "name2", "latitudeC", "longitudeC")val calculateAzimuthUDF = udf(calculateAzimuth _)// 执行内连接操作,计算方位角并添加到新列 "azimuth"val azimuthDF = A.join(C, A("id1") === C("id2")).withColumn("azimuth", calculateAzimuthUDF($"longitudeA", $"latitudeA", $"longitudeC", $"latitudeC"))// 计算得到的方位角数据azimuthDF.show(false)val haversineDistanceUDF = udf((lat1: Double, lon1: Double, lat2: Double, lon2: Double) => haversineDistance(lat1, lon1, lat2, lon2))//距离字段添加,@author lixhval resultDf = azimuthDF.withColumn("distance", haversineDistanceUDF($"latitudeA", $"longitudeA", $"latitudeC", $"longitudeC"))resultDf.show()spark.stop()}
}

代码输出结果

到这里基本就完成了,你可以对输出结果进行小数点位限制,一个round函数就解决。

参考资料:

https://wikipredia.net/zh/Haversine_formula

http://www.lryc.cn/news/418746.html

相关文章:

  • [C++] : std::copy_n
  • centos上传工具
  • 【C++】vector习题
  • Webpack Bundle Analysis:减少包体积的技巧
  • 如何利用 ChatGPT 提高工作效率?
  • 使用 Redisson 、Redis实现分布式锁
  • Typro + PicGo 图床 + Docsify + GitHub Pages,玩转个人知识库搭建,写给小白的建站入门课
  • 多角度文字识别:应对复杂环境的智能解决方案
  • 笔记:简单介绍WPF中RenderTransform,LayoutTransform, VisualTransform区别
  • 【AI大模型】LangChain框架:示例选择器与输出解析器携手,编织NLP高效精准之网
  • 苹果电脑玩的游戏有哪些 Mac电脑怎么玩Windows游戏 苹果电脑可以装模拟器玩游戏吗
  • 【mathtype】word中如何输入4×4的矩阵,甚至阶数更多
  • ByteArrayOutputStream
  • 使用CLIP模型进行零样本图像分类的分步指南
  • Llama 3.1用了1.6万个英伟达H100 GPU,耗费......
  • 学习c语言第24天(练习)
  • 【微信小程序开发】——奶茶点餐小程序的制作(一)
  • 鱼眼相机去畸变和矫正
  • Llama 3.1论文中文对照翻译
  • Vue js-cookie的使用存储token操作
  • C到C++——C++基础
  • trie算法
  • Kubernetes之pod的基本概念
  • PostgreSQL的学习心得和知识总结(一百五十)|[performance]更好地处理冗余 IS [NOT] NULL 限定符
  • sqllabs游戏
  • React Native Firebase:移动应用后端集成
  • 趣味算法------开灯问题
  • 如何长生?重要的是对内求索!
  • SD-WAN解决方案
  • 什么是C++的引用,请举例说明