zoukankan      html  css  js  c++  java
  • Redis实战之通讯录自动补全(php)

    Redis 实战之通讯录补全

    前言

    自动补全的例子在很多场景中都能看到,如浏览器输入框的常用网址补全,或是百度搜索框的自动补全

    实现功能

    第一阶段:需要保留最新的100个联系人,并且能够根据前缀自动弹出关联联系人名称 ,如:to 要出现 tom,toms

    第二阶段:使用有序集合来存储联系人,且不限制100人,但是只允许向同一个群组的人员发送

    // 公共代码部分,以便后面不在重复写
    $redis = new Redis();
    $redis->connect('127.0.0.1','6379','3');
    $redis->select(9);
    

    前提条件

    联系人名称都是要26个字母组成无任何特殊符号.

    第一阶段功能实现

    思路:最新的100个在考虑到负载的情况下,使用list列表来存储,消耗最少的存储空间,自动补全的部分由后端语言来实现,如PHP(别的也不会)

    // 添加/更新联系人
    function add_update_contact($conn, $user, $contact) {
        $ac_list = "recent:" . $user;
        $pipe = $conn->multi(Redis::PIPLINE);
        $pipe->lRem($ac_list, $contact, 0);		// 移除所有相同的联系人
        $pipe->lpush($ac_list, $contact);
        $pipe->ltrim($ac_list, 0, 99);			// 删除所有100个之后的联系人
        $pipe->exec();
        echo "联系人添加成功";
        return true;
    }
    
    // 移除联系人
    function remove_contact($conn, $user, $contact) {
        $ac_list = "recent:" . $user;
        return $conn->lRem($ac_list, $contact, 0);
    }
    
    // $prefix 搜索前缀 
    function fetch_autoComplete_list($conn, $user, $prefix) {
        $ac_list = "recent:" . $user;
        $candidates = $conn->lRange($ac_list, 0, -1);
        $matches = [];
        foreach ($candidates as $candidate) {
            if (strpos(strtolower($candidate), strtolower($prefix)) === 0) {
             	$matches[] = strtolower($candidate);   
            }
        }
        return $matches;
    }
    
    // 测试代码
    add_update_contact($redis, 'mowang', 'john');
    add_update_contact($redis, 'mowang', 'jojo');
    add_update_contact($redis, 'mowang', 'join');
    add_update_contact($redis, 'mowang', 'johns');
    var_dump(fetch_autoComplete_list($redis, 'mowang', 'jo'));
    

    第二阶段功能实现

    // 加入群组
    function join_guild($conn, $guild, $user) {
        $members_list = "members:" . $guild;
        $conn->zAdd($members_list, 0, $user);
        echo "加入群组成功";
        return true;
    }
    
    // 离开群组
    function leave_guild($conn, $guild, $user) {
        $members_list = "members:" . $guild;
        $conn->zRem($members_list, $user);
        echo "离开群组成功";
        return true;
    }
    
    function find_prefix_range($prefix) {
        $valid_chars = "`abcdefghijklmnopqrstuvwxyz{";
        // $prefix = 'dqc'  // 输出dq
        $position = strpos($valid_chars, substr($prefix, 0, -1));
        $suffix = $valid_chars[$position > 0 ? $position - 1 : 0];
        return [
            substr($prefix, 0, -1) . $suffix . "{",
            $prefix . "{"
        ];
    }
    
    function autocomplete_on_prefix($conn, $guild, $user) {
        list($start, $end) = find_prefix_range($prefix);
        $identifier = Uuid::uuid4()->toString();
        $start .= $identifier;
        $end .= $identifier;
        $zset_name = 'members:'. $guild;
        $conn->zAdd($zset_name, 0, $start);
        $conn->zAdd($zset_name, 0, $end);
        // zrange 是闭合区间,即0,0也是有值的
        while (1) {
            try {
                $conn->watch($zset_name);
                $sindex = $conn->zRank($zset_name, $start);
                $eindex = $conn->zRank($zset_name, $end);
                $erange = min($sindex + 9, $eindex - 2);		// 最多取10条
                $trans = $conn->multi(Redis::PIPELINE);
                $trans->zrem($zset_name, $start);
                $trans->zrem($zset_name, $end);
                $trans->zRange($zset_name, $sindex, $erange);
                $baidu = $trans->exec();
                $items = end($baidu);
                break;
            } catch (Exception $e) {
                continue;
            }
        }
        // 过滤掉带有`{`符号的数据
        return array_filter(
            $items,
            function ($item) {
                return strpos($item, '{') === false;
            }
        )
    }
    
    

    结语

    后续会补充支持中文等不同方式的自动补全,此博文只作为个人记录用

    想生活,不想谋生
  • 相关阅读:
    React生命周期, 兄弟组件之间通信
    React组件式编程Demo-用户的增删改查
    React之this.refs, 实现数据双向绑定
    CCF CSP 201812-4 数据中心
    CCF CSP 201812-4 数据中心
    PAT 顶级 1020 Delete At Most Two Characters (35 分)
    PAT 顶级 1020 Delete At Most Two Characters (35 分)
    Codeforces 1245C Constanze's Machine
    Codeforces 1245C Constanze's Machine
    CCF CSP 201712-4 行车路线
  • 原文地址:https://www.cnblogs.com/Daneil/p/15322436.html
Copyright © 2011-2022 走看看