DrMark-thinking-sphinx 1.1.15 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +22 -0
- data/VERSION.yml +4 -0
- data/lib/thinking_sphinx/active_record/scopes.rb +39 -0
- data/lib/thinking_sphinx/active_record.rb +27 -7
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +9 -3
- data/lib/thinking_sphinx/association.rb +4 -1
- data/lib/thinking_sphinx/attribute.rb +91 -30
- data/lib/thinking_sphinx/configuration.rb +51 -12
- data/lib/thinking_sphinx/deltas/datetime_delta.rb +2 -2
- data/lib/thinking_sphinx/deltas/default_delta.rb +1 -1
- data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
- data/lib/thinking_sphinx/deltas/delayed_delta.rb +3 -0
- data/lib/thinking_sphinx/deploy/capistrano.rb +25 -8
- data/lib/thinking_sphinx/excerpter.rb +22 -0
- data/lib/thinking_sphinx/facet.rb +1 -1
- data/lib/thinking_sphinx/facet_search.rb +134 -0
- data/lib/thinking_sphinx/index.rb +2 -1
- data/lib/thinking_sphinx/rails_additions.rb +14 -0
- data/lib/thinking_sphinx/search.rb +599 -658
- data/lib/thinking_sphinx/search_methods.rb +421 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +1 -1
- data/lib/thinking_sphinx/source/sql.rb +17 -13
- data/lib/thinking_sphinx/source.rb +6 -6
- data/lib/thinking_sphinx/tasks.rb +42 -8
- data/lib/thinking_sphinx.rb +82 -54
- data/rails/init.rb +14 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +5 -5
- data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +96 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +51 -31
- data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +4 -5
- data/spec/lib/thinking_sphinx/attribute_spec.rb +465 -0
- data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +161 -29
- data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
- data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
- data/spec/{unit → lib}/thinking_sphinx/facet_spec.rb +24 -0
- data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +8 -8
- data/spec/{unit → lib}/thinking_sphinx/index/builder_spec.rb +6 -2
- data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/index_spec.rb +45 -0
- data/spec/{unit → lib}/thinking_sphinx/rails_additions_spec.rb +25 -5
- data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
- data/spec/lib/thinking_sphinx/search_spec.rb +960 -0
- data/spec/{unit → lib}/thinking_sphinx/source_spec.rb +63 -2
- data/spec/{unit → lib}/thinking_sphinx_spec.rb +32 -4
- data/tasks/distribution.rb +36 -35
- data/vendor/riddle/lib/riddle/client/message.rb +4 -3
- data/vendor/riddle/lib/riddle/client.rb +3 -0
- data/vendor/riddle/lib/riddle/configuration/section.rb +8 -2
- data/vendor/riddle/lib/riddle/controller.rb +17 -7
- data/vendor/riddle/lib/riddle.rb +1 -1
- metadata +79 -83
- data/lib/thinking_sphinx/active_record/search.rb +0 -57
- data/lib/thinking_sphinx/collection.rb +0 -148
- data/lib/thinking_sphinx/facet_collection.rb +0 -59
- data/lib/thinking_sphinx/search/facets.rb +0 -98
- data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
- data/spec/unit/thinking_sphinx/attribute_spec.rb +0 -232
- data/spec/unit/thinking_sphinx/collection_spec.rb +0 -14
- data/spec/unit/thinking_sphinx/facet_collection_spec.rb +0 -64
- data/spec/unit/thinking_sphinx/index_spec.rb +0 -139
- data/spec/unit/thinking_sphinx/search_spec.rb +0 -130
@@ -0,0 +1,22 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
class Excerpter
|
3
|
+
CoreMethods = %w( kind_of? object_id respond_to? should should_not stub! )
|
4
|
+
# Hide most methods, to allow them to be passed through to the instance.
|
5
|
+
instance_methods.select { |method|
|
6
|
+
method.to_s[/^__/].nil? && !CoreMethods.include?(method.to_s)
|
7
|
+
}.each { |method|
|
8
|
+
undef_method method
|
9
|
+
}
|
10
|
+
|
11
|
+
def initialize(search, instance)
|
12
|
+
@search = search
|
13
|
+
@instance = instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(method, *args, &block)
|
17
|
+
string = @instance.send(method, *args, &block).to_s
|
18
|
+
|
19
|
+
@search.excerpt_for(string, @instance.class)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -92,7 +92,7 @@ module ThinkingSphinx
|
|
92
92
|
|
93
93
|
def translate(object, attribute_value)
|
94
94
|
column.__stack.each { |method|
|
95
|
-
object = object.send(method)
|
95
|
+
return nil unless object = object.send(method)
|
96
96
|
}
|
97
97
|
if object.is_a?(Array)
|
98
98
|
object.collect { |item| item.send(column.__name) }
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
class FacetSearch < Hash
|
3
|
+
attr_accessor :args, :options
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
@options = args.extract_options!
|
7
|
+
@args = args
|
8
|
+
|
9
|
+
set_default_options
|
10
|
+
|
11
|
+
populate
|
12
|
+
end
|
13
|
+
|
14
|
+
def for(hash = {})
|
15
|
+
for_options = {:with => {}}.merge(options)
|
16
|
+
|
17
|
+
hash.each do |key, value|
|
18
|
+
attrib = ThinkingSphinx::Facet.attribute_name_from_value(key, value)
|
19
|
+
for_options[:with][attrib] = underlying_value key, value
|
20
|
+
end
|
21
|
+
|
22
|
+
ThinkingSphinx.search *(args + [for_options])
|
23
|
+
end
|
24
|
+
|
25
|
+
def facet_names
|
26
|
+
@facet_names ||= begin
|
27
|
+
names = options[:all_facets] ?
|
28
|
+
facet_names_for_all_classes : facet_names_common_to_all_classes
|
29
|
+
|
30
|
+
names.delete "class_crc" unless options[:class_facet]
|
31
|
+
names
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def set_default_options
|
38
|
+
options[:all_facets] ||= false
|
39
|
+
if options[:class_facet].nil?
|
40
|
+
options[:class_facet] = ((options[:classes] || []).length != 1)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def populate
|
45
|
+
facet_names.each do |name|
|
46
|
+
search_options = facet_search_options.merge(:group_by => name)
|
47
|
+
add_from_results name, ThinkingSphinx.search(
|
48
|
+
*(args + [search_options])
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def facet_search_options
|
54
|
+
config = ThinkingSphinx::Configuration.instance
|
55
|
+
max = config.configuration.searchd.max_matches || 1000
|
56
|
+
|
57
|
+
options.merge(
|
58
|
+
:group_function => :attr,
|
59
|
+
:limit => max,
|
60
|
+
:max_matches => max,
|
61
|
+
:page => 1
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def facet_classes
|
66
|
+
(
|
67
|
+
options[:classes] || ThinkingSphinx.indexed_models.collect { |model|
|
68
|
+
model.constantize
|
69
|
+
}
|
70
|
+
).select { |klass| klass.sphinx_facets.any? }
|
71
|
+
end
|
72
|
+
|
73
|
+
def all_facets
|
74
|
+
facet_classes.collect { |klass|
|
75
|
+
klass.sphinx_facets
|
76
|
+
}.flatten.select { |facet|
|
77
|
+
options[:facets].blank? || Array(options[:facets]).include?(facet.name)
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def facet_names_for_all_classes
|
82
|
+
all_facets.group_by { |facet|
|
83
|
+
facet.name
|
84
|
+
}.collect { |name, facets|
|
85
|
+
if facets.collect { |facet| facet.type }.uniq.length > 1
|
86
|
+
raise "Facet #{name} exists in more than one model with different types"
|
87
|
+
end
|
88
|
+
facets.first.attribute_name
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
def facet_names_common_to_all_classes
|
93
|
+
facet_names_for_all_classes.select { |name|
|
94
|
+
facet_classes.all? { |klass|
|
95
|
+
klass.sphinx_facets.detect { |facet|
|
96
|
+
facet.attribute_name == name
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_from_results(facet, results)
|
103
|
+
name = ThinkingSphinx::Facet.name_for(facet)
|
104
|
+
|
105
|
+
self[name] ||= {}
|
106
|
+
|
107
|
+
return if results.empty?
|
108
|
+
|
109
|
+
facet = facet_from_object(results.first, facet) if facet.is_a?(String)
|
110
|
+
|
111
|
+
results.each_with_groupby_and_count { |result, group, count|
|
112
|
+
facet_value = facet.value(result, group)
|
113
|
+
|
114
|
+
self[name][facet_value] ||= 0
|
115
|
+
self[name][facet_value] += count
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def underlying_value(key, value)
|
120
|
+
case value
|
121
|
+
when Array
|
122
|
+
value.collect { |item| underlying_value(key, item) }
|
123
|
+
when String
|
124
|
+
value.to_crc32
|
125
|
+
else
|
126
|
+
value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def facet_from_object(object, name)
|
131
|
+
object.sphinx_facets.detect { |facet| facet.attribute_name == name }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -63,7 +63,8 @@ module ThinkingSphinx
|
|
63
63
|
def options
|
64
64
|
all_index_options = ThinkingSphinx::Configuration.instance.index_options.clone
|
65
65
|
@options.keys.select { |key|
|
66
|
-
ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s)
|
66
|
+
ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s) ||
|
67
|
+
ThinkingSphinx::Configuration::CustomOptions.include?(key.to_s)
|
67
68
|
}.each { |key| all_index_options[key.to_sym] = @options[key] }
|
68
69
|
all_index_options
|
69
70
|
end
|
@@ -134,3 +134,17 @@ end
|
|
134
134
|
Class.extend(
|
135
135
|
ThinkingSphinx::ClassAttributeMethods
|
136
136
|
) unless Class.respond_to?(:cattr_reader)
|
137
|
+
|
138
|
+
module ThinkingSphinx
|
139
|
+
module MetaClass
|
140
|
+
def metaclass
|
141
|
+
class << self
|
142
|
+
self
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
unless Object.new.respond_to?(:metaclass)
|
149
|
+
Object.send(:include, ThinkingSphinx::MetaClass)
|
150
|
+
end
|