From 5a2be87f658d01bc5b3b7ecdba92ac69bf09dcf7 Mon Sep 17 00:00:00 2001
From: ai_xiaopei <xiaopei@aisim.cn>
Date: Thu, 03 Sep 2026 15:15:37 +0800
Subject: [PATCH] fix(search): 搜索准确性四连修——FTS5 MATCH 引号包裹(连字符不再被解析成 MINUS);KeywordSearch 截断按命中关键词数排序(高频 bigram 不再挤出强相关文档);原词奖励档(完整短语压过泛化 bigram);tags 字段真实参与评分(此前误用 Section)
---
internal/graph/rwr.go | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 106 insertions(+), 0 deletions(-)
diff --git a/internal/graph/rwr.go b/internal/graph/rwr.go
new file mode 100644
index 0000000..d1d2252
--- /dev/null
+++ b/internal/graph/rwr.go
@@ -0,0 +1,106 @@
+package graph
+
+// AdjEdge 带权邻接边(导出:index 包 LoadRWRGraph 需引用该类型)
+type AdjEdge struct {
+ To int64
+ Weight float64
+}
+
+// RWR Random-Walk-with-Restart(个性化 PageRank):
+// 从种子集合出发在无向带权图上做 power iteration,restart 概率 alpha 回到种子。
+// 返回归一化到 [0,1] 的游走质量。确定性算法,无随机数。
+func RWR(seedIDs []int64, adj map[int64][]AdjEdge, alpha float64) map[int64]float64 {
+ if len(seedIDs) == 0 {
+ return map[int64]float64{}
+ }
+ // 收集参与节点:种子 + 邻接可达
+ nodes := make(map[int64]bool)
+ for _, s := range seedIDs {
+ nodes[s] = true
+ }
+ for from := range adj {
+ nodes[from] = true
+ for _, e := range adj[from] {
+ nodes[e.To] = true
+ }
+ }
+ n := len(nodes)
+ if n == 0 {
+ return map[int64]float64{}
+ }
+ idx := make(map[int64]int, n)
+ ids := make([]int64, 0, n)
+ for id := range nodes {
+ idx[id] = len(ids)
+ ids = append(ids, id)
+ }
+
+ // 重启向量:种子均匀
+ r := make([]float64, n)
+ for _, s := range seedIDs {
+ if i, ok := idx[s]; ok {
+ r[i] = 1.0 / float64(len(seedIDs))
+ }
+ }
+
+ const maxIter = 50
+ const eps = 1e-6
+ newR := make([]float64, n)
+ for iter := 0; iter < maxIter; iter++ {
+ for i := range newR {
+ newR[i] = 0
+ }
+ // 游走传播:out[i] = sum(w_ij)
+ for i, id := range ids {
+ var total float64
+ for _, e := range adj[id] {
+ total += e.Weight
+ }
+ if total == 0 {
+ continue
+ }
+ for _, e := range adj[id] {
+ j, ok := idx[e.To]
+ if !ok {
+ continue
+ }
+ newR[j] += (1 - alpha) * r[i] * e.Weight / total
+ }
+ }
+ // restart
+ for i := range newR {
+ newR[i] += alpha * r[i]
+ }
+ // 收敛判断
+ diff := 0.0
+ for i := range newR {
+ d := newR[i] - r[i]
+ if d < 0 {
+ d = -d
+ }
+ diff += d
+ }
+ r, newR = newR, r
+ if diff < eps {
+ break
+ }
+ }
+ // 归一化 [0,1]
+ maxV := 0.0
+ for _, v := range r {
+ if v > maxV {
+ maxV = v
+ }
+ }
+ out := make(map[int64]float64, n)
+ if maxV == 0 {
+ for _, id := range ids {
+ out[id] = 0
+ }
+ return out
+ }
+ for i, id := range ids {
+ out[id] = r[i] / maxV
+ }
+ return out
+}
--
Gitblit v1.10.0