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)


191
192
193
194
195
196
197
# File 'lib/ultrasphinx/ultrasphinx.rb', line 191

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:



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

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.



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

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.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/ultrasphinx/ultrasphinx.rb', line 121

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
    # Convert to a hash
    options = section.split("\n").map do |line|
      line =~ /\s*(.*?)\s*=\s*([^\#]*)/
      $1 ? [$1, $2.strip] : []
    end      
    Hash[*options.flatten] 
  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.



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

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