For most of our projects over at Syndeomedia, we have been using Andrew Aksyonoff’s Sphinx search engine to handle the search functionality, and Evan Weaver’s Ultrasphinx Ruby on Rails plugin to serve as an API to the search daemon. Sphinx is an incredibly efficient full-text stand-alone search engine that has the ability to gracefully handle large bulks of data, while Ultrasphinx brags a configurator that can automatically generate a Sphinx configuration file from specifications in the models themselves. Ultrasphinx also handles generation of the actual result objects with extras, of course.
Sphinx/Ultrasphinx served our purposes together perfectly until we needed to sort some search results according to the distance between the objects that they represent and a varying location in order to increase relevance of the search results. The search engine actually already handles @geodist computations (and sorting), but there seems no way to do this with Ultrasphinx. While it is relatively easy to sort all search results, which would later be paginated, through a MySQL query, and even more convenient when using the :origin specifier from the GeoKit plugin, doing these involve incredible overload, especially if the application is dealing with more than just a thousand rows.
Now, both projects are relatively young, and I can imagine how the Ruby on Rails plugin always has to hurry after changes in the search engine. I got myself a bit more familiar with Sphinx and Ultrasphinx (and Pat Allen’s Riddle plugin, which Ultrasphinx uses), and made a few changes.
Patch anchor_support_added_to_search:
Index: lib/ultrasphinx/search/internals.rb
===================================================================
--- lib/ultrasphinx/search/internals.rb (revision 1701)
+++ lib/ultrasphinx/search/internals.rb (working copy)
@@ -18,6 +18,7 @@
@offset = opts['per_page'] * (opts['page'] - 1)
@limit = opts['per_page']
@max_matches = [@offset + @limit, MAX_MATCHES].min
+ @anchor = opts['anchor']
end
# Sorting
@@ -329,4 +330,4 @@
end
end
-end
\ No newline at end of file
+end
Index: lib/ultrasphinx/search.rb
===================================================================
— lib/ultrasphinx/search.rb (revision 1701)
+++ lib/ultrasphinx/search.rb (working copy)
@@ -103,7 +103,8 @@
:weights => {},
:class_names => [],
:filters => {},
- :facets => []
+ :facets => [],
+ :anchor => {}
})
cattr_accessor :excerpting_options
Simple. Riddle already supports use of anchors. What the patch does is just allow the anchor to be set in the Riddle client instance that Ultrasphinx::Search instantiates.
If the anchor is set for the search session and the "extended" sort_mode is used, @geodist already becomes available for use in the sort_by declaration. Below would be an example of a search that would sort matches according to @geodist primarily, and name secondarily:
@search = Ultrasphinx::Search.new(:query => "east", :class_names => ["branch"], :per_page => 20, :page => 3, :sort_mode => “extended”, :sort_by => “@geodist asc, name asc”, :anchor => {:latitude_attribute => “lat”, :longtitude_attribute => “lng”, :latitude => degrees_to_radians(user.location.lat), :longtitude => degrees_to_radians(user.location.lng)})
@search.run(false)
Yes, that is “longtitude”.
I hope this saves people some time.