ultrasphinx 1.6 → 1.6.7
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +5 -1
- data/Manifest +47 -7
- data/README +4 -4
- data/TODO +1 -0
- data/examples/default.base +6 -2
- data/lib/ultrasphinx.rb +1 -1
- data/lib/ultrasphinx/configure.rb +53 -28
- data/lib/ultrasphinx/fields.rb +16 -13
- data/lib/ultrasphinx/postgresql/concat_ws.sql +35 -0
- data/lib/ultrasphinx/postgresql/crc32.sql +7 -0
- data/lib/ultrasphinx/postgresql/group_concat.sql +25 -0
- data/lib/ultrasphinx/{hex_to_int.sql → postgresql/hex_to_int.sql} +0 -0
- data/lib/ultrasphinx/postgresql/language.sql +1 -0
- data/lib/ultrasphinx/postgresql/unix_timestamp.sql +12 -0
- data/lib/ultrasphinx/search/internals.rb +42 -16
- data/lib/ultrasphinx/ultrasphinx.rb +23 -12
- data/test/integration/app/app/models/person/user.rb +1 -1
- data/test/integration/app/config/database.yml +9 -13
- data/test/integration/app/config/ultrasphinx/development.conf +6 -6
- data/test/integration/app/config/ultrasphinx/development.conf.canonical +6 -6
- data/test/integration/app/db/schema.rb +9 -2
- data/test/integration/search_test.rb +16 -6
- data/test/setup.rb +5 -1
- data/test/ts.multi +2 -0
- data/ultrasphinx.gemspec +5 -5
- data/vendor/riddle/{MIT-LICENSE → MIT-LICENCE} +0 -0
- data/vendor/riddle/README +60 -0
- data/vendor/riddle/Rakefile +25 -0
- data/vendor/riddle/{riddle.rb → lib/riddle.rb} +3 -0
- data/vendor/riddle/{riddle → lib/riddle}/client.rb +73 -4
- data/vendor/riddle/{riddle → lib/riddle}/client/filter.rb +0 -0
- data/vendor/riddle/{riddle → lib/riddle}/client/message.rb +2 -0
- data/vendor/riddle/{riddle → lib/riddle}/client/response.rb +0 -0
- 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/filter.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/filter_array.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/filter_array_exclude.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/filter_floats.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/filter_floats_exclude.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/filter_floats_range.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/filter_range.bin +0 -0
- data/vendor/riddle/spec/fixtures/data/filter_range_exclude.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/phrase.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/sphinx/configuration.erb +38 -0
- data/vendor/riddle/spec/fixtures/sql/conf.example.yml +3 -0
- data/vendor/riddle/spec/fixtures/sql/data.sql +25000 -0
- data/vendor/riddle/spec/fixtures/sql/structure.sql +16 -0
- data/vendor/riddle/spec/functional/excerpt_spec.rb +102 -0
- data/vendor/riddle/spec/functional/search_spec.rb +69 -0
- data/vendor/riddle/spec/functional/update_spec.rb +41 -0
- data/vendor/riddle/spec/spec_helper.rb +25 -0
- data/vendor/riddle/spec/sphinx_helper.rb +91 -0
- data/vendor/riddle/spec/unit/client_spec.rb +140 -0
- data/vendor/riddle/spec/unit/filter_spec.rb +33 -0
- data/vendor/riddle/spec/unit/message_spec.rb +63 -0
- data/vendor/riddle/spec/unit/response_spec.rb +64 -0
- metadata +95 -55
- metadata.gz.sig +0 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
/*
|
3
|
+
mysqlcompat-1.0b3
|
4
|
+
public domain
|
5
|
+
GROUP_CONCAT()
|
6
|
+
Note: For DISTINCT and ORDER BY a subquery is required
|
7
|
+
*/
|
8
|
+
|
9
|
+
CREATE OR REPLACE FUNCTION _group_concat(text, text)
|
10
|
+
RETURNS text AS $$
|
11
|
+
SELECT CASE
|
12
|
+
WHEN $2 IS NULL THEN $1
|
13
|
+
WHEN $1 IS NULL THEN $2
|
14
|
+
ELSE $1 operator(pg_catalog.||) ' ' operator(pg_catalog.||) $2
|
15
|
+
END
|
16
|
+
$$ IMMUTABLE LANGUAGE SQL;
|
17
|
+
|
18
|
+
DROP AGGREGATE IF EXISTS group_concat(text);
|
19
|
+
|
20
|
+
CREATE AGGREGATE group_concat (
|
21
|
+
BASETYPE = text,
|
22
|
+
SFUNC = _group_concat,
|
23
|
+
STYPE = text
|
24
|
+
);
|
25
|
+
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
CREATE LANGUAGE 'plpgsql';
|
@@ -157,28 +157,53 @@ module Ultrasphinx
|
|
157
157
|
|
158
158
|
def rebuild_facet_cache(facet)
|
159
159
|
# Cache the reverse hash map for the textual facet if it hasn't been done yet
|
160
|
-
# XXX
|
160
|
+
# XXX Not necessarily optimal since it requires a direct DB hit once per mongrel
|
161
161
|
Ultrasphinx.say "caching hash reverse map for text facet #{facet}"
|
162
162
|
|
163
|
-
Fields.instance.classes[facet].
|
164
|
-
|
165
|
-
|
166
|
-
|
163
|
+
configured_classes = Fields.instance.classes[facet].map do |klass|
|
164
|
+
|
165
|
+
# Concatenates might not work well
|
166
|
+
type, configuration = nil, nil
|
167
|
+
MODEL_CONFIGURATION[klass.name].except('conditions').each do |_type, values|
|
168
|
+
type = _type
|
169
|
+
configuration = values.detect { |this_field| this_field['as'] == facet }
|
170
|
+
break if configuration
|
167
171
|
end
|
168
172
|
|
169
|
-
|
170
|
-
|
173
|
+
unless configuration and configuration['facet']
|
174
|
+
Ultrasphinx.say "model #{klass.name} has the requested '#{facet}' field, but it was not configured for faceting, and will be skipped"
|
175
|
+
next
|
176
|
+
end
|
177
|
+
|
178
|
+
FACET_CACHE[facet] ||= {}
|
171
179
|
|
172
|
-
|
173
|
-
|
180
|
+
# XXX This is a duplication of stuff already known in configure.rb, and ought to be cleaned up,
|
181
|
+
# but that would mean we have to either parse the .conf or configure every time at boot
|
182
|
+
|
183
|
+
field_string, join_string = case type
|
184
|
+
when 'fields'
|
185
|
+
[configuration['field'], ""]
|
186
|
+
when 'include'
|
187
|
+
# XXX Only handles the basic case. No test coverage.
|
188
|
+
["included.#{configuration['field']}",
|
189
|
+
(configuration['association_sql'] or "LEFT OUTER JOIN #{configuration['table']} AS included ON included.#{configuration['class_name'].constantize.primary_key} = #{klass.table_name}.#{configuration['class_name'].underscore}_id")
|
190
|
+
]
|
191
|
+
when 'concatenate'
|
192
|
+
# Wait for someone to complain before worrying about this
|
193
|
+
raise "Concatenation text facets have not been implemented"
|
174
194
|
end
|
175
|
-
|
176
|
-
klass.connection.execute("SELECT #{
|
177
|
-
|
195
|
+
|
196
|
+
klass.connection.execute("SELECT #{field_string} AS value, CRC32(#{field_string}) AS hash FROM #{klass.table_name} #{join_string} GROUP BY value").each do |value, hash|
|
197
|
+
FACET_CACHE[facet][hash.to_i] = value
|
178
198
|
end
|
199
|
+
klass
|
179
200
|
end
|
201
|
+
|
202
|
+
configured_classes.compact!
|
203
|
+
raise ConfigurationError, "no classes were correctly configured for text faceting on '#{facet}'" if configured_classes.empty?
|
204
|
+
|
180
205
|
FACET_CACHE[facet]
|
181
|
-
end
|
206
|
+
end
|
182
207
|
|
183
208
|
# Inverse-modulus map the Sphinx ids to the table-specific ids
|
184
209
|
def convert_sphinx_ids(sphinx_ids)
|
@@ -204,12 +229,13 @@ module Ultrasphinx
|
|
204
229
|
end
|
205
230
|
|
206
231
|
# Load it
|
207
|
-
|
232
|
+
begin
|
208
233
|
# XXX Does not use Memcached's multiget, or MySQL's, for that matter
|
209
|
-
klass.send(finder, id)
|
234
|
+
record = klass.send(finder, id)
|
235
|
+
raise ActiveRecord::RecordNotFound unless record
|
210
236
|
rescue ActiveRecord::RecordNotFound => e
|
211
237
|
if Ultrasphinx::Search.client_options['ignore_missing_records']
|
212
|
-
|
238
|
+
say "warning; #{klass}.#{finder}(#{id}) returned RecordNotFound"
|
213
239
|
else
|
214
240
|
raise(e)
|
215
241
|
end
|
@@ -49,18 +49,26 @@ module Ultrasphinx
|
|
49
49
|
CONNECTION_DEFAULTS = {
|
50
50
|
:host => 'localhost'
|
51
51
|
}
|
52
|
+
|
53
|
+
mattr_accessor :with_rake
|
54
|
+
|
55
|
+
def self.load_stored_procedure(name)
|
56
|
+
open("#{THIS_DIR}/postgresql/#{name}.sql").read.gsub(/\s+/, ' ')
|
57
|
+
end
|
52
58
|
|
53
59
|
ADAPTER_SQL_FUNCTIONS = {
|
54
60
|
'mysql' => {
|
55
|
-
'
|
56
|
-
'
|
57
|
-
|
58
|
-
},
|
61
|
+
'group_concat' => "CAST(GROUP_CONCAT(DISTINCT ? SEPARATOR ' ') AS CHAR)",
|
62
|
+
'stored_procedures' => {}
|
63
|
+
},
|
59
64
|
'postgresql' => {
|
60
|
-
'
|
61
|
-
'
|
62
|
-
|
63
|
-
|
65
|
+
'group_concat' => "GROUP_CONCAT(?)",
|
66
|
+
'stored_procedures' => Hash[*(
|
67
|
+
['hex_to_int', 'group_concat', 'concat_ws', 'unix_timestamp', 'crc32'].map do |name|
|
68
|
+
[name, load_stored_procedure(name)]
|
69
|
+
end.flatten
|
70
|
+
)
|
71
|
+
]
|
64
72
|
}
|
65
73
|
}
|
66
74
|
|
@@ -72,14 +80,17 @@ sql_query_pre = SET NAMES utf8
|
|
72
80
|
),
|
73
81
|
'postgresql' => %(
|
74
82
|
type = pgsql
|
75
|
-
sql_query_pre = ) + ADAPTER_SQL_FUNCTIONS['postgresql']['
|
83
|
+
sql_query_pre = ) + ADAPTER_SQL_FUNCTIONS['postgresql']['stored_procedures'].values.join(' ') + %(
|
76
84
|
)
|
77
85
|
}
|
78
86
|
|
79
87
|
ADAPTER = ActiveRecord::Base.connection.instance_variable_get("@config")[:adapter] rescue 'mysql'
|
80
|
-
|
81
|
-
|
82
|
-
|
88
|
+
|
89
|
+
# Install the stored procedures
|
90
|
+
ADAPTER_SQL_FUNCTIONS[ADAPTER]['stored_procedures'].each do |key, value|
|
91
|
+
ActiveRecord::Base.connection.execute(value)
|
92
|
+
end
|
93
|
+
|
83
94
|
# Logger.
|
84
95
|
def self.say msg
|
85
96
|
if with_rake
|
@@ -5,6 +5,6 @@ class User < ActiveRecord::Base
|
|
5
5
|
is_indexed :fields => ['login', 'email', 'deleted'],
|
6
6
|
:include => [{:class_name => 'Seller', :field => 'company_name', :as => 'company'},
|
7
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 =>
|
8
|
+
:conditions => "deleted = '0'"
|
9
9
|
|
10
10
|
end
|
@@ -1,21 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
adapter: mysql
|
1
|
+
defaults: &defaults
|
2
|
+
adapter: <%= ENV['DB'] || 'mysql' %>
|
4
3
|
host: localhost
|
5
|
-
database: ultrasphinx_development
|
6
4
|
username: root
|
7
5
|
password:
|
6
|
+
|
7
|
+
development:
|
8
|
+
<<: *defaults
|
9
|
+
database: ultrasphinx_development
|
8
10
|
|
9
11
|
test:
|
10
|
-
|
11
|
-
host: localhost
|
12
|
+
<<: *defaults
|
12
13
|
database: ultrasphinx_test
|
13
|
-
|
14
|
-
password:
|
15
|
-
|
14
|
+
|
16
15
|
production:
|
17
|
-
|
18
|
-
host: localhost
|
16
|
+
<<: *defaults
|
19
17
|
database: ultrasphinx_production
|
20
|
-
username: root
|
21
|
-
password:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
|
-
# Auto-generated at Wed
|
2
|
+
# Auto-generated at Wed Dec 12 12:09:45 -0500 2007.
|
3
3
|
# Hand modifications will be overwritten.
|
4
|
-
# /Users/eweaver/Desktop/projects/
|
4
|
+
# /Users/eweaver/Desktop/projects/chow/vendor/plugins/ultrasphinx/test/integration/app/config/ultrasphinx/default.base
|
5
5
|
indexer {
|
6
6
|
mem_limit = 256M
|
7
7
|
}
|
@@ -34,7 +34,7 @@ sql_host = localhost
|
|
34
34
|
sql_pass =
|
35
35
|
sql_user = root
|
36
36
|
sql_query_range = SELECT MIN(id), MAX(id) FROM states
|
37
|
-
sql_query = SELECT (states.id * 4 + 0) AS id, CAST(GROUP_CONCAT(DISTINCT addresses.name SEPARATOR ' ') AS CHAR) AS address_name, 0 AS capitalization, 'Geo::State' AS class, 0 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS company_two, '' AS content,
|
37
|
+
sql_query = SELECT (states.id * 4 + 0) AS id, CAST(GROUP_CONCAT(DISTINCT addresses.name SEPARATOR ' ') AS CHAR) AS address_name, 0 AS capitalization, 'Geo::State' AS class, 0 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS company_two, '' AS content, 18000 AS created_at, 0 AS deleted, '' AS email, '' AS login, '' AS mission_statement, '' AS name, '' AS state, 0 AS user_id FROM states LEFT OUTER JOIN addresses AS addresses ON states.id = addresses.state_id WHERE states.id >= $start AND states.id <= $end GROUP BY states.id
|
38
38
|
|
39
39
|
sql_group_column = capitalization
|
40
40
|
sql_group_column = class_id
|
@@ -65,7 +65,7 @@ sql_host = localhost
|
|
65
65
|
sql_pass =
|
66
66
|
sql_user = root
|
67
67
|
sql_query_range = SELECT MIN(id), MAX(id) FROM sellers
|
68
|
-
sql_query = SELECT (sellers.id * 4 + 1) AS id, '' AS address_name, sellers.capitalization AS capitalization, 'Seller' AS class, 1 AS class_id, '' AS company, sellers.company_name AS company_name, CRC32(sellers.company_name) AS company_name_facet, '' AS company_two, '' AS content, UNIX_TIMESTAMP(sellers.created_at) AS created_at, 0 AS deleted, '' AS email, '' AS login, sellers.mission_statement AS mission_statement, '' AS name, '' AS state, sellers.user_id AS user_id FROM sellers WHERE sellers.id >= $start AND sellers.id <= $end GROUP BY id
|
68
|
+
sql_query = SELECT (sellers.id * 4 + 1) AS id, '' AS address_name, sellers.capitalization AS capitalization, 'Seller' AS class, 1 AS class_id, '' AS company, sellers.company_name AS company_name, CRC32(sellers.company_name) AS company_name_facet, '' AS company_two, '' AS content, UNIX_TIMESTAMP(sellers.created_at) AS created_at, 0 AS deleted, '' AS email, '' AS login, sellers.mission_statement AS mission_statement, '' AS name, '' AS state, sellers.user_id AS user_id FROM sellers WHERE sellers.id >= $start AND sellers.id <= $end GROUP BY sellers.id
|
69
69
|
|
70
70
|
sql_group_column = capitalization
|
71
71
|
sql_group_column = class_id
|
@@ -96,7 +96,7 @@ sql_host = localhost
|
|
96
96
|
sql_pass =
|
97
97
|
sql_user = root
|
98
98
|
sql_query_range = SELECT MIN(id), MAX(id) FROM addresses
|
99
|
-
sql_query = SELECT (addresses.id * 4 + 2) AS id, '' AS address_name, 0 AS capitalization, 'Geo::Address' AS class, 2 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS company_two, CONCAT_WS(' ', addresses.line_1, addresses.line_2, addresses.city, addresses.province_region, addresses.zip_postal_code) AS content,
|
99
|
+
sql_query = SELECT (addresses.id * 4 + 2) AS id, '' AS address_name, 0 AS capitalization, 'Geo::Address' AS class, 2 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS company_two, CONCAT_WS(' ', addresses.line_1, addresses.line_2, addresses.city, addresses.province_region, addresses.zip_postal_code) AS content, 18000 AS created_at, 0 AS deleted, '' AS email, '' AS login, '' AS mission_statement, addresses.name AS name, states.name AS state, 0 AS user_id FROM addresses LEFT OUTER JOIN states AS states ON states.id = addresses.state_id WHERE addresses.id >= $start AND addresses.id <= $end GROUP BY addresses.id
|
100
100
|
|
101
101
|
sql_group_column = capitalization
|
102
102
|
sql_group_column = class_id
|
@@ -127,7 +127,7 @@ sql_host = localhost
|
|
127
127
|
sql_pass =
|
128
128
|
sql_user = root
|
129
129
|
sql_query_range = SELECT MIN(id), MAX(id) FROM users
|
130
|
-
sql_query = SELECT (users.id * 4 + 3) AS id, '' AS address_name, 0 AS capitalization, 'User' AS class, 3 AS class_id, sellers.company_name AS company, '' AS company_name, 0 AS company_name_facet, REPLACE(sellers_two.company_name, '6', ' replacement ') AS company_two, '' AS content,
|
130
|
+
sql_query = SELECT (users.id * 4 + 3) AS id, '' AS address_name, 0 AS capitalization, 'User' AS class, 3 AS class_id, sellers.company_name AS company, '' AS company_name, 0 AS company_name_facet, REPLACE(sellers_two.company_name, '6', ' replacement ') AS company_two, '' AS content, 18000 AS created_at, users.deleted AS deleted, users.email AS email, users.login AS login, '' AS mission_statement, '' AS name, '' AS state, 0 AS user_id FROM users LEFT OUTER JOIN sellers AS sellers ON users.id = sellers.user_id LEFT OUTER JOIN sellers AS sellers_two ON users.id = sellers_two.user_id WHERE users.id >= $start AND users.id <= $end AND (deleted = '0') GROUP BY users.id
|
131
131
|
|
132
132
|
sql_group_column = capitalization
|
133
133
|
sql_group_column = class_id
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
|
-
# Auto-generated at Wed
|
2
|
+
# Auto-generated at Wed Dec 12 02:47:44 -0500 2007.
|
3
3
|
# Hand modifications will be overwritten.
|
4
|
-
# /Users/eweaver/Desktop/projects/
|
4
|
+
# /Users/eweaver/Desktop/projects/chow/vendor/plugins/ultrasphinx/test/integration/app/config/ultrasphinx/default.base
|
5
5
|
indexer {
|
6
6
|
mem_limit = 256M
|
7
7
|
}
|
@@ -34,7 +34,7 @@ sql_host = localhost
|
|
34
34
|
sql_pass =
|
35
35
|
sql_user = root
|
36
36
|
sql_query_range = SELECT MIN(id), MAX(id) FROM states
|
37
|
-
sql_query = SELECT (states.id * 4 + 0) AS id, CAST(GROUP_CONCAT(DISTINCT addresses.name SEPARATOR ' ') AS CHAR) AS address_name, 0 AS capitalization, 'Geo::State' AS class, 0 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS company_two, '' AS content,
|
37
|
+
sql_query = SELECT (states.id * 4 + 0) AS id, CAST(GROUP_CONCAT(DISTINCT addresses.name SEPARATOR ' ') AS CHAR) AS address_name, 0 AS capitalization, 'Geo::State' AS class, 0 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS company_two, '' AS content, 18000 AS created_at, 0 AS deleted, '' AS email, '' AS login, '' AS mission_statement, '' AS name, '' AS state, 0 AS user_id FROM states LEFT OUTER JOIN addresses AS addresses ON states.id = addresses.state_id WHERE states.id >= $start AND states.id <= $end GROUP BY states.id
|
38
38
|
|
39
39
|
sql_group_column = capitalization
|
40
40
|
sql_group_column = class_id
|
@@ -65,7 +65,7 @@ sql_host = localhost
|
|
65
65
|
sql_pass =
|
66
66
|
sql_user = root
|
67
67
|
sql_query_range = SELECT MIN(id), MAX(id) FROM sellers
|
68
|
-
sql_query = SELECT (sellers.id * 4 + 1) AS id, '' AS address_name, sellers.capitalization AS capitalization, 'Seller' AS class, 1 AS class_id, '' AS company, sellers.company_name AS company_name, CRC32(sellers.company_name) AS company_name_facet, '' AS company_two, '' AS content, UNIX_TIMESTAMP(sellers.created_at) AS created_at, 0 AS deleted, '' AS email, '' AS login, sellers.mission_statement AS mission_statement, '' AS name, '' AS state, sellers.user_id AS user_id FROM sellers WHERE sellers.id >= $start AND sellers.id <= $end GROUP BY id
|
68
|
+
sql_query = SELECT (sellers.id * 4 + 1) AS id, '' AS address_name, sellers.capitalization AS capitalization, 'Seller' AS class, 1 AS class_id, '' AS company, sellers.company_name AS company_name, CRC32(sellers.company_name) AS company_name_facet, '' AS company_two, '' AS content, UNIX_TIMESTAMP(sellers.created_at) AS created_at, 0 AS deleted, '' AS email, '' AS login, sellers.mission_statement AS mission_statement, '' AS name, '' AS state, sellers.user_id AS user_id FROM sellers WHERE sellers.id >= $start AND sellers.id <= $end GROUP BY sellers.id
|
69
69
|
|
70
70
|
sql_group_column = capitalization
|
71
71
|
sql_group_column = class_id
|
@@ -96,7 +96,7 @@ sql_host = localhost
|
|
96
96
|
sql_pass =
|
97
97
|
sql_user = root
|
98
98
|
sql_query_range = SELECT MIN(id), MAX(id) FROM addresses
|
99
|
-
sql_query = SELECT (addresses.id * 4 + 2) AS id, '' AS address_name, 0 AS capitalization, 'Geo::Address' AS class, 2 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS company_two, CONCAT_WS(' ', addresses.line_1, addresses.line_2, addresses.city, addresses.province_region, addresses.zip_postal_code) AS content,
|
99
|
+
sql_query = SELECT (addresses.id * 4 + 2) AS id, '' AS address_name, 0 AS capitalization, 'Geo::Address' AS class, 2 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS company_two, CONCAT_WS(' ', addresses.line_1, addresses.line_2, addresses.city, addresses.province_region, addresses.zip_postal_code) AS content, 18000 AS created_at, 0 AS deleted, '' AS email, '' AS login, '' AS mission_statement, addresses.name AS name, states.name AS state, 0 AS user_id FROM addresses LEFT OUTER JOIN states AS states ON states.id = addresses.state_id WHERE addresses.id >= $start AND addresses.id <= $end GROUP BY addresses.id
|
100
100
|
|
101
101
|
sql_group_column = capitalization
|
102
102
|
sql_group_column = class_id
|
@@ -127,7 +127,7 @@ sql_host = localhost
|
|
127
127
|
sql_pass =
|
128
128
|
sql_user = root
|
129
129
|
sql_query_range = SELECT MIN(id), MAX(id) FROM users
|
130
|
-
sql_query = SELECT (users.id * 4 + 3) AS id, '' AS address_name, 0 AS capitalization, 'User' AS class, 3 AS class_id, sellers.company_name AS company, '' AS company_name, 0 AS company_name_facet, REPLACE(sellers_two.company_name, '6', ' replacement ') AS company_two, '' AS content,
|
130
|
+
sql_query = SELECT (users.id * 4 + 3) AS id, '' AS address_name, 0 AS capitalization, 'User' AS class, 3 AS class_id, sellers.company_name AS company, '' AS company_name, 0 AS company_name_facet, REPLACE(sellers_two.company_name, '6', ' replacement ') AS company_two, '' AS content, 18000 AS created_at, users.deleted AS deleted, users.email AS email, users.login AS login, '' AS mission_statement, '' AS name, '' AS state, 0 AS user_id FROM users LEFT OUTER JOIN sellers AS sellers ON users.id = sellers.user_id LEFT OUTER JOIN sellers AS sellers_two ON users.id = sellers_two.user_id WHERE users.id >= $start AND users.id <= $end AND (deleted = '0') GROUP BY users.id
|
131
131
|
|
132
132
|
sql_group_column = capitalization
|
133
133
|
sql_group_column = class_id
|
@@ -1,6 +1,13 @@
|
|
1
|
-
# This file is
|
2
|
-
# migrations feature of ActiveRecord to incrementally modify your database, and
|
1
|
+
# This file is auto-generated from the current state of the database. Instead of editing this file,
|
2
|
+
# please use the migrations feature of ActiveRecord to incrementally modify your database, and
|
3
3
|
# then regenerate this schema definition.
|
4
|
+
#
|
5
|
+
# Note that this schema.rb definition is the authoritative source for your database schema. If you need
|
6
|
+
# to create the application database on another system, you should be using db:schema:load, not running
|
7
|
+
# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
8
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
9
|
+
#
|
10
|
+
# It's strongly recommended to check this file into your version control system.
|
4
11
|
|
5
12
|
ActiveRecord::Schema.define(:version => 8) do
|
6
13
|
|
@@ -68,18 +68,20 @@ class SearchTest < Test::Unit::TestCase
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def test_empty_query
|
71
|
+
assert_nothing_raised do
|
72
|
+
@s = S.new.run
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_total_entries
|
71
77
|
@total = Ultrasphinx::MODEL_CONFIGURATION.keys.inject(0) do |acc, class_name|
|
72
78
|
acc + class_name.constantize.count
|
73
79
|
end - User.count(:conditions => {:deleted => true })
|
74
80
|
|
75
|
-
assert_nothing_raised do
|
76
|
-
@s = S.new.run
|
77
|
-
end
|
78
|
-
|
79
81
|
assert_equal(
|
80
82
|
@total,
|
81
|
-
@s.total_entries
|
82
|
-
)
|
83
|
+
@s = S.new.run.total_entries
|
84
|
+
)
|
83
85
|
end
|
84
86
|
|
85
87
|
def test_sort_by_date
|
@@ -101,8 +103,16 @@ class SearchTest < Test::Unit::TestCase
|
|
101
103
|
Seller.find(:all, :limit => 5, :order => 'mission_statement ASC').map(&:mission_statement),
|
102
104
|
S.new(:class_names => 'Seller', :sort_by => 'mission_statement', :sort_mode => 'ascending', :per_page => 5).run.map(&:mission_statement)
|
103
105
|
)
|
106
|
+
assert S.new(:sort_by => 'mission_statement', :sort_mode => 'ascending').run.size > 0
|
104
107
|
end
|
105
108
|
|
109
|
+
def test_sort_by_string_using_query
|
110
|
+
assert_equal(
|
111
|
+
Seller.find(10,11, :order => 'mission_statement ASC').map(&:mission_statement),
|
112
|
+
S.new(:class_names => 'Seller', :query => 'seller10 or seller11', :sort_by => 'mission_statement', :sort_mode => 'ascending', :per_page => 2).run.map(&:mission_statement)
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
106
116
|
def test_filter
|
107
117
|
assert_equal(
|
108
118
|
Seller.count(:conditions => 'user_id = 17'),
|
data/test/setup.rb
CHANGED
@@ -5,11 +5,15 @@ puts ["Please make sure that test/integration/app/vendor/rails is symlinked",
|
|
5
5
|
"to a Rails trunk checkout in order for the rake tasks to run properly."]
|
6
6
|
|
7
7
|
Dir.chdir "#{File.dirname(__FILE__)}/integration/app/" do
|
8
|
+
system("killall searchd")
|
9
|
+
system("rm -rf /tmp/sphinx")
|
10
|
+
system("rm -rf config/ultrasphinx/development.conf")
|
8
11
|
Dir.chdir "vendor/plugins" do
|
9
12
|
system("rm ultrasphinx; ln -s ../../../../../ ultrasphinx")
|
10
13
|
end
|
11
14
|
system("rake db:create")
|
12
15
|
system("rake db:migrate db:fixtures:load")
|
13
16
|
system("rake us:boot")
|
14
|
-
system("
|
17
|
+
system("rm /tmp/ultrasphinx-stopwords.txt")
|
18
|
+
system("rake ultrasphinx:spelling:build")
|
15
19
|
end
|
data/test/ts.multi
ADDED
data/ultrasphinx.gemspec
CHANGED
@@ -1,24 +1,24 @@
|
|
1
1
|
|
2
|
-
# Gem::Specification for Ultrasphinx-1.6
|
2
|
+
# Gem::Specification for Ultrasphinx-1.6.7
|
3
3
|
# Originally generated by Echoe
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = %q{ultrasphinx}
|
7
|
-
s.version = "1.6"
|
7
|
+
s.version = "1.6.7"
|
8
8
|
|
9
9
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.authors = [""]
|
13
|
-
s.date = %q{2007-
|
13
|
+
s.date = %q{2007-12-13}
|
14
14
|
s.description = %q{Ruby on Rails configurator and client to the Sphinx fulltext search engine.}
|
15
15
|
s.email = %q{}
|
16
|
-
s.files = ["CHANGELOG", "examples/ap.multi", "examples/default.base", "init.rb", "lib/ultrasphinx/autoload.rb", "lib/ultrasphinx/configure.rb", "lib/ultrasphinx/core_extensions.rb", "lib/ultrasphinx/fields.rb", "lib/ultrasphinx/hex_to_int.sql", "lib/ultrasphinx/
|
16
|
+
s.files = ["CHANGELOG", "examples/ap.multi", "examples/default.base", "init.rb", "lib/ultrasphinx/autoload.rb", "lib/ultrasphinx/configure.rb", "lib/ultrasphinx/core_extensions.rb", "lib/ultrasphinx/fields.rb", "lib/ultrasphinx/is_indexed.rb", "lib/ultrasphinx/postgresql/concat_ws.sql", "lib/ultrasphinx/postgresql/crc32.sql", "lib/ultrasphinx/postgresql/group_concat.sql", "lib/ultrasphinx/postgresql/hex_to_int.sql", "lib/ultrasphinx/postgresql/language.sql", "lib/ultrasphinx/postgresql/unix_timestamp.sql", "lib/ultrasphinx/search/internals.rb", "lib/ultrasphinx/search/parser.rb", "lib/ultrasphinx/search.rb", "lib/ultrasphinx/spell.rb", "lib/ultrasphinx/ultrasphinx.rb", "lib/ultrasphinx.rb", "LICENSE", "Manifest", "README", "tasks/ultrasphinx.rake", "test/config/ultrasphinx/test.base", "test/integration/app/app/controllers/addresses_controller.rb", "test/integration/app/app/controllers/application.rb", "test/integration/app/app/controllers/sellers_controller.rb", "test/integration/app/app/controllers/states_controller.rb", "test/integration/app/app/controllers/users_controller.rb", "test/integration/app/app/helpers/addresses_helper.rb", "test/integration/app/app/helpers/application_helper.rb", "test/integration/app/app/helpers/sellers_helper.rb", "test/integration/app/app/helpers/states_helper.rb", "test/integration/app/app/helpers/users_helper.rb", "test/integration/app/app/models/geo/address.rb", "test/integration/app/app/models/geo/state.rb", "test/integration/app/app/models/person/user.rb", "test/integration/app/app/models/seller.rb", "test/integration/app/app/views/addresses/edit.html.erb", "test/integration/app/app/views/addresses/index.html.erb", "test/integration/app/app/views/addresses/new.html.erb", "test/integration/app/app/views/addresses/show.html.erb", "test/integration/app/app/views/layouts/addresses.html.erb", "test/integration/app/app/views/layouts/sellers.html.erb", "test/integration/app/app/views/layouts/states.html.erb", "test/integration/app/app/views/layouts/users.html.erb", "test/integration/app/app/views/sellers/edit.html.erb", "test/integration/app/app/views/sellers/index.html.erb", "test/integration/app/app/views/sellers/new.html.erb", "test/integration/app/app/views/sellers/show.html.erb", "test/integration/app/app/views/states/edit.html.erb", "test/integration/app/app/views/states/index.html.erb", "test/integration/app/app/views/states/new.html.erb", "test/integration/app/app/views/states/show.html.erb", "test/integration/app/app/views/users/edit.html.erb", "test/integration/app/app/views/users/index.html.erb", "test/integration/app/app/views/users/new.html.erb", "test/integration/app/app/views/users/show.html.erb", "test/integration/app/config/boot.rb", "test/integration/app/config/database.yml", "test/integration/app/config/environment.rb", "test/integration/app/config/environments/development.rb", "test/integration/app/config/environments/production.rb", "test/integration/app/config/environments/test.rb", "test/integration/app/config/locomotive.yml", "test/integration/app/config/routes.rb", "test/integration/app/config/ultrasphinx/default.base", "test/integration/app/config/ultrasphinx/development.conf", "test/integration/app/config/ultrasphinx/development.conf.canonical", "test/integration/app/db/migrate/001_create_users.rb", "test/integration/app/db/migrate/002_create_sellers.rb", "test/integration/app/db/migrate/003_create_addresses.rb", "test/integration/app/db/migrate/004_create_states.rb", "test/integration/app/db/migrate/005_add_capitalization_to_seller.rb", "test/integration/app/db/migrate/006_add_deleted_to_user.rb", "test/integration/app/db/migrate/007_add_lat_and_long_to_address.rb", "test/integration/app/db/migrate/008_add_mission_statement_to_seller.rb", "test/integration/app/db/schema.rb", "test/integration/app/doc/README_FOR_APP", "test/integration/app/public/404.html", "test/integration/app/public/500.html", "test/integration/app/public/dispatch.cgi", "test/integration/app/public/dispatch.fcgi", "test/integration/app/public/dispatch.rb", "test/integration/app/public/favicon.ico", "test/integration/app/public/images/rails.png", "test/integration/app/public/index.html", "test/integration/app/public/javascripts/application.js", "test/integration/app/public/javascripts/controls.js", "test/integration/app/public/javascripts/dragdrop.js", "test/integration/app/public/javascripts/effects.js", "test/integration/app/public/javascripts/prototype.js", "test/integration/app/public/robots.txt", "test/integration/app/public/stylesheets/scaffold.css", "test/integration/app/Rakefile", "test/integration/app/README", "test/integration/app/script/about", "test/integration/app/script/breakpointer", "test/integration/app/script/console", "test/integration/app/script/destroy", "test/integration/app/script/generate", "test/integration/app/script/performance/benchmarker", "test/integration/app/script/performance/profiler", "test/integration/app/script/plugin", "test/integration/app/script/process/inspector", "test/integration/app/script/process/reaper", "test/integration/app/script/process/spawner", "test/integration/app/script/runner", "test/integration/app/script/server", "test/integration/app/test/fixtures/addresses.yml", "test/integration/app/test/fixtures/sellers.yml", "test/integration/app/test/fixtures/states.yml", "test/integration/app/test/fixtures/users.yml", "test/integration/app/test/functional/addresses_controller_test.rb", "test/integration/app/test/functional/sellers_controller_test.rb", "test/integration/app/test/functional/states_controller_test.rb", "test/integration/app/test/functional/users_controller_test.rb", "test/integration/app/test/test_helper.rb", "test/integration/app/test/unit/address_test.rb", "test/integration/app/test/unit/seller_test.rb", "test/integration/app/test/unit/state_test.rb", "test/integration/app/test/unit/user_test.rb", "test/integration/configure_test.rb", "test/integration/search_test.rb", "test/integration/server_test.rb", "test/integration/spell_test.rb", "test/setup.rb", "test/test_all.rb", "test/test_helper.rb", "test/ts.multi", "test/unit/parser_test.rb", "TODO", "vendor/riddle/lib/riddle/client/filter.rb", "vendor/riddle/lib/riddle/client/message.rb", "vendor/riddle/lib/riddle/client/response.rb", "vendor/riddle/lib/riddle/client.rb", "vendor/riddle/lib/riddle.rb", "vendor/riddle/MIT-LICENCE", "vendor/riddle/Rakefile", "vendor/riddle/README", "vendor/riddle/spec/fixtures/data/anchor.bin", "vendor/riddle/spec/fixtures/data/any.bin", "vendor/riddle/spec/fixtures/data/boolean.bin", "vendor/riddle/spec/fixtures/data/distinct.bin", "vendor/riddle/spec/fixtures/data/filter.bin", "vendor/riddle/spec/fixtures/data/filter_array.bin", "vendor/riddle/spec/fixtures/data/filter_array_exclude.bin", "vendor/riddle/spec/fixtures/data/filter_floats.bin", "vendor/riddle/spec/fixtures/data/filter_floats_exclude.bin", "vendor/riddle/spec/fixtures/data/filter_floats_range.bin", "vendor/riddle/spec/fixtures/data/filter_range.bin", "vendor/riddle/spec/fixtures/data/filter_range_exclude.bin", "vendor/riddle/spec/fixtures/data/group.bin", "vendor/riddle/spec/fixtures/data/index.bin", "vendor/riddle/spec/fixtures/data/phrase.bin", "vendor/riddle/spec/fixtures/data/simple.bin", "vendor/riddle/spec/fixtures/data/sort.bin", "vendor/riddle/spec/fixtures/data/update_simple.bin", "vendor/riddle/spec/fixtures/data/weights.bin", "vendor/riddle/spec/fixtures/sphinx/configuration.erb", "vendor/riddle/spec/fixtures/sql/conf.example.yml", "vendor/riddle/spec/fixtures/sql/data.sql", "vendor/riddle/spec/fixtures/sql/structure.sql", "vendor/riddle/spec/functional/excerpt_spec.rb", "vendor/riddle/spec/functional/search_spec.rb", "vendor/riddle/spec/functional/update_spec.rb", "vendor/riddle/spec/spec_helper.rb", "vendor/riddle/spec/sphinx_helper.rb", "vendor/riddle/spec/unit/client_spec.rb", "vendor/riddle/spec/unit/filter_spec.rb", "vendor/riddle/spec/unit/message_spec.rb", "vendor/riddle/spec/unit/response_spec.rb", "vendor/will_paginate/LICENSE", "ultrasphinx.gemspec"]
|
17
17
|
s.has_rdoc = true
|
18
18
|
s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/ultrasphinx/}
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
s.rubyforge_project = %q{fauna}
|
21
|
-
s.rubygems_version = %q{0.9.
|
21
|
+
s.rubygems_version = %q{0.9.5}
|
22
22
|
s.summary = %q{Ruby on Rails configurator and client to the Sphinx fulltext search engine.}
|
23
23
|
s.test_files = ["test/test_all.rb"]
|
24
24
|
|
File without changes
|
@@ -0,0 +1,60 @@
|
|
1
|
+
This client has been written to interface with Sphinx[http://sphinxsearch.com/]. It is written by
|
2
|
+
{Pat Allan}[http://freelancing-gods.com], and has been influenced by both Dmytro Shteflyuk's Ruby
|
3
|
+
client and the original PHP client - credit where credit's due, after all.
|
4
|
+
|
5
|
+
It does not follow the same syntax as those two, though (not much point writing this otherwise) -
|
6
|
+
opting for a more Ruby-like structure.
|
7
|
+
|
8
|
+
While it doesn't (yet) exist as a gem, you can obtain the sourcecode via subversion. If you
|
9
|
+
are after a specific release, use the tag as follows:
|
10
|
+
|
11
|
+
svn co http://rails-oceania.googlecode.com/svn/patallan/riddle/tags/0.9.8-r871 riddle
|
12
|
+
|
13
|
+
Or for the most current, just use trunk:
|
14
|
+
|
15
|
+
svn co http://rails-oceania.googlecode.com/svn/patallan/riddle/trunk riddle
|
16
|
+
|
17
|
+
Please note that at the time of writing, only 0.9.8r871 is supported.
|
18
|
+
|
19
|
+
To get started, just instantiate a Client object:
|
20
|
+
|
21
|
+
client = Riddle::Client.new # defaults to localhost and port 3312
|
22
|
+
client = Riddle::Client.new "sphinxserver.domain.tld", 3333 # custom settings
|
23
|
+
|
24
|
+
And then set the parameters to what you want, before running a query:
|
25
|
+
|
26
|
+
client.match_mode = :extended
|
27
|
+
client.query "Pat Allan @state Victoria"
|
28
|
+
|
29
|
+
The results from a query are similar to the other clients - but here's the details. It's a hash with
|
30
|
+
the following keys:
|
31
|
+
|
32
|
+
* :matches
|
33
|
+
* :fields
|
34
|
+
* :attributes
|
35
|
+
* :attribute_names
|
36
|
+
* :words
|
37
|
+
* :total
|
38
|
+
* :total_found
|
39
|
+
* :time
|
40
|
+
* :status
|
41
|
+
* :warning (if appropriate)
|
42
|
+
* :error (if appropriate)
|
43
|
+
|
44
|
+
The key <tt>:matches</tt> returns an array of hashes - the actual search results. Each hash has the
|
45
|
+
document id (<tt>:doc</tt>), the result weighting (<tt>:weight</tt>), and a hash of the attributes for
|
46
|
+
the document (<tt>:attributes</tt>).
|
47
|
+
|
48
|
+
The <tt>:fields</tt> and <tt>:attribute_names</tt> keys return list of fields and attributes for the
|
49
|
+
documents. The key <tt>:attributes</tt> will return a hash of attribute name and type pairs, and
|
50
|
+
<tt>:words</tt> returns a hash of hashes representing the words from the search, with the number of
|
51
|
+
documents and hits for each, along the lines of:
|
52
|
+
|
53
|
+
results[:words]["Pat"] #=> {:docs => 12, :hits => 15}
|
54
|
+
|
55
|
+
<tt>:total</tt>, <tt>:total_found</tt> and <tt>:time</tt> return the number of matches available, the
|
56
|
+
total number of matches (which may be greater than the maximum available), and the time in milliseconds
|
57
|
+
that the query took to run.
|
58
|
+
|
59
|
+
<tt>:status</tt> is the error code for the query - and if there was a related warning, it will be under
|
60
|
+
the <tt>:warning</tt> key. Fatal errors will be described under <tt>:error</tt>.
|