首页

    博客标题搜索-按分数排序

    标签:algorithm,go,blog

    搜索的时候想把点击多的搜索结果优先显示,这就需要记录点击搜索结果这个行为。可以给搜索结果绑定分数,点击搜索结果,分数加1.搜索时,结果总是按分数由高到低显示

    redis sorted set

    increase score

    由于标题的所有前缀都存在sorted set,增加分数只需对每个前缀执行ZINCRBY操作即可

    prefixList := Convert(title)
    for _, key := range prefixList {
        redisClient.PipeAppend("ZINCRBY", key, title)
    }
    

    search order by score

    由于ZREVRANGE返回的结果是按分数由高到低排列的,搜索时直接使用就行了

    Returns the specified range of elements in the sorted set stored at key. The elements are considered to be ordered from the highest to the lowest score

    resp := redisClient.Cmd("ZREVRANGE", vars["query"], 0, -1)
    l, _ := resp.List()
    for _, item := range l {
        redisClient.PipeAppend("HGET", "title_path", item)
    }
    for i := 0; i < len(l); i++ {
        path, _ := redisClient.PipeResp().Str()
        result = append(result, SearchResult{Title: l[i], Path: path})
    }
    

    trie方式

    increase score

    • trie的end节点增加一个字段score
    func Generate(root string, bytes []byte) string {
        redisClient := GetRedisClient()
        defer RedisPool.Put(redisClient)
    
        var cur string
        size := len(bytes)
        var err error
        if len(root) == 0 {
            uid := uuid.Must(uuid.NewV4(), err).String()
    
            redisClient.Cmd("HSET", uid, "end", 0)
            root, cur = uid, uid
        } else {
            cur = root
        }
    
        for i := 0; i < size; i++ {
            next, _ := redisClient.Cmd("HGET", cur, bytes[i]).Str()
            if next != "" {
                cur = next
            } else {
                uid := uuid.Must(uuid.NewV4(), err).String()
                redisClient.Cmd("HSET", cur, bytes[i], uid)
                cur = uid
            }
        }
        redisClient.Cmd("HSET", cur, "end", 1, "score", 1)
        return root
    }
    
    • 增加分数只需找到end节点,HINCRBY操作即可
    root, _ := redisClient.Cmd("GET", "root").Str()
    lastNode := redis_impl.Find(root, <-pinyinCh)
    redisClient.Cmd("HINCRBY", lastNode, "score", 1)
    

    search order by score

    将搜索结果取出,再根据end节点的score排序

    root, _ := redisClient.Cmd("GET", "root").Str()
    trieResult := redis_impl.FindBySuffix(vars["query"], root)
    sort.Sort(redis_impl.ByScore(trieResult))
    
    for _, item := range trieResult {
        path, _ := redisClient.Cmd("HGET", "title_path", title).Str()
    }
    

    TranversalFindBySuffix方法也要改一下

    func Tranversal(root string) []TrieResult {
        result := []TrieResult{}
        var dfs func(head string, str string)
        dfs = func(head string, str string) {
            resp, i := redisClient.Cmd("HGETALL", head), 0
            elems, _ := resp.Array()
            for i < len(elems) {
                key, _ := elems[i].Str()
                val, _ := elems[i+1].Str()
                if key == "end" {
                    if val == "1" {
                        score, _ := elems[i+3].Int()
                        result = append(result, TrieResult{Word: str, Score: score})
                        i += 2
                    }
                } else {
                    ch, _ := elems[i].Int()
                    dfs(val, str+string(ch))
                }
                i += 2
            }
        }
        dfs(root, "")
        return result
    }
    
    func FindBySuffix(suffix string, root string) []TrieResult {
        result := []TrieResult{}
        size, cur := len(suffix), root
    
        for i := 0; i < size; i++ {
            next, _ := redisClient.Cmd("HGET", cur, suffix[i]).Str()
            if next != "" {
                cur = next
            } else {
                return []TrieResult{}
            }
        }
        for _, v := range Tranversal(cur) {
            result = append(result, TrieResult{Word: suffix + v.Word, Score: v.Score})
        }
        return result
    }
    

    不定期更新