案例分析参考Redis实战第6章第1篇。
/**
* 实现自动补全
*/
public class Auto_Complete {
//unicode编码
private String coding(String s) {
char[] chars = s.toCharArray();
StringBuffer buffer = new StringBuffer();
for (char aChar : chars) {
String s1 = Integer.toString(aChar, 16);
buffer.append("-" + s1);
}
String encoding = buffer.toString();
return encoding;
}
//unicode解码
private String decoding(String s ) {
String[] split = s.split("-");
StringBuffer buffer = new StringBuffer();
for (String s1 : split) {
if(!s1.trim().equals("")) {
char i = (char)Integer.parseInt(s1, 16);
buffer.append(i);
}
}
return buffer.toString();
}
//添加数据
public long add(Jedis con, String member, String key) {
//进行编码
String coding = coding(member);
Long zadd = con.zadd(key, 0, coding);
return zadd;
}
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 = prefix.substring(0, prefix.length() - 1) + suffix + 'g'; //生成前缀字符串的前驱字符串
String end = prefix + 'g'; //生成前缀字符串的后继字符串
return new String[]{start, end};
}
//查找数据
public List<String> find(Jedis con,String member,String key) {
List<String> list = new ArrayList<>();
member = coding(member);//把输入的字符转换成16进制字符串,因为redis里面存的是每个字符对应的16进制字符串
String[] range = findPrefixRange(member);
String start = range[0];
String end = range[1];
String identifier = UUID.randomUUID().toString();
start += identifier;
end += identifier; // 防止多个群成员可以同时操作有序集合,将相同的前驱字符串和后继字符串插入有序集合
con.zadd(key, 0, start);
con.zadd(key, 0, end);
System.out.println();
while (true) {
con.watch(key);
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<Object> results = transaction.exec();
if (results != null) {
Set<String> set = (Set<String>) results.get(results.size() - 1);
list.addAll(set);
break;
}
}
ListIterator<String> 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;
}
}