feat: harden search ranking and deduplication

This commit is contained in:
zhaoyilun
2026-07-10 09:39:18 +08:00
parent 1d6dd2f504
commit 6ca6c08b62
13 changed files with 368 additions and 56 deletions

View File

@@ -38,24 +38,32 @@ func SearchGroupsFromMessages(messages []Message, query SearchGroupsQuery) Searc
}
}
queryText := strings.ToLower(strings.TrimSpace(query.Query))
ids := make([]string, 0, len(unique))
for id := range unique {
if queryText == "" || strings.Contains(strings.ToLower(id), queryText) || strings.Contains(strings.ToLower(unique[id].DisplayName), queryText) {
ids = append(ids, id)
queryText := normalizedSearchText(query.Query)
groups := make([]Group, 0, len(unique))
for _, group := range unique {
if groupMatchesQuery(group, queryText) {
groups = append(groups, group)
}
}
sort.Strings(ids)
sort.Slice(groups, func(i, j int) bool {
leftRank := groupSearchRank(groups[i], queryText)
rightRank := groupSearchRank(groups[j], queryText)
if leftRank != rightRank {
return leftRank < rightRank
}
leftID := strings.ToLower(groups[i].GroupID)
rightID := strings.ToLower(groups[j].GroupID)
if leftID != rightID {
return leftID < rightID
}
return groups[i].GroupID < groups[j].GroupID
})
limit := query.Limit
if limit <= 0 || limit > len(ids) {
limit = len(ids)
if limit <= 0 || limit > len(groups) {
limit = len(groups)
}
groups := make([]Group, 0, limit)
for _, id := range ids[:limit] {
groups = append(groups, unique[id])
}
return SearchGroupsResult{Groups: groups}
return SearchGroupsResult{Groups: groups[:limit]}
}
func addMessageGroup(unique map[string]Group, id string) {
@@ -63,10 +71,11 @@ func addMessageGroup(unique map[string]Group, id string) {
if trimmed == "" || !isLikelyGroupJID(trimmed) {
return
}
if _, exists := unique[trimmed]; exists {
key := strings.ToLower(trimmed)
if _, exists := unique[key]; exists {
return
}
unique[trimmed] = Group{
unique[key] = Group{
GroupID: trimmed,
DisplayName: trimmed,
Source: "local_readonly",
@@ -79,3 +88,32 @@ func isLikelyGroupJID(id string) bool {
lower := strings.ToLower(strings.TrimSpace(id))
return strings.Contains(lower, "conference") || strings.Contains(lower, "muc") || strings.Contains(lower, "group")
}
func groupMatchesQuery(group Group, queryText string) bool {
if queryText == "" {
return true
}
return strings.Contains(strings.ToLower(group.GroupID), queryText) ||
strings.Contains(strings.ToLower(group.DisplayName), queryText)
}
func groupSearchRank(group Group, queryText string) int {
if queryText == "" {
return 0
}
values := []string{
strings.ToLower(group.GroupID),
strings.ToLower(group.DisplayName),
}
for _, value := range values {
if value == queryText {
return 0
}
}
for _, value := range values {
if strings.HasPrefix(value, queryText) {
return 1
}
}
return 2
}