freelancing-god-thinking-sphinx 1.1.8 → 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -0
- data/lib/thinking_sphinx.rb +1 -1
- data/lib/thinking_sphinx/facet.rb +14 -1
- data/lib/thinking_sphinx/facet_collection.rb +14 -14
- data/lib/thinking_sphinx/search.rb +14 -3
- data/spec/unit/thinking_sphinx/facet_collection_spec.rb +64 -0
- data/spec/unit/thinking_sphinx/facet_spec.rb +46 -0
- data/spec/unit/thinking_sphinx/search_spec.rb +44 -0
- metadata +6 -2
data/README
CHANGED
data/lib/thinking_sphinx.rb
CHANGED
@@ -9,10 +9,23 @@ module ThinkingSphinx
|
|
9
9
|
raise "Can't translate Facets on multiple-column field or attribute"
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
def self.name_for(facet)
|
14
|
+
case facet
|
15
|
+
when Facet
|
16
|
+
facet.name
|
17
|
+
when String, Symbol
|
18
|
+
facet.to_s.gsub(/(_facet|_crc)$/,'').to_sym
|
19
|
+
end
|
20
|
+
end
|
12
21
|
|
13
22
|
def name
|
14
23
|
reference.unique_name
|
15
24
|
end
|
25
|
+
|
26
|
+
def self.attribute_name_for(name)
|
27
|
+
name.to_s == 'class' ? 'class_crc' : "#{name}_facet"
|
28
|
+
end
|
16
29
|
|
17
30
|
def attribute_name
|
18
31
|
# @attribute_name ||= case @reference
|
@@ -55,4 +68,4 @@ module ThinkingSphinx
|
|
55
68
|
@reference.columns.first
|
56
69
|
end
|
57
70
|
end
|
58
|
-
end
|
71
|
+
end
|
@@ -5,22 +5,26 @@ module ThinkingSphinx
|
|
5
5
|
def initialize(arguments)
|
6
6
|
@arguments = arguments.clone
|
7
7
|
@attribute_values = {}
|
8
|
-
@
|
8
|
+
@facet_names = []
|
9
9
|
end
|
10
10
|
|
11
11
|
def add_from_results(facet, results)
|
12
|
+
name = ThinkingSphinx::Facet.name_for(facet)
|
13
|
+
|
14
|
+
self[name] ||= {}
|
15
|
+
@attribute_values[name] ||= {}
|
16
|
+
@facet_names << name
|
17
|
+
|
18
|
+
return if results.empty?
|
19
|
+
|
12
20
|
facet = facet_from_object(results.first, facet) if facet.is_a?(String)
|
13
21
|
|
14
|
-
self[facet.name] ||= {}
|
15
|
-
@attribute_values[facet.name] ||= {}
|
16
|
-
@facets << facet
|
17
|
-
|
18
22
|
results.each_with_groupby_and_count { |result, group, count|
|
19
23
|
facet_value = facet.value(result, group)
|
20
24
|
|
21
|
-
self[
|
22
|
-
self[
|
23
|
-
@attribute_values[
|
25
|
+
self[name][facet_value] ||= 0
|
26
|
+
self[name][facet_value] += count
|
27
|
+
@attribute_values[name][facet_value] = group
|
24
28
|
}
|
25
29
|
end
|
26
30
|
|
@@ -30,7 +34,7 @@ module ThinkingSphinx
|
|
30
34
|
options[:with] ||= {}
|
31
35
|
|
32
36
|
hash.each do |key, value|
|
33
|
-
attrib =
|
37
|
+
attrib = ThinkingSphinx::Facet.attribute_name_for(key)
|
34
38
|
options[:with][attrib] = underlying_value key, value
|
35
39
|
end
|
36
40
|
|
@@ -49,12 +53,8 @@ module ThinkingSphinx
|
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
52
|
-
def facet_for_key(key)
|
53
|
-
@facets.detect { |facet| facet.name == key }
|
54
|
-
end
|
55
|
-
|
56
56
|
def facet_from_object(object, name)
|
57
57
|
object.sphinx_facets.detect { |facet| facet.attribute_name == name }
|
58
58
|
end
|
59
59
|
end
|
60
|
-
end
|
60
|
+
end
|
@@ -720,11 +720,11 @@ module ThinkingSphinx
|
|
720
720
|
|
721
721
|
def facets_for_model(klass, args, options)
|
722
722
|
hash = ThinkingSphinx::FacetCollection.new args + [options]
|
723
|
-
options = options.clone.merge!
|
723
|
+
options = options.clone.merge! facet_query_options
|
724
724
|
|
725
725
|
klass.sphinx_facets.inject(hash) do |hash, facet|
|
726
726
|
unless facet.name == :class && !options[:class_facet]
|
727
|
-
options[:group_by]
|
727
|
+
options[:group_by] = facet.attribute_name
|
728
728
|
hash.add_from_results facet, search(*(args + [options]))
|
729
729
|
end
|
730
730
|
|
@@ -735,7 +735,7 @@ module ThinkingSphinx
|
|
735
735
|
def facets_for_all_models(args, options)
|
736
736
|
options = GlobalFacetOptions.merge(options)
|
737
737
|
hash = ThinkingSphinx::FacetCollection.new args + [options]
|
738
|
-
options = options.merge!
|
738
|
+
options = options.merge! facet_query_options
|
739
739
|
|
740
740
|
facet_names(options).inject(hash) do |hash, name|
|
741
741
|
options[:group_by] = name
|
@@ -744,6 +744,17 @@ module ThinkingSphinx
|
|
744
744
|
end
|
745
745
|
end
|
746
746
|
|
747
|
+
def facet_query_options
|
748
|
+
config = ThinkingSphinx::Configuration.instance
|
749
|
+
max = config.configuration.searchd.max_matches || 1000
|
750
|
+
|
751
|
+
{
|
752
|
+
:group_function => :attr,
|
753
|
+
:limit => max,
|
754
|
+
:max_matches => max
|
755
|
+
}
|
756
|
+
end
|
757
|
+
|
747
758
|
def facet_classes(options)
|
748
759
|
options[:classes] || ThinkingSphinx.indexed_models.collect { |model|
|
749
760
|
model.constantize
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::FacetCollection do
|
4
|
+
before do
|
5
|
+
@facet_collection = ThinkingSphinx::FacetCollection.new([])
|
6
|
+
end
|
7
|
+
|
8
|
+
# TODO fix nasty hack when we have internet!
|
9
|
+
def mock_results
|
10
|
+
return @results if defined? @results
|
11
|
+
@result = Person.find(:first)
|
12
|
+
@results = [@result]
|
13
|
+
@results.stub!(:each_with_groupby_and_count).and_yield(@result, @result.city.to_crc32, 1)
|
14
|
+
@results
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#add_from_results" do
|
18
|
+
describe "with empty result set" do
|
19
|
+
before do
|
20
|
+
@facet_collection.add_from_results('attribute_facet', [])
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should add key as attribute" do
|
24
|
+
@facet_collection.should have_key(:attribute)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return an empty hash for the facet results" do
|
28
|
+
@facet_collection[:attribute].should be_empty
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "with non-empty result set" do
|
33
|
+
before do
|
34
|
+
@facet_collection.add_from_results('city_facet', mock_results)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return a hash" do
|
38
|
+
@facet_collection.should be_a_kind_of(Hash)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should add key as attribute" do
|
42
|
+
@facet_collection.keys.should include(:city)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return a hash" do
|
46
|
+
@facet_collection[:city].should == {@result.city => 1}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#for" do
|
52
|
+
before do
|
53
|
+
@facet_collection.add_from_results('city_facet', mock_results)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should return the search results for the attribute and key pair" do
|
57
|
+
ThinkingSphinx::Search.should_receive(:search) do |options|
|
58
|
+
options[:with].should have_key('city_facet')
|
59
|
+
options[:with]['city_facet'].should == @result.city.to_crc32
|
60
|
+
end
|
61
|
+
@facet_collection.for(:city => @result.city)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Facet do
|
4
|
+
describe ".name_for" do
|
5
|
+
it "should remove '_facet' from provided string and return a symbol" do
|
6
|
+
ThinkingSphinx::Facet.name_for('attribute_facet').should == :attribute
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should remove '_facet' from provided symbol" do
|
10
|
+
ThinkingSphinx::Facet.name_for(:attribute_facet).should == :attribute
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return the name of the facet if a Facet is passed" do
|
14
|
+
facet = ThinkingSphinx::Facet.new(
|
15
|
+
ThinkingSphinx::Attribute.stub_instance(:unique_name => :attribute, :columns => ['attribute'])
|
16
|
+
)
|
17
|
+
ThinkingSphinx::Facet.name_for(facet).should == :attribute
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return 'class' for special case name 'class_crc'" do
|
21
|
+
ThinkingSphinx::Facet.name_for(:class_crc).should == :class
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should cycle" do
|
25
|
+
ThinkingSphinx::Facet.name_for(ThinkingSphinx::Facet.attribute_name_for(:attribute)).should == :attribute
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe ".attribute_name_for" do
|
30
|
+
it "should append '_facet' to provided string" do
|
31
|
+
ThinkingSphinx::Facet.attribute_name_for('attribute').should == 'attribute_facet'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should append '_facet' to provided symbol and return a string" do
|
35
|
+
ThinkingSphinx::Facet.attribute_name_for(:attribute).should == 'attribute_facet'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return 'class_crc' for special case attribute 'class'" do
|
39
|
+
ThinkingSphinx::Facet.attribute_name_for(:class).should == 'class_crc'
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should cycle" do
|
43
|
+
ThinkingSphinx::Facet.attribute_name_for(ThinkingSphinx::Facet.name_for('attribute_facet')).should == 'attribute_facet'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -50,6 +50,50 @@ describe ThinkingSphinx::Search do
|
|
50
50
|
|
51
51
|
end
|
52
52
|
end
|
53
|
+
|
54
|
+
describe "facets method" do
|
55
|
+
before :each do
|
56
|
+
@results = [Person.find(:first)]
|
57
|
+
@results.stub!(:each_with_groupby_and_count).
|
58
|
+
and_yield(@results.first, @results.first.city.to_crc32, 1)
|
59
|
+
ThinkingSphinx::Search.stub!(:search => @results)
|
60
|
+
|
61
|
+
@config = ThinkingSphinx::Configuration.instance
|
62
|
+
@config.configuration.searchd.max_matches = 10_000
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should use the system-set max_matches for limit on facet calls" do
|
66
|
+
ThinkingSphinx::Search.should_receive(:search) do |options|
|
67
|
+
options[:max_matches].should == 10_000
|
68
|
+
options[:limit].should == 10_000
|
69
|
+
end
|
70
|
+
|
71
|
+
ThinkingSphinx::Search.facets :all_attributes => true
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should use the default max-matches if there is no explicit setting" do
|
75
|
+
@config.configuration.searchd.max_matches = nil
|
76
|
+
ThinkingSphinx::Search.should_receive(:search) do |options|
|
77
|
+
options[:max_matches].should == 1000
|
78
|
+
options[:limit].should == 1000
|
79
|
+
end
|
80
|
+
|
81
|
+
ThinkingSphinx::Search.facets :all_attributes => true
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should ignore user-provided max_matches and limit on facet calls" do
|
85
|
+
ThinkingSphinx::Search.should_receive(:search) do |options|
|
86
|
+
options[:max_matches].should == 10_000
|
87
|
+
options[:limit].should == 10_000
|
88
|
+
end
|
89
|
+
|
90
|
+
ThinkingSphinx::Search.facets(
|
91
|
+
:all_attributes => true,
|
92
|
+
:max_matches => 500,
|
93
|
+
:limit => 200
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
53
97
|
end
|
54
98
|
|
55
99
|
describe ThinkingSphinx::Search, "playing nice with Search model" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: freelancing-god-thinking-sphinx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pat Allan
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -109,6 +109,8 @@ files:
|
|
109
109
|
- spec/unit/thinking_sphinx/collection_spec.rb
|
110
110
|
- spec/unit/thinking_sphinx/configuration_spec.rb
|
111
111
|
- spec/unit/thinking_sphinx/core/string_spec.rb
|
112
|
+
- spec/unit/thinking_sphinx/facet_collection_spec.rb
|
113
|
+
- spec/unit/thinking_sphinx/facet_spec.rb
|
112
114
|
- spec/unit/thinking_sphinx/field_spec.rb
|
113
115
|
- spec/unit/thinking_sphinx/index/builder_spec.rb
|
114
116
|
- spec/unit/thinking_sphinx/index/faux_column_spec.rb
|
@@ -154,6 +156,8 @@ test_files:
|
|
154
156
|
- spec/unit/thinking_sphinx/collection_spec.rb
|
155
157
|
- spec/unit/thinking_sphinx/configuration_spec.rb
|
156
158
|
- spec/unit/thinking_sphinx/core/string_spec.rb
|
159
|
+
- spec/unit/thinking_sphinx/facet_collection_spec.rb
|
160
|
+
- spec/unit/thinking_sphinx/facet_spec.rb
|
157
161
|
- spec/unit/thinking_sphinx/field_spec.rb
|
158
162
|
- spec/unit/thinking_sphinx/index/builder_spec.rb
|
159
163
|
- spec/unit/thinking_sphinx/index/faux_column_spec.rb
|