package main import ( "cmp" "maps" "regexp" "slices" "time" ) type searchCache map[string]searchCacheEntry type searchResult struct { NameIndices [][]int `json:"name_matches"` DescIndices [][]int `json:"desc_matches,omitempty"` Score float64 `json:"score"` *metadata } type searchCacheEntry struct { query string results []searchResult expiry time.Time } func (index *packageIndex) performSearchQuery(limit int, i int, search string, desc bool) (int, []searchResult, error) { entry, ok := index.search[search] if ok { return len(entry.results), entry.results[i:min(i+limit, len(entry.results))], nil } regex, err := regexp.Compile(search) if err != nil { return 0, make([]searchResult, 0), err } res := make([]searchResult, 0) for p := range maps.Values(index.names) { nameIndices := regex.FindAllIndex([]byte(p.Name), -1) var descIndices [][]int = nil if desc { descIndices = regex.FindAllIndex([]byte(p.Description), -1) } if nameIndices == nil && descIndices == nil { continue } score := float64(indexsum(nameIndices)) / (float64(len(nameIndices)) + 1) if desc { score += float64(indexsum(descIndices)) / (float64(len(descIndices)) + 1) / 10.0 } res = append(res, searchResult{ NameIndices: nameIndices, DescIndices: descIndices, Score: score, metadata: p, }) } slices.SortFunc(res[:], func(a, b searchResult) int { return -cmp.Compare(a.Score, b.Score) }) expiry := time.Now().Add(1 * time.Minute) entry = searchCacheEntry{ query: search, results: res, expiry: expiry, } index.search[search] = entry return len(res), res[i:min(i+limit, len(entry.results))], nil } func (s *searchCache) clean() { maps.DeleteFunc(*s, func(_ string, v searchCacheEntry) bool { return v.expiry.Before(time.Now()) }) } func indexsum(in [][]int) int { sum := 0 for i := 0; i < len(in); i++ { sum += in[i][1] - in[i][0] } return sum }