Module: Ultrasphinx

Defined in:
lib/ultrasphinx/spell.rb,
lib/ultrasphinx/fields.rb,
lib/ultrasphinx/search.rb,
lib/ultrasphinx/configure.rb,
lib/ultrasphinx/ultrasphinx.rb,
lib/ultrasphinx/associations.rb,
lib/ultrasphinx/search/parser.rb,
lib/ultrasphinx/search/internals.rb

Defined Under Namespace

Modules: Associations, DateSelf, NumericSelf, Spell Classes: ConfigurationError, Configure, DaemonError, Error, Fields, Search, UsageError

Constant Summary collapse

SUBDIR =

Internal file paths

"config/ultrasphinx"
DIR =
"#{RAILS_ROOT}/#{SUBDIR}"
THIS_DIR =
File.expand_path(File.dirname(__FILE__))
CONF_PATH =
"#{DIR}/#{RAILS_ENV}.conf"
ENV_BASE_PATH =
"#{DIR}/#{RAILS_ENV}.base"
GENERIC_BASE_PATH =
"#{DIR}/default.base"
BASE_PATH =
(File.exist?(ENV_BASE_PATH) ? ENV_BASE_PATH : GENERIC_BASE_PATH)
MAX_INT =

Some miscellaneous constants

2**32-1
MAX_WORDS =

The maximum number of stopwords built

2**16
MAIN_INDEX =
"main"
DELTA_INDEX =
"delta"
INDEXES =
[MAIN_INDEX, DELTA_INDEX]
CONFIG_MAP =
{
  # These must be symbols for key mapping against Rails itself.
  :username => 'sql_user',
  :password => 'sql_pass',
  :host => 'sql_host',
  :database => 'sql_db',
  :port => 'sql_port',
  :socket => 'sql_sock'
}
CONNECTION_DEFAULTS =
{
  :host => 'localhost',
  :password => '',
  :username => 'root'
}
SQL_FUNCTIONS =
{
  'mysql' => {
    'group_concat' => "CAST(GROUP_CONCAT(DISTINCT ? ? SEPARATOR ' ') AS CHAR)",
    'delta' => "DATE_SUB(NOW(), INTERVAL ? SECOND)",      
    'hash' => "CAST(CRC32(?) AS unsigned)",
    'range_cast' => "?"
  },
  'postgresql' => {
    'group_concat' => "GROUP_CONCAT(?)",
    'delta' => "(NOW() - '? SECOND'::interval)",
    'range_cast' => "cast(coalesce(?,1) AS integer)",
    'hash' => "CRC32(?)"
  }      
}
DEFAULTS =
{
  'mysql' => %(
    type = mysql
    sql_query_pre = SET SESSION group_concat_max_len = 65535
    sql_query_pre = SET NAMES utf8
  ), 
  'postgresql' => %(
    type = pgsql
    sql_query_pre =
  )
}
ADAPTER =
ActiveRecord::Base.connection.instance_variable_get("@config")[:adapter] rescue 'mysql'
INDEXER_SETTINGS =

Introspect on the existing generated conf files.

options_for('indexer', BASE_PATH)
CLIENT_SETTINGS =
options_for('client', BASE_PATH)
DAEMON_SETTINGS =
options_for('searchd', BASE_PATH)
SOURCE_SETTINGS =
options_for('source', BASE_PATH)
INDEX_SETTINGS =
options_for('index', BASE_PATH)
DICTIONARY =
CLIENT_SETTINGS['dictionary_name'] || 'ap'
STOPWORDS_PATH =
"#{Ultrasphinx::INDEX_SETTINGS['path']}/#{DICTIONARY}-stopwords.txt"
MODEL_CONFIGURATION =
{}

Class Method Summary collapse

Class Method Details

.delta_index_present?Boolean

See if a delta index was defined.

Returns:

  • (Boolean)


