kmp openharmony Z-Score 时序异常打分与异常点排行
本文介绍了一个基于Z-Score算法的时序异常检测工具,使用Kotlin Multiplatform实现核心计算逻辑,并通过OpenHarmony进行可视化展示。该工具能够对接口耗时、QPS、错误率等时序指标进行异常打分,识别出偏离整体平均水平的数据点,并按异常程度排序输出TopK异常点。系统支持灵活配置,提供均值、标准差等统计信息,帮助开发者快速定位异常时段。文章详细阐述了算法原理、输入格式设计

在接口耗时、QPS、错误率、资源利用率等时序指标中,我们经常想知道:
在这一串数据里,到底哪些点算“明显异常”?
是不是只有少数点特别离谱,其余都还算正常波动?
本案例基于 Kotlin Multiplatform(KMP)与 OpenHarmony,实现了一个Z-Score 时序异常打分与异常点排行器:
- 使用 Z-Score(标准分)对每个样本点进行“异常程度”打分;
- 支持配置 TopK,输出最异常的 K 个点(按 \(|Z|\) 从大到小排序);
- 给出均值、标准差等整体统计信息,帮助理解异常点相对位置与严重程度;
- 通过 ArkTS 单页面展示完整报告,便于在终端侧快速识别异常点。
一、问题背景与典型场景
在 AIOps 与业务监控中,常见需求包括:
-
接口耗时异常点识别
一串耗时数据中,哪些请求远高于整体水平?Z-Score 可以快速标出这些异常请求。 -
QPS 或流量异常突刺
某一时刻的 QPS 是否远超其他时间点?是否属于“流量洪峰”的一部分? -
错误次数或重试次数异常升高
某些时刻的错误计数或重试计数是否明显偏高,值得重点关注? -
业务指标异常点检测
对订单量、支付失败量、点击次数等指标进行异常打分,快速定位“异常行为”时段。
Z-Score 是一个经典、简单且易于解释的统计工具:
对于样本 \( x_i \),其 Z-Score 定义为 \( z_i = (x_i - \mu) / \sigma \),
其中 \( \mu \) 为均值,\( \sigma \) 为标准差。\(|z_i|\) 越大,说明 \( x_i \) 越偏离整体平均水平。
二、Kotlin Z-Score 异常打分引擎
1. 输入格式设计
沿用本系列案例的配置风格,本案例支持如下输入形式:
k=5
series=10,12,11,13,50,14,12,11,60,13,12
k:TopK 异常点数量(可选,默认可视为 5);series:一串以,/ 空格 /;/ 换行分隔的数值样本。
也支持类似:
series=10,12,11,13,50
12,11,60,13,12
解析逻辑会从每一行中尝试解析所有可转换为 Double 的数值。
2. Kotlin 分析主入口
在 App.kt 中,我们定义了对外暴露的分析函数,并通过 @JsExport 让 OpenHarmony 端可以调用:
@JsExport
fun zScoreAnomalyRanker(inputData: String): String {
val sanitized = inputData.trim()
if (sanitized.isEmpty()) {
return "❌ 输入为空,请按 k=5\\nseries=10,12,11,13,50,... 形式提供数据"
}
val lines = sanitized.lines()
.map { it.trim() }
.filter { it.isNotEmpty() }
var k: Int? = null
val values = mutableListOf<Double>()
for (line in lines) {
when {
line.startsWith("k=", ignoreCase = true) -> {
k = line.substringAfter("=").trim().toIntOrNull()
}
line.startsWith("series=", ignoreCase = true) -> {
val parsed = line.substringAfter("=")
.split(",", " ", ";", "\n")
.mapNotNull { it.trim().takeIf { s -> s.isNotEmpty() }?.toDoubleOrNull() }
values += parsed
}
else -> {
val parsed = line.split(",", " ", ";", "\n")
.mapNotNull { it.trim().takeIf { s -> s.isNotEmpty() }?.toDoubleOrNull() }
values += parsed
}
}
}
if (values.size < 3) {
return "❌ 至少需要 3 个及以上样本点才能计算 Z-Score 异常分数"
}
val topK = (k ?: 5).coerceAtMost(values.size)
val n = values.size
val mean = values.sum() / n
val variance = values.fold(0.0) { acc, v -> acc + (v - mean) * (v - mean) } / n
val std = kotlin.math.sqrt(variance)
if (std == 0.0) {
return "ℹ️ 所有样本值完全相同 (均值=$mean, 方差=0),无法基于 Z-Score 识别异常点"
}
data class ScoredPoint(val index: Int, val value: Double, val z: Double)
val scored = values.mapIndexed { idx, v ->
val z = (v - mean) / std
ScoredPoint(idx, v, z)
}
val ranked = scored.sortedByDescending { kotlin.math.abs(it.z) }
val builder = StringBuilder()
builder.appendLine("📊 Z-Score 时序异常打分与异常点排行报告")
builder.appendLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
builder.appendLine("样本数量: $n")
builder.appendLine("均值 (mean): ${round2(mean)}")
builder.appendLine("标准差 (std): ${round2(std)}")
builder.appendLine("TopK 异常点数量: $topK")
builder.appendLine()
builder.appendLine("🧮 原始序列")
builder.appendLine(values.joinToString(prefix = "[", postfix = "]"))
builder.appendLine()
builder.appendLine("🏅 TopK 异常点排行(按 |Z-Score| 从高到低)")
ranked.take(topK).forEachIndexed { rank, p ->
builder.appendLine(
"第 ${rank + 1} 名: 索引=${p.index}, 值=${p.value}, Z-Score=${round2(p.z)} (|Z|=${round2(kotlin.math.abs(p.z))})"
)
}
builder.appendLine()
builder.appendLine("🧠 工程化解读")
builder.appendLine("- Z-Score 异常打分适合用于“整体波动较平稳”的指标,快速标记明显偏离均值的点;")
builder.appendLine("- 一般认为 |Z| > 2 或 |Z| > 3 的点具有明显异常性,可作为告警候选;")
builder.appendLine("- 在非高斯分布场景下,可结合分位数/箱线图等方法综合判断,避免单一标准产生误报。")
return builder.toString().trim()
}
核心步骤:
- 解析
k和series; - 计算样本均值
mean与标准差std; - 对每个点计算 Z-Score:\( z_i = (x_i - \mu) / \sigma \);
- 按 \(|z_i|\) 从大到小排序,取前 TopK 作为“最异常的 K 个点”。
三、OpenHarmony 侧调用与 UI 展示思路
在 ArkTS 页面中,可以像其他案例一样导入并调用:
import { zScoreAnomalyRanker } from './hellokjs'
页面状态建议包括:
kValue: TopK 数量(默认"5");seriesInput: 时序样本数据字符串(如"10,12,11,13,50,14,12,11,60,13,12")。
调用示例:
const seriesLine = this.seriesInput.includes('series=') ? this.seriesInput : `series=${this.seriesInput}`
const payload = `k=${this.kValue}\n${seriesLine}`
this.result = zScoreAnomalyRanker(payload)
展示层可以:
- 使用等宽字体展示“原始序列 + TopK 异常点列表”;
- 对“TopK 异常点排行”部分做重点高亮,例如用不同颜色或图标标记;
- 可以进一步将异常点索引映射回图形化折线图中,在 ArkTS 侧以“红点”形式标出。
四、复杂度与工程实践建议
复杂度分析:
- 统计均值与标准差:\( O(n) \);
- 计算每个点的 Z-Score:\( O(n) \);
- 排序获取 TopK:\( O(n \log n) \);
- 整体复杂度约为 \( O(n \log n) \),在典型终端侧数据规模下完全可接受。
工程实践中的扩展方向:
-
滑动窗口 Z-Score
对滑动窗口内的数据计算 Z-Score,检测“局部异常点”,而不是全局异常。 -
与分位数/箱线图组合
将 Z-Score 与 P95/P99、IQR 离群值检测组合使用,降低单一统计方法在非正态分布场景中的误报概率。 -
多维异常打分
在多指标场景下,对多维数据计算“综合异常分数”(例如将各指标 Z-Score 做加权合成)。 -
端侧轻量异常检测
将该 Z-Score 异常打分逻辑嵌入 OpenHarmony 设备端,实现本地轻量异常检测与 TopK 报告,无需依赖后端大数据平台。
通过这个 Z-Score 时序异常打分与异常点排行案例,你可以在设备侧快速定位“最值得关注的少数异常点”,
为后续的日志钻取、链路追踪与根因分析节省大量时间与精力。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)