您的当前位置:首页正文

redis-缓存设计-搜索前缀匹配

2024-07-24 来源:好走旅游网
redis-缓存设计-搜索前缀匹配

说明

录⼊:

是将录⼊字符的String 的各个char 的ASCII码转为16进制 在通过-拼接起来,通过zadd新增 score设置为0 则会通过value 16进制进⾏排序查找

将查找的字符转换为16进制通过-拼接

start计算:通过匹配字符16进制最后以为进1算出起始16进制 再+g 包括所有起始范围end计算:通过匹配字符16进制+g 包括所有范围

然后zadd临时加⼊到redis 默认通过value排序则将匹配字符⼤概包裹起来

然后通过2个临时数据获得rank 再根据起始和结zrank获得数据 过滤掉多余的 再讲16进制转换为字符 返回

录⼊数据

//unicode编码

private String coding(String s) { char[] chars = s.toCharArray();

StringBuffer buffer = new StringBuffer(); for (char aChar : chars) {

//通过字符对应的ASCII码转换为16进制再根据-拼接起来 -4f60-7231-5e7f-5dde-30 String s1 = Integer.toString(aChar, 16); buffer.append(\"-\" + s1); }

String encoding = buffer.toString(); return encoding; }

//添加数据

public long add(Jedis con, String member, String key) { //进⾏编码 存储的是 每个字符进⾏ASCII码转换的16进制 String coding = coding(member);

//如果score为0 则会根据value来进⾏排序 Long zadd = con.zadd(key, 0, coding); return zadd; }

匹配数据

/**

* unicode解码 字符通过16进制转换为ASCII码 即可得到对应字符 *

* @param s * @return */

private String decoding(String s) { String[] split = s.split(\"-\");

StringBuffer buffer = new StringBuffer();

for (String s1 : split) {

if (!s1.trim().equals(\"\")) {

//将16进制 转换成ASCII码 ASCII码对应的字符 char i = (char) Integer.parseInt(s1, 16); buffer.append(i); } }

return buffer.toString(); }

/**

* 16进制

* ⼆进制与16进制对应 0-0 1-1 2-2 3-3 4-4 5-5- 6-6 7-7 8-8 9-9 10-a 11-b 12-c 13-d 14-e 15-f 16-g */

private static final String VALID_CHARACTERS = \"0123456789abcdefg\";

private String[] findPrefixRange(String prefix) {

int posn = VALID_CHARACTERS.indexOf(prefix.charAt(prefix.length() - 1)); //查找出前缀字符串最后⼀个字符在列表中的位置 char suffix = VALID_CHARACTERS.charAt(posn > 0 ? posn - 1 : 0); //找出前驱字符 String start = null; String end = null;

//针对于单纯查0的 没有前置了 所以不⽤拼g if (posn == 0) { start = prefix;

end = prefix + \"g\";//end拼g 把范围内的全查出来

} else {

start = prefix.substring(0, prefix.length() - 1) + suffix + 'g'; //⽣成前缀字符串的前驱字符串 end = prefix + 'g';

// 防⽌多个群成员可以同时操作有序集合,将相同的前驱字符串和后继字符串插⼊有序集合//⽣成前缀字符串的后继字符串 String identifier = UUID.randomUUID().toString(); start += identifier; end += identifier; }

return new String[]{start, end}; }

//查找数据

public List find(Jedis con, String member, String key) { List list = new ArrayList<>();

member = coding(member);//把输⼊的字符转换成16进制字符串,因为redis⾥⾯存的是每个字符对应的16进制字符串 String[] range = findPrefixRange(member); String start = range[0]; String end = range[1];

//往zset插⼊起始和结束的字符,将匹配的结果的数据包起来 con.zadd(key, 0, start); con.zadd(key, 0, end); while (true) {

con.watch(key);

//根据插⼊包起来的数据rank拿出启始和结束的字符 int sindex = con.zrank(key, start).intValue();

int eindex = con.zrank(key, end).intValue(); //找出两个插⼊元素的位置

int erange = Math.min(sindex + 9, eindex - 2); //因为最多展⽰10个,所以计算出结束为⽌ Transaction transaction = con.multi(); transaction.zrem(key, start); transaction.zrem(key, end);

transaction.zrange(key, sindex, erange); List results = transaction.exec(); if (results != null) {

Set set = (Set) results.get(results.size() - 1); list.addAll(set); break; } }

ListIterator iterator = list.listIterator();

// 这⾥过滤多个成员添加前驱字符串和后继字符串引起的不符合的数据 while (iterator.hasNext()) {

String string = iterator.next(); if (string.indexOf(\"g\") != -1) { iterator.remove(); } else {

iterator.set(decoding(string));//把16进制字符串转换回来 } }

return list; }

测试

public static void main(String[] args) throws Exception {

Jedis conn = new Jedis(\"127.0.0.1\ conn.flushDB();

AutoComplete auto_complete = new AutoComplete(); for (int i = 0; i < 1; i++) {

auto_complete.add(conn, \"你爱⼴州\" + i, \"test1\"); }

auto_complete.add(conn, \"我爱⼴州\ auto_complete.add(conn, \"我爱成都\ auto_complete.add(conn, \"你好啊\ auto_complete.add(conn, \"aaabbb\ auto_complete.add(conn, \"ac\ auto_complete.add(conn, \"01\ auto_complete.add(conn, \"02\ auto_complete.add(conn, \"11\

List numbers = auto_complete.find(conn, \"我爱成\ System.out.println(JSON.toJSONString(numbers)); }打印

[\"我爱成都\"]

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 版权所有