201
202
203
204
205
206
207
# File 'lib/ultrasphinx/ultrasphinx.rb', line 201

def self.delta_index_present?
  if File.exist?(CONF_PATH) 
    File.open(CONF_PATH).readlines.detect do |line|
      line =~ /^index delta/
    end
  end
end

.get_models_to_class_idsObject

:nodoc:



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
# File 'lib/ultrasphinx/ultrasphinx.rb', line 153

def self.get_models_to_class_ids #:nodoc:
  # Reading the conf file makes sure that we are in sync with the actual Sphinx index, not
  # whatever you happened to change your models to most recently.
  if File.exist? CONF_PATH
    lines, hash = open(CONF_PATH).readlines, {}
    msg = "#{CONF_PATH} file is corrupted. Please run 'rake ultrasphinx:configure'."
    
    lines.each_with_index do |line, index| 
      # Find the main sources
      if line =~ /^source ([\w\d_-]*)_#{MAIN_INDEX}/
        # Derive the model name
        model = $1.gsub('__', '/').classify

        # Get the id modulus out of the adjacent sql_query
        query = lines[index..-1].detect do |query_line|
          query_line =~ /^sql_query /
        end
        raise ConfigurationError, msg unless query
        hash[model] = query[/(\d*) AS class_id/, 1].to_i
      end  
    end            
    raise ConfigurationError, msg unless hash.values.size == hash.values.uniq.size      
    hash          
  else
    # We can't raise here because you may be generating the configuration for the first time
    Ultrasphinx.say "configuration file not found for #{RAILS_ENV.inspect} environment"
    Ultrasphinx.say "please run 'rake ultrasphinx:configure'"
  end      
end

.load_stored_procedure(name) ⇒ Object



61
62
63
# File 'lib/ultrasphinx/ultrasphinx.rb', line 61

def self.load_stored_procedure(name)
  open("#{THIS_DIR}/postgresql/#{name}.sql").read.gsub(/\s+/, ' ')
end

.log(msg) ⇒ Object

Debug-mode logger.



113
114
115
116
117
118
119
120
# File 'lib/ultrasphinx/ultrasphinx.rb', line 113

def self.log msg
  # XXX Method name is stupid.
  if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER
    RAILS_DEFAULT_LOGGER.debug msg
  else
    STDERR.puts msg
  end
end

.options_for(heading, path) ⇒ Object

Configuration file parser.



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
# File 'lib/ultrasphinx/ultrasphinx.rb', line 123

def self.options_for(heading, path)
  # Evaluate ERB
  template = ERB.new(File.open(path) {|f| f.read})
  contents = template.result(binding)
  
  # Find the correct heading.
  section = contents[/^#{heading.gsub('/', '__')}\s*?\{(.*?)\}/m, 1]
  
  if section
    # Strip comments and leading/trailing whitespace
    section.gsub!(/^\s*(.*?)\s*(?:#.*)?$/, '\1')

    # Convert to a hash
    returning({}) do |options|
      lines = section.split(/\n+/)
      while line = lines.shift
        if line =~ /(.*?)\s*=\s*(.*)/
          key, value = $1, [$2]
          value << (line = lines.shift) while line =~ /\\$/
          options[key] = value.join("\n    ")
        end
      end
    end
  else
    # XXX Is it safe to raise here?
    Ultrasphinx.say "warning; heading #{heading} not found in #{path}; it may be corrupted. "
    {}    
  end    
end

.say(msg) ⇒ Object

Warn-mode logger. Also called from rake tasks.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/ultrasphinx/ultrasphinx.rb', line 97

def self.say msg
  # XXX Method name is stupid.
  if with_rake
    puts msg[0..0].upcase + msg[1..-1]
  else
    msg = "** ultrasphinx: #{msg}"
    if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER
      RAILS_DEFAULT_LOGGER.warn msg
    else
      STDERR.puts msg
    end
  end        
  nil # Explicitly return nil
end