如何使用redis实现自动填充?
比方说,我有一个数组["alfred","joel","jeff","addick"]
。当我输入a
时,我会收到["alfred", "addick"]
我希望你明白这一点。如何有效地使用redis命令实现这一点(如果可能,但我认为是)。如果我可以通过telnet尝试一些简单的命令来模仿这种行为,那就太好了。
由于
P.S:给你们所有人的快乐x-mas:)
答案 0 :(得分:19)
如果你正在处理一个大型数据集,我建议考虑将其作为一个trie来实现。我把一小部分Ruby扔在一起就可以做到这一点:
require 'rubygems'
require 'redis'
class RedisTrie
TERMINAL = '+'
def initialize(prefix)
@prefix = prefix
@r = Redis.new
end
def add_word(word)
w = word.gsub(/[^a-zA-Z0-9_-]/, '')
key = "#{@prefix}:"
w.each_char do |c|
@r.zset_add key, c.bytes.first, c
key += c
end
@r.zset_add key, 0, TERMINAL
end
def add_words(*words)
words.flatten.compact.each {|word| add_word word}
end
def suggest(text)
@r.zset_range("#{@prefix}:#{text}", 0, -1).map do |c|
(c == TERMINAL) ? text : suggest(text + c)
end.flatten
end
end
rt = RedisTrie.new('trie')
rt.add_words %w( apple automobile carwash oil-change cranky five ruthie axe auto )
p rt.suggest(ARGV.shift.to_s)
例如:
$ ruby RedisTrie.rb
["apple", "auto", "automobile", "axe", "carwash", "cranky", "five", "oil-change", "ruthie"]
$ ruby RedisTrie.rb a
["apple", "auto", "automobile", "axe"]
$ ruby RedisTrie.rb au
["auto", "automobile"]
$ ruby RedisTrie.rb aux
[]
在Wikipedia's entry on Tries了解有关尝试的更多信息。
您肯定希望优化您的建议方法以不返回所有值,而只返回它找到的前X值。它会破坏迭代整个数据结构的目的。
答案 1 :(得分:9)
答案 2 :(得分:6)
在阅读Simon Willison令人印象深刻的Redis tutorial时,我也发现了这个片段。
Hello Max,
KEYS不是最好的方式 你能做的就是用一个 排序集。你想要的是转向 前4或5个字符 字符串成一个整数(你可以 想象每个字符都是一个数字 例如,基数为256的数字,但是 有更好的代表性)和 将所有用户名添加到已排序的 集。
然后使用ZRANGEBYSCORE即可获得 给定之间的所有元素 范围。
这种方法的可扩展性更高 这是一个O(log(N))的事情。
我正在报道这些东西 慢慢发展的Redis书......
干杯,Salvatore
答案 3 :(得分:3)
这是PHP中用于使用redis按字母顺序自动完成的简单算法:
function getNextChar($char) {
$char++;
if(strlen($char) > 1) { $char--; }
return $char;
}
function createDictionary($redis, $key, $wordList) {
if(!$redis->exists($key)) {
foreach($wordList as $word) {
$redis->zadd($key, 0, $word);
}
}
}
function getLexicalAutocomplete($redis, $dictionaryKey, $input) {
$inputNext = substr($input, 0, -1) . getNextChar(substr($input, -1)); //ab -> ac
$redis->zadd($dictionaryKey, 0, $input);
$redis->zadd($dictionaryKey, 0, $inputNext);
$rangeStart = $redis->zrank($dictionaryKey, $input)+1;
$rangeEnd = $redis->zrank($dictionaryKey, $inputNext)-1;
$autocompleteResults = $redis->zrange($dictionaryKey, $rangeStart, $rangeEnd);
$redis->zrem($dictionaryKey, $input);
$redis->zrem($dictionaryKey, $inputNext);
return $autocompleteResults;
}
$redis = new Redis();
$redis->connect('', 0); //Your redis server ip/port goes here
createDictionary($redis, "dict", array("alfred", "joel", "jeff", "addick"));
$result = getLexicalAutocomplete($redis, "dict", $argv[1]);
echo json_encode($result);
基于Salvatore的文章Auto Complete with Redis,除了我需要生成一个额外的自动完成字典,代价是一点点的性能损失(几个zadds和zrems额外),但在大多数情况下它应该表现良好的情况。该脚本假定为phpredis,但实际上它与predis相同。
输出示例:
> php redisauto.php a
["addick","alfred"]
> php redisauto.php ad
["addick"]
> php redisauto.php al
["alfred"]
> php redisauto.php j
["jeff","joel"]
> php redisauto.php je
["jeff"]
答案 4 :(得分:2)
以下是Python中原始antirez的Ruby实现的端口:
http://www.varunpant.com/posts/auto-complete-with-redis-python
答案 5 :(得分:2)
我刚刚通过一篇很棒的文章,提供了您正在谈论的确切问题,以及更多内容。 Check it out
答案 6 :(得分:0)
可能不相关,但是如果你在这里登陆,你可能也会对使用建议自动填充UI字段的简单,正确,快速和可扩展的方式感兴趣: