mongodb_fulltext_search_er 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +164 -0
- data/Rakefile +26 -0
- data/lib/generators/mongodb_fulltext_search/config_generator.rb +9 -0
- data/lib/generators/mongodb_fulltext_search/templates/fulltext_search.yml +1 -0
- data/lib/mongodb_fulltext_search.rb +12 -0
- data/lib/mongodb_fulltext_search/helpers.rb +51 -0
- data/lib/mongodb_fulltext_search/mixins.rb +221 -0
- data/lib/mongodb_fulltext_search/mongodb_fulltext_search.rb +12 -0
- data/lib/mongodb_fulltext_search/version.rb +3 -0
- data/lib/tasks/mongodb_fulltext_search_tasks.rake +45 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c5c193692d9add9fc4b9faa7f5d212b3007e3279
|
4
|
+
data.tar.gz: 20382936bcc690b7de6ddafcbd0bf2069beb42d1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e919d05ebe300c5a467763c9ef2a6a029d08019af77575ee5cfac57c1ee4e34db07a1de72f2d7ed049866da4a7087116af6a2767a84ae68dbadea8f2f04813ec
|
7
|
+
data.tar.gz: 30e36fdcbcc829f1e50c9883df3327c764b8de6e841a8eb903a8aae1b1a18172b91c4068ff07940fb390e014a4fec4ff1f5459e4faa75cf091a84fc3ec71de82
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Christopher Fuller
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
== same as chrisfuller's mongodb_fulltext_search, but excludes rails as a dependency
|
2
|
+
|
3
|
+
This was done to allow use of mongodb_fulltext_search with any version/branch of rails
|
4
|
+
|
5
|
+
= mongodb_fulltext_search
|
6
|
+
|
7
|
+
A gem that adds fulltext search capability to Mongoid[http://mongoid.org/] or MongoMapper[http://mongomapper.com/] documents. The MongoDB[http://mongodb.org/] aggregation framework is utilized to perform searches quickly and efficiently.
|
8
|
+
|
9
|
+
== Prerequisites
|
10
|
+
|
11
|
+
Rails must be configured to use either Mongoid or MongoMapper and MongoDB[http://mongodb.org/] version 2.1.0 (or higher) is required.
|
12
|
+
|
13
|
+
Please get in touch if you’d like to see added support for another MongoDB object mapper (ODM).
|
14
|
+
|
15
|
+
== Installation
|
16
|
+
|
17
|
+
$ gem install mongodb_fulltext_search
|
18
|
+
|
19
|
+
== Rails Configuration
|
20
|
+
|
21
|
+
Add to Gemfile:
|
22
|
+
|
23
|
+
gem 'mongodb_fulltext_search'
|
24
|
+
|
25
|
+
== Indexes
|
26
|
+
|
27
|
+
This gem implements indexes specifically for the fulltext search.
|
28
|
+
|
29
|
+
The fulltext indexes are maintained automatically via the +before_save+ and +before_destroy+ callbacks on models, however you MUST run the rake task (below) to rebuild the indexes any time your models change.
|
30
|
+
|
31
|
+
The indexes are implemented as MongoDB collections (since MongoDB's built-in indexes do not currently support fulltext search), therefore the fulltext indexes are actually "index collections". The "index collections" are stored in the same database that the models are persisted to.
|
32
|
+
|
33
|
+
The "index collections" benefit from using MongoDB indexes themselves and have MongoDB indexes defined via the underlying ODM, therefore be sure to create the indexes following the instructions for the ODM you are using.
|
34
|
+
|
35
|
+
With Mongoid for example, use the normal rake command <tt>rake db:mongoid:create_indexes</tt>. With MongoMapper for example, the indexes should be created automatically by default.
|
36
|
+
|
37
|
+
For the remainder of the documentation, the "index collections" will now simply be referred to as "indexes".
|
38
|
+
|
39
|
+
== Examples
|
40
|
+
|
41
|
+
Mongoid example:
|
42
|
+
|
43
|
+
class Widget
|
44
|
+
|
45
|
+
include Mongoid::Document
|
46
|
+
include Mongoid::FullTextSearch
|
47
|
+
|
48
|
+
field :desc, :type => String
|
49
|
+
field :tags, :type => Array
|
50
|
+
|
51
|
+
fulltext_search_in :desc
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
MongoMapper example:
|
56
|
+
|
57
|
+
class Widget
|
58
|
+
|
59
|
+
include MongoMapper::Document
|
60
|
+
include MongoMapper::FullTextSearch
|
61
|
+
|
62
|
+
key :desc, String
|
63
|
+
key :tags, Array
|
64
|
+
|
65
|
+
fulltext_search_in :desc
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
Or index multiple attributes together:
|
70
|
+
|
71
|
+
fulltext_search_in :desc, :tags
|
72
|
+
|
73
|
+
Or index virtual attributes:
|
74
|
+
|
75
|
+
fulltext_search_in :desc_and_tags
|
76
|
+
|
77
|
+
def desc_and_tags
|
78
|
+
[ desc ] + tags
|
79
|
+
end
|
80
|
+
|
81
|
+
NOTE: All attributes (and virtual attributes) supplied to +fulltext_search_in+ must return either a string or an array of strings.
|
82
|
+
|
83
|
+
== Performing Searches
|
84
|
+
|
85
|
+
In controllers, perform searches with:
|
86
|
+
|
87
|
+
@widgets = Widget.fulltext_search params[:search_query]
|
88
|
+
|
89
|
+
After fulltext searches are performed, access scores via a +fulltext_search_score+ attribute on models:
|
90
|
+
|
91
|
+
@widgets.each { |widget| widget.fulltext_search_score }
|
92
|
+
|
93
|
+
== Multiple Indexes
|
94
|
+
|
95
|
+
It is possible to create more than one index on a model:
|
96
|
+
|
97
|
+
fulltext_search_in :desc, :index => 'desc_index'
|
98
|
+
fulltext_search_in :tags, :index => 'tags_index'
|
99
|
+
|
100
|
+
In this case, you MUST specify an index when performing a search:
|
101
|
+
|
102
|
+
@widgets = Widget.fulltext_search params[:search_query], :index => 'desc_index'
|
103
|
+
|
104
|
+
or
|
105
|
+
|
106
|
+
@widgets = Widget.fulltext_search params[:search_query], :index => 'tags_index'
|
107
|
+
|
108
|
+
NOTE: An +ArgumentError+ exception will be raised if multiple indexes exist but an index is not specified.
|
109
|
+
|
110
|
+
== Options
|
111
|
+
|
112
|
+
To match partial words, turn off exact matching:
|
113
|
+
|
114
|
+
@widgets = Widget.fulltext_search params[:search_query], :exact => false
|
115
|
+
|
116
|
+
By default, results are limited to 20 models but you can specify a limit when searching:
|
117
|
+
|
118
|
+
@widgets = Widget.fulltext_search params[:search_query], :limit => 10
|
119
|
+
|
120
|
+
And you can also specify an offset:
|
121
|
+
|
122
|
+
@widgets = Widget.fulltext_search params[:search_query], :offset => 20
|
123
|
+
|
124
|
+
To return document identifiers and search scores as a +Hash+ (instead of the returning the model objects):
|
125
|
+
|
126
|
+
@scores = Widget.fulltext_search params[:search_query], :return_scores => true
|
127
|
+
@scores.each { |id, score| id + ': ' + score }
|
128
|
+
|
129
|
+
== Normalization
|
130
|
+
|
131
|
+
Strings are normalized using <tt>normalize(:kd)</tt> (for queries and also indexes), so for example +resumé+ and +resume+ would match.
|
132
|
+
|
133
|
+
== Stop Words
|
134
|
+
|
135
|
+
Stop words (i.e. blacklisted words) can be specified in a YAML config file.
|
136
|
+
|
137
|
+
To generate a config file with a default set of stop words:
|
138
|
+
|
139
|
+
$ rails g mongodb_fulltext_search:config
|
140
|
+
|
141
|
+
The default stop words are:
|
142
|
+
|
143
|
+
a, an, and, are, as, at, be, but, by, for, if, in, into, is, it, no, not, of, on, or, such, that, the, their, then, there, these, they, this, to, was, will, with
|
144
|
+
|
145
|
+
== Rake Tasks
|
146
|
+
|
147
|
+
To rebuild indexes for all models:
|
148
|
+
|
149
|
+
$ rake db:mongo:rebuild_fulltext_search_indexes
|
150
|
+
|
151
|
+
To rebuild indexes for one model:
|
152
|
+
|
153
|
+
$ rake db:mongo:rebuild_fulltext_search_indexes[Widget]
|
154
|
+
|
155
|
+
NOTE: The indexes are maintained automatically via the +before_save+ and +before_destroy+ callbacks on models, however you MUST run this rake task any time your models change.
|
156
|
+
|
157
|
+
== To Do
|
158
|
+
|
159
|
+
* Filtered indexes
|
160
|
+
* Shared indexes
|
161
|
+
|
162
|
+
== Copyright
|
163
|
+
|
164
|
+
Copyright (c) 2012 Christopher Fuller. See MIT-LICENSE[http://github.com/chrisfuller/mongodb_fulltext_search/blob/master/MIT-LICENSE] for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'MongodbFulltextSearch'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module MongodbFulltextSearch::Generators
|
2
|
+
class ConfigGenerator < Rails::Generators::Base
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
desc 'Creates a MongodbFulltextSearch configuration file at config/fulltext_search.yml'
|
5
|
+
def create_config_file
|
6
|
+
template 'fulltext_search.yml', File.join('config', 'fulltext_search.yml')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
stop_words: a, an, and, are, as, at, be, but, by, for, if, in, into, is, it, no, not, of, on, or, such, that, the, their, then, there, these, they, this, to, was, will, with
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module MongodbFulltextSearch::Helpers
|
2
|
+
|
3
|
+
def mongo_session(model)
|
4
|
+
if mongoid?
|
5
|
+
mongo_session = model.mongo_session
|
6
|
+
elsif mongomapper?
|
7
|
+
mongo_session = MongoMapper.database
|
8
|
+
end
|
9
|
+
mongo_session
|
10
|
+
end
|
11
|
+
|
12
|
+
def words_for(text)
|
13
|
+
words = []
|
14
|
+
if text.is_a? String
|
15
|
+
text.mb_chars.normalize(:kd).to_s.downcase.gsub(/[^a-z0-9\s]/, '').split(/\s/).each do |word|
|
16
|
+
words << word unless word.blank? or stop_words.include? word
|
17
|
+
end
|
18
|
+
end
|
19
|
+
words
|
20
|
+
end
|
21
|
+
|
22
|
+
def mongoid?
|
23
|
+
if @mongoid.nil?
|
24
|
+
@mongoid = Object.const_defined?('Mongoid')
|
25
|
+
end
|
26
|
+
@mongoid
|
27
|
+
end
|
28
|
+
|
29
|
+
def mongomapper?
|
30
|
+
if @mongomapper.nil?
|
31
|
+
@mongomapper = Object.const_defined?('MongoMapper')
|
32
|
+
end
|
33
|
+
@mongomapper
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def stop_words
|
39
|
+
if @stop_words.nil?
|
40
|
+
file = "#{Rails.root}/config/fulltext_search.yml"
|
41
|
+
config = YAML.load(ERB.new(File.read(file)).result) if File.exists? file
|
42
|
+
if not config.nil? and config.include? 'stop_words'
|
43
|
+
@stop_words = config['stop_words'].gsub(/\s/, '').split ','
|
44
|
+
else
|
45
|
+
@stop_words = []
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@stop_words
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
module MongodbFulltextSearch::Mixins
|
2
|
+
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
|
7
|
+
cattr_accessor :fulltext_search_options
|
8
|
+
|
9
|
+
self.fulltext_search_options = {}
|
10
|
+
|
11
|
+
if MongodbFulltextSearch.mongoid?
|
12
|
+
(class << self; self; end).class_eval do
|
13
|
+
create_indexes = instance_method :create_indexes
|
14
|
+
define_method :create_indexes do
|
15
|
+
create_indexes.bind(self).call
|
16
|
+
fulltext_search_options.values.each do |options|
|
17
|
+
if options[:model].respond_to? :create_indexes
|
18
|
+
options[:model].send :create_indexes
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
|
29
|
+
def fulltext_search_in(*args)
|
30
|
+
|
31
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
32
|
+
|
33
|
+
if options.has_key? :index
|
34
|
+
collection_name = (options.delete :index).to_sym
|
35
|
+
else
|
36
|
+
count = fulltext_search_options.count
|
37
|
+
collection_name = "fulltext_search_index_#{collection.name}_#{count}".to_sym
|
38
|
+
end
|
39
|
+
|
40
|
+
if args.empty?
|
41
|
+
options[:attributes] = [:to_s]
|
42
|
+
else
|
43
|
+
options[:attributes] = args
|
44
|
+
end
|
45
|
+
|
46
|
+
if MongodbFulltextSearch.mongoid?
|
47
|
+
options[:model] = Class.new {
|
48
|
+
include Mongoid::Document
|
49
|
+
store_in collection: collection_name
|
50
|
+
index({
|
51
|
+
:source => 1,
|
52
|
+
'counts.word' => 1
|
53
|
+
})
|
54
|
+
field :source , :type => String
|
55
|
+
field :counts , :type => Array
|
56
|
+
}
|
57
|
+
elsif MongodbFulltextSearch.mongomapper?
|
58
|
+
options[:model] = Class.new {
|
59
|
+
include MongoMapper::Document
|
60
|
+
set_collection_name collection_name
|
61
|
+
ensure_index([
|
62
|
+
[ :source , 1 ],
|
63
|
+
[ 'counts.word' , 1 ]
|
64
|
+
])
|
65
|
+
key :source , String
|
66
|
+
key :counts , Array
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
fulltext_search_options[collection_name] = options
|
71
|
+
|
72
|
+
attr_accessor :fulltext_search_score
|
73
|
+
|
74
|
+
before_save :update_in_fulltext_search_indexes
|
75
|
+
|
76
|
+
before_destroy :remove_from_fulltext_search_indexes
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
def fulltext_search(query, options = {})
|
81
|
+
|
82
|
+
options = {
|
83
|
+
:exact => true,
|
84
|
+
:limit => 20,
|
85
|
+
:offset => 0,
|
86
|
+
:return_scores => false
|
87
|
+
}.merge options
|
88
|
+
|
89
|
+
results = []
|
90
|
+
|
91
|
+
if query.is_a? String
|
92
|
+
|
93
|
+
words = MongodbFulltextSearch.words_for query
|
94
|
+
|
95
|
+
unless words.empty?
|
96
|
+
|
97
|
+
queries = []; words.each do |word|
|
98
|
+
if !!options[:exact]
|
99
|
+
queries << { 'counts.word' => word }
|
100
|
+
else
|
101
|
+
queries << { 'counts.word' => { '$regex' => Regexp.escape(word) } }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
limit = options[:limit].to_i
|
106
|
+
|
107
|
+
pipeline = [
|
108
|
+
{ '$match' => { '$and' => queries } },
|
109
|
+
{ '$unwind' => '$counts' },
|
110
|
+
{ '$match' => { '$or' => queries } },
|
111
|
+
{ '$sort' => { 'source' => 1 } },
|
112
|
+
{ '$group' => {
|
113
|
+
'_id' => { 'source' => 1 },
|
114
|
+
'score' => { '$sum' => '$counts.count' }
|
115
|
+
} },
|
116
|
+
{ '$sort' => { 'score' => -1 } },
|
117
|
+
{ '$limit' => limit }
|
118
|
+
]
|
119
|
+
|
120
|
+
skip = options[:offset].to_i * limit
|
121
|
+
|
122
|
+
pipeline << { '$skip' => skip } if skip > 0
|
123
|
+
pipeline << { '$project' => { 'score' => 1 } }
|
124
|
+
|
125
|
+
if options.has_key? :index
|
126
|
+
collection_name = options[:index]
|
127
|
+
else
|
128
|
+
if fulltext_search_options.count == 1
|
129
|
+
collection_name = fulltext_search_options.keys.first
|
130
|
+
else
|
131
|
+
raise ArgumentError, 'index not specified', caller
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
aggregate = MongodbFulltextSearch.mongo_session(self).command(
|
136
|
+
:aggregate => collection_name.to_s,
|
137
|
+
:pipeline => pipeline
|
138
|
+
)
|
139
|
+
|
140
|
+
scores = {}; aggregate['result'].each do |result|
|
141
|
+
scores[result['_id']['source']] = result['score']
|
142
|
+
end
|
143
|
+
|
144
|
+
unless scores.empty?
|
145
|
+
if options[:return_scores]
|
146
|
+
results = scores
|
147
|
+
else
|
148
|
+
find(scores.keys).each do |result|
|
149
|
+
result.fulltext_search_score = scores[result._id.to_s]
|
150
|
+
results << result
|
151
|
+
end
|
152
|
+
results.sort_by! { |result| -result.fulltext_search_score }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
results
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def update_in_fulltext_search_indexes
|
169
|
+
|
170
|
+
fulltext_search_options.each do |collection_name, options|
|
171
|
+
|
172
|
+
if MongodbFulltextSearch.mongoid?
|
173
|
+
index = options[:model].find_or_initialize_by :source => _id.to_s
|
174
|
+
elsif MongodbFulltextSearch.mongomapper?
|
175
|
+
index = options[:model].find_or_initialize_by_source _id.to_s
|
176
|
+
end
|
177
|
+
|
178
|
+
index.counts = []
|
179
|
+
|
180
|
+
values = []; options[:attributes].each do |attribute|
|
181
|
+
if respond_to? attribute.to_sym
|
182
|
+
value_array = send(attribute.to_sym)
|
183
|
+
value_array = [value_array] if value_array.is_a? String
|
184
|
+
if value_array.is_a? Array
|
185
|
+
value_array.each do |value|
|
186
|
+
values << value if value.is_a? String
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
unless values.nil?
|
193
|
+
temp = {}; values.each do |value|
|
194
|
+
MongodbFulltextSearch.words_for(value).each do |word|
|
195
|
+
temp[word] = 0 if temp[word].nil?
|
196
|
+
temp[word] += 1
|
197
|
+
end
|
198
|
+
end
|
199
|
+
temp.sort.each do |word, count|
|
200
|
+
index.counts << { :word => word, :count => count }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
index.save
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
def remove_from_fulltext_search_indexes
|
211
|
+
fulltext_search_options.values.each do |options|
|
212
|
+
if MongodbFulltextSearch.mongoid?
|
213
|
+
index = options[:model].where :source => _id.to_s
|
214
|
+
elsif MongodbFulltextSearch.mongomapper?
|
215
|
+
index = options[:model].find_by_source _id.to_s
|
216
|
+
end
|
217
|
+
index.destroy unless index.nil?
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'mongodb_fulltext_search/helpers'
|
2
|
+
require 'mongodb_fulltext_search/mixins'
|
3
|
+
|
4
|
+
module MongodbFulltextSearch
|
5
|
+
extend MongodbFulltextSearch::Helpers
|
6
|
+
end
|
7
|
+
|
8
|
+
if MongodbFulltextSearch.mongoid?
|
9
|
+
Mongoid.const_set :FullTextSearch, MongodbFulltextSearch::Mixins
|
10
|
+
elsif MongodbFulltextSearch.mongomapper?
|
11
|
+
MongoMapper.const_set :FullTextSearch, MongodbFulltextSearch::Mixins
|
12
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
namespace :db do
|
2
|
+
namespace :mongo do
|
3
|
+
desc "Rebuild the fulltext search indexes"
|
4
|
+
task :rebuild_fulltext_search_indexes, [:model] => [:environment] do |t, args|
|
5
|
+
args.with_defaults(:model => false)
|
6
|
+
models = []; Dir[Rails.root.to_s + '/app/models/**/*.rb'].each do |path|
|
7
|
+
model_name = File.basename(path, '.rb').camelize
|
8
|
+
begin
|
9
|
+
model_class = model_name.constantize
|
10
|
+
if model_class.respond_to? :fulltext_search_options
|
11
|
+
models << model_name if model_class.send(:fulltext_search_options).is_a? Hash
|
12
|
+
end
|
13
|
+
rescue
|
14
|
+
end
|
15
|
+
end
|
16
|
+
error = false
|
17
|
+
if args.model
|
18
|
+
if models.include? args.model
|
19
|
+
models = [args.model]
|
20
|
+
else
|
21
|
+
models = []
|
22
|
+
puts "[Aborted] Unable to load model '#{args.model}'"
|
23
|
+
error = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
if models.empty?
|
27
|
+
unless error
|
28
|
+
puts "[Aborted] Unable to locate any models with fulltext search implemented"
|
29
|
+
end
|
30
|
+
else
|
31
|
+
models.each do |model_name|
|
32
|
+
puts "Recreating fulltext search index for model '#{model_name}' ..."
|
33
|
+
model_class = model_name.constantize
|
34
|
+
model_class.fulltext_search_options.keys.each do |collection_name|
|
35
|
+
MongodbFulltextSearch.mongo_session(model_class)[collection_name.to_s].drop
|
36
|
+
end
|
37
|
+
model_class.all.each do |model|
|
38
|
+
model.send :update_in_fulltext_search_indexes
|
39
|
+
end
|
40
|
+
end
|
41
|
+
puts "Operation completed"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mongodb_fulltext_search_er
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.14
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan T Hosford
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-18 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Same as mongodb_fulltext_search, except excludes rails as a dependency
|
14
|
+
email:
|
15
|
+
- tad.hosford@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/mongodb_fulltext_search.rb
|
21
|
+
- lib/mongodb_fulltext_search/version.rb
|
22
|
+
- lib/mongodb_fulltext_search/mongodb_fulltext_search.rb
|
23
|
+
- lib/mongodb_fulltext_search/helpers.rb
|
24
|
+
- lib/mongodb_fulltext_search/mixins.rb
|
25
|
+
- lib/generators/mongodb_fulltext_search/templates/fulltext_search.yml
|
26
|
+
- lib/generators/mongodb_fulltext_search/config_generator.rb
|
27
|
+
- lib/tasks/mongodb_fulltext_search_tasks.rake
|
28
|
+
- MIT-LICENSE
|
29
|
+
- Rakefile
|
30
|
+
- README.rdoc
|
31
|
+
homepage: http://github.com/chrisfuller/mongodb_fulltext_search
|
32
|
+
licenses: []
|
33
|
+
metadata: {}
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 2.1.11
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: Same as mongodb_fulltext_search, except excludes rails as a dependency
|
54
|
+
test_files: []
|