thinking-sphinx 1.2.13 → 1.4.0
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 +37 -4
- data/VERSION +1 -0
- data/features/abstract_inheritance.feature +10 -0
- data/features/alternate_primary_key.feature +1 -1
- data/features/attribute_updates.feature +49 -5
- data/features/deleting_instances.feature +3 -0
- data/features/excerpts.feature +8 -0
- data/features/facets.feature +15 -1
- data/features/facets_across_model.feature +2 -2
- data/features/field_sorting.feature +18 -0
- data/features/handling_edits.feature +1 -1
- data/features/searching_across_models.feature +2 -2
- data/features/searching_by_index.feature +40 -0
- data/features/searching_by_model.feature +1 -8
- data/features/sphinx_scopes.feature +33 -0
- data/features/step_definitions/alpha_steps.rb +14 -1
- data/features/step_definitions/beta_steps.rb +1 -1
- data/features/step_definitions/common_steps.rb +21 -2
- data/features/step_definitions/facet_steps.rb +4 -0
- data/features/step_definitions/scope_steps.rb +8 -0
- data/features/step_definitions/search_steps.rb +5 -0
- data/features/step_definitions/sphinx_steps.rb +8 -4
- data/features/sti_searching.feature +5 -0
- data/features/support/env.rb +7 -6
- data/features/{support → thinking_sphinx}/db/fixtures/betas.rb +1 -0
- data/features/{support → thinking_sphinx}/db/fixtures/comments.rb +1 -1
- data/features/{support → thinking_sphinx}/db/fixtures/developers.rb +2 -0
- data/features/thinking_sphinx/db/fixtures/foxes.rb +3 -0
- data/features/thinking_sphinx/db/fixtures/music.rb +4 -0
- data/features/{support → thinking_sphinx}/db/fixtures/people.rb +1 -1
- data/features/{support → thinking_sphinx}/db/fixtures/tags.rb +1 -1
- data/features/{support → thinking_sphinx}/db/migrations/create_alphas.rb +1 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_developers.rb +0 -2
- data/features/thinking_sphinx/db/migrations/create_genres.rb +3 -0
- data/features/thinking_sphinx/db/migrations/create_music.rb +6 -0
- data/features/thinking_sphinx/models/alpha.rb +23 -0
- data/features/thinking_sphinx/models/andrew.rb +17 -0
- data/features/{support → thinking_sphinx}/models/beta.rb +1 -1
- data/features/{support → thinking_sphinx}/models/developer.rb +2 -2
- data/features/{support → thinking_sphinx}/models/extensible_beta.rb +1 -1
- data/features/thinking_sphinx/models/fox.rb +5 -0
- data/features/thinking_sphinx/models/genre.rb +3 -0
- data/features/thinking_sphinx/models/medium.rb +5 -0
- data/features/thinking_sphinx/models/music.rb +8 -0
- data/features/{support → thinking_sphinx}/models/person.rb +2 -1
- data/features/{support → thinking_sphinx}/models/post.rb +2 -1
- data/lib/cucumber/thinking_sphinx/external_world.rb +12 -0
- data/lib/cucumber/thinking_sphinx/internal_world.rb +13 -11
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +17 -15
- data/lib/thinking_sphinx/active_record/delta.rb +0 -26
- data/lib/thinking_sphinx/active_record/has_many_association.rb +34 -11
- data/lib/thinking_sphinx/active_record/scopes.rb +46 -3
- data/lib/thinking_sphinx/active_record.rb +271 -193
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +45 -9
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +5 -1
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +9 -1
- data/lib/thinking_sphinx/attribute.rb +67 -23
- data/lib/thinking_sphinx/auto_version.rb +24 -0
- data/lib/thinking_sphinx/bundled_search.rb +44 -0
- data/lib/thinking_sphinx/class_facet.rb +3 -2
- data/lib/thinking_sphinx/configuration.rb +78 -64
- data/lib/thinking_sphinx/context.rb +76 -0
- data/lib/thinking_sphinx/deltas/default_delta.rb +14 -20
- data/lib/thinking_sphinx/deltas.rb +0 -2
- data/lib/thinking_sphinx/deploy/capistrano.rb +1 -1
- data/lib/thinking_sphinx/excerpter.rb +1 -1
- data/lib/thinking_sphinx/facet.rb +6 -5
- data/lib/thinking_sphinx/facet_search.rb +54 -24
- data/lib/thinking_sphinx/field.rb +2 -4
- data/lib/thinking_sphinx/index/builder.rb +36 -20
- data/lib/thinking_sphinx/index/faux_column.rb +8 -0
- data/lib/thinking_sphinx/index.rb +77 -19
- data/lib/thinking_sphinx/join.rb +37 -0
- data/lib/thinking_sphinx/property.rb +9 -2
- data/lib/thinking_sphinx/rails_additions.rb +4 -4
- data/lib/thinking_sphinx/search.rb +212 -66
- data/lib/thinking_sphinx/search_methods.rb +22 -4
- data/lib/thinking_sphinx/source/internal_properties.rb +2 -2
- data/lib/thinking_sphinx/source/sql.rb +5 -3
- data/lib/thinking_sphinx/source.rb +21 -12
- data/lib/thinking_sphinx/tasks.rb +26 -58
- data/lib/thinking_sphinx/test.rb +55 -0
- data/lib/thinking_sphinx.rb +70 -38
- data/rails/init.rb +4 -2
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/active_record/delta_spec.rb +6 -8
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/active_record/has_many_association_spec.rb +26 -3
- data/spec/thinking_sphinx/active_record/scopes_spec.rb +176 -0
- data/spec/thinking_sphinx/active_record_spec.rb +618 -0
- data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +134 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/association_spec.rb +1 -1
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/attribute_spec.rb +87 -46
- data/spec/thinking_sphinx/auto_version_spec.rb +47 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/configuration_spec.rb +73 -63
- data/spec/thinking_sphinx/context_spec.rb +127 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/core/array_spec.rb +1 -1
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/core/string_spec.rb +1 -1
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/excerpter_spec.rb +1 -9
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/facet_search_spec.rb +76 -82
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/facet_spec.rb +5 -5
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/field_spec.rb +1 -42
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/index/builder_spec.rb +71 -31
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/index/faux_column_spec.rb +8 -2
- data/spec/thinking_sphinx/index_spec.rb +183 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/rails_additions_spec.rb +5 -5
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/search_methods_spec.rb +5 -1
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/search_spec.rb +183 -31
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/source_spec.rb +18 -2
- data/spec/thinking_sphinx/test_spec.rb +20 -0
- data/spec/thinking_sphinx_spec.rb +204 -0
- data/tasks/distribution.rb +7 -26
- data/tasks/testing.rb +32 -20
- metadata +488 -147
- data/VERSION.yml +0 -5
- data/features/datetime_deltas.feature +0 -66
- data/features/delayed_delta_indexing.feature +0 -37
- data/features/step_definitions/datetime_delta_steps.rb +0 -15
- data/features/step_definitions/delayed_delta_indexing_steps.rb +0 -7
- data/features/support/database.yml +0 -5
- data/features/support/db/active_record.rb +0 -40
- data/features/support/db/database.yml +0 -5
- data/features/support/db/fixtures/delayed_betas.rb +0 -10
- data/features/support/db/fixtures/thetas.rb +0 -10
- data/features/support/db/migrations/create_delayed_betas.rb +0 -17
- data/features/support/db/migrations/create_thetas.rb +0 -5
- data/features/support/db/mysql.rb +0 -3
- data/features/support/db/postgresql.rb +0 -3
- data/features/support/models/alpha.rb +0 -10
- data/features/support/models/delayed_beta.rb +0 -7
- data/features/support/models/theta.rb +0 -7
- data/features/support/post_database.rb +0 -43
- data/lib/thinking_sphinx/deltas/datetime_delta.rb +0 -50
- data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +0 -24
- data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +0 -27
- data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +0 -26
- data/lib/thinking_sphinx/deltas/delayed_delta.rb +0 -30
- data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +0 -96
- data/spec/lib/thinking_sphinx/active_record_spec.rb +0 -353
- data/spec/lib/thinking_sphinx/deltas/job_spec.rb +0 -32
- data/spec/lib/thinking_sphinx/index_spec.rb +0 -45
- data/spec/lib/thinking_sphinx_spec.rb +0 -162
- data/vendor/after_commit/LICENSE +0 -20
- data/vendor/after_commit/README +0 -16
- data/vendor/after_commit/Rakefile +0 -22
- data/vendor/after_commit/init.rb +0 -8
- data/vendor/after_commit/lib/after_commit/active_record.rb +0 -114
- data/vendor/after_commit/lib/after_commit/connection_adapters.rb +0 -103
- data/vendor/after_commit/lib/after_commit.rb +0 -45
- data/vendor/after_commit/test/after_commit_test.rb +0 -53
- data/vendor/delayed_job/lib/delayed/job.rb +0 -251
- data/vendor/delayed_job/lib/delayed/message_sending.rb +0 -7
- data/vendor/delayed_job/lib/delayed/performable_method.rb +0 -55
- data/vendor/delayed_job/lib/delayed/worker.rb +0 -54
- data/vendor/riddle/lib/riddle/client/filter.rb +0 -53
- data/vendor/riddle/lib/riddle/client/message.rb +0 -66
- data/vendor/riddle/lib/riddle/client/response.rb +0 -84
- data/vendor/riddle/lib/riddle/client.rb +0 -635
- data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +0 -48
- data/vendor/riddle/lib/riddle/configuration/index.rb +0 -142
- data/vendor/riddle/lib/riddle/configuration/indexer.rb +0 -19
- data/vendor/riddle/lib/riddle/configuration/remote_index.rb +0 -17
- data/vendor/riddle/lib/riddle/configuration/searchd.rb +0 -25
- data/vendor/riddle/lib/riddle/configuration/section.rb +0 -43
- data/vendor/riddle/lib/riddle/configuration/source.rb +0 -23
- data/vendor/riddle/lib/riddle/configuration/sql_source.rb +0 -34
- data/vendor/riddle/lib/riddle/configuration/xml_source.rb +0 -28
- data/vendor/riddle/lib/riddle/configuration.rb +0 -33
- data/vendor/riddle/lib/riddle/controller.rb +0 -53
- data/vendor/riddle/lib/riddle.rb +0 -30
- data/features/{support → thinking_sphinx}/database.example.yml +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/alphas.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/authors.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/boxes.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/categories.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/cats.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/dogs.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/extensible_betas.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/gammas.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/posts.rb +0 -0
- data/features/{support → thinking_sphinx}/db/fixtures/robots.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_animals.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_authors.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_authors_posts.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_betas.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_boxes.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_categories.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_comments.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_extensible_betas.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_gammas.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_people.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_posts.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_robots.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_taggings.rb +0 -0
- data/features/{support → thinking_sphinx}/db/migrations/create_tags.rb +0 -0
- data/features/{support → thinking_sphinx}/models/animal.rb +0 -0
- data/features/{support → thinking_sphinx}/models/author.rb +0 -0
- data/features/{support → thinking_sphinx}/models/box.rb +0 -0
- data/features/{support → thinking_sphinx}/models/cat.rb +0 -0
- data/features/{support → thinking_sphinx}/models/category.rb +0 -0
- data/features/{support → thinking_sphinx}/models/comment.rb +3 -3
- /data/features/{support → thinking_sphinx}/models/dog.rb +0 -0
- /data/features/{support → thinking_sphinx}/models/gamma.rb +0 -0
- /data/features/{support → thinking_sphinx}/models/robot.rb +0 -0
- /data/features/{support → thinking_sphinx}/models/tag.rb +0 -0
- /data/features/{support → thinking_sphinx}/models/tagging.rb +0 -0
|
@@ -3,6 +3,8 @@ module ThinkingSphinx
|
|
|
3
3
|
attr_accessor :args, :options
|
|
4
4
|
|
|
5
5
|
def initialize(*args)
|
|
6
|
+
ThinkingSphinx.context.define_indexes
|
|
7
|
+
|
|
6
8
|
@options = args.extract_options!
|
|
7
9
|
@args = args
|
|
8
10
|
|
|
@@ -42,29 +44,27 @@ module ThinkingSphinx
|
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
def populate
|
|
45
|
-
facet_names
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
end
|
|
47
|
+
ThinkingSphinx::Search.bundle_searches(facet_names) { |sphinx, name|
|
|
48
|
+
sphinx.search *(args + [facet_search_options(name)])
|
|
49
|
+
}.each_with_index { |search, index|
|
|
50
|
+
add_from_results facet_names[index], search
|
|
51
|
+
}
|
|
51
52
|
end
|
|
52
53
|
|
|
53
|
-
def facet_search_options
|
|
54
|
-
config = ThinkingSphinx::Configuration.instance
|
|
55
|
-
max = config.configuration.searchd.max_matches || 1000
|
|
56
|
-
|
|
54
|
+
def facet_search_options(facet_name)
|
|
57
55
|
options.merge(
|
|
58
56
|
:group_function => :attr,
|
|
59
|
-
:limit =>
|
|
60
|
-
:max_matches =>
|
|
61
|
-
:page => 1
|
|
57
|
+
:limit => max_matches,
|
|
58
|
+
:max_matches => max_matches,
|
|
59
|
+
:page => 1,
|
|
60
|
+
:group_by => facet_name,
|
|
61
|
+
:ids_only => !translate?(facet_name)
|
|
62
62
|
)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def facet_classes
|
|
66
66
|
(
|
|
67
|
-
options[:classes] || ThinkingSphinx.indexed_models.collect { |model|
|
|
67
|
+
options[:classes] || ThinkingSphinx.context.indexed_models.collect { |model|
|
|
68
68
|
model.constantize
|
|
69
69
|
}
|
|
70
70
|
).select { |klass| klass.sphinx_facets.any? }
|
|
@@ -99,21 +99,34 @@ module ThinkingSphinx
|
|
|
99
99
|
}
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
-
def
|
|
103
|
-
|
|
102
|
+
def translate?(name)
|
|
103
|
+
facet = facet_from_name(name)
|
|
104
|
+
facet.translate? || facet.float?
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def config
|
|
108
|
+
ThinkingSphinx::Configuration.instance
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def max_matches
|
|
112
|
+
@max_matches ||= config.configuration.searchd.max_matches || 1000
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# example: facet = country_facet; name = :country
|
|
116
|
+
def add_from_results(facet, search)
|
|
117
|
+
name = ThinkingSphinx::Facet.name_for(facet)
|
|
118
|
+
facet = facet_from_name(facet)
|
|
104
119
|
|
|
105
120
|
self[name] ||= {}
|
|
106
121
|
|
|
107
|
-
return if
|
|
122
|
+
return if search.empty?
|
|
108
123
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
results.each_with_groupby_and_count { |result, group, count|
|
|
112
|
-
facet_value = facet.value(result, group)
|
|
124
|
+
search.each_with_match do |result, match|
|
|
125
|
+
facet_value = facet.value(result, match[:attributes])
|
|
113
126
|
|
|
114
127
|
self[name][facet_value] ||= 0
|
|
115
|
-
self[name][facet_value] += count
|
|
116
|
-
|
|
128
|
+
self[name][facet_value] += match[:attributes]["@count"]
|
|
129
|
+
end
|
|
117
130
|
end
|
|
118
131
|
|
|
119
132
|
def underlying_value(key, value)
|
|
@@ -128,7 +141,24 @@ module ThinkingSphinx
|
|
|
128
141
|
end
|
|
129
142
|
|
|
130
143
|
def facet_from_object(object, name)
|
|
131
|
-
|
|
144
|
+
facet = nil
|
|
145
|
+
klass = object.class
|
|
146
|
+
|
|
147
|
+
while klass != ::ActiveRecord::Base && facet.nil?
|
|
148
|
+
facet = klass.sphinx_facets.detect { |facet|
|
|
149
|
+
facet.attribute_name == name
|
|
150
|
+
}
|
|
151
|
+
klass = klass.superclass
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
facet
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def facet_from_name(name)
|
|
158
|
+
name = ThinkingSphinx::Facet.name_for(name)
|
|
159
|
+
all_facets.detect { |facet|
|
|
160
|
+
facet.name == name
|
|
161
|
+
}
|
|
132
162
|
end
|
|
133
163
|
end
|
|
134
164
|
end
|
|
@@ -69,14 +69,12 @@ module ThinkingSphinx
|
|
|
69
69
|
# multiple data values (has_many or has_and_belongs_to_many associations).
|
|
70
70
|
#
|
|
71
71
|
def to_select_sql
|
|
72
|
-
clause =
|
|
73
|
-
column_with_prefix(column)
|
|
74
|
-
}.join(', ')
|
|
72
|
+
clause = columns_with_prefixes.join(', ')
|
|
75
73
|
|
|
76
74
|
clause = adapter.concatenate(clause) if concat_ws?
|
|
77
75
|
clause = adapter.group_concatenate(clause) if is_many?
|
|
78
76
|
|
|
79
|
-
"#{
|
|
77
|
+
"#{clause} AS #{quote_column(unique_name)}"
|
|
80
78
|
end
|
|
81
79
|
end
|
|
82
80
|
end
|
|
@@ -20,9 +20,9 @@ module ThinkingSphinx
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
def self.generate(model, &block)
|
|
23
|
+
def self.generate(model, name = nil, &block)
|
|
24
24
|
index = ThinkingSphinx::Index.new(model)
|
|
25
|
-
|
|
25
|
+
index.name = name unless name.nil?
|
|
26
26
|
|
|
27
27
|
Builder.new(index, &block) if block_given?
|
|
28
28
|
|
|
@@ -32,15 +32,11 @@ module ThinkingSphinx
|
|
|
32
32
|
|
|
33
33
|
def initialize(index, &block)
|
|
34
34
|
@index = index
|
|
35
|
-
@source = ThinkingSphinx::Source.new(@index)
|
|
36
|
-
@index.sources << @source
|
|
37
35
|
@explicit_source = false
|
|
38
36
|
|
|
39
37
|
self.instance_eval &block
|
|
40
38
|
|
|
41
|
-
if
|
|
42
|
-
source.fields.length == 0
|
|
43
|
-
}
|
|
39
|
+
if no_fields?
|
|
44
40
|
raise "At least one field is necessary for an index"
|
|
45
41
|
end
|
|
46
42
|
end
|
|
@@ -105,7 +101,7 @@ module ThinkingSphinx
|
|
|
105
101
|
def indexes(*args)
|
|
106
102
|
options = args.extract_options!
|
|
107
103
|
args.each do |columns|
|
|
108
|
-
field = Field.new(
|
|
104
|
+
field = Field.new(source, FauxColumn.coerce(columns), options)
|
|
109
105
|
|
|
110
106
|
add_sort_attribute field, options if field.sortable
|
|
111
107
|
add_facet_attribute field, options if field.faceted
|
|
@@ -123,13 +119,13 @@ module ThinkingSphinx
|
|
|
123
119
|
# database.
|
|
124
120
|
#
|
|
125
121
|
# Attributes are limited to the following types: integers, floats,
|
|
126
|
-
# datetimes (converted to timestamps), booleans and
|
|
127
|
-
# forget that Sphinx converts string attributes to
|
|
128
|
-
# useful for sorting, but that's about it.
|
|
122
|
+
# datetimes (converted to timestamps), booleans, strings and MVAs
|
|
123
|
+
# (:multi). Don't forget that Sphinx converts string attributes to
|
|
124
|
+
# integers, which are useful for sorting, but that's about it.
|
|
129
125
|
#
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
126
|
+
# Collection of integers are known as multi-value attributes (MVAs).
|
|
127
|
+
# Generally these would be through a has_many relationship, like in this
|
|
128
|
+
# example:
|
|
133
129
|
#
|
|
134
130
|
# has posts(:id), :as => :post_ids
|
|
135
131
|
#
|
|
@@ -151,7 +147,7 @@ module ThinkingSphinx
|
|
|
151
147
|
def has(*args)
|
|
152
148
|
options = args.extract_options!
|
|
153
149
|
args.each do |columns|
|
|
154
|
-
attribute = Attribute.new(
|
|
150
|
+
attribute = Attribute.new(source, FauxColumn.coerce(columns), options)
|
|
155
151
|
|
|
156
152
|
add_facet_attribute attribute, options if attribute.faceted
|
|
157
153
|
end
|
|
@@ -162,12 +158,18 @@ module ThinkingSphinx
|
|
|
162
158
|
options[:facet] = true
|
|
163
159
|
|
|
164
160
|
args.each do |columns|
|
|
165
|
-
attribute = Attribute.new(
|
|
161
|
+
attribute = Attribute.new(source, FauxColumn.coerce(columns), options)
|
|
166
162
|
|
|
167
163
|
add_facet_attribute attribute, options
|
|
168
164
|
end
|
|
169
165
|
end
|
|
170
166
|
|
|
167
|
+
def join(*args)
|
|
168
|
+
args.each do |association|
|
|
169
|
+
Join.new(source, association)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
171
173
|
# Use this method to add some manual SQL conditions for your index
|
|
172
174
|
# request. You can pass in as many strings as you like, they'll get
|
|
173
175
|
# joined together with ANDs later on.
|
|
@@ -176,7 +178,7 @@ module ThinkingSphinx
|
|
|
176
178
|
# where "parent_type = 'Article'", "created_at < NOW()"
|
|
177
179
|
#
|
|
178
180
|
def where(*args)
|
|
179
|
-
|
|
181
|
+
source.conditions += args
|
|
180
182
|
end
|
|
181
183
|
|
|
182
184
|
# Use this method to add some manual SQL strings to the GROUP BY
|
|
@@ -186,7 +188,7 @@ module ThinkingSphinx
|
|
|
186
188
|
# group_by "lat", "lng"
|
|
187
189
|
#
|
|
188
190
|
def group_by(*args)
|
|
189
|
-
|
|
191
|
+
source.groupings += args
|
|
190
192
|
end
|
|
191
193
|
|
|
192
194
|
# This is what to use to set properties on the index. Chief amongst
|
|
@@ -251,10 +253,18 @@ module ThinkingSphinx
|
|
|
251
253
|
|
|
252
254
|
private
|
|
253
255
|
|
|
256
|
+
def source
|
|
257
|
+
@source ||= begin
|
|
258
|
+
source = ThinkingSphinx::Source.new(@index)
|
|
259
|
+
@index.sources << source
|
|
260
|
+
source
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
254
264
|
def set_single_property(key, value)
|
|
255
265
|
source_options = ThinkingSphinx::Configuration::SourceOptions
|
|
256
266
|
if source_options.include?(key.to_s)
|
|
257
|
-
|
|
267
|
+
source.options.merge! key => value
|
|
258
268
|
else
|
|
259
269
|
@index.local_options.merge! key => value
|
|
260
270
|
end
|
|
@@ -272,7 +282,7 @@ module ThinkingSphinx
|
|
|
272
282
|
def add_internal_attribute(property, options, suffix, crc = false)
|
|
273
283
|
return unless ThinkingSphinx::Facet.translate?(property)
|
|
274
284
|
|
|
275
|
-
Attribute.new(
|
|
285
|
+
Attribute.new(source,
|
|
276
286
|
property.columns.collect { |col| col.clone },
|
|
277
287
|
options.merge(
|
|
278
288
|
:type => property.is_a?(Field) ? :string : options[:type],
|
|
@@ -281,6 +291,12 @@ module ThinkingSphinx
|
|
|
281
291
|
).except(:facet)
|
|
282
292
|
)
|
|
283
293
|
end
|
|
294
|
+
|
|
295
|
+
def no_fields?
|
|
296
|
+
@index.sources.empty? || @index.sources.any? { |source|
|
|
297
|
+
source.fields.length == 0
|
|
298
|
+
}
|
|
299
|
+
end
|
|
284
300
|
end
|
|
285
301
|
end
|
|
286
302
|
end
|
|
@@ -42,6 +42,10 @@ module ThinkingSphinx
|
|
|
42
42
|
@stack
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
def __path
|
|
46
|
+
@stack + [@name]
|
|
47
|
+
end
|
|
48
|
+
|
|
45
49
|
# Returns true if the stack is empty *and* if the name is a string -
|
|
46
50
|
# which is an indication that of raw SQL, as opposed to a value from a
|
|
47
51
|
# table's column.
|
|
@@ -50,6 +54,10 @@ module ThinkingSphinx
|
|
|
50
54
|
@name.is_a?(String) && @stack.empty?
|
|
51
55
|
end
|
|
52
56
|
|
|
57
|
+
def to_ary
|
|
58
|
+
[self]
|
|
59
|
+
end
|
|
60
|
+
|
|
53
61
|
# This handles any 'invalid' method calls and sets them as the name,
|
|
54
62
|
# and pushing the previous name into the stack. The object returns
|
|
55
63
|
# itself.
|
|
@@ -2,14 +2,8 @@ require 'thinking_sphinx/index/builder'
|
|
|
2
2
|
require 'thinking_sphinx/index/faux_column'
|
|
3
3
|
|
|
4
4
|
module ThinkingSphinx
|
|
5
|
-
# The Index class is a ruby representation of a Sphinx source (not a Sphinx
|
|
6
|
-
# index - yes, I know it's a little confusing. You'll manage). This is
|
|
7
|
-
# another 'internal' Thinking Sphinx class - if you're using it directly,
|
|
8
|
-
# you either know what you're doing, or messing with things beyond your ken.
|
|
9
|
-
# Enjoy.
|
|
10
|
-
#
|
|
11
5
|
class Index
|
|
12
|
-
attr_accessor :model, :sources, :delta_object
|
|
6
|
+
attr_accessor :name, :model, :sources, :delta_object
|
|
13
7
|
|
|
14
8
|
# Create a new index instance by passing in the model it is tied to, and
|
|
15
9
|
# a block to build it with (optional but recommended). For documentation
|
|
@@ -26,6 +20,7 @@ module ThinkingSphinx
|
|
|
26
20
|
# end
|
|
27
21
|
#
|
|
28
22
|
def initialize(model, &block)
|
|
23
|
+
@name = self.class.name_for model
|
|
29
24
|
@model = model
|
|
30
25
|
@sources = []
|
|
31
26
|
@options = {}
|
|
@@ -40,8 +35,19 @@ module ThinkingSphinx
|
|
|
40
35
|
@sources.collect { |source| source.attributes }.flatten
|
|
41
36
|
end
|
|
42
37
|
|
|
43
|
-
def
|
|
44
|
-
|
|
38
|
+
def core_name
|
|
39
|
+
"#{name}_core"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def delta_name
|
|
43
|
+
"#{name}_delta"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def all_names
|
|
47
|
+
names = [core_name]
|
|
48
|
+
names << delta_name if delta?
|
|
49
|
+
|
|
50
|
+
names
|
|
45
51
|
end
|
|
46
52
|
|
|
47
53
|
def self.name_for(model)
|
|
@@ -61,7 +67,7 @@ module ThinkingSphinx
|
|
|
61
67
|
end
|
|
62
68
|
|
|
63
69
|
def options
|
|
64
|
-
all_index_options =
|
|
70
|
+
all_index_options = config.index_options.clone
|
|
65
71
|
@options.keys.select { |key|
|
|
66
72
|
ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s) ||
|
|
67
73
|
ThinkingSphinx::Configuration::CustomOptions.include?(key.to_s)
|
|
@@ -73,6 +79,12 @@ module ThinkingSphinx
|
|
|
73
79
|
!@delta_object.nil?
|
|
74
80
|
end
|
|
75
81
|
|
|
82
|
+
def to_riddle(offset)
|
|
83
|
+
indexes = [to_riddle_for_core(offset)]
|
|
84
|
+
indexes << to_riddle_for_delta(offset) if delta?
|
|
85
|
+
indexes << to_riddle_for_distributed
|
|
86
|
+
end
|
|
87
|
+
|
|
76
88
|
private
|
|
77
89
|
|
|
78
90
|
def adapter
|
|
@@ -83,17 +95,63 @@ module ThinkingSphinx
|
|
|
83
95
|
options[:charset_type] == "utf-8"
|
|
84
96
|
end
|
|
85
97
|
|
|
86
|
-
# Does all the magic with the block provided to the base #initialize.
|
|
87
|
-
# Creates a new class subclassed from Builder, and evaluates the block
|
|
88
|
-
# on it, then pulls all relevant settings - fields, attributes, conditions,
|
|
89
|
-
# properties - into the new index.
|
|
90
|
-
#
|
|
91
|
-
def initialize_from_builder(&block)
|
|
92
|
-
#
|
|
93
|
-
end
|
|
94
|
-
|
|
95
98
|
def sql_query_pre_for_delta
|
|
96
99
|
[""]
|
|
97
100
|
end
|
|
101
|
+
|
|
102
|
+
def config
|
|
103
|
+
@config ||= ThinkingSphinx::Configuration.instance
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def to_riddle_for_core(offset)
|
|
107
|
+
index = Riddle::Configuration::Index.new core_name
|
|
108
|
+
index.path = File.join config.searchd_file_path, index.name
|
|
109
|
+
|
|
110
|
+
set_configuration_options_for_indexes index
|
|
111
|
+
set_field_settings_for_indexes index
|
|
112
|
+
|
|
113
|
+
sources.each_with_index do |source, i|
|
|
114
|
+
index.sources << source.to_riddle_for_core(offset, i)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
index
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def to_riddle_for_delta(offset)
|
|
121
|
+
index = Riddle::Configuration::Index.new delta_name
|
|
122
|
+
index.parent = core_name
|
|
123
|
+
index.path = File.join config.searchd_file_path, index.name
|
|
124
|
+
|
|
125
|
+
sources.each_with_index do |source, i|
|
|
126
|
+
index.sources << source.to_riddle_for_delta(offset, i)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
index
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def to_riddle_for_distributed
|
|
133
|
+
index = Riddle::Configuration::DistributedIndex.new name
|
|
134
|
+
index.local_indexes << core_name
|
|
135
|
+
index.local_indexes.unshift delta_name if delta?
|
|
136
|
+
index
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def set_configuration_options_for_indexes(index)
|
|
140
|
+
config.index_options.each do |key, value|
|
|
141
|
+
method = "#{key}=".to_sym
|
|
142
|
+
index.send(method, value) if index.respond_to?(method)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
options.each do |key, value|
|
|
146
|
+
index.send("#{key}=".to_sym, value) if ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s) && !value.nil?
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def set_field_settings_for_indexes(index)
|
|
151
|
+
field_names = lambda { |field| field.unique_name.to_s }
|
|
152
|
+
|
|
153
|
+
index.prefix_field_names += prefix_fields.collect(&field_names)
|
|
154
|
+
index.infix_field_names += infix_fields.collect(&field_names)
|
|
155
|
+
end
|
|
98
156
|
end
|
|
99
157
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module ThinkingSphinx
|
|
2
|
+
class Join
|
|
3
|
+
attr_accessor :source, :column, :associations
|
|
4
|
+
|
|
5
|
+
def initialize(source, column)
|
|
6
|
+
@source = source
|
|
7
|
+
@column = column
|
|
8
|
+
|
|
9
|
+
@associations = association_stack(column.__path.clone).each { |assoc|
|
|
10
|
+
assoc.join_to(source.base)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
source.joins << self
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Gets a stack of associations for a specific path.
|
|
19
|
+
#
|
|
20
|
+
def association_stack(path, parent = nil)
|
|
21
|
+
assocs = []
|
|
22
|
+
|
|
23
|
+
if parent.nil?
|
|
24
|
+
assocs = @source.association(path.shift)
|
|
25
|
+
else
|
|
26
|
+
assocs = parent.children(path.shift)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
until path.empty?
|
|
30
|
+
point = path.shift
|
|
31
|
+
assocs = assocs.collect { |assoc| assoc.children(point) }.flatten
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
assocs
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -13,6 +13,7 @@ module ThinkingSphinx
|
|
|
13
13
|
@alias = options[:as]
|
|
14
14
|
@faceted = options[:facet]
|
|
15
15
|
@admin = options[:admin]
|
|
16
|
+
@sortable = options[:sortable] || false
|
|
16
17
|
|
|
17
18
|
@alias = @alias.to_sym unless @alias.blank?
|
|
18
19
|
|
|
@@ -136,10 +137,16 @@ module ThinkingSphinx
|
|
|
136
137
|
assoc.has_column?(column.__name) ?
|
|
137
138
|
"#{quote_with_table(assoc.join.aliased_table_name, column.__name)}" :
|
|
138
139
|
nil
|
|
139
|
-
}.compact
|
|
140
|
+
}.compact
|
|
140
141
|
end
|
|
141
142
|
end
|
|
142
143
|
|
|
144
|
+
def columns_with_prefixes
|
|
145
|
+
@columns.collect { |column|
|
|
146
|
+
column_with_prefix column
|
|
147
|
+
}.flatten
|
|
148
|
+
end
|
|
149
|
+
|
|
143
150
|
# Gets a stack of associations for a specific path.
|
|
144
151
|
#
|
|
145
152
|
def association_stack(path, parent = nil)
|
|
@@ -159,4 +166,4 @@ module ThinkingSphinx
|
|
|
159
166
|
assocs
|
|
160
167
|
end
|
|
161
168
|
end
|
|
162
|
-
end
|
|
169
|
+
end
|
|
@@ -136,8 +136,8 @@ Class.extend(
|
|
|
136
136
|
) unless Class.respond_to?(:cattr_reader)
|
|
137
137
|
|
|
138
138
|
module ThinkingSphinx
|
|
139
|
-
module
|
|
140
|
-
def
|
|
139
|
+
module SingletonClass
|
|
140
|
+
def singleton_class
|
|
141
141
|
class << self
|
|
142
142
|
self
|
|
143
143
|
end
|
|
@@ -145,6 +145,6 @@ module ThinkingSphinx
|
|
|
145
145
|
end
|
|
146
146
|
end
|
|
147
147
|
|
|
148
|
-
unless Object.new.respond_to?(:
|
|
149
|
-
Object.send(:include, ThinkingSphinx::
|
|
148
|
+
unless Object.new.respond_to?(:singleton_class)
|
|
149
|
+
Object.send(:include, ThinkingSphinx::SingletonClass)
|
|
150
150
|
end
|