0
@@ -5,7 +5,7 @@ module ThinkingSphinx
0
# Most times, you will just want a specific model's results - to search and
0
# search_for_ids methods will do the job in exactly the same manner when
0
# Searches for results that match the parameters provided. Will only
0
@@ -14,10 +14,10 @@ module ThinkingSphinx
0
def search_for_ids(*args)
0
results, client = search_results(*args.clone)
0
options = args.extract_options!
0
page = options[:page] ? options[:page].to_i : 1
0
pager = WillPaginate::Collection.new(page,
0
client.limit, results[:total] || 0)
0
@@ -35,11 +35,11 @@ module ThinkingSphinx
0
# just like paginate. The same parameters - :page and :per_page - work as
0
# expected, and the returned result set can be used by the will_paginate
0
# The simplest way of searching is straight text.
0
# ThinkingSphinx::Search.search "pat"
0
# ThinkingSphinx::Search.search "google"
0
# User.search "pat", :page => (params[:page] || 1)
0
@@ -47,14 +47,14 @@ module ThinkingSphinx
0
# If you specify :include, like in an #find call, this will be respected
0
# when loading the relevant models from the search results.
0
# User.search "pat", :include => :posts
0
# == Searching by Fields
0
# If you want to step it up a level, you can limit your search terms to
0
# User.search :conditions => {:name => "pat"}
0
# This uses Sphinx's extended match mode, unless you specify a different
0
@@ -74,11 +74,11 @@ module ThinkingSphinx
0
# (not multi-model searching). With a single model, Thinking Sphinx
0
# can figure out what attributes and fields are available, so you can
0
# put it all in the :conditions hash, and it will sort it out.
0
# Node.search :conditions => {:parent_id => 10}
0
# Filters can be single values, arrays of values, or ranges.
0
# Article.search "East Timor", :conditions => {:rating => 3..5}
0
# == Excluding by Attributes
0
@@ -87,7 +87,7 @@ module ThinkingSphinx
0
# attribute values to exclude. This is done with the :without option:
0
# User.search :without => {:role_id => 1}
0
# Sphinx can only sort by attributes, so generally you will need to avoid
0
@@ -112,13 +112,13 @@ module ThinkingSphinx
0
# For this you can use the group_by, group_clause and group_function
0
# options - which are all directly linked to Sphinx's expectations. No
0
# magic from Thinking Sphinx. It can get a little tricky, so make sure
0
# you read all the relevant
0
# documentation[http://sphinxsearch.com/doc.html#clustering] first.
0
# Yes this section will be expanded, but this is a start.
0
# == Geo/Location Searching
0
@@ -128,11 +128,11 @@ module ThinkingSphinx
0
# take advantage of this, you will need to have both of those values in
0
# attributes. To search with that point, you can then use one of the
0
# following syntax examples:
0
# Address.search "Melbourne", :geo => [1.4, -2.217]
0
# Address.search "Australia", :geo => [-0.55, 3.108],
0
# :latitude_attr => "latit", :longitude_attr => "longit"
0
# The first example applies when your latitude and longitude attributes
0
# are named any of lat, latitude, lon, long or longitude. If that's not
0
# the case, you will need to explicitly state them in your search, _or_
0
@@ -141,17 +141,17 @@ module ThinkingSphinx
0
# has :latit # Float column, stored in radians
0
# has :longit # Float column, stored in radians
0
# set_property :latitude_attr => "latit"
0
# set_property :longitude_attr => "longit"
0
# Now, geo-location searching really only has an affect if you have a
0
# filter, sort or grouping clause related to it - otherwise it's just a
0
# normal search. To make use of the positioning difference, use the
0
# special attribute "@geodist" in any of your filters or sorting or grouping
0
# And don't forget - both the latitude and longitude you use in your
0
# search, and the values in your indexes, need to be stored as a float in radians,
0
# _not_ degrees. Keep in mind that if you do this conversion in SQL
0
@@ -161,7 +161,7 @@ module ThinkingSphinx
0
# has 'RADIANS(lat)', :as => :lat, :type => :float
0
results, client = search_results(*args.clone)
0
@@ -186,55 +186,55 @@ module ThinkingSphinx
0
# Checks if a document with the given id exists within a specific index.
0
# - Index to check within
0
# - Options hash (defaults to {})
0
# ThinkingSphinx::Search.search_for_id(10, "user_core", :class => User)
0
def search_for_id(*args)
0
options = args.extract_options!
0
client = client_from_options options
0
query, filters = search_conditions(
0
options[:class], options[:conditions] || {}
0
client.filters += filters
0
client.match_mode = :extended unless query.empty?
0
client.id_range = args.first..args.first
0
return client.query(query, args[1])[:matches].length > 0
0
rescue Errno::ECONNREFUSED => err
0
raise ThinkingSphinx::ConnectionError, "Connection to Sphinx Daemon (searchd) failed."
0
# This method handles the common search functionality, and returns both
0
# the result hash and the client. Not super elegant, but it'll do for
0
def search_results(*args)
0
options = args.extract_options!
0
client = client_from_options options
0
query, filters = search_conditions(
0
options[:class], options[:conditions] || {}
0
client.filters += filters
0
client.match_mode = :extended unless query.empty?
0
query = args.join(" ") + query
0
set_sort_options! client, options
0
client.limit = options[:per_page].to_i if options[:per_page]
0
page = options[:page] ? options[:page].to_i : 1
0
client.offset = (page - 1) * client.limit
0
@@ -246,10 +246,21 @@ module ThinkingSphinx
0
rescue Errno::ECONNREFUSED => err
0
raise ThinkingSphinx::ConnectionError, "Connection to Sphinx Daemon (searchd) failed."
0
+ # This function loops over the records and appends a 'distance' variable to each one with
0
+ # the value from Sphinx
0
+ def append_distances(instances, results, distance_name)
0
+ instances.each_with_index do |record, index|
0
+ distance = (results[index][:attributes]['@geodist'] or nil)
0
+ record.instance_variable_get('@attributes')["#{distance_name}"] = distance
0
def instances_from_results(results, options = {}, klass = nil)
0
results.collect { |result| instance_from_result result, options }
0
@@ -261,43 +272,47 @@ module ThinkingSphinx
0
:include => options[:include],
0
:select => options[:select]
0
- ids.collect { |obj_id| instances.detect { |obj| obj.id == obj_id } }
0
+ final_instances = ids.collect { |obj_id| instances.detect { |obj| obj.id == obj_id } }
0
+ final_instances = append_distances(final_instances, results, options[:distance_name]) if options[:distance_name] && (results.collect { |result| result[:attributes]['@geodist'] }.length > 0)
0
+ return final_instances
0
# Either use the provided class to instantiate a result from a model, or
0
# get the result's CRC value and determine the class from that.
0
def instance_from_result(result, options)
0
class_from_crc(result[:attributes]["class_crc"]).find(
0
result[:doc], :include => options[:include], :select => options[:select]
0
# Convert a CRC value to the corresponding class.
0
def class_from_crc(crc)
0
Configuration.new.load_models
0
@models_by_crc = ThinkingSphinx.indexed_models.inject({}) do |hash, model|
0
hash[model.constantize.to_crc32] = model
0
@models_by_crc[crc].constantize
0
# Set all the appropriate settings for the client, using the provided
0
def client_from_options(options)
0
config = ThinkingSphinx::Configuration.new
0
client = Riddle::Client.new config.address, config.port
0
klass = options[:class]
0
index_options = klass ? klass.indexes.last.options : {}
0
:max_matches, :match_mode, :sort_mode, :sort_by, :id_range,
0
:group_by, :group_function, :group_clause, :group_distinct, :cut_off,
0
@@ -309,9 +324,9 @@ module ThinkingSphinx
0
options[key] || index_options[key] || client.send(key)
0
client.anchor = anchor_conditions(klass, options) || {} if client.anchor.empty?
0
client.filters << Riddle::Client::Filter.new(
0
@@ -319,20 +334,20 @@ module ThinkingSphinx
0
client.filters << Riddle::Client::Filter.new(
0
"class_crc", options[:classes].collect { |klass| klass.to_crc32 }
0
# normal attribute filters
0
client.filters += options[:with].collect { |attr,val|
0
Riddle::Client::Filter.new attr.to_s, filter_value(val)
0
# exclusive attribute filters
0
client.filters += options[:without].collect { |attr,val|
0
Riddle::Client::Filter.new attr.to_s, filter_value(val), true
0
def filter_value(value)
0
@@ -343,18 +358,18 @@ module ThinkingSphinx
0
# Translate field and attribute conditions to the relevant search string
0
def search_conditions(klass, conditions={})
0
attributes = klass ? klass.indexes.collect { |index|
0
index.attributes.collect { |attrib| attrib.unique_name }
0
conditions.each do |key,val|
0
if attributes.include?(key.to_sym)
0
filters << Riddle::Client::Filter.new(
0
@@ -365,48 +380,48 @@ module ThinkingSphinx
0
search_string << "@#{key} #{val} "
0
filters << Riddle::Client::Filter.new(
0
"class_crc", [klass.to_crc32]
0
return search_string, filters
0
# Return the appropriate latitude and longitude values, depending on
0
# whether the relevant attributes have been defined, and also whether
0
# there's actually any values.
0
def anchor_conditions(klass, options)
0
attributes = klass ? klass.indexes.collect { |index|
0
index.attributes.collect { |attrib| attrib.unique_name }
0
lat_attr = klass ? klass.indexes.collect { |index|
0
index.options[:latitude_attr]
0
lon_attr = klass ? klass.indexes.collect { |index|
0
index.options[:longitude_attr]
0
lat_attr = options[:latitude_attr] if options[:latitude_attr]
0
lat_attr ||= :lat if attributes.include?(:lat)
0
lat_attr ||= :latitude if attributes.include?(:latitude)
0
lon_attr = options[:longitude_attr] if options[:longitude_attr]
0
lon_attr ||= :lon if attributes.include?(:lon)
0
lon_attr ||= :long if attributes.include?(:long)
0
lon_attr ||= :longitude if attributes.include?(:longitude)
0
lat = options[:geo].first
0
lon = options[:geo].last
0
:latitude_attribute => lat_attr,
0
@@ -414,16 +429,16 @@ module ThinkingSphinx
0
# Set the sort options using the :order key as well as the appropriate
0
def set_sort_options!(client, options)
0
klass = options[:class]
0
fields = klass ? klass.indexes.collect { |index|
0
index.fields.collect { |field| field.unique_name }
0
case order = options[:order]
0
client.sort_mode ||= :attr_asc
0
@@ -438,23 +453,23 @@ module ThinkingSphinx
0
client.sort_mode = :attr_asc if client.sort_mode == :asc
0
client.sort_mode = :attr_desc if client.sort_mode == :desc
0
# Search through a collection of fields and translate any appearances
0
# of them in a string to their attribute equivalent for sorting.
0
def sorted_fields_to_attributes(string, fields)
0
string.gsub!(/(^|\s)#{field}(,?\s|$)/) { |match|
0
match.gsub field.to_s, field.to_s.concat("_sort")
0
\ No newline at end of file
Comments
No one has commented yet.