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;
            }
        )
    }
    
    

    结语

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

    想生活,不想谋生
  • 相关阅读:
    matab plot指令和低通滤波器的响应图
    matlab中hold指令、figure指令及subplot指令的使用
    matlab中axis的使用
    matlab switch case 和 try catch用法示例
    matlab中使用elseif和if嵌套的对比
    matlab中运用项目思维分析问题并解决问题
    matlab图像显示程序模板
    matlab最简单程序模板
    第06篇 MyEclipse 2016 安装/破解
    第05篇. Tomcat和JDK的内存配置
  • 原文地址:https://www.cnblogs.com/Daneil/p/15322436.html
Copyright © 2011-2022 走看看