增加搜索功能

This commit is contained in:
2026-04-08 19:04:15 +08:00
parent 1d3570a505
commit 6637dff254
3 changed files with 190 additions and 7 deletions
+78 -6
View File
@@ -35,11 +35,12 @@ type SnippetEntry struct {
Timestamp int64 `json:"ts"` // 抓取该页面时的 Unix 时间戳
}
// 个 bbolt bucket 的名称(以字节数组存储,bbolt 要求 key/value 均为字节)
// 个 bbolt bucket 的名称(以字节数组存储,bbolt 要求 key/value 均为字节)
var (
bucketIndex = []byte("index") // 倒排索引 bucket
bucketGate = []byte("gate") // URL 摘要缓存 bucket
bucketSiteGate = []byte("site_gate") // 网站元信息 bucket
bucketIndex = []byte("index") // 倒排索引 bucket
bucketGate = []byte("gate") // URL 摘要缓存 bucket
bucketSiteGate = []byte("site_gate") // 网站元信息 bucket
bucketPriority = []byte("priority") // 优先爬取 URL bucket
)
// DB 封装一个 bbolt 数据库,提供类型化的存取接口。
@@ -62,9 +63,9 @@ func Open(dir string) (*DB, error) {
if err != nil {
return nil, fmt.Errorf("storage.Open bolt: %w", err)
}
// 启动时确保个 bucket 都存在(不存在则创建)
// 启动时确保个 bucket 都存在(不存在则创建)
err = db.Update(func(tx *bolt.Tx) error {
for _, b := range [][]byte{bucketIndex, bucketGate, bucketSiteGate} {
for _, b := range [][]byte{bucketIndex, bucketGate, bucketSiteGate, bucketPriority} {
if _, err := tx.CreateBucketIfNotExists(b); err != nil {
return err
}
@@ -328,3 +329,74 @@ func (d *DB) ForEachSnippet(fn func(url string, entry *SnippetEntry) error) erro
})
})
}
// ---- 优先爬取队列(Priority Queue)相关方法 ----
// PriorityEntry 记录一条待优先爬取的 URL 或域名。
type PriorityEntry struct {
URL string `json:"url"` // 用户提交的 URL 或域名(会自动规范化为带 scheme 的 URL)
IsDomain bool `json:"domain"` // 是否为纯域名(true=仅域名,false=完整 URL
AddedAt int64 `json:"added_at"` // 添加时的 Unix 时间戳
Visited bool `json:"visited"` // 是否已爬取(crawler 爬完后标记)
}
// GetPriorityURLs 返回所有未访问的 priority 条目(按添加时间升序)。
func (d *DB) GetPriorityURLs() ([]PriorityEntry, error) {
var entries []PriorityEntry
err := d.db.View(func(tx *bolt.Tx) error {
return tx.Bucket(bucketPriority).ForEach(func(k, v []byte) error {
var e PriorityEntry
if err := decompressUnmarshal(v, &e); err != nil {
return nil // 跳过损坏条目
}
if !e.Visited {
entries = append(entries, e)
}
return nil
})
})
return entries, err
}
// AddPriorityURL 添加一条 priority 条目(key = URLvalue = PriorityEntry)。
// 若已存在(且未访问)则忽略。
func (d *DB) AddPriorityURL(entry PriorityEntry) error {
return d.db.Update(func(tx *bolt.Tx) error {
k := []byte(entry.URL)
existing := tx.Bucket(bucketPriority).Get(k)
if existing != nil {
var e PriorityEntry
if err := decompressUnmarshal(existing, &e); err == nil && !e.Visited {
return nil // 已存在且未访问,忽略
}
}
data, err := marshalCompress(entry)
if err != nil {
return err
}
return tx.Bucket(bucketPriority).Put(k, data)
})
}
// RemovePriorityURL 删除指定 URL 的 priority 条目。
func (d *DB) RemovePriorityURL(url string) error {
return d.db.Update(func(tx *bolt.Tx) error {
return tx.Bucket(bucketPriority).Delete([]byte(url))
})
}
// ClearVisitedPriorityURLs 批量删除所有已标记为 visited 的条目(crawler 爬完后调用)。
func (d *DB) ClearVisitedPriorityURLs() error {
return d.db.Update(func(tx *bolt.Tx) error {
return tx.Bucket(bucketPriority).ForEach(func(k, v []byte) error {
var e PriorityEntry
if err := decompressUnmarshal(v, &e); err != nil {
return nil
}
if e.Visited {
return tx.Bucket(bucketPriority).Delete(k)
}
return nil
})
})
}