-1

I'd like to do a complex search with thinking sphinx:

Search for users which: -> live in a city (city_id attribute) -> or has hability to move to a city (mobile_cities association) -> or live at a maximum distance from a lat/long point, the maximum distance is different for each user and set in a mobility_distance attribute.

For now I did that with 3 differents search, I volontary set a big per_page number, then i merge the 3 results on a single array, an then paginate this array :

#users living in the @city
search_set_living = search_set.merge({:city_id => @city.id })
users_living =  User.search :with => search_set_living.dup,
                                :page => 1, :per_page => 1000

#users declaring hability to move to the @city
search_set_mobile = search_set.merge({:mobile_cities_ids => @city.id })
users_mobile =  User.search :with => search_set_mobile.dup, :page => 1, :per_page => 1000

#users living at a maximum distance from the origin point(custom distance for each user, max 30km)   
search_set_around = search_set.merge({"@geodist" => 0.0..30_000.0})
users_around =  User.search :geo => [@search_latitude * Math::PI / 180 , @search_longitude * Math::PI / 180],
                                  :with => search_set_around.dup,
                                  :page => 1, :per_page => 1000
users_around_filtered = users_around.dup.delete_if{|user| (user.mobility_distance * 1000 )< user.sphinx_attributes['@geodist'] }


#merge the 3 results in a array
all_users =  (users_mobile.flatten + users_around_filtered.flatten).uniq

#look for facets and paginate the array
@facets = User.facets :with => {:user_id => all_users.map(&:id)}
@users_to_display =  all_users.paginate(:page => params[:page], :per_page => 10)

This is working fine but i'm not satisfied: -performance are not so good, -I want the ability to sort on multiple attributes like this :order => "created_at DESC, @relevance DESC"

I want to do the exact same search but in a single sphinx's search. I know that I should use the "OR Logic with Attribute Filters" from the docs but I don't know how to mix it with a geo_search call... I really have no idea how to do that, can you guys help me ?

Many thanks,

alex
  • 357
  • 3
  • 14

2 Answers2

3

The :sphinx_select option is definitely your friend here, as you've guessed. Let's piece it together bit by bit:

logic = [
  "city_id = #{@city.id}",
  "IN(mobile_cities_ids, #{@city.id}",
  "GEODIST(lat, lng, #{lat}, #{lng}) < (mobility_distance * 1000)"
]

User.search :sphinx_select => "*, #{logic.join(" OR ")}) AS valid",
  :with => {:valid => true}

Add pagination as you like, tweak the attribute names if needed (maybe your lat/lng attributes are named something else). I don't think you need the IF call around that custom attribute like in the docs, but if things aren't working when they should be, maybe give it a shot. Should be good in a facets call too.

pat
  • 16,116
  • 5
  • 40
  • 46
-1

Great ! Thank you so much. I just needed to correct a little your syntax (some parenthesis missing) in order to get it work. I had to add per_page and page arguments too, don't know really why.

logic = ["city_id = #{@city.id}",
         "IN(mobile_cities_ids, #{@city.id})",
         "GEODIST(latitude, longitude, #{@search_latitude * Math::PI / 180}, #{@search_longitude * Math::PI / 180}) < (mobility_distance * 1000)"]

search_set_logic = search_set.merge({:valid => true})
@users_to_display = User.search :sphinx_select => "*, (#{logic.join(" OR ")}) AS valid",
                 :with => search_set_logic.dup,
                 :sort_mode => :extended,
                 :order => "visibility DESC, last_login_at DESC",
                 :page => params[:page], :per_page => 10
alex
  • 357
  • 3
  • 14