Hi,
I needed facetings (also called slicing or drill-down, example on the
left here: http://www.newegg.com/Store/SubCategory.aspx?SubCategory=14&name=Inte...)
for my current project, and managed to implement this using thinking
sphinx. I took me some time to get it working OK, so i'm sharing it
here for the next guy/girl ;-).
Tom Davies (you rule!) added this monkeypatch (put at the end of
environment.rb for example) to query for multiple facets
require 'thinking_sphinx'
module ThinkingSphinx
class Search
class << self
# Add facet support
def facets(query, attrs, options={})
options.merge!({:group_function => :attr, :group_clauses =>
"@count desc"})
attrs = [attrs] unless attrs.is_a? Array
attr_facets = {}
attrs.each do |attr|
options[:group_by]=attr
results, client = search_results(query, options)
facets = {}
results[:matches].each {|e| facets[e[:attributes]
['@groupby']]=e[:attributes]['@count']}
attr_facets[attr] = facets
end
attr_facets
end
end
end
end
Next I specified in my model the attributes that are used in the
faceting (mysql database):
has "(SELECT GROUP_CONCAT(match_crit.id) from vacature v join
match_set on (v.match_id=match_set.match_id) join match_crit on
(match_set.match_crit_id=match_crit.id) where match_crit.soort =
'region' and v.id = vacature.id)", :as => 'region', :type => :multi
Some explanations about the sql: it returns a string of comma
seperated id's of the values of the attribute 'region'. the :type
=> :multi tells sphinx that it should treat the string as an array of
values. I needed customed sql, because the database scheme it a bit
more complex. It's important to use the correct syntax for "v.id =
vacature.id". vacature.id is the field that is used in the where
clause of the query used by sphinx for loading the field values of a
'vacature' record. The query above is used as a subselect in that
query. The full query is something like this (simplified) "SELECT *,
(SELECT GROUP_CONCAT FROM Vacature v WHERE v.id = Vacature.id) as
region WHERE Vacature.id = x"
You now can start with the indexing. In the Rake task you should see a
line that signals it's creating an index voor the MVA (multi-value
attributes) which are used for creating the facets.
When done indexing, you can query for the facet values of 'region' for
a specific query, in this example we are looking for a carpenter job
offers:
result = ThinkingSphinx::Search.facets("carpenter", ['region'])
the result hash contents if for example: {'region' => {1 => 10, 2 =>
30}}. This means that there are 10 job offers found for carpenters in
region 1, and 30 in region two. The important think to note here is
that a single job offer can be in multiple regions. So the total
results of the query doesn't have to be 10 + 30 = 40, but can be as
low as 30.
Let's say the user want's to see all carpenter job offers of region 1,
the query becomes (this is helpfull when drilling down if you have
more attributes than region alone):
result = ThinkingSphinx::Search.facets("carpenter", ['region'], :with
=> { 'region' => 1"})
Propably obvious, but to get the actual job offers, you need to
execute
Model.search("carpenter", :with => { 'region' => 1"})
Have fun!,
Ward