ai_xiaopei
2 days ago ada154418fb223e742112e58ef169193e588eafb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package index
 
import (
    "path/filepath"
    "testing"
 
    "github.com/aisim/kb-cli/internal/graph"
)
 
func TestFTSSearch(t *testing.T) {
    tmpDir := t.TempDir()
    dbPath := filepath.Join(tmpDir, "test.db")
 
    store, err := Open(dbPath)
    if err != nil {
        t.Fatalf("Open failed: %v", err)
    }
    defer store.Close()
 
    // 插入测试数据
    store.InsertNode(&graph.Node{
        ID:      1,
        Path:    "FAQ/充装类/001-test.md",
        Title:   "充装问题排查",
        Section: "FAQ",
        Tags:    []string{"充装"},
        Content: "关于智能枪充装问题的排查方法",
    })
    store.InsertNode(&graph.Node{
        ID:      2,
        Path:    "知识/002-config.md",
        Title:   "充装规格配置",
        Section: "知识",
        Tags:    []string{"配置"},
        Content: "充装规格配置说明",
    })
 
    // 创建 FTS
    if err := store.CreateFTS(); err != nil {
        t.Fatalf("CreateFTS failed: %v", err)
    }
    if err := store.PopulateFTS(); err != nil {
        t.Fatalf("PopulateFTS failed: %v", err)
    }
 
    // 搜索 - FTS5 对中文按字符 tokenize,"充装" 两个节点都包含
    results, err := store.FTSSearch([]string{"充装"}, 10)
    if err != nil {
        t.Fatalf("FTSSearch failed: %v", err)
    }
    if len(results) < 1 {
        t.Errorf("result count = %d, want >= 1", len(results))
    }
}
 
// TestKeywordSearchASCII 覆盖 KeywordSearch 的 FTS 通道(ASCII 词 MATCH + rank 排序)
func TestKeywordSearchASCII(t *testing.T) {
    store, err := Open(filepath.Join(t.TempDir(), "test.db"))
    if err != nil {
        t.Fatalf("Open failed: %v", err)
    }
    defer store.Close()
 
    // 两个节点都含 "pump",但 node1 标题也含(title 权重高 → rank 更靠前)
    store.InsertNode(&graph.Node{
        ID:      1,
        Path:    "知识/001-pump.md",
        Title:   "pump failure",
        Section: "知识",
        Content: "pump failure troubleshooting guide",
    })
    store.InsertNode(&graph.Node{
        ID:      2,
        Path:    "知识/002-valve.md",
        Title:   "valve config",
        Section: "知识",
        Content: "the pump is configured here",
    })
    if err := store.CreateFTS(); err != nil {
        t.Fatalf("CreateFTS failed: %v", err)
    }
    if err := store.PopulateFTS(); err != nil {
        t.Fatalf("PopulateFTS failed: %v", err)
    }
 
    results, err := store.KeywordSearch([]string{"pump"}, 10)
    if err != nil {
        t.Fatalf("KeywordSearch failed: %v", err)
    }
    if len(results) != 2 {
        t.Fatalf("result count = %d, want 2 (FTS 通道应命中两节点)", len(results))
    }
    // FTS 通道 rank 排序:标题含 pump 的 node1 应排第一
    if results[0].ID != 1 {
        t.Errorf("FTS rank 排序: 首位 = %d, want 1", results[0].ID)
    }
}
 
// TestKeywordSearchMixed 覆盖双通道混合(ASCII 走 FTS + CJK 走 LIKE,seen 去重)
func TestKeywordSearchMixed(t *testing.T) {
    store, err := Open(filepath.Join(t.TempDir(), "test.db"))
    if err != nil {
        t.Fatalf("Open failed: %v", err)
    }
    defer store.Close()
 
    store.InsertNode(&graph.Node{
        ID:      1,
        Path:    "FAQ/001-pump.md",
        Title:   "pump 补气",
        Section: "FAQ",
        Content: "pump 补气失败排查",
    })
    if err := store.CreateFTS(); err != nil {
        t.Fatalf("CreateFTS failed: %v", err)
    }
    if err := store.PopulateFTS(); err != nil {
        t.Fatalf("PopulateFTS failed: %v", err)
    }
 
    // 同一节点被两个通道命中 → 去重后只出现一次
    results, err := store.KeywordSearch([]string{"pump", "补气"}, 10)
    if err != nil {
        t.Fatalf("KeywordSearch failed: %v", err)
    }
    if len(results) != 1 {
        t.Fatalf("双通道去重: count = %d, want 1", len(results))
    }
    if results[0].ID != 1 {
        t.Errorf("命中节点 = %d, want 1", results[0].ID)
    }
}