Skip to content

Instantly share code, notes, and snippets.

@waynerobinson
Created September 25, 2012 03:26
Show Gist options
  • Save waynerobinson/3779810 to your computer and use it in GitHub Desktop.
Save waynerobinson/3779810 to your computer and use it in GitHub Desktop.
Cached Autocompleter
class Autocompleter
def self.parse_street_input(input)
matches = /
(
(?:[Uu](?:nit)?\s*)? #U or Unit, any casing, maybe with following spaces, non-captured
[\d\/\s\\\-,]+ #Unit number (Digits, spaces, dashes, both slashes)
\d?) #Street Number
?\s? #Spacing and Optionality for Numbering
([\w\-\s']+) #Street Name - Match any combination of words and spaces (And apostrophe)
/x.match(input)
numbermatch = /
(?:
(?:[Uu]nit\s*)? #Unit word
(\d+?) #Unit number
\s*[\/\-\\,\s]\s* #Unit separator - Any number of spaces surrounding
)?
(\d+) #Street number
/x.match(matches[1]) || []
{:number => numbermatch[2], :unit => numbermatch[1], :street => matches[2]}
end
def self.get_auto_complete_suggestions(fleet, street)
MTDataStone.addresses.get_autocomplete_suggestions(fleet, street)
end
def self.autocomplete(autocompletion_term)
autocomplete_terms = prepare_autocomplete_term(autocompletion_term)
result_set = []
if proceed_with_search?(autocomplete_terms)
autocompletion_data = get_autocomplete_suggestions(7, autocomplete_terms[:street])
puts "ACD: #{autocompletion_data}"
result_set = build_autocompletion_result_set(autocomplete_terms, autocompletion_data)
end
end
def self.prepare_autocomplete_term(autocompletion_term)
term_hash = Autocompleter.parse_street_input(autocompletion_term)
term_hash = self.filter_symbols(term_hash)
end
def self.build_autocompletion_result_set(autocomplete_term, autocompletion_data)
autocomplete_set = []
# Putting records into the DB to save passing all the data to the front end.
autocompletion_data.each do |ac|
query_terms = {:street_name => ac.street_name, :suburb_name => ac.suburb_name, :designation_name => ac.designation_name,
:unit_number => autocomplete_term[:unit], :street_number => autocomplete_term[:number],
:street_id => ac.street_id, :designation_id => ac.designation_id, :suburb_id => ac.suburb_id}
stripped_query_terms = query_terms.delete_if {|k,v| v.nil?}
autocomplete_item = MtDataAddress.find_or_create_full_record(stripped_query_terms)
autocomplete_item.save if autocomplete_item.new_record?
autocomplete_set << autocomplete_item
end
return autocomplete_set
end
# Returns true if it is worthwhile checking for street completion, otherwise returns false
def self.proceed_with_search?(terms)
terms[:street].length > 2
end
def self.filter_symbols(unfiltered_terms)
filtered_results = unfiltered_terms.clone
filtered_results[:street] = unfiltered_terms[:street].delete("'").capitalize
filtered_results
end
end
class CachedAutocompleter < Autocompleter
EXPIRY_PERIOD = 60.days
def self.get_auto_complete_suggestions(fleet, street)
cached_or_cache("#{fleet}:#{street}") do
super(fleet, street)
end
end
def self.cached_or_cache(key, &block)
cached = fetch_cached(key)
unless cached
cached = yield
set_cached(key, cached)
end
cached
end
def self.fetch_cached(key)
cached_result = AutocompleterCache.where(:query => key).first
if cached_result && (cached_result.updated_at + EXPIRY_PERIOD) > Time.current
YAML.load(cached_result.data)
elsif cached_result
cached_result.delete
end
end
def self.set_cached(key, value)
cached_result = AutocompleterCache.where(:query => key).first
cached_result ||= AutocompleterCache.new(:query => key)
cached_result.data = value.to_yaml
cached_result.save! # will only execute if data is different
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment