watson-acts_as_ferret 0.4.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +104 -0
- data/acts_as_ferret.gemspec +58 -0
- data/bin/aaf_install +29 -0
- data/config/ferret_server.yml +24 -0
- data/doc/README.win32 +23 -0
- data/doc/demo/README +154 -0
- data/doc/demo/README_DEMO +23 -0
- data/doc/demo/Rakefile +10 -0
- data/doc/demo/app/controllers/admin/backend_controller.rb +14 -0
- data/doc/demo/app/controllers/admin_area_controller.rb +4 -0
- data/doc/demo/app/controllers/application.rb +5 -0
- data/doc/demo/app/controllers/contents_controller.rb +49 -0
- data/doc/demo/app/controllers/searches_controller.rb +8 -0
- data/doc/demo/app/helpers/admin/backend_helper.rb +2 -0
- data/doc/demo/app/helpers/application_helper.rb +3 -0
- data/doc/demo/app/helpers/content_helper.rb +2 -0
- data/doc/demo/app/helpers/search_helper.rb +2 -0
- data/doc/demo/app/models/comment.rb +48 -0
- data/doc/demo/app/models/content.rb +12 -0
- data/doc/demo/app/models/content_base.rb +28 -0
- data/doc/demo/app/models/search.rb +19 -0
- data/doc/demo/app/models/shared_index1.rb +3 -0
- data/doc/demo/app/models/shared_index2.rb +3 -0
- data/doc/demo/app/models/special_content.rb +3 -0
- data/doc/demo/app/models/stats.rb +20 -0
- data/doc/demo/app/views/admin/backend/search.rhtml +18 -0
- data/doc/demo/app/views/contents/_form.rhtml +10 -0
- data/doc/demo/app/views/contents/edit.rhtml +9 -0
- data/doc/demo/app/views/contents/index.rhtml +24 -0
- data/doc/demo/app/views/contents/new.rhtml +8 -0
- data/doc/demo/app/views/contents/show.rhtml +8 -0
- data/doc/demo/app/views/layouts/application.html.erb +17 -0
- data/doc/demo/app/views/searches/_content.html.erb +2 -0
- data/doc/demo/app/views/searches/search.html.erb +20 -0
- data/doc/demo/config/boot.rb +109 -0
- data/doc/demo/config/database.yml +38 -0
- data/doc/demo/config/environment.rb +69 -0
- data/doc/demo/config/environments/development.rb +16 -0
- data/doc/demo/config/environments/production.rb +19 -0
- data/doc/demo/config/environments/test.rb +21 -0
- data/doc/demo/config/ferret_server.yml +18 -0
- data/doc/demo/config/lighttpd.conf +40 -0
- data/doc/demo/config/routes.rb +9 -0
- data/doc/demo/db/development_structure.sql +15 -0
- data/doc/demo/db/migrate/001_initial_migration.rb +18 -0
- data/doc/demo/db/migrate/002_add_type_to_contents.rb +9 -0
- data/doc/demo/db/migrate/003_create_shared_index1s.rb +11 -0
- data/doc/demo/db/migrate/004_create_shared_index2s.rb +11 -0
- data/doc/demo/db/migrate/005_special_field.rb +9 -0
- data/doc/demo/db/migrate/006_create_stats.rb +15 -0
- data/doc/demo/db/schema.sql +18 -0
- data/doc/demo/db/schema.sqlite +14 -0
- data/doc/demo/doc/README_FOR_APP +2 -0
- data/doc/demo/doc/howto.txt +70 -0
- data/doc/demo/public/404.html +8 -0
- data/doc/demo/public/500.html +8 -0
- data/doc/demo/public/dispatch.cgi +10 -0
- data/doc/demo/public/dispatch.fcgi +24 -0
- data/doc/demo/public/dispatch.rb +10 -0
- data/doc/demo/public/favicon.ico +0 -0
- data/doc/demo/public/images/rails.png +0 -0
- data/doc/demo/public/index.html +277 -0
- data/doc/demo/public/robots.txt +1 -0
- data/doc/demo/public/stylesheets/scaffold.css +74 -0
- data/doc/demo/script/about +3 -0
- data/doc/demo/script/breakpointer +3 -0
- data/doc/demo/script/console +3 -0
- data/doc/demo/script/destroy +3 -0
- data/doc/demo/script/ferret_server +10 -0
- data/doc/demo/script/generate +3 -0
- data/doc/demo/script/performance/benchmarker +3 -0
- data/doc/demo/script/performance/profiler +3 -0
- data/doc/demo/script/plugin +3 -0
- data/doc/demo/script/process/inspector +3 -0
- data/doc/demo/script/process/reaper +3 -0
- data/doc/demo/script/process/spawner +3 -0
- data/doc/demo/script/process/spinner +3 -0
- data/doc/demo/script/runner +3 -0
- data/doc/demo/script/server +3 -0
- data/doc/demo/test/fixtures/comments.yml +12 -0
- data/doc/demo/test/fixtures/contents.yml +13 -0
- data/doc/demo/test/fixtures/remote_contents.yml +9 -0
- data/doc/demo/test/fixtures/shared_index1s.yml +7 -0
- data/doc/demo/test/fixtures/shared_index2s.yml +7 -0
- data/doc/demo/test/functional/admin/backend_controller_test.rb +35 -0
- data/doc/demo/test/functional/contents_controller_test.rb +81 -0
- data/doc/demo/test/functional/searches_controller_test.rb +71 -0
- data/doc/demo/test/smoke/drb_smoke_test.rb +321 -0
- data/doc/demo/test/smoke/process_stats.rb +21 -0
- data/doc/demo/test/test_helper.rb +30 -0
- data/doc/demo/test/unit/comment_test.rb +217 -0
- data/doc/demo/test/unit/content_test.rb +705 -0
- data/doc/demo/test/unit/ferret_result_test.rb +24 -0
- data/doc/demo/test/unit/multi_index_test.rb +329 -0
- data/doc/demo/test/unit/remote_index_test.rb +23 -0
- data/doc/demo/test/unit/shared_index1_test.rb +108 -0
- data/doc/demo/test/unit/shared_index2_test.rb +13 -0
- data/doc/demo/test/unit/sort_test.rb +21 -0
- data/doc/demo/test/unit/special_content_test.rb +25 -0
- data/doc/demo/vendor/plugins/will_paginate/LICENSE +18 -0
- data/doc/demo/vendor/plugins/will_paginate/README +108 -0
- data/doc/demo/vendor/plugins/will_paginate/Rakefile +23 -0
- data/doc/demo/vendor/plugins/will_paginate/init.rb +21 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/collection.rb +45 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb +44 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/finder.rb +159 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb +95 -0
- data/doc/demo/vendor/plugins/will_paginate/test/array_pagination_test.rb +23 -0
- data/doc/demo/vendor/plugins/will_paginate/test/boot.rb +27 -0
- data/doc/demo/vendor/plugins/will_paginate/test/console +10 -0
- data/doc/demo/vendor/plugins/will_paginate/test/finder_test.rb +219 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/admin.rb +3 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/companies.yml +24 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/company.rb +23 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/developer.rb +11 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml +13 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/project.rb +4 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/projects.yml +7 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/replies.yml +20 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/reply.rb +5 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/schema.sql +44 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/topic.rb +19 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/topics.yml +30 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/user.rb +2 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/users.yml +35 -0
- data/doc/demo/vendor/plugins/will_paginate/test/helper.rb +42 -0
- data/doc/demo/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb +64 -0
- data/doc/demo/vendor/plugins/will_paginate/test/lib/load_fixtures.rb +10 -0
- data/doc/demo/vendor/plugins/will_paginate/test/pagination_test.rb +136 -0
- data/doc/monit-example +22 -0
- data/init.rb +24 -0
- data/install.rb +18 -0
- data/lib/act_methods.rb +147 -0
- data/lib/acts_as_ferret.rb +593 -0
- data/lib/ar_mysql_auto_reconnect_patch.rb +41 -0
- data/lib/blank_slate.rb +54 -0
- data/lib/bulk_indexer.rb +56 -0
- data/lib/class_methods.rb +279 -0
- data/lib/ferret_extensions.rb +192 -0
- data/lib/ferret_find_methods.rb +142 -0
- data/lib/ferret_result.rb +58 -0
- data/lib/ferret_server.rb +238 -0
- data/lib/index.rb +99 -0
- data/lib/instance_methods.rb +172 -0
- data/lib/local_index.rb +202 -0
- data/lib/more_like_this.rb +217 -0
- data/lib/multi_index.rb +133 -0
- data/lib/rdig_adapter.rb +149 -0
- data/lib/remote_functions.rb +43 -0
- data/lib/remote_index.rb +54 -0
- data/lib/remote_multi_index.rb +20 -0
- data/lib/search_results.rb +50 -0
- data/lib/server_manager.rb +71 -0
- data/lib/unix_daemon.rb +86 -0
- data/lib/without_ar.rb +52 -0
- data/recipes/aaf_recipes.rb +116 -0
- data/script/ferret_daemon +94 -0
- data/script/ferret_server +12 -0
- data/script/ferret_service +178 -0
- data/tasks/ferret.rake +39 -0
- metadata +246 -0
data/lib/multi_index.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
module ActsAsFerret #:nodoc:
|
2
|
+
|
3
|
+
# Base class for remote and local multi-indexes
|
4
|
+
class MultiIndexBase
|
5
|
+
include FerretFindMethods
|
6
|
+
attr_accessor :logger
|
7
|
+
|
8
|
+
def initialize(indexes, options = {})
|
9
|
+
# ensure all models indexes exist
|
10
|
+
@indexes = indexes
|
11
|
+
indexes.each { |i| i.ensure_index_exists }
|
12
|
+
default_fields = indexes.inject([]) do |fields, idx|
|
13
|
+
fields + [ idx.index_definition[:ferret][:default_field] ]
|
14
|
+
end.flatten.uniq
|
15
|
+
# Patch to pass an or_default setting on to ferret.
|
16
|
+
# Without an or_default set, ferret will use OR queries by default.
|
17
|
+
# This implementation will use OR if any model asks for OR, otherwise
|
18
|
+
# AND. -- Paul Fitzpatrick, 11/1/2010 (contributed to public domain)
|
19
|
+
or_default =
|
20
|
+
indexes.select{|idx| idx.index_definition[:ferret][:or_default]}.size>0
|
21
|
+
@options = {
|
22
|
+
:default_field => default_fields,
|
23
|
+
:or_default => or_default
|
24
|
+
}.update(options)
|
25
|
+
@logger = IndexLogger.new(ActsAsFerret::logger, "multi: #{indexes.map(&:index_name).join(',')}")
|
26
|
+
end
|
27
|
+
|
28
|
+
def ar_find(query, options = {}, ar_options = {})
|
29
|
+
limit = options.delete(:limit)
|
30
|
+
offset = options.delete(:offset) || 0
|
31
|
+
options[:limit] = :all
|
32
|
+
total_hits, result = super query, options, ar_options
|
33
|
+
total_hits = result.size if ar_options[:conditions]
|
34
|
+
# if limit && limit != :all
|
35
|
+
# result = result[offset..limit+offset-1]
|
36
|
+
# end
|
37
|
+
[total_hits, result]
|
38
|
+
end
|
39
|
+
|
40
|
+
def determine_stored_fields(options)
|
41
|
+
return nil unless options.has_key?(:lazy)
|
42
|
+
stored_fields = []
|
43
|
+
@indexes.each do |index|
|
44
|
+
stored_fields += index.determine_stored_fields(options)
|
45
|
+
end
|
46
|
+
return stored_fields.uniq
|
47
|
+
end
|
48
|
+
|
49
|
+
def shared?
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
# This class can be used to search multiple physical indexes at once.
|
56
|
+
class MultiIndex < MultiIndexBase
|
57
|
+
|
58
|
+
def extract_stored_fields(doc, stored_fields)
|
59
|
+
ActsAsFerret::get_index_for(doc[:class_name]).extract_stored_fields(doc, stored_fields) unless stored_fields.blank?
|
60
|
+
end
|
61
|
+
|
62
|
+
def total_hits(q, options = {})
|
63
|
+
search(q, options).total_hits
|
64
|
+
end
|
65
|
+
|
66
|
+
def search(query, options={})
|
67
|
+
query = process_query(query, options)
|
68
|
+
logger.debug "parsed query: #{query.to_s}"
|
69
|
+
searcher.search(query, options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def search_each(query, options = {}, &block)
|
73
|
+
query = process_query(query, options)
|
74
|
+
searcher.search_each(query, options, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
# checks if all our sub-searchers still are up to date
|
78
|
+
def latest?
|
79
|
+
#return false unless @reader
|
80
|
+
# segfaults with 0.10.4 --> TODO report as bug @reader.latest?
|
81
|
+
@reader and @reader.latest?
|
82
|
+
#@sub_readers.each do |r|
|
83
|
+
# return false unless r.latest?
|
84
|
+
#end
|
85
|
+
#true
|
86
|
+
end
|
87
|
+
|
88
|
+
def searcher
|
89
|
+
ensure_searcher
|
90
|
+
@searcher
|
91
|
+
end
|
92
|
+
|
93
|
+
def doc(i)
|
94
|
+
searcher[i]
|
95
|
+
end
|
96
|
+
alias :[] :doc
|
97
|
+
|
98
|
+
def query_parser
|
99
|
+
@query_parser ||= Ferret::QueryParser.new(@options)
|
100
|
+
end
|
101
|
+
|
102
|
+
def process_query(query, options = {})
|
103
|
+
query = query_parser.parse(query) if query.is_a?(String)
|
104
|
+
return query
|
105
|
+
end
|
106
|
+
|
107
|
+
def close
|
108
|
+
@searcher.close if @searcher
|
109
|
+
@reader.close if @reader
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
|
114
|
+
def ensure_searcher
|
115
|
+
unless latest?
|
116
|
+
@sub_readers = @indexes.map { |idx|
|
117
|
+
begin
|
118
|
+
reader = Ferret::Index::IndexReader.new(idx.index_definition[:index_dir])
|
119
|
+
logger.debug "sub-reader opened: #{reader}"
|
120
|
+
reader
|
121
|
+
rescue Exception
|
122
|
+
raise "error opening reader on index for class #{clazz.inspect}: #{$!}"
|
123
|
+
end
|
124
|
+
}
|
125
|
+
close
|
126
|
+
@reader = Ferret::Index::IndexReader.new(@sub_readers)
|
127
|
+
@searcher = Ferret::Search::Searcher.new(@reader)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end # of class MultiIndex
|
132
|
+
|
133
|
+
end
|
data/lib/rdig_adapter.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
begin
|
2
|
+
require 'rdig'
|
3
|
+
rescue LoadError
|
4
|
+
puts "RDig gem not found, searching and indexing static pages won't work."
|
5
|
+
end
|
6
|
+
require 'digest/md5'
|
7
|
+
|
8
|
+
module ActsAsFerret
|
9
|
+
|
10
|
+
# The RdigAdapter is automatically included into your model if you specify
|
11
|
+
# the +:rdig+ options hash in your call to acts_as_ferret. It overrides
|
12
|
+
# several methods declared by aaf to retrieve documents with the help of
|
13
|
+
# RDig's http crawler when you call rebuild_index.
|
14
|
+
module RdigAdapter
|
15
|
+
|
16
|
+
if defined?(RDig)
|
17
|
+
|
18
|
+
def self.included(target)
|
19
|
+
target.extend ClassMethods
|
20
|
+
target.send :include, InstanceMethods
|
21
|
+
target.alias_method_chain :ferret_key, :md5
|
22
|
+
end
|
23
|
+
|
24
|
+
# Indexer class to replace RDig's original indexer
|
25
|
+
class Indexer
|
26
|
+
include MonitorMixin
|
27
|
+
def initialize(batch_size, model_class, &block)
|
28
|
+
@batch_size = batch_size
|
29
|
+
@model_class = model_class
|
30
|
+
@documents = []
|
31
|
+
@offset = 0
|
32
|
+
@block = block
|
33
|
+
super()
|
34
|
+
end
|
35
|
+
|
36
|
+
def add(doc)
|
37
|
+
synchronize do
|
38
|
+
@documents << @model_class.new(doc.uri.to_s, doc)
|
39
|
+
process_batch if @documents.size >= @batch_size
|
40
|
+
end
|
41
|
+
end
|
42
|
+
alias << add
|
43
|
+
|
44
|
+
def close
|
45
|
+
synchronize do
|
46
|
+
process_batch
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
def process_batch
|
52
|
+
ActsAsFerret::logger.info "RdigAdapter::Indexer#process_batch: #{@documents.size} docs in queue, offset #{@offset}"
|
53
|
+
@block.call @documents, @offset
|
54
|
+
@offset += @documents.size
|
55
|
+
@documents = []
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module ClassMethods
|
60
|
+
# overriding aaf to return the documents fetched via RDig
|
61
|
+
def records_for_rebuild(batch_size = 1000, &block)
|
62
|
+
indexer = Indexer.new(batch_size, self, &block)
|
63
|
+
configure_rdig do
|
64
|
+
crawler = RDig::Crawler.new RDig.configuration, ActsAsFerret::logger
|
65
|
+
crawler.instance_variable_set '@indexer', indexer
|
66
|
+
ActsAsFerret::logger.debug "now crawling..."
|
67
|
+
crawler.crawl
|
68
|
+
end
|
69
|
+
rescue => e
|
70
|
+
ActsAsFerret::logger.error e
|
71
|
+
ActsAsFerret::logger.debug e.backtrace.join("\n")
|
72
|
+
ensure
|
73
|
+
indexer.close if indexer
|
74
|
+
end
|
75
|
+
|
76
|
+
# overriding aaf to skip reindexing records changed during the rebuild
|
77
|
+
# when rebuilding with the rake task
|
78
|
+
def records_modified_since(time)
|
79
|
+
[]
|
80
|
+
end
|
81
|
+
|
82
|
+
# unfortunately need to modify global RDig.configuration because it's
|
83
|
+
# used everywhere in RDig
|
84
|
+
def configure_rdig
|
85
|
+
# back up original config
|
86
|
+
old_logger = RDig.logger
|
87
|
+
old_cfg = RDig.configuration.dup
|
88
|
+
RDig.logger = ActsAsFerret.logger
|
89
|
+
rdig_configuration[:crawler].each { |k,v| RDig.configuration.crawler.send :"#{k}=", v } if rdig_configuration[:crawler]
|
90
|
+
if ce_config = rdig_configuration[:content_extraction]
|
91
|
+
RDig.configuration.content_extraction = OpenStruct.new( :hpricot => OpenStruct.new( ce_config ) )
|
92
|
+
end
|
93
|
+
yield
|
94
|
+
ensure
|
95
|
+
# restore original config
|
96
|
+
RDig.configuration.crawler = old_cfg.crawler
|
97
|
+
RDig.configuration.content_extraction = old_cfg.content_extraction
|
98
|
+
RDig.logger = old_logger
|
99
|
+
end
|
100
|
+
|
101
|
+
# overriding aaf to enforce loading page title and content from the
|
102
|
+
# ferret index
|
103
|
+
def find_with_ferret(q, options = {}, find_options = {})
|
104
|
+
options[:lazy] = true
|
105
|
+
super
|
106
|
+
end
|
107
|
+
|
108
|
+
def find_for_id(id)
|
109
|
+
new id
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
module InstanceMethods
|
114
|
+
def initialize(uri, rdig_document = nil)
|
115
|
+
@id = uri
|
116
|
+
@rdig_document = rdig_document
|
117
|
+
end
|
118
|
+
|
119
|
+
# Title of the document.
|
120
|
+
# Use the +:title_tag_selector+ option to declare the hpricot expression
|
121
|
+
# that should be used for selecting the content for this field.
|
122
|
+
def title
|
123
|
+
@rdig_document.title
|
124
|
+
end
|
125
|
+
|
126
|
+
# Content of the document.
|
127
|
+
# Use the +:content_tag_selector+ option to declare the hpricot expression
|
128
|
+
# that should be used for selecting the content for this field.
|
129
|
+
def content
|
130
|
+
@rdig_document.body
|
131
|
+
end
|
132
|
+
|
133
|
+
# Url of this document.
|
134
|
+
def id
|
135
|
+
@id
|
136
|
+
end
|
137
|
+
|
138
|
+
def ferret_key_with_md5
|
139
|
+
Digest::MD5.hexdigest(ferret_key_without_md5)
|
140
|
+
end
|
141
|
+
|
142
|
+
def to_s
|
143
|
+
"Page at #{id}, title: #{title}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ActsAsFerret
|
2
|
+
module RemoteFunctions
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def yield_results(total_hits, results)
|
7
|
+
results.each do |result|
|
8
|
+
yield result[:model], result[:id], result[:score], result[:data]
|
9
|
+
end
|
10
|
+
total_hits
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def handle_drb_error(return_value_in_case_of_error = false)
|
15
|
+
yield
|
16
|
+
rescue DRb::DRbConnError => e
|
17
|
+
logger.error "DRb connection error: #{e}"
|
18
|
+
logger.warn e.backtrace.join("\n")
|
19
|
+
raise e if ActsAsFerret::raise_drb_errors?
|
20
|
+
return_value_in_case_of_error
|
21
|
+
end
|
22
|
+
|
23
|
+
alias :old_handle_drb_error :handle_drb_error
|
24
|
+
def handle_drb_error(return_value_in_case_of_error = false)
|
25
|
+
handle_drb_restart do
|
26
|
+
old_handle_drb_error(return_value_in_case_of_error) { yield }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_drb_restart
|
31
|
+
trys = 1
|
32
|
+
begin
|
33
|
+
return yield
|
34
|
+
rescue ActsAsFerret::IndexNotDefined
|
35
|
+
logger.warn "Recovering from ActsAsFerret::IndexNotDefined exception"
|
36
|
+
ActsAsFerret::ferret_indexes[index_name] = ActsAsFerret::create_index_instance( index_definition )
|
37
|
+
ActsAsFerret::ferret_indexes[index_name].register_class ActsAsFerret::index_using_classes.index(index_name).constantize, {}
|
38
|
+
retry if (trys -= 1) > 0
|
39
|
+
end
|
40
|
+
yield
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/remote_index.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'drb'
|
2
|
+
module ActsAsFerret
|
3
|
+
|
4
|
+
# This index implementation connects to a remote ferret server instance. It
|
5
|
+
# basically forwards all calls to the remote server.
|
6
|
+
class RemoteIndex < AbstractIndex
|
7
|
+
include RemoteFunctions
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
super
|
11
|
+
@server = DRbObject.new(nil, ActsAsFerret::remote)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Cause model classes to be loaded (and indexes get declared) on the DRb
|
15
|
+
# side of things.
|
16
|
+
def register_class(clazz, options)
|
17
|
+
handle_drb_error { @server.register_class clazz.name }
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(method_name, *args)
|
21
|
+
args.unshift index_name
|
22
|
+
handle_drb_error { @server.send(method_name, *args) }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Proxy any methods that require special return values in case of errors
|
26
|
+
{
|
27
|
+
:highlight => []
|
28
|
+
}.each do |method_name, default_result|
|
29
|
+
define_method method_name do |*args|
|
30
|
+
args.unshift index_name
|
31
|
+
handle_drb_error(default_result) { @server.send method_name, *args }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def find_ids(q, options = {}, &proc)
|
36
|
+
total_hits, results = handle_drb_error([0, []]) { @server.find_ids(index_name, q, options) }
|
37
|
+
block_given? ? yield_results(total_hits, results, &proc) : [ total_hits, results ]
|
38
|
+
end
|
39
|
+
|
40
|
+
# add record to index
|
41
|
+
def add(record)
|
42
|
+
handle_drb_error { @server.add index_name, record.to_doc }
|
43
|
+
end
|
44
|
+
alias << add
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
#def model_class_name
|
49
|
+
# index_definition[:class_name]
|
50
|
+
#end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActsAsFerret
|
2
|
+
class RemoteMultiIndex < MultiIndexBase
|
3
|
+
include RemoteFunctions
|
4
|
+
|
5
|
+
def initialize(indexes, options = {})
|
6
|
+
@index_names = indexes.map(&:index_name)
|
7
|
+
@server = DRbObject.new(nil, ActsAsFerret::remote)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_ids(query, options, &proc)
|
12
|
+
total_hits, results = handle_drb_error([0, []]) { @server.multi_find_ids(@index_names, query, options) }
|
13
|
+
block_given? ? yield_results(total_hits, results, &proc) : [ total_hits, results ]
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(name, *args)
|
17
|
+
handle_drb_error { @server.send(:"multi_#{name}", @index_names, *args) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActsAsFerret
|
2
|
+
|
3
|
+
# decorator that adds a total_hits accessor and will_paginate compatible
|
4
|
+
# paging support to search result arrays
|
5
|
+
class SearchResults < ActsAsFerret::BlankSlate
|
6
|
+
reveal :methods
|
7
|
+
attr_reader :current_page, :per_page, :total_hits, :total_pages
|
8
|
+
alias total_entries total_hits # will_paginate compatibility
|
9
|
+
alias page_count total_pages # will_paginate backwards compatibility
|
10
|
+
|
11
|
+
def initialize(results, total_hits, current_page = 1, per_page = nil)
|
12
|
+
@results = results
|
13
|
+
@total_hits = total_hits
|
14
|
+
@current_page = current_page
|
15
|
+
@per_page = (per_page || total_hits)
|
16
|
+
@total_pages = @per_page > 0 ? (@total_hits / @per_page.to_f).ceil : 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(symbol, *args, &block)
|
20
|
+
@results.send(symbol, *args, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def respond_to?(name)
|
24
|
+
methods.include?(name.to_s) || @results.respond_to?(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# code from here on was directly taken from will_paginate's collection.rb
|
29
|
+
|
30
|
+
# Current offset of the paginated collection. If we're on the first page,
|
31
|
+
# it is always 0. If we're on the 2nd page and there are 30 entries per page,
|
32
|
+
# the offset is 30. This property is useful if you want to render ordinals
|
33
|
+
# besides your records: simply start with offset + 1.
|
34
|
+
#
|
35
|
+
def offset
|
36
|
+
(current_page - 1) * per_page
|
37
|
+
end
|
38
|
+
|
39
|
+
# current_page - 1 or nil if there is no previous page
|
40
|
+
def previous_page
|
41
|
+
current_page > 1 ? (current_page - 1) : nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# current_page + 1 or nil if there is no next page
|
45
|
+
def next_page
|
46
|
+
current_page < total_pages ? (current_page + 1) : nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|