When a user asks for all the words starting with “foobar” let’s check the cache for fooba,foob,foo,fo,f and see if any of these results already include a full set of words.
This saved us ~30% of our db queries and makes the ui more responsive.
# given a start word of foobar check caches for ["fooba", "foob", "foo", "fo", "f"]
# to see if any of the simpler queries already had a complete response
def cached_autocomplete(start)
limit = 1000
short = start.dup
shorter = Array.new(start.size - 1){ short.chop!.dup }
cached = Rails.cache.read_multi(*shorter.map { |s| "autocomplete-#{s}" })
cached.each_value do |tags|
if tags.size < limit # complete response / nothing is missing
tags.select! { |t| t.start_with?(start) } # filter non-matches
return tags
end
end
Rails.cache.fetch("autocomplete-#{start}", expires_in: 15.minutes, race_condition_ttl: 1.minute) do
... hit the db ... limit(limit) ...
... prevent multiple cache refreshes with race_condition_ttl ...
end
end