DrMark-thinking-sphinx 1.1.15 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|