ultrasphinx 1.8 → 1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data.tar.gz.sig +1 -3
  2. data/CHANGELOG +4 -0
  3. data/DEPLOYMENT_NOTES +7 -3
  4. data/Manifest +10 -0
  5. data/RAKE_TASKS +4 -2
  6. data/README +35 -18
  7. data/TODO +0 -1
  8. data/examples/default.base +24 -19
  9. data/lib/ultrasphinx.rb +1 -1
  10. data/lib/ultrasphinx/configure.rb +66 -25
  11. data/lib/ultrasphinx/core_extensions.rb +10 -1
  12. data/lib/ultrasphinx/is_indexed.rb +49 -6
  13. data/lib/ultrasphinx/search.rb +81 -69
  14. data/lib/ultrasphinx/search/internals.rb +61 -38
  15. data/lib/ultrasphinx/search/parser.rb +17 -7
  16. data/lib/ultrasphinx/ultrasphinx.rb +69 -16
  17. data/tasks/ultrasphinx.rake +47 -29
  18. data/test/config/ultrasphinx/test.base +50 -21
  19. data/test/integration/app/app/models/geo/address.rb +2 -1
  20. data/test/integration/app/app/models/person/user.rb +12 -3
  21. data/test/integration/app/app/models/seller.rb +2 -1
  22. data/test/integration/app/config/environment.rb +2 -0
  23. data/test/integration/app/config/ultrasphinx/default.base +16 -8
  24. data/test/integration/app/config/ultrasphinx/development.conf +319 -0
  25. data/test/integration/app/config/ultrasphinx/development.conf.canonical +152 -24
  26. data/test/integration/app/db/schema.rb +56 -0
  27. data/test/integration/app/test/fixtures/sellers.yml +1 -1
  28. data/test/integration/app/test/fixtures/users.yml +1 -1
  29. data/test/integration/app/test/unit/country_test.rb +8 -0
  30. data/test/integration/delta_test.rb +39 -0
  31. data/test/integration/search_test.rb +60 -1
  32. data/test/integration/spell_test.rb +6 -2
  33. data/test/profile/benchmark.rb +44 -0
  34. data/test/test_helper.rb +6 -1
  35. data/test/unit/parser_test.rb +21 -2
  36. data/ultrasphinx.gemspec +4 -4
  37. data/vendor/riddle/README +2 -2
  38. data/vendor/riddle/lib/riddle.rb +1 -1
  39. data/vendor/riddle/lib/riddle/client.rb +45 -10
  40. data/vendor/riddle/spec/fixtures/data/anchor.bin +0 -0
  41. data/vendor/riddle/spec/fixtures/data/any.bin +0 -0
  42. data/vendor/riddle/spec/fixtures/data/boolean.bin +0 -0
  43. data/vendor/riddle/spec/fixtures/data/distinct.bin +0 -0
  44. data/vendor/riddle/spec/fixtures/data/field_weights.bin +0 -0
  45. data/vendor/riddle/spec/fixtures/data/filter.bin +0 -0
  46. data/vendor/riddle/spec/fixtures/data/group.bin +0 -0
  47. data/vendor/riddle/spec/fixtures/data/index.bin +0 -0
  48. data/vendor/riddle/spec/fixtures/data/index_weights.bin +0 -0
  49. data/vendor/riddle/spec/fixtures/data/phrase.bin +0 -0
  50. data/vendor/riddle/spec/fixtures/data/rank_mode.bin +0 -0
  51. data/vendor/riddle/spec/fixtures/data/simple.bin +0 -0
  52. data/vendor/riddle/spec/fixtures/data/sort.bin +0 -0
  53. data/vendor/riddle/spec/fixtures/data/update_simple.bin +0 -0
  54. data/vendor/riddle/spec/fixtures/data/weights.bin +0 -0
  55. data/vendor/riddle/spec/fixtures/data_generator.php +130 -0
  56. data/vendor/riddle/spec/fixtures/sphinxapi.php +1066 -0
  57. data/vendor/riddle/spec/spec_helper.rb +1 -0
  58. data/vendor/riddle/spec/unit/client_spec.rb +18 -4
  59. metadata +12 -2
  60. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
