DistanceCalculator - 向量距离计算器
DistanceCalculator 用于计算两个 CVSS 向量之间的距离。它支持多种距离算法,可用于向量相似性分析和聚类。
距离是如何计算的
两个向量先被投影到数值特征空间(每个指标 → 其评分权重),再由所选度量将两个特征向量归并为一个数:
距离与相似度
欧氏 / 曼哈顿 / 汉明 / 评分差返回距离(0 表示完全相同,越大越不同);Jaccard 返回相似度(1 表示完全相同,0 表示完全不相交)。按场景选择:聚类偏向距离,去重偏向相似度。
所有度量均使用基础值
距离度量比较两个向量的基础指标取值。时间与环境指标不参与距离计算。若需比较考虑环境修正后的评分,请自行计算各向量的 GetEnvironmentalScore() 再取绝对差。
类型定义
DistanceCalculator 是一个持有两个 *Cvss3x 引用的结构体。通过 NewDistanceCalculator 构造,度量方法定义在 *DistanceCalculator 接收者上:
type DistanceCalculator struct {
// 非导出:持有两个 *Cvss3x 向量
}
func NewDistanceCalculator(vector1, vector2 *Cvss3x) *DistanceCalculator
func (dc *DistanceCalculator) EuclideanDistance() float64
func (dc *DistanceCalculator) ManhattanDistance() float64
func (dc *DistanceCalculator) HammingDistance() int
func (dc *DistanceCalculator) JaccardSimilarity() float64
func (dc *DistanceCalculator) ScoreDifference() float64没有 Checked 或 WithEnv 变体
距离方法返回裸 float64(HammingDistance 返回 int),没有返回错误或环境感知的变体。nil 接收者或 nil 向量会静默返回 0 —— 若需防范,请在构造计算器前自行校验输入(见错误处理)。
创建计算器
NewDistanceCalculator
func NewDistanceCalculator(vector1, vector2 *Cvss3x) *DistanceCalculator为两个 CVSS 向量创建新的距离计算器。
参数:
vector1: 第一个 CVSS 向量vector2: 第二个 CVSS 向量
返回值:
*DistanceCalculator: 距离计算器实例
示例:
calc := cvss.NewDistanceCalculator(vector1, vector2)距离算法
EuclideanDistance
func (dc *DistanceCalculator) EuclideanDistance() float64计算两个向量之间的欧几里得距离。
公式:
distance = √(Σ(xi - yi)²)其中 xi 和 yi 是两个向量在第 i 个维度上的值。
返回值:
float64: 欧几里得距离值 (0.0 到 ~3.0,取决于所含指标)
示例:
distance := calc.EuclideanDistance()
fmt.Printf("欧几里得距离: %.3f\n", distance)用途:
- 向量相似性分析
- 聚类算法
- 异常检测
ManhattanDistance
func (dc *DistanceCalculator) ManhattanDistance() float64计算两个向量之间的曼哈顿距离(也称为城市街区距离)。
公式:
distance = Σ|xi - yi|返回值:
float64: 曼哈顿距离值 (0.0 到 ~8.0,取决于所含指标)
示例:
distance := calc.ManhattanDistance()
fmt.Printf("曼哈顿距离: %.3f\n", distance)特点:
- 对异常值不敏感
- 计算效率高
- 适用于高维数据
HammingDistance
func (dc *DistanceCalculator) HammingDistance() int统计两个向量在指标位置上不同(按短值)的个数。仅比较两个向量上都存在的指标。
公式:
distance = #{ i : xi != yi }返回值:
int: 不同的位置数(0 表示每个共有指标都相同)
示例:
distance := calc.HammingDistance()
fmt.Printf("汉明距离: %d\n", distance)应用场景:
- 类别型差异计数
- 快速检查"改动了几项指标"
- 向量修订间的变更检测
评分差度量
ScoreDifference
func (dc *DistanceCalculator) ScoreDifference() float64返回两个向量计算所得评分之差的绝对值。与逐指标距离不同,它先将整个向量塌缩为评分,再取 |scoreA − scoreB|。
公式:
difference = |Calculate(A) − Calculate(B)|返回值:
float64: 评分差的绝对值 (0.0 到 10.0)
示例:
diff := calc.ScoreDifference()
fmt.Printf("评分差: %.3f\n", diff)
if diff < 0.5 {
fmt.Println("评分几乎相同")
} else if diff < 2.0 {
fmt.Println("评分有差异")
} else {
fmt.Println("评分差异显著")
}优势:
- 直接反映真实影响差距,而非指标数量
- 适合判断评分是否跨越严重性边界(如是否越过 9.0)
- 优先级排序:按真实影响增量而非指标计数来排列向量对
JaccardSimilarity
func (dc *DistanceCalculator) JaccardSimilarity() float64计算两个向量之间的雅卡德相似度。
公式:
similarity = |A ∩ B| / |A ∪ B|返回值:
float64: 雅卡德相似度值 (0.0 到 1.0)- 1.0: 完全相同
- 0.0: 完全不同
示例:
similarity := calc.JaccardSimilarity()
fmt.Printf("雅卡德相似度: %.3f\n", similarity)应用:
- 集合相似性分析
- 二进制特征比较
- 推荐系统
实际应用示例
基本距离计算
package main
import (
"fmt"
"github.com/scagogogo/cvss-skills/pkg/cvss"
"github.com/scagogogo/cvss-skills/pkg/parser"
)
func main() {
// 解析两个 CVSS 向量
vector1Str := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
vector2Str := "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L"
parser1 := parser.NewCvss3xParser(vector1Str)
vector1, _ := parser1.Parse()
parser2 := parser.NewCvss3xParser(vector2Str)
vector2, _ := parser2.Parse()
// 创建距离计算器
calc := cvss.NewDistanceCalculator(vector1, vector2)
// 计算各种距离
fmt.Printf("欧几里得距离: %.3f\n", calc.EuclideanDistance())
fmt.Printf("曼哈顿距离: %.3f\n", calc.ManhattanDistance())
fmt.Printf("汉明距离: %d\n", calc.HammingDistance())
fmt.Printf("评分差: %.3f\n", calc.ScoreDifference())
fmt.Printf("雅卡德相似度: %.3f\n", calc.JaccardSimilarity())
}向量聚类分析
func clusterVectors(vectors []*cvss.Cvss3x, threshold float64) [][]int {
var clusters [][]int
used := make([]bool, len(vectors))
for i, vector1 := range vectors {
if used[i] {
continue
}
cluster := []int{i}
used[i] = true
for j, vector2 := range vectors {
if i == j || used[j] {
continue
}
calc := cvss.NewDistanceCalculator(vector1, vector2)
distance := calc.EuclideanDistance()
if distance <= threshold {
cluster = append(cluster, j)
used[j] = true
}
}
clusters = append(clusters, cluster)
}
return clusters
}相似性分析
func analyzeSimilarity(v1, v2 *cvss.Cvss3x) {
calc := cvss.NewDistanceCalculator(v1, v2)
euclidean := calc.EuclideanDistance()
jaccard := calc.JaccardSimilarity()
fmt.Printf("向量1: %s\n", v1.String())
fmt.Printf("向量2: %s\n", v2.String())
fmt.Printf("欧几里得距离: %.3f\n", euclidean)
fmt.Printf("雅卡德相似度: %.3f\n", jaccard)
// 相似性判断(Jaccard:越大越相似)
if jaccard > 0.9 {
fmt.Println("结论: 向量非常相似")
} else if jaccard > 0.7 {
fmt.Println("结论: 向量相似")
} else if jaccard > 0.3 {
fmt.Println("结论: 向量有一定相似性")
} else {
fmt.Println("结论: 向量差异较大")
}
}性能优化
带缓存的成对计算
DistanceCalculator 不持有可变状态,但反复重算同一向量对是浪费。用按向量对索引的应用层小缓存可实现 O(1) 重复查询。由于距离方法返回裸 float64(无 error 变体),先一次性校验所有向量,之后即可放心缓存:
// 应用层向量对缓存;库不提供。
type pairCache struct {
vectors []*cvss.Cvss3x
cache map[[2]int]float64
}
func newPairCache(vectors []*cvss.Cvss3x) (*pairCache, error) {
// 先一次性校验,确保缓存查询永不遇到坏向量。
for _, v := range vectors {
if v == nil {
return nil, fmt.Errorf("nil vector in input")
}
if err := v.Check(); err != nil {
return nil, fmt.Errorf("invalid vector %s: %w", v.String(), err)
}
}
return &pairCache{vectors: vectors, cache: make(map[[2]int]float64)}, nil
}
// Euclidean 返回向量对 (i, j) 的缓存欧氏距离,首次访问时计算。
// 顺序无关:(i,j) 与 (j,i) 共享同一缓存项。
func (c *pairCache) Euclidean(i, j int) float64 {
if i == j {
return 0
}
if i > j {
i, j = j, i
}
key := [2]int{i, j}
if d, ok := c.cache[key]; ok {
return d
}
d := cvss.NewDistanceCalculator(c.vectors[i], c.vectors[j]).EuclideanDistance()
c.cache[key] = d
return d
}最佳实践
算法选择指南
欧几里得距离
- 适用于连续数值特征
- 对异常值敏感
- 常用于聚类分析
曼哈顿距离
- 适用于高维数据
- 对异常值不敏感
- 计算效率高
汉明距离
- 适用于类别型差异计数
- "改了几项指标"的直观度量
- 变更检测
评分差(ScoreDifference)
- 直接反映真实影响差距
- 判断是否跨越严重性边界
- 按影响增量排序向量对
雅卡德相似度
- 适用于集合/二进制特征
- 集合相似性分析
- 去重场景
错误处理
func safeDistanceCalculation(v1, v2 *cvss.Cvss3x) (float64, error) {
if v1 == nil || v2 == nil {
return 0, fmt.Errorf("向量不能为空")
}
if err := v1.Check(); err != nil {
return 0, fmt.Errorf("向量1无效: %w", err)
}
if err := v2.Check(); err != nil {
return 0, fmt.Errorf("向量2无效: %w", err)
}
calc := cvss.NewDistanceCalculator(v1, v2)
return calc.EuclideanDistance(), nil
}相关文档
- CVSS 数据结构 - 了解 CVSS 向量结构
- Calculator 计算器 - 评分计算
- 距离计算示例 - 含层次聚类与并行距离矩阵
- 向量比较 - 跨向量集合的比较