68 lines
1.4 KiB
Go
68 lines
1.4 KiB
Go
|
|
package knowledge
|
||
|
|
|
||
|
|
import (
|
||
|
|
"strings"
|
||
|
|
"unicode/utf8"
|
||
|
|
)
|
||
|
|
|
||
|
|
const maxDerivedTagRunes = 8
|
||
|
|
|
||
|
|
func DeriveSearchTagsFromGraph(graph *Graph) {
|
||
|
|
if graph == nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
for i := range graph.Nodes {
|
||
|
|
graph.Nodes[i].DerivedTags = deriveNodeTags(graph.Nodes[i])
|
||
|
|
}
|
||
|
|
graph.PainTagCount = CountPainTagCandidates(graph.Nodes)
|
||
|
|
}
|
||
|
|
|
||
|
|
func deriveNodeTags(node Node) DerivedTags {
|
||
|
|
label := strings.TrimSpace(node.Label)
|
||
|
|
if label == "" {
|
||
|
|
return DerivedTags{}
|
||
|
|
}
|
||
|
|
relevance := []string{clampTag(label)}
|
||
|
|
recency := []string{}
|
||
|
|
if IsPainNode(node) {
|
||
|
|
if q := BuildRecencyQuery(label); q != "" {
|
||
|
|
recency = append(recency, clampTag(q))
|
||
|
|
}
|
||
|
|
if node.Layer >= 1 {
|
||
|
|
recency = append(recency, clampTag(label+" 推薦"))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
relevance = uniqueTags(relevance)
|
||
|
|
recency = uniqueTags(recency)
|
||
|
|
return DerivedTags{Relevance: relevance, Recency: recency}
|
||
|
|
}
|
||
|
|
|
||
|
|
func clampTag(text string) string {
|
||
|
|
text = strings.TrimSpace(text)
|
||
|
|
if text == "" {
|
||
|
|
return ""
|
||
|
|
}
|
||
|
|
if utf8.RuneCountInString(text) <= maxDerivedTagRunes {
|
||
|
|
return text
|
||
|
|
}
|
||
|
|
runes := []rune(text)
|
||
|
|
return string(runes[:maxDerivedTagRunes])
|
||
|
|
}
|
||
|
|
|
||
|
|
func uniqueTags(items []string) []string {
|
||
|
|
seen := map[string]struct{}{}
|
||
|
|
out := make([]string, 0, len(items))
|
||
|
|
for _, item := range items {
|
||
|
|
item = strings.TrimSpace(item)
|
||
|
|
if item == "" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if _, ok := seen[item]; ok {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
seen[item] = struct{}{}
|
||
|
|
out = append(out, item)
|
||
|
|
}
|
||
|
|
return out
|
||
|
|
}
|