自动补全往往给出部分提示供用户选择,这就涉及排序。有几下几种方法:
一、需要添加元素且数据量少
?1、方案:数据量非常小时,程序从redis中获取数据后,在程序中排序。
(1)写数据:如实现记忆补全,当用户选择性补全后,可以将该元素从列表中LREM删除再LPUSH推进最左端,下次再取出来就靠前了。
(2)排序:使用Redis存储列表,Redis仅做存储功能,自动补全在代码中完成,代码获取整个列表再来进行匹配。
二、需要添加元素且数据量大
1、方案:对于非常长的列表,仅仅为了找到几个元素而获取整个列表,比较浪费资源。可以使用有序集合。直接在redis中排序,并返回自动补全的数据。添加/移除元素使用ZADD、ZREM,难点在于排序。
2、排序:根据有序集合的特点,
假定所有名字都是英文字母,将所有分值都设置为0,通过将给定前缀的 “最后一个字符” “替换”为第一个排在该字符前面的字符,可以得到前缀的前驱;通过给前缀的末尾“拼接”上做花括号,可以得到前缀的后继。 为了防止多个前缀同时进行时出现任何问题,程序还给钱最拼接一个左花括号,以便在需要的时候,根据这个左花括号来过滤掉被插入有序集合里面的起始元素和结束元素。
(1)已前缀字符序列abc为例,查找abc前缀的单词实际上是查找介于 abbz……和 abd…… 之间的字符串。如果知道第一个排在abbz之前元素的排名,以及第一个排在abd之后的元素的排名,那么就可以用一个zrange调用来取得所有abc前缀的列表
(2)为了知道这两个元素的定位,需要向有序集合中插入两个元素,一个排在abbz的后面(这个元素是ab`),另一个排在abd的前面(这个元素是ab{)。这是因为在ASCII编码里面,排在z后面的第一个字符就是做花括号{??? 所以,只要把 {?? 拼接到abc前缀的末尾,就可以了;而ASCII中,排在a前面的就是反引号? ` 。
若使用的不是ASCII编码,而使用的是UTF-8、UTF-16、UTF-32等,则需要如下步骤
(1)想办法把所有字符都转换为字节,如UTF-8、UTF-16(大端)、UTF-32(大端)
(2)找出自己想要支持的字符范围,并确保字符编码在所选范围的前面和后面都至少留有一个字符
(3)用支持的字符范围中最前面的字符替换`???? 最后面的字符替换? {
3、注意点:
(1)为了避免滋扰用户,每次只自动补全 几个元素
(2)为了避免将多个相同的起始元素或结束元素重复地添加到有序集合,或者错误地从有序集合中移除了有其他自动补全程序添加的起始元素或结束元素,建议程序生成UUID,添加到起始元素和结束元素的后面,并使用加锁机制,进行插入。
三、不需要添加元素,来获取自动补全范围。(使用redis进行搜索)