Search code examples
autocompleteredis

Redis autocomplete


How can I implement an autocomplete using redis?

Say for example I have an array ["alfred","joel","jeff","addick"]. When I type a I get ["alfred", "addick"]

I hope you get the point. How can I implement this using redis commands efficiently(if possible but I think it is). It would be great if I could get some simple commands I can try out via telnet to mimic this behaviour.

Thanks

P.S: Merry x-mas to all of you :)


Solution

  • If you're dealing with a large data set, I would suggest considering implementing this as a trie. I have thrown together a small bit of Ruby that would do this:

        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)
    

    For example:

        $ 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
        []
    

    Read more on Tries at Wikipedia's entry on Tries.

    You will definitely want to optimize your suggest method to not return ALL values, instead only returning the first X values it finds. It would defeat the purpose to iterate the entire data structure.