ultrasphinx 1.8 → 1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +1 -3
- data/CHANGELOG +4 -0
- data/DEPLOYMENT_NOTES +7 -3
- data/Manifest +10 -0
- data/RAKE_TASKS +4 -2
- data/README +35 -18
- data/TODO +0 -1
- data/examples/default.base +24 -19
- data/lib/ultrasphinx.rb +1 -1
- data/lib/ultrasphinx/configure.rb +66 -25
- data/lib/ultrasphinx/core_extensions.rb +10 -1
- data/lib/ultrasphinx/is_indexed.rb +49 -6
- data/lib/ultrasphinx/search.rb +81 -69
- data/lib/ultrasphinx/search/internals.rb +61 -38
- data/lib/ultrasphinx/search/parser.rb +17 -7
- data/lib/ultrasphinx/ultrasphinx.rb +69 -16
- data/tasks/ultrasphinx.rake +47 -29
- data/test/config/ultrasphinx/test.base +50 -21
- data/test/integration/app/app/models/geo/address.rb +2 -1
- data/test/integration/app/app/models/person/user.rb +12 -3
- data/test/integration/app/app/models/seller.rb +2 -1
- data/test/integration/app/config/environment.rb +2 -0
- data/test/integration/app/config/ultrasphinx/default.base +16 -8
- data/test/integration/app/config/ultrasphinx/development.conf +319 -0
- data/test/integration/app/config/ultrasphinx/development.conf.canonical +152 -24
- data/test/integration/app/db/schema.rb +56 -0
- data/test/integration/app/test/fixtures/sellers.yml +1 -1
- data/test/integration/app/test/fixtures/users.yml +1 -1
- data/test/integration/app/test/unit/country_test.rb +8 -0
- data/test/integration/delta_test.rb +39 -0
- data/test/integration/search_test.rb +60 -1
- data/test/integration/spell_test.rb +6 -2
- data/test/profile/benchmark.rb +44 -0
- data/test/test_helper.rb +6 -1
- data/test/unit/parser_test.rb +21 -2
- data/ultrasphinx.gemspec +4 -4
- data/vendor/riddle/README +2 -2
- data/vendor/riddle/lib/riddle.rb +1 -1
- data/vendor/riddle/lib/riddle/client.rb +45 -10
- data/vendor/riddle/spec/fixtures/data/anchor.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/any.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/boolean.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/distinct.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/field_weights.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/filter.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/group.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/index.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/index_weights.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/phrase.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/rank_mode.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/simple.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/sort.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/update_simple.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/weights.bin +0 -0
- data/vendor/riddle/spec/fixtures/data_generator.php +130 -0
- data/vendor/riddle/spec/fixtures/sphinxapi.php +1066 -0
- data/vendor/riddle/spec/spec_helper.rb +1 -0
- data/vendor/riddle/spec/unit/client_spec.rb +18 -4
- metadata +12 -2
- metadata.gz.sig +0 -0
@@ -2,8 +2,7 @@
|
|
2
2
|
module Ultrasphinx
|
3
3
|
class Search
|
4
4
|
module Parser
|
5
|
-
# We could rewrite this in Treetop, but
|
6
|
-
# probably faster this way. Ragel would speed it up, but be too much work.
|
5
|
+
# We could rewrite this in Treetop, but for now it works well.
|
7
6
|
|
8
7
|
class Error < RuntimeError
|
9
8
|
end
|
@@ -50,7 +49,15 @@ module Ultrasphinx
|
|
50
49
|
query << ")" if field and contents.size > 1
|
51
50
|
end
|
52
51
|
|
53
|
-
#
|
52
|
+
# Collapse fieldsets early so that the swap doesn't split them
|
53
|
+
query.each_with_index do |token, index|
|
54
|
+
if token =~ /^@/
|
55
|
+
query[index] = "#{token} #{query[index + 1]}"
|
56
|
+
query[index + 1] = nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Swap the first pair if the order is reversed
|
54
61
|
if [OPERATORS['NOT'], OPERATORS['OR']].include? query.first.upcase
|
55
62
|
query[0], query[1] = query[1], query[0]
|
56
63
|
end
|
@@ -83,10 +90,11 @@ module Ultrasphinx
|
|
83
90
|
if subtoken =~ /\"(.*)\"/
|
84
91
|
subtoken.sub!($1, $1.gsub(/[()]/, ''))
|
85
92
|
end
|
86
|
-
|
87
|
-
#
|
93
|
+
|
94
|
+
# Add to the stream, converting the operator
|
88
95
|
if !has_operator
|
89
|
-
if OPERATORS.to_a.flatten.include? subtoken and index != (query.size - 1)
|
96
|
+
if OPERATORS.to_a.flatten.include? subtoken and index != (query.size - 1)
|
97
|
+
# Note that operators at the end of the string are not parsed
|
90
98
|
token_stream << OPERATORS[subtoken] || subtoken
|
91
99
|
has_operator = true # flip
|
92
100
|
else
|
@@ -103,7 +111,9 @@ module Ultrasphinx
|
|
103
111
|
end
|
104
112
|
end
|
105
113
|
|
106
|
-
|
114
|
+
if token_stream.size.zero? or token_stream.size.odd?
|
115
|
+
raise Error, "#{token_stream.inspect} is not a valid token stream"
|
116
|
+
end
|
107
117
|
token_stream.in_groups_of(2)
|
108
118
|
end
|
109
119
|
|
@@ -32,12 +32,16 @@ module Ultrasphinx
|
|
32
32
|
|
33
33
|
MAX_INT = 2**32-1
|
34
34
|
|
35
|
-
MAX_WORDS = 2**16 # maximum number of stopwords built
|
35
|
+
MAX_WORDS = 2**16 # The maximum number of stopwords built
|
36
36
|
|
37
|
-
|
37
|
+
MAIN_INDEX = "main"
|
38
|
+
|
39
|
+
DELTA_INDEX = "delta"
|
40
|
+
|
41
|
+
INDEXES = [MAIN_INDEX, DELTA_INDEX]
|
38
42
|
|
39
43
|
CONFIG_MAP = {
|
40
|
-
# These must be symbols for key mapping against Rails itself
|
44
|
+
# These must be symbols for key mapping against Rails itself.
|
41
45
|
:username => 'sql_user',
|
42
46
|
:password => 'sql_pass',
|
43
47
|
:host => 'sql_host',
|
@@ -59,12 +63,14 @@ module Ultrasphinx
|
|
59
63
|
SQL_FUNCTIONS = {
|
60
64
|
'mysql' => {
|
61
65
|
'group_concat' => "CAST(GROUP_CONCAT(DISTINCT ? SEPARATOR ' ') AS CHAR)",
|
66
|
+
'delta' => "DATE_SUB(NOW(), INTERVAL ? SECOND)",
|
62
67
|
'hash' => "CAST(CRC32(?) AS unsigned)",
|
63
68
|
'range_cast' => "?",
|
64
69
|
'stored_procedures' => {}
|
65
70
|
},
|
66
71
|
'postgresql' => {
|
67
72
|
'group_concat' => "GROUP_CONCAT(?)",
|
73
|
+
'delta' => "(NOW() - '? SECOND'::interval)",
|
68
74
|
'range_cast' => "cast(coalesce(?,1) AS integer)",
|
69
75
|
'hash' => "CRC32(?)",
|
70
76
|
'stored_procedures' => Hash[*(
|
@@ -90,7 +96,8 @@ sql_query_pre = ) + SQL_FUNCTIONS['postgresql']['stored_procedures'].values.join
|
|
90
96
|
|
91
97
|
ADAPTER = ActiveRecord::Base.connection.instance_variable_get("@config")[:adapter] rescue 'mysql'
|
92
98
|
|
93
|
-
# Install the stored procedures
|
99
|
+
# Install the stored procedures.
|
100
|
+
# XXX This shouldn't be done at every index, say the Postgres people.
|
94
101
|
SQL_FUNCTIONS[ADAPTER]['stored_procedures'].each do |key, value|
|
95
102
|
ActiveRecord::Base.connection.execute(value)
|
96
103
|
end
|
@@ -106,34 +113,71 @@ sql_query_pre = ) + SQL_FUNCTIONS['postgresql']['stored_procedures'].values.join
|
|
106
113
|
else
|
107
114
|
STDERR.puts msg
|
108
115
|
end
|
109
|
-
end
|
116
|
+
end
|
117
|
+
nil # Explicitly return nil
|
110
118
|
end
|
111
119
|
|
112
120
|
# Configuration file parser.
|
113
121
|
def self.options_for(heading, path)
|
114
|
-
|
122
|
+
# Evaluate ERB
|
123
|
+
template = ERB.new(File.open(path) {|f| f.read})
|
124
|
+
contents = template.result(binding)
|
115
125
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
126
|
+
# Find the correct heading.
|
127
|
+
section = contents[/^#{heading.gsub('/', '__')}\s*?\{(.*?)\}/m, 1]
|
128
|
+
|
129
|
+
if section
|
130
|
+
# Convert to a hash
|
120
131
|
options = section.split("\n").map do |line|
|
121
132
|
line =~ /\s*(.*?)\s*=\s*([^\#]*)/
|
122
133
|
$1 ? [$1, $2.strip] : []
|
123
134
|
end
|
124
135
|
Hash[*options.flatten]
|
125
|
-
|
126
|
-
|
136
|
+
else
|
137
|
+
# XXX Is it safe to raise here?
|
138
|
+
Ultrasphinx.say "warning; heading #{heading} not found in #{path}; it may be corrupted. "
|
139
|
+
{}
|
140
|
+
end
|
127
141
|
end
|
142
|
+
|
143
|
+
def self.get_models_to_class_ids #:nodoc:
|
144
|
+
# Reading the conf file makes sure that we are in sync with the actual Sphinx index, not
|
145
|
+
# whatever you happened to change your models to most recently.
|
146
|
+
if File.exist? CONF_PATH
|
147
|
+
lines, hash = open(CONF_PATH).readlines, {}
|
148
|
+
msg = "#{CONF_PATH} file is corrupted. Please run 'rake ultrasphinx:configure'."
|
149
|
+
|
150
|
+
lines.each_with_index do |line, index|
|
151
|
+
# Find the main sources
|
152
|
+
if line =~ /^source ([\w\d_-]*)_#{MAIN_INDEX}/
|
153
|
+
# Derive the model name
|
154
|
+
model = $1.gsub('__', '/').classify
|
128
155
|
|
129
|
-
|
156
|
+
# Get the id modulus out of the adjacent sql_query
|
157
|
+
query = lines[index..-1].detect do |query_line|
|
158
|
+
query_line =~ /^sql_query /
|
159
|
+
end
|
160
|
+
raise ConfigurationError, msg unless query
|
161
|
+
hash[model] = query[/(\d*) AS class_id/, 1].to_i
|
162
|
+
end
|
163
|
+
end
|
164
|
+
raise ConfigurationError, msg unless hash.values.size == hash.values.uniq.size
|
165
|
+
hash
|
166
|
+
else
|
167
|
+
# We can't raise here because you may be generating the configuration for the first time
|
168
|
+
Ultrasphinx.say "configuration file not found for #{RAILS_ENV.inspect} environment"
|
169
|
+
Ultrasphinx.say "please run 'rake ultrasphinx:configure'"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Introspect on the existing generated conf files.
|
130
174
|
INDEXER_SETTINGS = options_for('indexer', BASE_PATH)
|
131
175
|
CLIENT_SETTINGS = options_for('client', BASE_PATH)
|
132
176
|
DAEMON_SETTINGS = options_for('searchd', BASE_PATH)
|
133
177
|
SOURCE_SETTINGS = options_for('source', BASE_PATH)
|
134
178
|
INDEX_SETTINGS = options_for('index', BASE_PATH)
|
135
179
|
|
136
|
-
# Make sure there's a trailing slash
|
180
|
+
# Make sure there's a trailing slash.
|
137
181
|
INDEX_SETTINGS['path'] = INDEX_SETTINGS['path'].chomp("/") + "/"
|
138
182
|
|
139
183
|
DICTIONARY = CLIENT_SETTINGS['dictionary_name'] || 'ap'
|
@@ -148,7 +192,7 @@ sql_query_pre = ) + SQL_FUNCTIONS['postgresql']['stored_procedures'].values.join
|
|
148
192
|
if File.exist? CONF_PATH
|
149
193
|
begin
|
150
194
|
if options_for(
|
151
|
-
"source #{MODEL_CONFIGURATION.keys.first.tableize}",
|
195
|
+
"source #{MODEL_CONFIGURATION.keys.first.tableize}_#{MAIN_INDEX}",
|
152
196
|
CONF_PATH
|
153
197
|
)['sql_db'] != ActiveRecord::Base.connection.instance_variable_get("@config")[:database]
|
154
198
|
say "warning; configured database name is out-of-date"
|
@@ -158,5 +202,14 @@ sql_query_pre = ) + SQL_FUNCTIONS['postgresql']['stored_procedures'].values.join
|
|
158
202
|
end
|
159
203
|
end
|
160
204
|
end
|
161
|
-
|
205
|
+
|
206
|
+
# See if a delta index was defined.
|
207
|
+
def self.delta_index_present?
|
208
|
+
if File.exist?(CONF_PATH)
|
209
|
+
File.open(CONF_PATH).readlines.detect do |line|
|
210
|
+
line =~ /^index delta/
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
162
215
|
end
|
data/tasks/ultrasphinx.rake
CHANGED
@@ -12,7 +12,7 @@ namespace :ultrasphinx do
|
|
12
12
|
desc "Bootstrap a full Sphinx environment"
|
13
13
|
task :bootstrap => [:_environment, :configure, :index, :"daemon:restart"] do
|
14
14
|
say "done"
|
15
|
-
say "please restart
|
15
|
+
say "please restart your application containers"
|
16
16
|
end
|
17
17
|
|
18
18
|
desc "Rebuild the configuration file for this particular environment."
|
@@ -20,31 +20,23 @@ namespace :ultrasphinx do
|
|
20
20
|
Ultrasphinx::Configure.run
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
cmd = "indexer --config '#{Ultrasphinx::CONF_PATH}'"
|
29
|
-
cmd << " #{ENV['OPTS']} " if ENV['OPTS']
|
30
|
-
cmd << " --rotate" if rotate
|
31
|
-
cmd << " #{Ultrasphinx::UNIFIED_INDEX_NAME}"
|
32
|
-
|
33
|
-
say cmd
|
34
|
-
system cmd
|
35
|
-
|
36
|
-
if rotate
|
37
|
-
sleep(4)
|
38
|
-
failed = Dir[Ultrasphinx::INDEX_SETTINGS['path'] + "/*.new.*"]
|
39
|
-
if failed.any?
|
40
|
-
say "warning; index failed to rotate! Deleting new indexes"
|
41
|
-
failed.each {|f| File.delete f }
|
42
|
-
else
|
43
|
-
say "index rotated ok"
|
44
|
-
end
|
23
|
+
namespace :index do
|
24
|
+
desc "Reindex and rotate the main index."
|
25
|
+
task :main => [:_environment] do
|
26
|
+
ultrasphinx_index(Ultrasphinx::MAIN_INDEX)
|
45
27
|
end
|
28
|
+
|
29
|
+
desc "Reindex and rotate the delta index."
|
30
|
+
task :delta => [:_environment] do
|
31
|
+
ultrasphinx_index(Ultrasphinx::DELTA_INDEX)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Reindex and rotate all indexes."
|
37
|
+
task :index => [:_environment] do
|
38
|
+
ultrasphinx_index("--all")
|
46
39
|
end
|
47
|
-
|
48
40
|
|
49
41
|
namespace :daemon do
|
50
42
|
desc "Start the search daemon"
|
@@ -125,30 +117,56 @@ namespace :us do
|
|
125
117
|
task :restart => ["ultrasphinx:daemon:restart"]
|
126
118
|
task :stop => ["ultrasphinx:daemon:stop"]
|
127
119
|
task :stat => ["ultrasphinx:daemon:status"]
|
120
|
+
task :index => ["ultrasphinx:index"]
|
128
121
|
task :in => ["ultrasphinx:index"]
|
122
|
+
task :main => ["ultrasphinx:index:main"]
|
123
|
+
task :delta => ["ultrasphinx:index:delta"]
|
129
124
|
task :spell => ["ultrasphinx:spelling:build"]
|
130
125
|
task :conf => ["ultrasphinx:configure"]
|
131
126
|
task :boot => ["ultrasphinx:bootstrap"]
|
132
127
|
end
|
133
128
|
|
134
|
-
#
|
129
|
+
# Support methods
|
135
130
|
|
136
131
|
def ultrasphinx_daemon_pid
|
137
|
-
open(
|
138
|
-
line[/^\s*pid_file\s*=\s*([^\s\#]*)/, 1]
|
139
|
-
end.compact.first).readline.chomp rescue nil # XXX ridiculous
|
132
|
+
open(Ultrasphinx::DAEMON_SETTINGS['pid_file']).readline.chomp rescue nil
|
140
133
|
end
|
141
134
|
|
142
135
|
def ultrasphinx_daemon_running?
|
143
136
|
if ultrasphinx_daemon_pid and `ps #{ultrasphinx_daemon_pid} | wc`.to_i > 1
|
144
137
|
true
|
145
138
|
else
|
146
|
-
#
|
139
|
+
# Remove bogus lockfiles.
|
147
140
|
Dir[Ultrasphinx::INDEX_SETTINGS["path"] + "*spl"].each {|file| File.delete(file)}
|
148
141
|
false
|
149
142
|
end
|
150
143
|
end
|
151
144
|
|
145
|
+
def ultrasphinx_index(index)
|
146
|
+
rotate = ultrasphinx_daemon_running?
|
147
|
+
index_path = Ultrasphinx::INDEX_SETTINGS['path']
|
148
|
+
mkdir_p index_path unless File.directory? index_path
|
149
|
+
|
150
|
+
cmd = "indexer --config '#{Ultrasphinx::CONF_PATH}'"
|
151
|
+
cmd << " #{ENV['OPTS']} " if ENV['OPTS']
|
152
|
+
cmd << " --rotate" if rotate
|
153
|
+
cmd << " #{index}"
|
154
|
+
|
155
|
+
say "$ #{cmd}"
|
156
|
+
system cmd
|
157
|
+
|
158
|
+
if rotate
|
159
|
+
sleep(4)
|
160
|
+
failed = Dir[index_path + "/*.new.*"]
|
161
|
+
if failed.any?
|
162
|
+
say "warning; index failed to rotate! Deleting new indexes"
|
163
|
+
failed.each {|f| File.delete f }
|
164
|
+
else
|
165
|
+
say "index rotated ok"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
152
170
|
def say msg
|
153
171
|
Ultrasphinx.say msg
|
154
172
|
end
|
@@ -2,55 +2,84 @@
|
|
2
2
|
#
|
3
3
|
# Sphinx/Ultrasphinx user-configurable options.
|
4
4
|
#
|
5
|
-
# Copy this file to RAILS_ROOT/config/ultrasphinx.
|
6
|
-
#
|
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). Note that ERb is also allowed.
|
8
|
+
#
|
9
|
+
# This file should not be handed directly to Sphinx. Use the rake task
|
10
|
+
#
|
11
|
+
# rake ultrasphinx::configure
|
12
|
+
#
|
13
|
+
# to generate a parallel default.conf file. This is the file that Sphinx itself will
|
14
|
+
# use. The Ultrasphinx rake tasks automatically pass the correct file to
|
15
|
+
# to Sphinx.
|
16
|
+
#
|
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; it's wrong.
|
7
19
|
#
|
8
20
|
|
21
|
+
<% path = "/opt/local/var/db/sphinx/" %>
|
22
|
+
|
23
|
+
# Indexing options
|
9
24
|
indexer
|
10
|
-
{
|
11
|
-
# Indexer running options
|
25
|
+
{
|
12
26
|
mem_limit = 256M
|
27
|
+
|
28
|
+
# Ultrasphinx-specific key
|
29
|
+
delta = <%= 1.day + 30.minutes %>
|
13
30
|
}
|
14
31
|
|
32
|
+
# Daemon options
|
15
33
|
searchd
|
16
|
-
{
|
17
|
-
# Daemon options
|
34
|
+
{
|
18
35
|
# What interface the search daemon should listen on and where to store its logs
|
19
36
|
address = 0.0.0.0
|
20
37
|
port = 3312
|
21
|
-
|
22
|
-
|
38
|
+
seamless_rotate = 1
|
39
|
+
log = <%= path %>log/searchd.log
|
40
|
+
query_log = <%= path %>log/query.log
|
23
41
|
read_timeout = 5
|
24
42
|
max_children = 300
|
25
|
-
pid_file =
|
43
|
+
pid_file = <%= path %>log/searchd.pid
|
26
44
|
max_matches = 100000
|
27
45
|
}
|
28
46
|
|
47
|
+
# Client options
|
29
48
|
client
|
30
49
|
{
|
31
|
-
#
|
50
|
+
# Name of the Aspell dictionary (two letters max)
|
51
|
+
dictionary_name = ap
|
52
|
+
|
32
53
|
# How your application connects to the search daemon (not necessarily the same as above)
|
33
54
|
server_host = localhost
|
34
55
|
server_port = 3312
|
35
56
|
}
|
36
57
|
|
58
|
+
# Individual SQL source options
|
37
59
|
source
|
38
|
-
{
|
39
|
-
|
40
|
-
sql_range_step =
|
41
|
-
strip_html = 0
|
42
|
-
index_html_attrs =
|
60
|
+
{
|
61
|
+
sql_ranged_throttle = 0
|
62
|
+
sql_range_step = 5000
|
43
63
|
sql_query_post =
|
44
64
|
}
|
45
65
|
|
66
|
+
# Index building options
|
46
67
|
index
|
47
|
-
{
|
48
|
-
|
49
|
-
|
50
|
-
docinfo = extern # just leave this alone
|
68
|
+
{
|
69
|
+
path = <%= path %>
|
70
|
+
docinfo = extern # Just leave this alone
|
51
71
|
morphology = stem_en
|
52
|
-
stopwords = #
|
72
|
+
stopwords = # <%= path %>/ap-stopwords.txt
|
53
73
|
min_word_len = 1
|
74
|
+
|
75
|
+
# HTML-specific options
|
76
|
+
html_strip = 0
|
77
|
+
html_index_attrs =
|
78
|
+
|
79
|
+
# Enable these if you need wildcard searching. They will slow down indexing significantly.
|
80
|
+
# min_infix_len = 1
|
81
|
+
# enable_star = 1
|
82
|
+
|
54
83
|
charset_type = utf-8 # or sbcs (Single Byte Character Set)
|
55
|
-
charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z,
|
84
|
+
charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F,U+C5->U+E5, U+E5, U+C4->U+E4, U+E4, U+D6->U+F6, U+F6, U+16B, U+0c1->a, U+0c4->a, U+0c9->e, U+0cd->i, U+0d3->o, U+0d4->o, U+0da->u, U+0dd->y, U+0e1->a, U+0e4->a, U+0e9->e, U+0ed->i, U+0f3->o, U+0f4->o, U+0fa->u, U+0fd->y, U+104->U+105, U+105, U+106->U+107, U+10c->c, U+10d->c, U+10e->d, U+10f->d, U+116->U+117, U+117, U+118->U+119, U+11a->e, U+11b->e, U+12E->U+12F, U+12F, U+139->l, U+13a->l, U+13d->l, U+13e->l, U+141->U+142, U+142, U+143->U+144, U+144,U+147->n, U+148->n, U+154->r, U+155->r, U+158->r, U+159->r, U+15A->U+15B, U+15B, U+160->s, U+160->U+161, U+161->s, U+164->t, U+165->t, U+16A->U+16B, U+16B, U+16e->u, U+16f->u, U+172->U+173, U+173, U+179->U+17A, U+17A, U+17B->U+17C, U+17C, U+17d->z, U+17e->z,
|
56
85
|
}
|
@@ -4,5 +4,6 @@ class Geo::Address < ActiveRecord::Base
|
|
4
4
|
|
5
5
|
is_indexed 'fields' => ['name'],
|
6
6
|
'concatenate' => [{'fields' => ['line_1', 'line_2', 'city', 'province_region', 'zip_postal_code'], 'as' => 'content'}],
|
7
|
-
'include' => [{'association_name' => 'state', 'field' => 'name', 'as' => 'state'}]
|
7
|
+
'include' => [{'association_name' => 'state', 'field' => 'name', 'as' => 'state'}],
|
8
|
+
'delta' => true
|
8
9
|
end
|
@@ -3,8 +3,17 @@ class User < ActiveRecord::Base
|
|
3
3
|
has_one :address, :class_name => "Geo::Address"
|
4
4
|
|
5
5
|
is_indexed :fields => ['login', 'email', 'deleted'],
|
6
|
-
:include => [{:association_name => 'specific_seller', :field => 'company_name', :as => 'company'},
|
7
|
-
{:class_name => 'Seller', :field => 'sellers_two.company_name', :as => 'company_two', 'association_sql' => 'LEFT OUTER JOIN sellers AS sellers_two ON users.id = sellers_two.user_id', 'function_sql' => "REPLACE(?, '6', ' replacement ')"}],
|
8
|
-
:conditions => "deleted = '0'"
|
6
|
+
:include => [{:association_name => 'specific_seller', :field => 'company_name', :as => 'company', :facet => true},
|
7
|
+
{:class_name => 'Seller', :field => 'sellers_two.company_name', :as => 'company_two', :facet => true, 'association_sql' => 'LEFT OUTER JOIN sellers AS sellers_two ON users.id = sellers_two.user_id', 'function_sql' => "REPLACE(?, '6', ' replacement ')"}],
|
8
|
+
:conditions => "deleted = '0'",
|
9
|
+
:delta => {:field => 'created_at'}
|
10
|
+
|
11
|
+
def self.find_all_by_id(*args)
|
12
|
+
raise "Wrong finder"
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.custom_find(*args)
|
16
|
+
method_missing(:find_all_by_id, *args)
|
17
|
+
end
|
9
18
|
|
10
19
|
end
|