freelancing-god-thinking-sphinx 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -94,3 +94,8 @@ Since I first released this library, there's been quite a few people who have su
94
94
  - Henrik Nyh
95
95
  - Emil Tin
96
96
  - Doug Cole
97
+ - Ed Hickey
98
+ - Evan Weaver
99
+ - Thibaut Barrere
100
+ - Kristopher Chambers
101
+ - Dmitrij Smalko
@@ -31,7 +31,7 @@ module ThinkingSphinx
31
31
  module Version #:nodoc:
32
32
  Major = 1
33
33
  Minor = 1
34
- Tiny = 1
34
+ Tiny = 2
35
35
 
36
36
  String = [Major, Minor, Tiny].join('.')
37
37
  end
@@ -131,13 +131,11 @@ module ThinkingSphinx
131
131
  end
132
132
 
133
133
  def self.sphinx_running?
134
- pid_file = ThinkingSphinx::Configuration.instance.pid_file
135
-
136
- if pid_file && File.exists?(pid_file)
137
- pid = `cat #{pid_file}`[/\d+/]
138
- `ps -p #{pid} | wc -l`.to_i > 1
139
- else
140
- false
141
- end
134
+ !!sphinx_pid
135
+ end
136
+
137
+ def self.sphinx_pid
138
+ pid_file = ThinkingSphinx::Configuration.instance.pid_file
139
+ `cat #{pid_file}`[/\d+/] if File.exists?(pid_file)
142
140
  end
143
141
  end
@@ -42,7 +42,11 @@ module ThinkingSphinx
42
42
  # if running in the test environment.
43
43
  #
44
44
  def index_delta(instance = nil)
45
- self.sphinx_indexes.first.delta_object.index(self, instance)
45
+ delta_object.index(self, instance)
46
+ end
47
+
48
+ def delta_object
49
+ self.sphinx_indexes.first.delta_object
46
50
  end
47
51
  end
48
52
 
@@ -50,14 +54,18 @@ module ThinkingSphinx
50
54
 
51
55
  # Set the delta value for the model to be true.
52
56
  def toggle_delta
53
- self.class.sphinx_indexes.first.delta_object.toggle(self)
57
+ self.class.delta_object.toggle(self) if should_toggle_delta?
54
58
  end
55
59
 
56
60
  # Build the delta index for the related model. This won't be called
57
61
  # if running in the test environment.
58
62
  #
59
63
  def index_delta
60
- self.class.index_delta(self)
64
+ self.class.index_delta(self) if self.class.delta_object.toggled(self)
65
+ end
66
+
67
+ def should_toggle_delta?
68
+ !self.respond_to?(:changed?) || self.changed? || self.new_record?
61
69
  end
62
70
  end
63
71
  end
@@ -175,7 +175,7 @@ module ThinkingSphinx
175
175
  when "ActiveRecord::ConnectionAdapters::MysqlAdapter"
176
176
  "UNIX_TIMESTAMP(#{clause})"
177
177
  when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
178
- clause # Rails' datetimes are timestamps in PostgreSQL
178
+ "cast(extract(epoch from #{clause}) as int)"
179
179
  else
180
180
  clause
181
181
  end
@@ -263,11 +263,7 @@ module ThinkingSphinx
263
263
  when @associations.values.flatten.length > 1
264
264
  :string
265
265
  else
266
- klass = @associations.values.flatten.first ?
267
- @associations.values.flatten.first.reflection.klass : @model
268
- klass.columns.detect { |col|
269
- @columns.collect { |c| c.__name.to_s }.include? col.name
270
- }.type
266
+ translated_type_from_database
271
267
  end
272
268
  end
273
269
 
@@ -281,5 +277,33 @@ module ThinkingSphinx
281
277
  }
282
278
  }
283
279
  end
280
+
281
+ def type_from_database
282
+ klass = @associations.values.flatten.first ?
283
+ @associations.values.flatten.first.reflection.klass : @model
284
+
285
+ klass.columns.detect { |col|
286
+ @columns.collect { |c| c.__name.to_s }.include? col.name
287
+ }.type
288
+ end
289
+
290
+ def translated_type_from_database
291
+ case type_from_db = type_from_database
292
+ when :datetime, :string, :float, :boolean, :integer
293
+ type_from_db
294
+ when :decimal
295
+ :float
296
+ when :timestamp, :date
297
+ :datetime
298
+ else
299
+ raise <<-MESSAGE
300
+
301
+ Cannot automatically map column type #{type_from_db} to an equivalent Sphinx
302
+ type (integer, float, boolean, datetime, string as ordinal). You could try to
303
+ explicitly convert the column's value in your define_index block:
304
+ has "CAST(column AS INT)", :type => :integer, :as => :column
305
+ MESSAGE
306
+ end
307
+ end
284
308
  end
