xapian_db 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +12 -0
- data/README.rdoc +10 -10
- data/lib/xapian_db/adapters/base_adapter.rb +4 -3
- data/lib/xapian_db/database.rb +8 -4
- data/lib/xapian_db/query_parser.rb +1 -0
- data/lib/xapian_db/railtie.rb +2 -2
- data/lib/xapian_db/resultset.rb +36 -34
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
##0.5.4 (February 22th, 2011)
|
2
|
+
|
3
|
+
Fixes:
|
4
|
+
|
5
|
+
- relative database paths in the config file are resolved correctly when the Rails server is started as a daemon (-d)
|
6
|
+
|
7
|
+
Breaking Changes:
|
8
|
+
|
9
|
+
- the spelling suggestion of a query is now nil instead of an empty string if no suggestions were returned from xapian
|
10
|
+
- the resultset class (what you get back from a query) has been refactored for easier handling. See the README ("Process the results")
|
11
|
+
for details
|
12
|
+
|
1
13
|
##0.5.3 (February 15th, 2011)
|
2
14
|
|
3
15
|
Fixes:
|
data/README.rdoc
CHANGED
@@ -149,22 +149,27 @@ You can query objects of a specific class:
|
|
149
149
|
|
150
150
|
results = Person.search "name:Foo"
|
151
151
|
|
152
|
-
If you want to
|
152
|
+
If you want to paginate the result, pass the :per_page argument:
|
153
153
|
|
154
154
|
results = Person.search "name:Foo", :per_page => 20
|
155
155
|
|
156
|
+
If you want to limit the number of results, pass the :limit argument (handy if you use the query for autocompletion):
|
157
|
+
|
158
|
+
results = Person.search "name:Foo", :limit => 10
|
159
|
+
|
156
160
|
On class queries you can specifiy order options:
|
157
161
|
|
158
162
|
results = Person.search "name:Foo", :order => :first_name
|
159
163
|
results = Person.search "Fo*", :order => [:name, :first_name], :sort_decending => true
|
160
164
|
|
161
|
-
Please note that the order option is not
|
165
|
+
Please note that the order option is not available for global searches (XapianDb.search...)
|
162
166
|
|
163
167
|
=== Process the results
|
164
168
|
|
165
169
|
<code>XapianDb.search</code> returns a resultset object. You can access the number of hits directly:
|
166
170
|
|
167
|
-
results.
|
171
|
+
results.hits # Very fast, does not load the resulting documents; always returns the actual hit count
|
172
|
+
# even if a limit option was set in the query
|
168
173
|
|
169
174
|
If you use a persistent database, the resultset may contain a spelling correction:
|
170
175
|
|
@@ -172,14 +177,9 @@ If you use a persistent database, the resultset may contain a spelling correctio
|
|
172
177
|
results = XapianDb.search("moose")
|
173
178
|
results.spelling_suggestion # "mouse"
|
174
179
|
|
175
|
-
|
176
|
-
|
177
|
-
page = results.paginate # Get the first page
|
178
|
-
page = results.paginate :page => 2 # Get the second page
|
179
|
-
|
180
|
-
Now you can access the documents:
|
180
|
+
The results behave like an array:
|
181
181
|
|
182
|
-
doc =
|
182
|
+
doc = results.first
|
183
183
|
puts doc.indexed_class # Get the type of the indexed object as a string, e.g. "Person"
|
184
184
|
puts doc.name # We can access the configured attributes
|
185
185
|
person = doc.indexed_object # Access the object behind this doc (lazy loaded)
|
@@ -30,8 +30,9 @@ module XapianDb
|
|
30
30
|
options = {:sort_decending => false}.merge options
|
31
31
|
class_scope = "indexed_class:#{klass.name.downcase}"
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
order = options.delete :order
|
34
|
+
if order
|
35
|
+
attr_names = [order].flatten
|
35
36
|
blueprint = XapianDb::DocumentBlueprint.blueprint_for klass
|
36
37
|
sort_indices = attr_names.map {|attr_name| blueprint.value_index_for(attr_name)}
|
37
38
|
options[:sort_indices] = attr_names.map {|attr_name| blueprint.value_index_for(attr_name)}
|
@@ -39,7 +40,7 @@ module XapianDb
|
|
39
40
|
result = XapianDb.database.search "#{class_scope} and (#{expression})", options
|
40
41
|
|
41
42
|
# Remove the class scope from the spelling suggestion (if any)
|
42
|
-
|
43
|
+
if result.spelling_suggestion
|
43
44
|
scope_length = "#{class_scope} and (".size
|
44
45
|
result.spelling_suggestion = result.spelling_suggestion.slice scope_length..-2
|
45
46
|
end
|
data/lib/xapian_db/database.rb
CHANGED
@@ -67,13 +67,17 @@ module XapianDb
|
|
67
67
|
|
68
68
|
Rails.logger.info "Executing XapianDb search: #{expression}" if defined?(Rails)
|
69
69
|
|
70
|
-
enquiry
|
71
|
-
enquiry.query
|
72
|
-
|
70
|
+
enquiry = Xapian::Enquire.new(reader)
|
71
|
+
enquiry.query = query
|
72
|
+
sort_indices = opts.delete :sort_indices
|
73
|
+
sort_decending = opts.delete :sort_decending
|
74
|
+
|
75
|
+
if sort_indices
|
73
76
|
raise ArgumentError.new("Sorting is available for class scoped searches only") unless expression =~ /^indexed_class:/
|
74
77
|
sorter = Xapian::MultiValueSorter.new
|
78
|
+
|
75
79
|
options[:sort_indices].each do |index|
|
76
|
-
sorter.add(index,
|
80
|
+
sorter.add(index, sort_decending)
|
77
81
|
end
|
78
82
|
enquiry.set_sort_by_key_then_relevance(sorter)
|
79
83
|
end
|
@@ -41,6 +41,7 @@ module XapianDb
|
|
41
41
|
XapianDb::DocumentBlueprint.searchable_prefixes.each{|prefix| parser.add_prefix(prefix.to_s.downcase, "X#{prefix.to_s.upcase}") }
|
42
42
|
query = parser.parse_query(expression, @query_flags)
|
43
43
|
@spelling_suggestion = parser.get_corrected_query_string
|
44
|
+
@spelling_suggestion = nil if @spelling_suggestion.empty?
|
44
45
|
query
|
45
46
|
end
|
46
47
|
|
data/lib/xapian_db/railtie.rb
CHANGED
@@ -21,13 +21,13 @@ module XapianDb
|
|
21
21
|
if File.exist?(config_file_path)
|
22
22
|
db_config = YAML::load_file config_file_path
|
23
23
|
env_config = db_config[Rails.env]
|
24
|
-
database_path = env_config["database"] || ":memory:"
|
24
|
+
database_path = File.expand_path(env_config["database"]) || ":memory:"
|
25
25
|
adapter = env_config["adapter"] || :active_record
|
26
26
|
writer = env_config["writer"] || :direct
|
27
27
|
beanstalk_daemon = env_config["beanstalk_daemon"]
|
28
28
|
else
|
29
29
|
# No config file, set the defaults
|
30
|
-
Rails.env == "test" ? database_path = ":memory:" : database_path = "db/xapian_db/#{Rails.env}"
|
30
|
+
Rails.env == "test" ? database_path = ":memory:" : database_path = File.expand_path("db/xapian_db/#{Rails.env}")
|
31
31
|
adapter = :active_record
|
32
32
|
writer = :direct
|
33
33
|
beanstalk_daemon = nil
|
data/lib/xapian_db/resultset.rb
CHANGED
@@ -12,11 +12,11 @@ module XapianDb
|
|
12
12
|
# @example Use the resultset and will_paginate in a view
|
13
13
|
# <%= will_paginate resultset %>
|
14
14
|
# @author Gernot Kogler
|
15
|
-
class Resultset
|
15
|
+
class Resultset < Array
|
16
16
|
|
17
|
-
# The number of
|
17
|
+
# The number of hits
|
18
18
|
# @return [Integer]
|
19
|
-
attr_reader :
|
19
|
+
attr_reader :hits
|
20
20
|
|
21
21
|
# The number of pages
|
22
22
|
# @return [Integer]
|
@@ -34,29 +34,36 @@ module XapianDb
|
|
34
34
|
# @param [Xapian::Enquire] enquiry a Xapian query result (see http://xapian.org/docs/apidoc/html/classXapian_1_1Enquire.html).
|
35
35
|
# Pass nil to get an empty result set.
|
36
36
|
# @param [Hash] options
|
37
|
-
# @option options [Integer] :
|
37
|
+
# @option options [Integer] :db_size The current size (nr of docs) of the database
|
38
|
+
# @option options [Integer] :limit The maximum number of documents to retrieve
|
39
|
+
# @option options [Integer] :page (1) The page number to retrieve
|
40
|
+
# @option options [Integer] :per_page (10) How many docs per page? Ignored if a limit option is given
|
38
41
|
# @option options [String] :spelling_suggestion (nil) The spelling corrected query (if a language is configured)
|
39
|
-
def initialize(enquiry, options)
|
42
|
+
def initialize(enquiry, options={})
|
43
|
+
|
40
44
|
@enquiry = enquiry
|
41
|
-
if @enquiry.nil?
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@spelling_suggestion = options
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
return build_empty_resultset if @enquiry.nil?
|
46
|
+
|
47
|
+
db_size = options.delete :db_size
|
48
|
+
limit = options.delete :limit
|
49
|
+
page = options.delete :page
|
50
|
+
per_page = options.delete :per_page
|
51
|
+
@spelling_suggestion = options.delete :spelling_suggestion
|
52
|
+
raise ArgumentError.new "unsupported options for resultset: #{options}" if options.size > 0
|
53
|
+
raise ArgumentError.new "db_size option is required" unless db_size
|
54
|
+
|
55
|
+
@hits = enquiry.mset(0, db_size).matches_estimated
|
56
|
+
limit ||= @hits
|
57
|
+
per_page ||= limit
|
58
|
+
@total_pages = (limit / per_page.to_f).ceil
|
59
|
+
page = page.nil? ? 1 : page.to_i
|
60
|
+
offset = (page - 1) * per_page
|
61
|
+
count = offset + per_page < limit ? per_page : limit - offset
|
62
|
+
raise ArgumentError.new "page #{@page} does not exist" if @hits > 0 && offset >= limit
|
52
63
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def paginate(options={})
|
57
|
-
@current_page = options[:page] ? options[:page].to_i : 1
|
58
|
-
return [] if @current_page < 1 || @current_page > @total_pages
|
59
|
-
build_page(@current_page)
|
64
|
+
result_window = @enquiry.mset(offset, count)
|
65
|
+
self.replace result_window.matches.map{|match| decorate(match.document)}
|
66
|
+
@current_page = page
|
60
67
|
end
|
61
68
|
|
62
69
|
# The previous page number
|
@@ -73,17 +80,12 @@ module XapianDb
|
|
73
80
|
|
74
81
|
private
|
75
82
|
|
76
|
-
# Build
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
result_window = @enquiry.mset(offset, @per_page)
|
83
|
-
result_window.matches.each do |match|
|
84
|
-
docs << decorate(match.document)
|
85
|
-
end
|
86
|
-
docs
|
83
|
+
# Build an empty resultset
|
84
|
+
def build_empty_resultset
|
85
|
+
@hits = 0
|
86
|
+
@total_pages = 0
|
87
|
+
@current_page = 0
|
88
|
+
self
|
87
89
|
end
|
88
90
|
|
89
91
|
# Decorate a Xapian document with field accessors for each configured attribute
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: xapian_db
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.5.
|
5
|
+
version: 0.5.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Gernot Kogler
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-02-
|
13
|
+
date: 2011-02-22 00:00:00 +01:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|