议题相似度算法
加权混合相似度算法(Weighted Hybrid Similarity Algorithm)
算法概述
议题相似度算法采用混合检索(Hybrid Retrieval)策略,结合了基于向量的语义匹配和基于集合/类别的精确匹配。 该算法能够同时捕捉议题的非结构化语义信息(如情绪色彩、隐含意图)和结构化特征(如地理实体、参与方、事件类型等)。
核心优势
- • 语义相似度:捕捉模糊语境和隐含信息(如"鬼鬼祟祟"与"伺机"的语义关联)
- • 结构化匹配:精确匹配关键要素(如必须发生在"仁爱礁",必须是"执法对峙")
- • 加权融合:通过可调权重平衡语义和结构化特征的重要性
核心公式
总相似度计算公式
Stotal = α · Ssemantic + β · Sstructure
其中 α + β = 1,默认 α = 0.4,β = 0.6
Ssemantic:基于 input_text 的嵌入向量余弦相似度,负责捕捉整体语境、情绪和隐含意图
Sstructure:六大核心要素的加权相似度,负责精确匹配议题的结构化特征
结构化相似度计算公式
Sstructure = Σ(Wi · Si)
i ∈ {geo, event, actor, nature, asset, temporal}
| 维度 | 默认权重 (Wi) | 说明 |
|---|---|---|
| 地理实体 (geo) | 0.25 | 发生在同一个礁盘是高相似度的核心 |
| 关键行动 (event) | 0.25 | 事件类型(如都是补给、都是撞船)决定性质 |
| 参与行为体 (actor) | 0.20 | 直接当事方的重合度影响相似度 |
| 核心性质 (nature) | 0.15 | 主权/管辖权通常比较固定 |
| 核心资产 (asset) | 0.10 | 往往依附于事件 |
| 时间动态 (temporal) | 0.05 | 状态描述,权重最低 |
算法流程图
输入议题A和议题B
↓
计算语义相似度
1. 获取 input_text 嵌入向量
2. 计算余弦相似度
3. 得到 Ssemantic
2. 计算余弦相似度
3. 得到 Ssemantic
计算结构化相似度
1. 计算六大要素相似度
2. 加权汇总
3. 得到 Sstructure
2. 加权汇总
3. 得到 Sstructure
↓
加权混合:Stotal = α·Ssemantic + β·Sstructure
↓
返回总相似度分数 [0, 1]
详细计算方法
1. 语义相似度 (Ssemantic)
算法:Embedding Cosine Similarity
1. 将 input_text 转化为向量 Vinput
2. 计算余弦相似度:cos(θ) = (VA · VB) / (||VA|| · ||VB||)
3. 得分范围:[0, 1]
2. 地理实体相似度 (Sgeo)
公式:
Sgeo = 0.5·J(Names_A, Names_B) + 0.3·I(Region_A == Region_B) + 0.2·I(Feature_A == Feature_B)
• J: Jaccard 相似系数(交集/并集)
• I: 指示函数(布尔匹配,0或1)
• I: 指示函数(布尔匹配,0或1)
3. 参与行为体相似度 (Sactor)
公式:
Sactor = 0.5·J(Direct_A, Direct_B) + 0.3·J(Third_A, Third_B) + 0.2·J(Org_A, Org_B)
• 直接当事方权重最高(0.5)
• 第三方和组织权重递减
• 第三方和组织权重递减
4. 核心性质相似度 (Snature)
公式:
Snature = (1/3) · [I(IssueType_A == IssueType_B) + I(Domain_A == Domain_B) + I(Posture_A == Posture_B)]
• 三个枚举字段的平均匹配率
• 完全匹配为1,否则为0
• 完全匹配为1,否则为0
5. 关键行动相似度 (Sevent)
公式:
Sevent = 0.4·I(Category_A == Category_B) + 0.6·TextSim(Desc_A, Desc_B)
• 类别精确匹配(0.4权重)
• 描述文本相似度(0.6权重,使用简化文本相似度)
• 描述文本相似度(0.6权重,使用简化文本相似度)
6. 核心资产相似度 (Sasset)
公式:
Sasset = 0.5·J(Tangible_A, Tangible_B) + 0.5·J(Intangible_A, Intangible_B)
• 有形资产和无形资产的 Jaccard 相似度各占50%
7. 时间动态相似度 (Stemporal)
公式:
Stemporal = (1/3) · [I(Freq_A == Freq_B) + I(Stage_A == Stage_B) + TextSim(Context_A, Context_B)]
• 频率和阶段的精确匹配
• 时间背景使用文本相似度
• 时间背景使用文本相似度
算法伪代码
function calculateSimilarity(issueA, issueB, weights):
// 1. 计算语义相似度
embeddingA = getTextEmbedding(issueA.input_text)
embeddingB = getTextEmbedding(issueB.input_text)
semanticSim = cosineSimilarity(embeddingA, embeddingB)
// 2. 计算结构化相似度
geoSim = calculateGeographicSimilarity(issueA.geographic_locus, issueB.geographic_locus)
actorSim = calculateActorsSimilarity(issueA.actors_involved, issueB.actors_involved)
natureSim = calculateNatureSimilarity(issueA.core_nature_of_issue, issueB.core_nature_of_issue)
eventSim = calculateEventSimilarity(issueA.key_actions_events, issueB.key_actions_events)
assetSim = calculateAssetSimilarity(issueA.core_assets_objectives, issueB.core_assets_objectives)
temporalSim = calculateTemporalSimilarity(issueA.temporal_dynamics, issueB.temporal_dynamics)
// 3. 加权汇总结构化相似度
structureSim = (
weights.geo * geoSim +
weights.event * eventSim +
weights.actor * actorSim +
weights.nature * natureSim +
weights.asset * assetSim +
weights.temporal * temporalSim
)
// 4. 最终融合
totalSimilarity = weights.alpha * semanticSim + weights.beta * structureSim
return clamp(totalSimilarity, 0, 1)
function jaccard(listA, listB):
setA = set(listA)
setB = set(listB)
intersection = len(setA ∩ setB)
union = len(setA ∪ setB)
return intersection / union if union > 0 else 1.0优化建议
1. 标准化词表
由于结构化描述是大模型生成的,可能会出现同义词(例如"中国海警"和"中方海警船")。 建议在计算 Jaccard 之前建立同义词映射表,或在 Prompt 中强制大模型使用标准实体名。
2. 非对称关注
对于舆情分析,"地理位置"和"触发原因"通常比"时间阶段"更能引起相似的舆情反应。 如果目标是预测舆情走势,应加大关键行动(Triggering Event)的权重。
3. 向量数据库
如果议题库很大(>100万),建议使用支持 Hybrid Search 的向量数据库(如 Milvus, Elasticsearch, Weaviate)。 可以将结构化字段作为 Filter,或将结构化字段序列化为文本后进行第二个向量的 Embedding。