285
309
  end
@@ -55,7 +55,7 @@ module ThinkingSphinx
55
55
 
56
56
  attr_accessor :config_file, :searchd_log_file, :query_log_file,
57
57
  :pid_file, :searchd_file_path, :address, :port, :allow_star,
58
- :database_yml_file, :app_root, :bin_path
58
+ :database_yml_file, :app_root, :bin_path, :model_directories
59
59
 
60
60
  attr_accessor :source_options, :index_options
61
61
 
@@ -85,6 +85,7 @@ module ThinkingSphinx
85
85
  self.searchd_file_path = "#{self.app_root}/db/sphinx/#{environment}"
86
86
  self.allow_star = false
87
87
  self.bin_path = ""
88
+ self.model_directories = ["#{app_root}/app/models/"]
88
89
 
89
90
  self.source_options = {}
90
91
  self.index_options = {
@@ -135,21 +136,22 @@ module ThinkingSphinx
135
136
  # messy dependencies issues).
136
137
  #
137
138
  def load_models
138
- base = "#{app_root}/app/models/"
139
- Dir["#{base}**/*.rb"].each do |file|
140
- model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
139
+ self.model_directories.each do |base|
140
+ Dir["#{base}**/*.rb"].each do |file|
141
+ model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
141
142
 
142
- next if model_name.nil?
143
- next if ::ActiveRecord::Base.send(:subclasses).detect { |model|
144
- model.name == model_name
145
- }
143
+ next if model_name.nil?
144
+ next if ::ActiveRecord::Base.send(:subclasses).detect { |model|
145
+ model.name == model_name
146
+ }
146
147
 
147
- begin
148
- model_name.camelize.constantize
149
- rescue LoadError
150
- model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
151
- rescue NameError
152
- next
148
+ begin
149
+ model_name.camelize.constantize
150
+ rescue LoadError
151
+ model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
152
+ rescue NameError
153
+ next
154
+ end
153
155
  end
154
156
  end
155
157
  end
@@ -240,6 +242,11 @@ module ThinkingSphinx
240
242
  end unless conf.nil?
241
243
 
242
244
  self.bin_path += '/' unless self.bin_path.blank?
245
+
246
+ if self.allow_star
247
+ self.index_options[:enable_star] = true
248
+ self.index_options[:min_prefix_len] = 1
249
+ end
243
250
  end
244
251
 
245
252
  def set_sphinx_setting(object, key, value, allowed = {})
@@ -1,5 +1,6 @@
1
1
  require 'thinking_sphinx/deltas/default_delta'
2
2
  require 'thinking_sphinx/deltas/delayed_delta'
3
+ require 'thinking_sphinx/deltas/datetime_delta'
3
4
 
4
5
  module ThinkingSphinx
5
6
  module Deltas
@@ -9,6 +10,8 @@ module ThinkingSphinx
9
10
  DefaultDelta.new index, options
10
11
  when :delayed
11
12
  DelayedDelta.new index, options
13
+ when :datetime
14
+ DatetimeDelta.new index, options
12
15
  when FalseClass, nil
13
16
  nil
14
17
  else
@@ -0,0 +1,61 @@
1
+ module ThinkingSphinx
2
+ module Deltas
3
+ class DatetimeDelta < ThinkingSphinx::Deltas::DefaultDelta
4
+ attr_accessor :column, :threshold
5
+
6
+ def initialize(index, options)
7
+ @index = index
8
+ @column = options.delete(:delta_column) || :updated_at
9
+ @threshold = options.delete(:threshold) || 1.day
10
+ end
11
+
12
+ def index(model, instance = nil)
13
+ # do nothing
14
+ true
15
+ end
16
+
17
+ def delayed_index(model)
18
+ config = ThinkingSphinx::Configuration.instance
19
+ rotate = ThinkingSphinx.sphinx_running? ? "--rotate" : ""
20
+
21
+ output = `#{config.bin_path}indexer --config #{config.config_file} #{rotate} #{delta_index_name model}`
22
+ output += `#{config.bin_path}indexer --config #{config.config_file} #{rotate} --merge #{core_index_name model} #{delta_index_name model} --merge-dst-range sphinx_deleted 0 0`
23
+ puts output unless ThinkingSphinx.suppress_delta_output?
24
+
25
+ true
26
+ end
27
+
28
+ def toggle(instance)
29
+ # do nothing
30
+ end
31
+
32
+ def toggled(instance)
33
+ instance.send(@column) > @threshold.ago
34
+ end
35
+
36
+ def reset_query(model)
37
+ nil
38
+ end
39
+
40
+ def clause(model, toggled)
41
+ if toggled
42
+ "#{model.quoted_table_name}.#{@index.quote_column(@column.to_s)}" +
43
+ " > #{time_difference}"
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ def time_difference
50
+ case @index.adapter
51
+ when :mysql
52
+ "DATE_SUB(NOW(), INTERVAL #{@threshold} SECOND)"
53
+ when :postgres
54
+ "current_timestamp - interval '#{@threshold} seconds'"
55
+ else
56
+ raise "Unknown Database Adapter"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -5,7 +5,7 @@ module ThinkingSphinx
5
5
 
6
6
  def initialize(index, options)
7
7
  @index = index
8
- @column = options.delete(:column) || :delta
8
+ @column = options.delete(:delta_column) || :delta
9
9
  end
10
10
 
11
11
  def index(model, instance = nil)
@@ -31,6 +31,15 @@ module ThinkingSphinx
31
31
  instance.delta = true
32
32
  end
33
33
 
34
+ def toggled(instance)
35
+ instance.delta
36
+ end
37
+
38
+ def reset_query(model)
39
+ "UPDATE #{model.quoted_table_name} SET " +
40
+ "#{@index.quote_column(@column.to_s)} = #{@index.db_boolean(false)}"
41
+ end
42
+
34
43
  def clause(model, toggled)
35
44
  "#{model.quoted_table_name}.#{@index.quote_column(@column.to_s)}" +
36
45
  " = #{@index.db_boolean(toggled)}"
@@ -44,7 +53,7 @@ module ThinkingSphinx
44
53
 
45
54
  def delta_index_name(model)
46
55
  "#{model.source_of_sphinx_index.name.underscore.tr(':/\\', '_')}_delta"
47
- end
56
+ end
48
57
  end
49
58
  end
50
59
  end
@@ -126,7 +126,7 @@ module ThinkingSphinx
126
126
  assocs = all_associations
127
127
 
128
128
  where_clause = ""
129
- if self.delta?
129
+ if self.delta? && !@delta_object.clause(@model, options[:delta]).blank?
130
130
  where_clause << " AND #{@delta_object.clause(@model, options[:delta])}"
131
131
  end
132
132
  unless @conditions.empty?
@@ -190,7 +190,10 @@ GROUP BY #{ (
190
190
 
191
191
  sql = "SELECT #{min_statement}, #{max_statement} " +
192
192
  "FROM #{@model.quoted_table_name} "
193
- sql << "WHERE #{@delta_object.clause(@model, options[:delta])}" if self.delta?
193
+ if self.delta? && !@delta_object.clause(@model, options[:delta]).blank?
194
+ sql << "WHERE #{@delta_object.clause(@model, options[:delta])}"
195
+ end
196
+
194
197
  sql
195
198
  end
196
199
 
@@ -436,8 +439,8 @@ GROUP BY #{ (
436
439
  end
437
440
 
438
441
  def sql_query_pre_for_core
439
- if self.delta?
440
- ["UPDATE #{@model.quoted_table_name} SET #{@delta_object.clause(@model, false)}"]
442
+ if self.delta? && !@delta_object.reset_query(@model).blank?
443
+ [@delta_object.reset_query(@model)]
441
444
  else
442
445
  []
443
446
  end
@@ -29,6 +29,18 @@ Array.send(
29
29
  :include, ThinkingSphinx::ArrayExtractOptions
30
30
  ) unless Array.instance_methods.include?("extract_options!")
31
31
 
32
+ module ThinkingSphinx
33
+ module AbstractQuotedTableName
34
+ def quote_table_name(name)
35
+ quote_column_name(name)
36
+ end
37
+ end
38
+ end
39
+
40
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.send(
41
+ :include, ThinkingSphinx::AbstractQuotedTableName
42
+ ) unless ActiveRecord::ConnectionAdapters::AbstractAdapter.instance_methods.include?("quote_table_name")
43
+
32
44
  module ThinkingSphinx
33
45
  module MysqlQuotedTableName
34
46
  def quote_table_name(name) #:nodoc:
@@ -72,7 +72,7 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
72
72
  before :each do
73
73
  ThinkingSphinx::Configuration.stub_method(:environment => "spec")
74
74
  ThinkingSphinx.stub_method(:deltas_enabled? => true, :sphinx_running? => true)
75
- Person.sphinx_indexes.first.delta_object.stub_method(:` => "")
75
+ Person.delta_object.stub_methods(:` => "", :toggled => true)
76
76
 
77
77
  @person = Person.new
78
78
  @person.stub_method(
@@ -37,8 +37,9 @@ namespace :thinking_sphinx do
37
37
  desc "Stop Sphinx using Thinking Sphinx's settings"
38
38
  task :stop => :app_env do
39
39
  raise RuntimeError, "searchd is not running." unless sphinx_running?
40
- pid = sphinx_pid
41
- system "kill #{pid}"
40
+ config = ThinkingSphinx::Configuration.instance
41
+ pid = sphinx_pid
42
+ system "searchd --stop --config #{config.config_file}"
42
43
  puts "Stopped search daemon (pid #{pid})."
43
44
  end
44
45
 
@@ -69,8 +70,22 @@ namespace :thinking_sphinx do
69
70
  system cmd
70
71
  end
71
72
 
73
+ namespace :index do
74
+ task :delta => :app_env do
75
+ ThinkingSphinx.indexed_models.select { |model|
76
+ model.constantize.sphinx_indexes.any? { |index| index.delta? }
77
+ }.each do |model|
78
+ model.constantize.sphinx_indexes.select { |index|
79
+ index.delta? && index.delta_object.respond_to?(:delayed_index)
80
+ }.each { |index|
81
+ index.delta_object.delayed_index(index.model)
82
+ }
83
+ end
84
+ end
85
+ end
86
+
72
87
  desc "Process stored delta index requests"
73
- task :delta => :app_env do
88
+ task :delayed_delta => :app_env do
74
89
  require 'delayed/worker'
75
90
 
76
91
  Delayed::Worker.new(
@@ -90,6 +105,9 @@ namespace :ts do
90
105
  desc "Index data for Sphinx using Thinking Sphinx's settings"
91
106
  task :in => "thinking_sphinx:index"
92
107
  desc "Index data for Sphinx using Thinking Sphinx's settings"
108
+ namespace :in do
109
+ task :delta => "thinking_sphinx:index:delta"
110
+ end
93
111
  task :index => "thinking_sphinx:index"
94
112
  desc "Restart Sphinx"
95
113
  task :restart => "thinking_sphinx:restart"
@@ -98,19 +116,13 @@ namespace :ts do
98
116
  desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
99
117
  task :config => "thinking_sphinx:configure"
100
118
  desc "Process stored delta index requests"
101
- task :delta => "thinking_sphinx:delta"
119
+ task :dd => "thinking_sphinx:delayed_delta"
102
120
  end
103
121
 
104
122
  def sphinx_pid
105
- config = ThinkingSphinx::Configuration.instance
106
-
107
- if File.exists?(config.pid_file)
108
- `cat #{config.pid_file}`[/\d+/]
109
- else
110
- nil
111
- end
123
+ ThinkingSphinx.sphinx_pid
112
124
  end
113
125
 
114
126
  def sphinx_running?
115
- sphinx_pid && `ps -p #{sphinx_pid} | wc -l`.to_i > 1
127
+ ThinkingSphinx.sphinx_running?
116
128
  end
@@ -10,7 +10,7 @@ module Riddle
10
10
  cmd << " --rotate" if running?
11
11
  `#{cmd}`
12
12
  end
13
-
13
+
14
14
  def start
15
15
  return if running?
16
16
 
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.1
4
+ version: 1.1.2
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-01-03 00:00:00 -08:00
12
+ date: 2009-01-08 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,6 +33,7 @@ files:
33
33
  - lib/thinking_sphinx/attribute.rb
34
34
  - lib/thinking_sphinx/collection.rb
35
35
  - lib/thinking_sphinx/configuration.rb
36
+ - lib/thinking_sphinx/deltas/datetime_delta.rb
36
37
  - lib/thinking_sphinx/deltas/default_delta.rb
37
38
  - lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb
38
39
  - lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb