在移动通信网络优化中,MR(Measurement Report,测量报告)数据是反映用户真实感知和网络覆盖质量的最核心数据源。传统的覆盖分析往往依赖于路测(DT/CQT),成本高且样本稀疏。随着大数据技术的发展,利用全量 MR 数据进行栅格化覆盖评估已成为行业主流。

本文将分享如何基于 Spring Cloud Alibaba 微服务架构与 Spark/Flink 大数据处理引擎,构建一个高效的 MR 数据处理流水线。我们将重点探讨如何利用 GeoHash 空间索引技术对海量离散采样点进行聚合,快速识别弱覆盖、重叠覆盖等网络问题,并通过 Vue 3 前端进行可视化呈现。

一、 业务背景与挑战

MR 数据具有“量大、点多、面广”的特点:

  • 海量性:全省每天产生的 MR 记录可达数十亿条。
  • 离散性:采样点分布不均,市区密集,郊区稀疏。
  • 复杂性:需要综合 RSRP(参考信号接收功率)、SINR(信噪比)、TA(时间提前量)等多个维度判断覆盖质量。

传统关系型数据库难以应对如此大规模的空间聚合查询。因此,我们引入大数据计算框架,实现从原始 MR 到“覆盖栅格”的实时/离线转换。

二、 总体架构设计

1. 数据链路

  1. 数据采集:网管系统采集原始 MR 话单,存入 HDFS 或 Kafka。
  2. 大数据计算层 (Spark/Flink)
    • 清洗:过滤无效采样点(如室内深度覆盖、GPS漂移点)。
    • 空间映射:利用 GeoHash 将经纬度映射为固定精度的网格 ID。
    • 聚合计算:以网格为单位,统计平均 RSRP、采样点数、弱覆盖比例等指标。
  3. 服务层 (Spring Cloud Alibaba)
    • Perf Service:提供栅格数据查询接口,对应原GridMrInfo和MRCoverSituationItem的业务逻辑。
    • Nacos:管理大数据任务配置与服务发现。
  4. 应用层 (Vue 3)
    • GIS 可视化:在地图上渲染覆盖热力图或栅格图层,直观展示问题区域。

三、 核心算法:基于 GeoHash 的空间聚合

1. 为什么选择 GeoHash?

GeoHash 是一种将二维经纬度编码为一维字符串的算法。相邻的地理位置通常具有相似的 GeoHash 前缀。这使得我们可以:

  • 快速分桶:将邻近的 MR 点归入同一个“桶”(即栅格)。
  • 高效索引:利用字符串前缀匹配快速检索特定区域的栅格。
  • 动态精度:通过调整 GeoHash 长度(如 6 位约 1.2km x 0.6km,7 位约 150m x 150m),平衡计算粒度与性能。

2. Spark 处理流程示例

我们使用 Spark SQL 或 DataFrame API 进行分布式计算:

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._
import ch.hsr.geohash.GeoHash // 引入 GeoHash 库

object MrCoverageAnalysis {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder().appName("MrCoverage").getOrCreate()
    import spark.implicits._

    // 1. 加载原始 MR 数据
    val mrDF = spark.read.parquet("/data/mr/raw/2023-10-01")

    // 2. 定义 UDF:将经纬度转换为 GeoHash (精度设为 7,约 150m 栅格)
    val toGeoHash = udf((lat: Double, lon: Double) => {
      GeoHash.geoHashStringWithCharacterPrecision(lat, lon, 7)
    })

    // 3. 数据清洗与映射
    val cleanedDF = mrDF.filter($"rsrp" > -140 && $"rsrp" < -40) // 过滤异常值
                        .withColumn("grid_id", toGeoHash($"latitude", $"longitude"))

    // 4. 按栅格聚合计算覆盖指标
    val gridStatsDF = cleanedDF.groupBy("grid_id")
                               .agg(
                                 avg("rsrp").alias("avg_rsrp"),
                                 count("*").alias("sample_count"),
                                 sum(when($"rsrp" < -110, 1).otherwise(0)).alias("weak_cover_count")
                               )

