Skip to content

Instantly share code, notes, and snippets.

@ql
Created May 27, 2010 07:40
Show Gist options
  • Save ql/415580 to your computer and use it in GitHub Desktop.
Save ql/415580 to your computer and use it in GitHub Desktop.
class Object
def _metaclass
class << self
self
end
end
end
module ThinkingSphinx
class Search
# Overwrite the configured content attributes with excerpted and highlighted versions of themselves.
# Runs run if it hasn't already been done.
def instances_from_matches #hacked from thinking_sphinx/search.rb
options = {
:before_match => '<strong class="highlight">',
:after_match => '</strong>',
:chunk_separator => "...",
:limit => 256,
:around => 5
}
res = if one_class
single_class_results
else
groups = results[:matches].group_by { |match|
match[:attributes]["class_crc"]
}
groups.each do |crc, group|
group.replace(
instances_from_class(class_from_crc(crc), group)
)
end
results[:matches].collect do |match|
groups.detect { |crc, group|
crc == match[:attributes]["class_crc"]
}[1].compact.detect { |obj|
obj.primary_key_for_sphinx == match[:attributes]["sphinx_internal_id"]
}
end
end
content_methods = %w{title game_title post_title name description description_html body body_html address aka developer publisher publisher_russian} # the attributes of any model you would like to have excerpted
content_h_methods = %w{title game_title post_title name aka address developer publisher publisher_russian} # methods that are escaped (h()) before having them excerpted
# See what fields in each result might respond to our excerptable methods
results_with_content_methods = res.map do |result|
[result,
content_methods.map do |methods|
methods.detect do |this|
result.respond_to? this
end
end
]
end
# Fetch the actual field contents
docs = results_with_content_methods.map do |result, methods|
methods.map do |method|
if content_h_methods.include?(method)
method and strip_bogus_characters(ERB::Util.html_escape(result.send(method))) or ""
else
method and strip_bogus_characters(result.send(method)) or ""
end
end
end.flatten
excerpting_options = {
:docs => docs,
# WARNING: extremely stupid, you need to have User indexed for anything to work
:index => "user_core", #MAIN_INDEX, # http://www.sphinxsearch.com/forum/view.html?id=100
:words => strip_query_commands(query.to_s)
}.merge(options)
responses = client.excerpts(excerpting_options)
responses = responses.in_groups_of(content_methods.size)
results_with_content_methods.each_with_index do |result_and_methods, i|
# Override the individual model accessors with the excerpted data
result, methods = result_and_methods
methods.each_with_index do |method, j|
data = responses[i][j]
if method
result._metaclass.send('define_method', method) { data }
attributes = result.instance_variable_get('@attributes')
attributes[method] = data if attributes[method]
end
end
end
res = results_with_content_methods.map do |result_and_content_method|
result_and_content_method.first.freeze
end
res
end
def search_with_excerpts(*args)
query = args.clone # an array
options = query.extract_options!
retry_search_on_stale_index(query, options) do
results, client = search_results(*(query + [options]))
::ActiveRecord::Base.logger.error(
"Sphinx Error: #{results[:error]}"
) if results[:error]
klass = options[:class]
page = options[:page] ? options[:page].to_i : 1
total = results[:total]
results = ThinkingSphinx::Collection.create_from_results(results, page, client.limit, options)
if options[:excerpts] and !results.empty?
exp = excerpts(results, client, query)
end
results
end
end
alias_method_chain :search, :excerpts
def search_with_hypen_escape(*args)
if args.size > 0 && args[0].is_a?(String)
args[0] = args[0].gsub(/([^\s])\-/, '\1\-')
end
search_without_hypen_escape(*args)
end
alias_method_chain :search, :hypen_escape
def strip_bogus_characters(s)
# Used to remove some garbage before highlighting
s.gsub(/<.*?>|\.\.\.|\342\200\246|\n|\r/, " ") if s
# s.gsub(/<.*?>|\.\.\.|\342\200\246|\n|\r/, " ").gsub(/http.*?( |$)/, ' ') if s
end
def strip_query_commands(s)
# XXX Hack for query commands, since Sphinx doesn't intelligently parse the query in excerpt mode
# Also removes apostrophes in the middle of words so that they don't get split in two.
s.gsub(/(^|\s)(AND|OR|NOT|\@\w+)(\s|$)/i, "").gsub(/(\w)\'(\w)/, '\1\2')
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment