public
Description: a maintained fork of Evan Weaver's Ultrasphinx code -- see the escape_sql branch
Homepage: http://blog.evanweaver.com/files/doc/fauna/ultrasphinx/files/README.html
Clone URL: git://github.com/DrMark/ultrasphinx.git
namespace


git-svn-id: svn://rubyforge.org/var/svn/fauna/ultrasphinx/trunk@299 
c1ad287d-65d5-445d-b84c-e64f8492f1e6
evanweaver (author)
Thu Jul 19 19:32:17 -0700 2007
commit  8ed574c6a67428450d86305e2ac0b342c1b00793
tree    9e375b648cbd6d088d9931de6881cd61988cd060
parent  0d5d6dbe380612e620cce89cdf3a26b31367458f
...
1
2
3
4
5
6
...
1
 
2
 
 
 
0
@@ -1,6 +1,2 @@
0
 
0
-require 'fields'
0
 require 'ultrasphinx'
0
-require 'autoload'
0
-require 'is_indexed'
0
-require 'search'
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
 
 
 
 
 
 
 
...
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
3
4
5
6
7
8
0
@@ -1,194 +1,8 @@
0
 
0
-require 'yaml'
0
-
0
-module Ultrasphinx
0
-
0
- class Exception < ::Exception
0
- end
0
- class ConfigurationError < Exception
0
- end
0
- class DaemonError < Exception
0
- end
0
-
0
- CONF_PATH = "#{RAILS_ROOT}/config/environments/sphinx.#{RAILS_ENV}.conf"
0
- ENV_BASE_PATH = "#{RAILS_ROOT}/config/environments/sphinx.#{RAILS_ENV}.base"
0
- GENERIC_BASE_PATH = "#{RAILS_ROOT}/config/sphinx.base"
0
- BASE_PATH = (File.exist?(ENV_BASE_PATH) ? ENV_BASE_PATH : GENERIC_BASE_PATH)
0
-
0
- raise ConfigurationError, "Please create a #{BASE_PATH} configuration file." unless File.exist? BASE_PATH
0
-
0
- def self.options_for(heading)
0
- section = open(BASE_PATH).read[/^#{heading}.*?\{(.*?)\}/m, 1]
0
- raise "missing heading #{heading} in #{BASE_PATH}" if section.nil?
0
- lines = section.split("\n").reject { |l| l.strip.empty? }
0
- options = lines.map do |c|
0
- c =~ /\s*(.*?)\s*=\s*([^\#]*)/
0
- $1 ? [$1, $2.strip] : []
0
- end
0
- Hash[*options.flatten]
0
- end
0
-
0
- SOURCE_DEFAULTS = %(
0
- strip_html = 0
0
- index_html_attrs =
0
- sql_query_pre = SET SESSION group_concat_max_len = 65535
0
- sql_query_pre = SET NAMES utf8
0
- sql_query_post =
0
- sql_range_step = 20000
0
- )
0
-
0
- MAX_INT = 2**32-1
0
- COLUMN_TYPES = {:string => 'text', :text => 'text', :integer => 'numeric', :date => 'date', :datetime => 'date' }
0
- CONFIG_MAP = {:username => 'sql_user',
0
- :password => 'sql_pass',
0
- :host => 'sql_host',
0
- :database => 'sql_db',
0
- :adapter => 'type',
0
- :port => 'sql_port',
0
- :socket => 'sql_sock'}
0
- OPTIONAL_SPHINX_KEYS = ['morphology', 'stopwords', 'min_word_len', 'charset_type', 'charset_table', 'docinfo']
0
- PLUGIN_SETTINGS = options_for('ultrasphinx')
0
- DAEMON_SETTINGS = options_for('searchd')
0
-
0
- MAX_WORDS = 2**16 # maximum number of stopwords built
0
- STOPWORDS_PATH = "#{Ultrasphinx::PLUGIN_SETTINGS['path']}/stopwords.txt}"
0
-
0
- #logger.debug "Ultrasphinx options are: #{PLUGIN_SETTINGS.inspect}"
0
-
0
- MODELS_HASH = {}
0
-
0
- class << self
0
- def load_constants
0
- Dir["#{RAILS_ROOT}/app/models/**/*.rb"].each do |filename|
0
- next if filename =~ /\/(\.svn|CVS|\.bzr)\//
0
- begin
0
- open(filename) {|file| load filename if file.grep(/is_indexed/).any?}
0
- rescue Object => e
0
- puts "Ultrasphinx: warning; autoload error on #{filename}"
0
- end
0
- end
0
- Fields.instance.configure(MODELS_HASH)
0
- end
0
-
0
- def configure
0
- load_constants
0
-
0
- puts "Rebuilding Ultrasphinx configurations for #{ENV['RAILS_ENV']} environment"
0
- puts "Available models are #{MODELS_HASH.keys.to_sentence}"
0
- File.open(CONF_PATH, "w") do |conf|
0
- conf.puts "\n# Auto-generated at #{Time.now}.\n# Hand modifications will be overwritten.\n"
0
-
0
- conf.puts "\n# #{BASE_PATH}"
0
- conf.puts open(BASE_PATH).read.sub(/^ultrasphinx.*?\{.*?\}/m, '') + "\n"
0
-
0
- index_list = {"complete" => []}
0
-
0
- conf.puts "\n# Source configuration\n\n"
0
-
0
- puts "Generating SQL"
0
- MODELS_HASH.each_with_index do |model_options, class_id|
0
- model, options = model_options
0
- klass, source = model.constantize, model.tableize
0
-
0
-# puts "SQL for #{model}"
0
-
0
- index_list[source] = [source]
0
- index_list["complete"] << source
0
-
0
- conf.puts "source #{source}\n{"
0
- conf.puts SOURCE_DEFAULTS
0
- klass.connection.instance_variable_get("@config").each do |key, value|
0
- conf.puts "#{CONFIG_MAP[key]} = #{value}" if CONFIG_MAP[key]
0
- end
0
-
0
- table, pkey = klass.table_name, klass.primary_key
0
- condition_strings, join_strings = Array(options[:conditions]).map{|condition| "(#{condition})"}, []
0
- column_strings = ["(#{table}.#{pkey} * #{MODELS_HASH.size} + #{class_id}) AS id",
0
- "#{class_id} AS class_id", "'#{klass.name}' AS class"]
0
- remaining_columns = Fields.instance.keys - ["class", "class_id"]
0
-
0
- conf.puts "\nsql_query_range = SELECT MIN(#{pkey}), MAX(#{pkey}) FROM #{table}"
0
-
0
- options[:fields].to_a.each do |f|
0
- column, as = f.is_a?(Hash) ? [f[:field], f[:as]] : [f, f]
0
- column_strings << Fields.instance.cast("#{table}.#{column}", as)
0
- remaining_columns.delete(as)
0
- end
0
-
0
- options[:includes].to_a.each do |join|
0
- join_klass = join[:model].constantize
0
- association = klass.reflect_on_association(join[:model].underscore.to_sym)
0
- join_strings << "LEFT OUTER JOIN #{join_klass.table_name} ON " +
0
- if (macro = association.macro) == :belongs_to
0
- "#{join_klass.table_name}.#{join_klass.primary_key} = #{table}.#{association.primary_key_name}"
0
- elsif macro == :has_one
0
- "#{table}.#{klass.primary_key} = #{join_klass.table_name}.#{association.instance_variable_get('@foreign_key_name')}"
0
- else
0
- raise ConfigurationError, "Unidentified association macro #{macro.inspect}"
0
- end
0
- column_strings << "#{join_klass.table_name}.#{join[:field]} AS #{join[:as] or join[:field]}"
0
- remaining_columns.delete(join[:as] || join[:field])
0
- end
0
-
0
- options[:concats].to_a.select{|concat| concat[:model] and concat[:field]}.each do |group|
0
- # only has_many's right now
0
- join_klass = group[:model].constantize
0
- association = klass.reflect_on_association(group[:association_name] ? group[:association_name].to_sym : group[:model].underscore.pluralize.to_sym)
0
- join_strings << "LEFT OUTER JOIN #{join_klass.table_name} ON #{table}.#{klass.primary_key} = #{join_klass.table_name}.#{association.primary_key_name}" + (" AND (#{group[:conditions]})" if group[:conditions]).to_s # XXX make sure foreign key is right for polymorphic relationships
0
- column_strings << Fields.instance.cast("GROUP_CONCAT(#{join_klass.table_name}.#{group[:field]} SEPARATOR ' ')", group[:as])
0
- remaining_columns.delete(group[:as])
0
- end
0
-
0
- options[:concats].to_a.select{|concat| concat[:fields]}.each do |concat|
0
- column_strings << Fields.instance.cast("CONCAT_WS(' ', #{concat[:fields].map{|field| "#{table}.#{field}"}.join(', ')})", concat[:as])
0
- remaining_columns.delete(concat[:as])
0
- end
0
-
0
-# puts "#{model} has #{remaining_columns.inspect} remaining"
0
- remaining_columns.each do |field|
0
- column_strings << Fields.instance.null(field)
0
- end
0
-
0
- query_strings = ["SELECT", column_strings.sort_by do |string|
0
- # sphinx wants them always in the same order, but "id" must be first
0
- (field = string[/.*AS (.*)/, 1]) == "id" ? "*" : field
0
- end.join(", ")]
0
- query_strings << "FROM #{table}"
0
- query_strings += join_strings.uniq
0
- query_strings << "WHERE #{table}.#{pkey} >= $start AND #{table}.#{pkey} <= $end"
0
- query_strings += condition_strings.uniq.map{|s| "AND #{s}"}
0
- query_strings << "GROUP BY id"
0
-
0
- conf.puts "sql_query = #{query_strings.join(" ")}"
0
-
0
- groups = []
0
- # group and date sorting params... this really only would have to be run once
0
- Fields.instance.each do |field, type|
0
- case type
0
- when 'numeric'
0
- groups << "sql_group_column = #{field}"
0
- when 'date'
0
- groups << "sql_date_column = #{field}"
0
- end
0
- end
0
- conf.puts "\n" + groups.sort_by{|s| s[/= (.*)/, 1]}.join("\n")
0
- conf.puts "\nsql_query_info = SELECT * FROM #{table} WHERE #{table}.#{pkey} = (($id - #{class_id}) / #{MODELS_HASH.size})"
0
- conf.puts "}\n\n"
0
- end
0
-
0
- conf.puts "\n# Index configuration\n\n"
0
- index_list.to_a.sort_by {|x| x.first == "complete" ? 1 : 0}.each do |name, source_list|
0
- conf.puts "index #{name}\n{"
0
- source_list.each {|source| conf.puts "source = #{source}"}
0
- OPTIONAL_SPHINX_KEYS.each do |key|
0
- conf.puts "#{key} = #{PLUGIN_SETTINGS[key]}" if PLUGIN_SETTINGS[key]
0
- end
0
- conf.puts "path = #{PLUGIN_SETTINGS["path"]}/sphinx_index_#{name}"
0
- conf.puts "}\n\n"
0
- end
0
- end
0
-
0
- end
0
-
0
- end
0
-end
0
+require 'ultrasphinx/core_extensions'
0
+require 'ultrasphinx/ultrasphinx'
0
+require 'ultrasphinx/autoload'
0
+require 'ultrasphinx/fields'
0
+require 'ultrasphinx/is_indexed'
0
+require 'ultrasphinx/search'
0
+require 'ultrasphinx/spell'
...
14
15
16
17
 
18
19
20
...
23
24
25
26
 
 
 
 
 
 
27
28
29
30
31
32
 
33
34
35
...
55
56
57
58
 
59
60
 
61
62
63
...
14
15
16
 
17
18
19
20
...
23
24
25
 
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
...
61
62
63
 
64
65
 
66
67
68
69
0
@@ -14,7 +14,7 @@ namespace :ultrasphinx do
0
     cmd << " --rotate" if daemon_running?
0
     cmd << " complete"
0
     puts cmd
0
- exec cmd
0
+ system cmd
0
   end
0
   
0
   namespace :daemon do
0
@@ -23,13 +23,19 @@ namespace :ultrasphinx do
0
       raise Ultrasphinx::DaemonError, "Already running" if daemon_running?
0
       # remove lockfiles
0
       Dir[Ultrasphinx::PLUGIN_SETTINGS["path"] + "*spl"].each {|file| File.delete(file)}
0
- exec "searchd --config #{Ultrasphinx::CONF_PATH}"
0
+ system "searchd --config #{Ultrasphinx::CONF_PATH}"
0
+ if daemon_running?
0
+ puts "Started successfully"
0
+ else
0
+ puts "Failed to start"
0
+ end
0
     end
0
     
0
     desc "Stop the search daemon"
0
     task :stop => [:environment] do
0
       raise Ultrasphinx::DaemonError, "Doesn't seem to be running" unless daemon_running?
0
       system "kill #{daemon_pid}"
0
+ puts "Stopped"
0
     end
0
 
0
     desc "Restart the search daemon"
0
@@ -55,9 +61,9 @@ namespace :ultrasphinx do
0
     desc "Check if the search daemon is running"
0
     task :status => :environment do
0
       if daemon_running?
0
- puts "Running."
0
+ puts "Daemon is running"
0
       else
0
- puts "Stopped."
0
+ puts "Daemon is stopped"
0
       end
0
     end
0
   end

Comments

    No one has commented yet.