    // 5. 判定覆盖问题类型
    val resultDF = gridStatsDF.withColumn("cover_type", 
      when($"avg_rsrp" < -110, "WEAK_COVERAGE") // 弱覆盖
      .when($"sample_count" > 50 && $"weak_cover_count" / $"sample_count" > 0.3, "OVERLAP_COVERAGE") // 重叠覆盖
      .otherwise("NORMAL")
    )

    // 6. 结果写入 MySQL 或 Elasticsearch 供前端查询
    resultDF.write.jdbc(jdbcUrl, "grid_coverage_result", connectionProperties)
  }
}

四、 后端服务实现:Spring Cloud Alibaba

在 perf-service 中,我们提供 RESTful 接口供前端调用。

@RestController
@RequestMapping("/api/perf/coverage")
public class CoverageAnalysisController {

    @Autowired
    private GridCoverageRepository coverageRepository;

    /**
     * 获取指定区域的栅格覆盖数据
     * 对应原 GridMrInfo 业务逻辑
     */
    @GetMapping("/grid-data")
    public List<GridCoverDto> getGridData(@RequestParam String bbox) {
        // bbox 格式: minLon,minLat,maxLon,maxLat
        return coverageRepository.findByBbox(bbox);
    }

    /**
     * 获取覆盖问题统计摘要
     * 对应原 MrCoverSituationItem 业务逻辑
     */
    @GetMapping("/summary")
    public CoverSummaryDto getSummary(@RequestParam String cityCode) {
        return coverageRepository.getCitySummary(cityCode);
    }
}

五、 前端可视化:Vue 3 + ECharts/Leaflet

前端根据后端返回的栅格数据,在地图上进行渲染。

1. 栅格图层渲染

利用 Leaflet 的 L.rectangle 或 ECharts 的 heatmap/scatter 组件。

<!-- CoverageMap.vue -->
<script setup lang="ts">
import { onMounted } from 'vue';
import L from 'leaflet';
import axios from 'axios';

const map = L.map('map').setView([32.06, 118.79], 13); // 南京中心

onMounted(async () => {
  // 加载底图
  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);

  // 请求栅格数据
  const { data } = await axios.get('/api/perf/coverage/grid-data', {
    params: { bbox: '118.7,32.0,118.8,32.1' }
  });

  // 渲染栅格
  data.forEach((grid: any) => {
    const color = grid.coverType === 'WEAK_COVERAGE' ? '#ff0000' : 
                  grid.coverType === 'OVERLAP_COVERAGE' ? '#ffa500' : '#00ff00';
    
    // 根据 GeoHash 解码获取边界,或直接用中心点画圆
    L.circle([grid.centerLat, grid.centerLon], {
      radius: 50,
      color: color,
      fillOpacity: 0.6
    }).addTo(map).bindPopup(`RSRP: ${grid.avgRsrp}<br>Type: ${grid.coverType}`);
  });
});
</script>

2. 交互式钻取

用户点击地图上的红色栅格(弱覆盖区),右侧面板展示该区域的详细 MR 分布直方图、主要服务小区列表等信息,辅助优化人员制定调整方案(如调整天线倾角、增加基站功率)。

六、 总结

通过引入 Spark/Flink 大数据处理框架和 GeoHash 空间索引技术,我们成功构建了基于 MR 数据的覆盖问题智能识别模型:

  1. 高效处理:实现了亿级 MR 数据的分钟级聚合计算。
  2. 精准识别:通过多维指标综合判定,准确定位弱覆盖和重叠覆盖区域。
  3. 可视化赋能:结合 Vue 3 前端,将抽象的数据转化为直观的地图语言,提升了网络优化的工作效率。

该模型不仅适用于 4G LTE 网络,也可无缝扩展至 5G NR 网络的覆盖优化场景,为构建自组织网络(SON)奠定了坚实的数据基础。

互动环节
💬 你们公司的动态指标计算引擎是怎么实现的?遇到过哪些难题?欢迎在评论区分享!

⭐ 如果觉得这篇文章有帮助,欢迎点赞、收藏、转发!

🔔 关注我,下一篇将分享《电信系统中的单元测试策略》

版权声明:本文为原创文章,转载请注明出处。商业转载请联系作者获得授权。

作者简介:系统架构 师,专注于电信大数据平台架构设计与运维。目前负责日均处理2亿条消息的ucp平台,擅长分布式系统设计、消息中间件运维和高可用架构

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