@@ -1,3 +1 @@
1
- U���%艠�}L~�@�0XU׸�
2
- �%�g($�.���#`������h�W����z\_{wo�N��@rf����4�EAʭ?��l��������П�;�g���͠v���
3
- �[�>A���"F������3d|�[4�Z������z�mD��E$`sˎ���b�+��*Q�ߩp�R`��#~"�׏�B�T��
1
+ (Qr��u '�9���_�U؇�4]�;��x�*����oA����[Y�?�.0�,7�˗�K�ƛ8@<�j�':��4|�F����)�ɝ�}a�m��g8E#�D^+(aX]LM�k�|��EL_P�b<�JU$����>��kr��>�Pp!�g ��m�Xy�T� �ZI��M�DB&�K�w��� �E���W�~�6��=���qO� v$��1!��u�Qȷ�n��5A�ٳ����=V��lz6Il
data/CHANGELOG CHANGED
@@ -1,4 +1,8 @@
1
1
 
2
+ v1.9. Delta indexing. ERb now supported in .base files. Allow setting the searched indexes at runtime.
3
+
4
+ v1.8.1. Use multifind/multiget for record loading; avoid using HashWithIndifferentAccess internally for speed; other minor performance improvements.
5
+
2
6
  v1.8. Update client for compatibility with Sphinx 0.9.8 r1112. This is a breaking release! You need to update Sphinx along with Ultrasphinx. Float range bugfix; text faceting on association_include bugfix. Postgres users, please note that the return type of CRC32() has changed to bigint.
3
7
 
4
8
  v1.7. Deployment docs. Postgres fixes. Support association_name instead of class_name (Daniel Higginbotham).
data/DEPLOYMENT_NOTES CHANGED
@@ -15,12 +15,16 @@ You will <b>not</b> want to keep the generated <tt>development.conf</tt> in the
15
15
 
16
16
  It's easy to keep the search daemon and the indexer running in a production environment. Cronjobs are the best way:
17
17
 
18
- 0,30 * * * * bash -c 'cd /path/to/production/current/; RAILS_ENV=production \
19
- rake ultrasphinx:index >> /log/ultrasphinx-index.log 2>&1'
18
+ */6 * * * * bash -c 'cd /path/to/production/current/; RAILS_ENV=production \
19
+ rake ultrasphinx:index:delta >> /log/ultrasphinx-index.log 2>&1'
20
+ 1 4 * * * * bash -c 'cd /path/to/production/current/; RAILS_ENV=production \
21
+ rake ultrasphinx:index:main >> /log/ultrasphinx-index.log 2>&1'
20
22
  */3 * * * * bash -c 'cd /path/to/production/current/; RAILS_ENV=production \
21
23
  rake ultrasphinx:daemon:start >> /log/ultrasphinx-daemon.log 2>&1'
22
24
 
23
- The first line runs the indexer every thirty minutes. The second line will try to restart the search daemon every three minutes. If it's already running, nothing happens.
25
+ The first line reindexes the delta index every 10 minutes. The second line reindexes the main index once a day at 4am. The third line will try to restart the search daemon every three minutes. If it's already running, nothing happens.
26
+
27
+ Of course if you don't have any models with deltas, don't include the <tt>ultrasphinx:index:delta</tt> task.
24
28
 
25
29
  If you are under severe memory limitations you might want to manage the daemon with Monit instead, so you can keep a closer eye on it. The search daemon is extremely reliable, so don't bother with fancy monitoring infrastructure unless you're sure you need it.
26
30
 
data/Manifest CHANGED
@@ -71,6 +71,7 @@ test/integration/app/config/environments/test.rb
71
71
  test/integration/app/config/locomotive.yml
72
72
  test/integration/app/config/routes.rb
73
73
  test/integration/app/config/ultrasphinx/default.base
74
+ test/integration/app/config/ultrasphinx/development.conf
74
75
  test/integration/app/config/ultrasphinx/development.conf.canonical
75
76
  test/integration/app/db/migrate/001_create_users.rb
76
77
  test/integration/app/db/migrate/002_create_sellers.rb
@@ -81,6 +82,7 @@ test/integration/app/db/migrate/006_add_deleted_to_user.rb
81
82
  test/integration/app/db/migrate/007_add_lat_and_long_to_address.rb
82
83
  test/integration/app/db/migrate/008_add_mission_statement_to_seller.rb
83
84
  test/integration/app/db/migrate/009_create_countries.rb
85
+ test/integration/app/db/schema.rb
84
86
  test/integration/app/doc/README_FOR_APP
85
87
  test/integration/app/public/404.html
86
88
  test/integration/app/public/500.html
@@ -123,13 +125,16 @@ test/integration/app/test/functional/states_controller_test.rb
123
125
  test/integration/app/test/functional/users_controller_test.rb
124
126
  test/integration/app/test/test_helper.rb
125
127
  test/integration/app/test/unit/address_test.rb
128
+ test/integration/app/test/unit/country_test.rb
126
129
  test/integration/app/test/unit/seller_test.rb
127
130
  test/integration/app/test/unit/state_test.rb
128
131
  test/integration/app/test/unit/user_test.rb
129
132
  test/integration/configure_test.rb
133
+ test/integration/delta_test.rb
130
134
  test/integration/search_test.rb
131
135
  test/integration/server_test.rb
132
136
  test/integration/spell_test.rb
137
+ test/profile/benchmark.rb
133
138
  test/setup.rb
134
139
  test/teardown.rb
135
140
  test/test_all.rb
@@ -149,6 +154,7 @@ vendor/riddle/spec/fixtures/data/anchor.bin
149
154
  vendor/riddle/spec/fixtures/data/any.bin
150
155
  vendor/riddle/spec/fixtures/data/boolean.bin
151
156
  vendor/riddle/spec/fixtures/data/distinct.bin
157
+ vendor/riddle/spec/fixtures/data/field_weights.bin
152
158
  vendor/riddle/spec/fixtures/data/filter.bin
153
159
  vendor/riddle/spec/fixtures/data/filter_array.bin
154
160
  vendor/riddle/spec/fixtures/data/filter_array_exclude.bin
@@ -159,12 +165,16 @@ vendor/riddle/spec/fixtures/data/filter_range.bin
159
165
  vendor/riddle/spec/fixtures/data/filter_range_exclude.bin
160
166
  vendor/riddle/spec/fixtures/data/group.bin
161
167
  vendor/riddle/spec/fixtures/data/index.bin
168
+ vendor/riddle/spec/fixtures/data/index_weights.bin
162
169
  vendor/riddle/spec/fixtures/data/phrase.bin
170
+ vendor/riddle/spec/fixtures/data/rank_mode.bin
163
171
  vendor/riddle/spec/fixtures/data/simple.bin
164
172
  vendor/riddle/spec/fixtures/data/sort.bin
165
173
  vendor/riddle/spec/fixtures/data/update_simple.bin
166
174
  vendor/riddle/spec/fixtures/data/weights.bin
175
+ vendor/riddle/spec/fixtures/data_generator.php
167
176
  vendor/riddle/spec/fixtures/sphinx/configuration.erb
177
+ vendor/riddle/spec/fixtures/sphinxapi.php
168
178
  vendor/riddle/spec/fixtures/sql/conf.example.yml
169
179
  vendor/riddle/spec/fixtures/sql/data.sql
170
180
  vendor/riddle/spec/fixtures/sql/structure.sql
data/RAKE_TASKS CHANGED
@@ -4,7 +4,9 @@
4
4
  These Rake tasks are made available to your Rails app:
5
5
 
6
6
  <tt>ultrasphinx:configure</tt>:: Rebuild the configuration file for this particular environment.
7
- <tt>ultrasphinx:index</tt>:: Reindex the database and send an update signal to the search daemon.
7
+ <tt>ultrasphinx:index</tt>:: Reindex and rotate all indexes.
8
+ <tt>ultrasphinx:index:delta</tt>:: Reindex and rotate the delta index.
9
+ <tt>ultrasphinx:index:main</tt>:: Reindex and rotate the main index.
8
10
  <tt>ultrasphinx:daemon:restart</tt>:: Restart the search daemon.
9
11
  <tt>ultrasphinx:daemon:start</tt>:: Start the search daemon.
10
12
  <tt>ultrasphinx:daemon:stop</tt>:: Stop the search daemon.
@@ -12,4 +14,4 @@ These Rake tasks are made available to your Rails app:
12
14
  <tt>ultrasphinx:spelling:build</tt>:: Rebuild the custom spelling dictionary. You may need to use <tt>sudo</tt> if your Aspell folder is not writable by the app user.
13
15
  <tt>ultrasphinx:bootstrap</tt>:: Bootstrap a full Sphinx environment by running configure, index, then daemon:start.
14
16
 
15
- All tasks have shortcuts. Use <tt>us:conf</tt>, <tt>us:in</tt>, <tt>us:restart</tt>, <tt>us:start</tt>, <tt>us:stop</tt>, <tt>us:stat</tt>, <tt>us:spell</tt>, and <tt>us:boot</tt>.
17
+ All tasks have shortcuts. Use <tt>us:conf</tt>, <tt>us:index</tt>, <tt>us:main</tt>, <tt>us:delta</tt>, <tt>us:restart</tt>, <tt>us:start</tt>, <tt>us:stop</tt>, <tt>us:stat</tt>, <tt>us:spell</tt>, and <tt>us:boot</tt>.
data/README CHANGED
@@ -5,7 +5,7 @@ Ruby on Rails configurator and client to the Sphinx full text search engine.
5
5
 
6
6
  == License
7
7
 
8
- Copyright 2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. Some portions copyright Pat Allan, distributed under the MIT license, and used with permission. Some portions copyright PJ Hyett and Mislav Marohnić, distributed under the MIT license, and used with permission.
8
+ Copyright 2007-2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. Some portions copyright Pat Allan, distributed under the MIT license, and used with permission. Some portions copyright PJ Hyett and Mislav Marohnić, distributed under the MIT license, and used with permission.
9
9
 
10
10
  The public certificate for the gem is here[http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem].
11
11
 
@@ -14,30 +14,27 @@ If you use this software, please {make a donation}[http://blog.evanweaver.com/do
14
14
  == Requirements
15
15
 
16
16
  * MySQL 5.0, or PostgreSQL 8.2
17
- * Sphinx 0.9.8-dev r1112
17
+ * Sphinx 0.9.8-rc1
18
18
  * Rails 2.0.2
19
19
 
20
20
  More recent versions than listed are usually ok.
21
21
 
22
22
  == Features
23
23
 
24
- Advanced Sphinx usage:
24
+ Sphinx/Ultrasphinx is the fastest and most stable Rails fulltext search solution.
25
+
26
+ Features include:
27
+
25
28
  * searching and ranking across orthogonal models
29
+ * delta index support
26
30
  * excerpt highlighting
27
- * field weighting
31
+ * Google-style query parser
32
+ * spellcheck
28
33
  * faceting on text, date, and numeric fields
29
-
30
- ActiveRecord-style SQL generation:
34
+ * field weighting, merging, and aliases
31
35
  * <tt>belongs_to</tt> and <tt>has_many</tt> includes
32
- * field merging
33
- * field aliasing
34
-
35
- Good Rails integration:
36
- * automatic memcached loads via <tt>cache_fu</tt>
37
- * <tt>will_paginate</tt> compatibility
38
- * query spellcheck
39
- * Google-style query parser
40
- * error recovery
36
+ * drop-in compatibility with will_paginate[http://err.lighthouseapp.com/projects/466/home]
37
+ * drop-in compatibility with Interlock[http://blog.evanweaver.com/files/doc/fauna/interlock/]
41
38
  * multiple deployment environments
42
39
  * comprehensive Rake tasks
43
40
 
@@ -57,7 +54,7 @@ Then, install the plugin:
57
54
 
58
55
  Next, copy the <tt>examples/default.base</tt> file to <tt>RAILS_ROOT/config/ultrasphinx/default.base</tt>. This file sets up the Sphinx daemon options such as port, host, and index location.
59
56
 
60
- If you need per-environment configuration, you can use <tt>RAILS_ROOT/config/ultrasphinx/development.base</tt>, etc.
57
+ If you need per-environment configuration, you can use <tt>RAILS_ROOT/config/ultrasphinx/development.base</tt>, etc. Note that ERb is also allowed within the <tt>.base</tt> files, and can be an alternative way to DRY up multiple configurations.
61
58
 
62
59
  Now, in your models, use the <tt>is_indexed</tt> method to configure a model as searchable. For example:
63
60
 
@@ -91,11 +88,29 @@ For more query options, including excerpt mode, see Ultrasphinx::Search.
91
88
 
92
89
  == Pagination
93
90
 
94
- Once the <tt>@search</tt> object has been <tt>run</tt>, it is directly compatible with the <tt>will_paginate</tt> view helper.
91
+ Once the <tt>@search</tt> object has been <tt>run</tt>, it is directly compatible with the <tt>will_paginate</tt> view helper. In your view, just do:
92
+ <%= will_paginate(@search) %>
95
93
 
96
94
  == Spell checking
97
95
 
98
96
  See Ultrasphinx::Spell.
97
+
98
+ == Delta indexing
99
+
100
+ Delta indexing speeds up your updates by not reindexing the entire dataset every time.
101
+
102
+ First, in your <tt>.base</tt> file, set the indexer option <tt>delta</tt> to your maximum interval between full reindexes. A day or a week is good, depending. Add a little bit to account for the time it takes the actual index to run:
103
+
104
+ delta = <%= 1.day + 30.minutes %>
105
+
106
+ Now, configure your models for delta indexing in the <tt>is_indexed</tt> call:
107
+
108
+ is_indexed :fields => ['created_at', 'title', 'body'],
109
+ :delta => true
110
+
111
+ Now you can run <tt>rake ultrasphinx:index:delta</tt> frequently, and only records that were changed within 1 day will be reindexed. You will need to run <tt>rake ultrasphinx:index:main</tt> once a day to move the delta contents into the main index.
112
+
113
+ See ActiveRecord::Base .is_indexed and DEPLOYMENT_NOTES[link:files/DEPLOYMENT_NOTES.html] for more.
99
114
 
100
115
  == Available Rake tasks
101
116
 
@@ -105,7 +120,9 @@ See RAKE_TASKS[link:files/RAKE_TASKS.html].
105
120
 
106
121
  See DEPLOYMENT_NOTES[link:files/DEPLOYMENT_NOTES.html].
107
122
 
108
- == A note about PostgreSQL
123
+ == Gotchas
124
+
125
+ Note that since Ultrasphinx preloads indexed models, you need to make sure those models have their own dependencies in place early in the boot process. This may require adjusting the general plugin load order or moving monkey-patches from <tt>lib/</tt> to <tt>vendor/plugins/</tt>.
109
126
 
110
127
  PostgreSQL 8.2 and higher are well supported. However, make sure you have executed <tt>CREATE LANGUAGE plpgsql;</tt> at least once. This step does not need to be repeated, so depending on your DB permissions, you might be able to put it in a migration.
111
128
 
data/TODO CHANGED
@@ -8,6 +8,5 @@ Planned:
8
8
 
9
9
  Not sure:
10
10
 
11
- * Delta indexing
12
11
  * Use Pat Allan's association configurator, possibly with an API change to avoid the message-passing DSL
13
12
  * Use Treetop for the query parser instead of regexes
@@ -3,8 +3,8 @@
3
3
  # Sphinx/Ultrasphinx user-configurable options.
4
4
  #
5
5
  # Copy this file to RAILS_ROOT/config/ultrasphinx. You can use individual
6
- # namespaces if you want (e.g. development.base, production.base,
7
- # test.base).
6
+ # namespaces if you want (e.g. development.base, production.base,
7
+ # test.base). Note that ERb is also allowed.
8
8
  #
9
9
  # This file should not be handed directly to Sphinx. Use the rake task
10
10
  #
@@ -15,56 +15,61 @@
15
15
  # to Sphinx.
16
16
  #
17
17
  # It is safe to edit .base files by hand. It is not safe to edit the generated
18
- # .conf files. Do not symlink the .conf file to the .base file! I don't know why
19
- # people think they need to do that. It's wrong.
18
+ # .conf files. Do not symlink the .conf file to the .base file; it's wrong.
20
19
  #
21
20
 
21
+ <% path = "/opt/local/var/db/sphinx/" %>
22
+
23
+ # Indexing options
22
24
  indexer
23
- {
24
- # Indexer running options
25
+ {
25
26
  mem_limit = 256M
27
+
28
+ # Ultrasphinx-specific key
29
+ delta = <%= 1.day + 30.minutes %>
26
30
  }
27
31
 
32
+ # Daemon options
28
33
  searchd
29
- {
30
- # Daemon options
34
+ {
31
35
  # What interface the search daemon should listen on and where to store its logs
32
36
  address = 0.0.0.0
33
37
  port = 3312
34
38
  seamless_rotate = 1
35
- log = /opt/local/var/db/sphinx/log/searchd.log
36
- query_log = /opt/local/var/db/sphinx/log/query.log
39
+ log = <%= path %>log/searchd.log
40
+ query_log = <%= path %>log/query.log
37
41
  read_timeout = 5
38
42
  max_children = 300
39
- pid_file = /opt/local/var/db/sphinx/log/searchd.pid
43
+ pid_file = <%= path %>log/searchd.pid
40
44
  max_matches = 100000
41
45
  }
42
46
 
47
+ # Client options
43
48
  client
44
49
  {
45
- # Client options
46
50
  # Name of the Aspell dictionary (two letters max)
47
51
  dictionary_name = ap
52
+
48
53
  # How your application connects to the search daemon (not necessarily the same as above)
49
54
  server_host = localhost
50
55
  server_port = 3312
51
56
  }
52
57
 
58
+ # Individual SQL source options
53
59
  source
54
- {
55
- # Individual SQL source options
60
+ {
56
61
  sql_ranged_throttle = 0
57
62
  sql_range_step = 5000
58
63
  sql_query_post =
59
64
  }
60
65
 
66
+ # Index building options
61
67
  index
62
- {
63
- # Index building options
64
- path = /opt/local/var/db/sphinx/
65
- docinfo = extern # just leave this alone
68
+ {
69
+ path = <%= path %>
70
+ docinfo = extern # Just leave this alone
66
71
  morphology = stem_en
67
- stopwords = # /path/to/stopwords.txt
72
+ stopwords = # <%= path %>/ap-stopwords.txt
68
73
  min_word_len = 1
69
74
 
70
75
  # HTML-specific options
data/lib/ultrasphinx.rb CHANGED
@@ -17,7 +17,7 @@ require 'ultrasphinx/associations'
17
17
  require 'ultrasphinx/core_extensions'
18
18
  require 'ultrasphinx/is_indexed'
19
19
 
20
- if (ActiveRecord::Base.connection rescue nil) # XXX Forget why this needed to be wrapped
20
+ if (ActiveRecord::Base.connection rescue nil) # XXX Not sure why this needed to be wrapped.
21
21
  require 'ultrasphinx/configure'
22
22
  require 'ultrasphinx/autoload'
23
23
  require 'ultrasphinx/fields'
@@ -12,7 +12,7 @@ module Ultrasphinx
12
12
  Dir["**/*.rb"].each do |filename|
13
13
  open(filename) do |file|
14
14
  begin
15
- if file.grep(/is_indexed/).any?
15
+ if file.grep(/^\s+is_indexed/).any?
16
16
  filename = filename[0..-4]
17
17
  begin
18
18
  File.basename(filename).camelize.constantize
@@ -41,21 +41,33 @@ module Ultrasphinx
41
41
 
42
42
  say "rebuilding configurations for #{RAILS_ENV} environment"
43
43
  say "available models are #{MODEL_CONFIGURATION.keys.to_sentence}"
44
- File.open(CONF_PATH, "w") do |conf|
45
-
44
+ File.open(CONF_PATH, "w") do |conf|
46
45
  conf.puts global_header
47
- sources = []
48
-
49
- say "generating SQL"
50
- cached_groups = Fields.instance.groups.join("\n")
51
- MODEL_CONFIGURATION.each_with_index do |model_options, class_id|
52
- model, options = model_options
53
- klass, source = model.constantize, model.tableize.gsub('/', '__')
54
- sources << source
55
- conf.puts build_source(Fields.instance, model, options, class_id, klass, source, cached_groups)
46
+ say "generating SQL"
47
+
48
+ INDEXES.each do |index|
49
+ sources = []
50
+ cached_groups = Fields.instance.groups.join("\n")
51
+
52
+ MODEL_CONFIGURATION.each_with_index do |model_and_options, class_id|
53
+ # This relies on hash sort order being deterministic per-machine
54
+ model, options = model_and_options
55
+ klass = model.constantize
56
+ source = "#{model.tableize.gsub('/', '__')}_#{index}"
57
+
58
+ if index != DELTA_INDEX or options['delta']
59
+ # If we are building the delta, we only want to include the models that requested it
60
+ conf.puts build_source(index, Fields.instance, model, options, class_id, klass, source, cached_groups)
61
+ sources << source
62
+ end
63
+ end
64
+
65
+ if sources.any?
66
+ # Don't generate a delta index if there are no delta tables
67
+ conf.puts build_index(index, sources)
68
+ end
69
+
56
70
  end
57
-
58
- conf.puts build_index(sources)
59
71
  end
60
72
  end
61
73
 
@@ -68,7 +80,8 @@ module Ultrasphinx
68
80
  ["\n# Auto-generated at #{Time.now}.",
69
81
  "# Hand modifications will be overwritten.",
70
82
  "# #{BASE_PATH}\n",
71
- INDEXER_SETTINGS._to_conf_string('indexer'),
83
+ INDEXER_SETTINGS.except('delta')._to_conf_string('indexer'),
84
+ "",
72
85
  DAEMON_SETTINGS._to_conf_string("searchd")]
73
86
  end
74
87
 
@@ -86,9 +99,31 @@ module Ultrasphinx
86
99
  end
87
100
  conf.sort.join("\n")
88
101
  end
102
+
103
+
104
+ def build_delta_condition(index, klass, options)
105
+ if index == DELTA_INDEX and options['delta']
106
+ # Add delta condition if necessary
107
+ table, field = klass.table_name, options['delta']['field']
108
+ source_string = "#{table}.#{field}"
109
+ delta_column = klass.columns_hash[field]
110
+
111
+ if delta_column
112
+ raise ConfigurationError, "#{source_string} is not a :datetime" unless delta_column.type == :datetime
113
+ if (options['fields'] + options['concatenate'] + options['include']).detect { |entry| entry['sortable'] }
114
+ # Warning about the sortable problem
115
+ # XXX Kind of in an odd place, but I want to happen at index time
116
+ Ultrasphinx.say "warning; text sortable columns on #{klass.name} will return wrong results with partial delta indexing"
117
+ end
118
+ string = "#{source_string} > #{SQL_FUNCTIONS[ADAPTER]['delta']._interpolate(INDEXER_SETTINGS['delta'])}";
119
+ else
120
+ Ultrasphinx.say "warning; #{klass.name} will reindex the entire table during delta indexing"
121
+ end
122
+ end
123
+ end
89
124
 
90
125
 
91
- def setup_source_arrays(klass, fields, class_id, conditions)
126
+ def setup_source_arrays(index, klass, fields, class_id, conditions)
92
127
  condition_strings = Array(conditions).map do |condition|
93
128
  "(#{condition})"
94
129
  end
@@ -101,12 +136,13 @@ module Ultrasphinx
101
136
  end
102
137
 
103
138
 
104
- def range_select_string(klass)
139
+ def range_select_string(klass, delta_condition)
105
140
  ["sql_query_range = SELECT",
106
141
  SQL_FUNCTIONS[ADAPTER]['range_cast']._interpolate("MIN(#{klass.primary_key})"),
107
- ", ",
142
+ ",",
108
143
  SQL_FUNCTIONS[ADAPTER]['range_cast']._interpolate("MAX(#{klass.primary_key})"),
109
- "FROM #{klass.table_name}"
144
+ "FROM #{klass.table_name}",
145
+ ("WHERE #{delta_condition}" if delta_condition),
110
146
  ].join(" ")
111
147
  end
112
148
 
@@ -116,11 +152,16 @@ module Ultrasphinx
116
152
  end
117
153
 
118
154
 
119
- def build_source(fields, model, options, class_id, klass, source, groups)
155
+ def build_source(index, fields, model, options, class_id, klass, source, groups)
120
156
 
121
157
  column_strings, join_strings, condition_strings, group_bys, use_distinct, remaining_columns =
122
158
  setup_source_arrays(
123
- klass, fields, class_id, options['conditions'])
159
+ index, klass, fields, class_id, options['conditions'])
160
+
161
+ delta_condition =
162
+ build_delta_condition(
163
+ index, klass, options)
164
+ condition_strings << delta_condition if delta_condition
124
165
 
125
166
  column_strings, join_strings, group_bys, remaining_columns =
126
167
  build_regular_fields(
@@ -140,7 +181,7 @@ module Ultrasphinx
140
181
  "source #{source}\n{",
141
182
  SOURCE_SETTINGS._to_conf_string,
142
183
  setup_source_database(klass),
143
- range_select_string(klass),
184
+ range_select_string(klass, delta_condition),
144
185
  build_query(klass, column_strings, join_strings, condition_strings, use_distinct, group_bys),
145
186
  "\n" + groups,
146
187
  query_info_string(klass, class_id),
@@ -271,13 +312,13 @@ module Ultrasphinx
271
312
  end
272
313
 
273
314
 
274
- def build_index(sources)
315
+ def build_index(index, sources)
275
316
  ["\n# Index configuration\n\n",
276
- "index #{UNIFIED_INDEX_NAME}\n{",
317
+ "index #{index}\n{",
277
318
  sources.sort.map do |source|
278
319
  " source = #{source}"
279
320
  end.join("\n"),
280
- INDEX_SETTINGS.merge('path' => INDEX_SETTINGS['path'] + "/sphinx_index_#{UNIFIED_INDEX_NAME}")._to_conf_string,
321
+ INDEX_SETTINGS.merge('path' => INDEX_SETTINGS['path'] + "/sphinx_index_#{index}")._to_conf_string,
281
322
  "}\n\n"]
282
323
  end
283
324