mongoid_fulltext 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +0 -1
- data/README.md +11 -0
- data/VERSION +1 -1
- data/lib/mongoid_fulltext.rb +15 -13
- data/lib/mongoid_indexes.rb +12 -0
- data/mongoid_fulltext.gemspec +3 -5
- data/spec/mongoid/fulltext_spec.rb +42 -1
- data/spec/spec_helper.rb +6 -4
- metadata +10 -20
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -261,6 +261,17 @@ method:
|
|
261
261
|
The methods on the model level perform bulk removal operations and are therefore faster that
|
262
262
|
updating or removing records individually.
|
263
263
|
|
264
|
+
Mongo Database Indexes
|
265
|
+
----------------------
|
266
|
+
|
267
|
+
Mongoid provides an indexing mechanism on its models triggered by the `create_indexes` method.
|
268
|
+
Mongoid_fulltext will hook into that behavior and create appropriate database indexes on its
|
269
|
+
collections. These indexes are required for an efficient full text search.
|
270
|
+
|
271
|
+
Creating database indexes is typically done with the `db:mongoid:create_indexes` task.
|
272
|
+
|
273
|
+
rake db:mongoid:create_indexes
|
274
|
+
|
264
275
|
Running the specs
|
265
276
|
-----------------
|
266
277
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.2
|
data/lib/mongoid_fulltext.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'mongoid_indexes'
|
2
|
+
|
1
3
|
module Mongoid::FullTextSearch
|
2
4
|
extend ActiveSupport::Concern
|
3
5
|
|
@@ -35,14 +37,18 @@ module Mongoid::FullTextSearch
|
|
35
37
|
config[:alphabet] = Hash[config[:alphabet].split('').map{ |ch| [ch,ch] }]
|
36
38
|
config[:word_separators] = Hash[config[:word_separators].split('').map{ |ch| [ch,ch] }]
|
37
39
|
self.mongoid_fulltext_config[index_name] = config
|
38
|
-
|
39
|
-
ensure_indexes(index_name, config)
|
40
40
|
|
41
41
|
before_save :update_ngram_index
|
42
42
|
before_destroy :remove_from_ngram_index
|
43
43
|
end
|
44
|
+
|
45
|
+
def create_fulltext_indexes
|
46
|
+
self.mongoid_fulltext_config.each_pair do |index_name, fulltext_config|
|
47
|
+
fulltext_search_ensure_indexes(index_name, fulltext_config)
|
48
|
+
end
|
49
|
+
end
|
44
50
|
|
45
|
-
def
|
51
|
+
def fulltext_search_ensure_indexes(index_name, config)
|
46
52
|
db = collection.db
|
47
53
|
coll = db.collection(index_name)
|
48
54
|
|
@@ -62,7 +68,7 @@ module Mongoid::FullTextSearch
|
|
62
68
|
next if !keys.member?('ngram')
|
63
69
|
all_filter_keys |= keys.find_all{ |key| key.starts_with?('filter_values.') }
|
64
70
|
if keys & correct_keys != correct_keys
|
65
|
-
|
71
|
+
Mongoid.logger.info "Droping #{name} [#{keys & correct_keys} <=> #{correct_keys}]"
|
66
72
|
coll.drop_index(name)
|
67
73
|
end
|
68
74
|
end
|
@@ -71,17 +77,13 @@ module Mongoid::FullTextSearch
|
|
71
77
|
filter_indexes = all_filter_keys.map { |key| [key, Mongo::ASCENDING] }.sort_by { |filter_index| filter_index[0] }
|
72
78
|
index_definition = [['ngram', Mongo::ASCENDING], ['score', Mongo::DESCENDING]].concat(filter_indexes)
|
73
79
|
end
|
74
|
-
|
75
|
-
|
76
|
-
coll.ensure_index(index_definition, { :name => 'fts_index'
|
77
|
-
|
78
|
-
coll.ensure_index([['document_id', Mongo::ASCENDING]]
|
80
|
+
|
81
|
+
Mongoid.logger.info "Ensuring fts_index on #{coll.name}: #{index_definition}"
|
82
|
+
coll.ensure_index(index_definition, { :name => 'fts_index' })
|
83
|
+
Mongoid.logger.info "Ensuring document_id index on #{coll.name}"
|
84
|
+
coll.ensure_index([['document_id', Mongo::ASCENDING]]) # to make removes fast
|
79
85
|
end
|
80
86
|
|
81
|
-
def fulltext_log(message)
|
82
|
-
Mongoid.logger.info("[mongoid_fulltext] #{message}") if Mongoid.logger
|
83
|
-
end
|
84
|
-
|
85
87
|
def fulltext_search(query_string, options={})
|
86
88
|
max_results = options.has_key?(:max_results) ? options.delete(:max_results) : 10
|
87
89
|
return_scores = options.has_key?(:return_scores) ? options.delete(:return_scores) : false
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# hook onto model index creation to create related FT indexes
|
2
|
+
module Mongoid::Indexes::ClassMethods
|
3
|
+
|
4
|
+
alias_method :create_fulltext_indexes_hook, :create_indexes
|
5
|
+
|
6
|
+
def create_indexes
|
7
|
+
create_fulltext_indexes if respond_to?(:create_fulltext_indexes)
|
8
|
+
create_fulltext_indexes_hook
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
data/mongoid_fulltext.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongoid_fulltext}
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Aaron Windsor"]
|
12
|
-
s.date = %q{2011-07-
|
12
|
+
s.date = %q{2011-07-28}
|
13
13
|
s.description = %q{Full-text search for the Mongoid ORM, using n-grams extracted from text}
|
14
14
|
s.email = %q{aaron.windsor@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
"Rakefile",
|
26
26
|
"VERSION",
|
27
27
|
"lib/mongoid_fulltext.rb",
|
28
|
+
"lib/mongoid_indexes.rb",
|
28
29
|
"mongoid_fulltext.gemspec",
|
29
30
|
"spec/models/advanced_artwork.rb",
|
30
31
|
"spec/models/basic_artwork.rb",
|
@@ -70,18 +71,15 @@ Gem::Specification.new do |s|
|
|
70
71
|
|
71
72
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
72
73
|
s.add_development_dependency(%q<mongoid>, ["~> 2.0.0"])
|
73
|
-
s.add_development_dependency(%q<database_cleaner>, ["~> 0.6.0"])
|
74
74
|
s.add_development_dependency(%q<rspec>, ["~> 2.5.0"])
|
75
75
|
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
76
76
|
else
|
77
77
|
s.add_dependency(%q<mongoid>, ["~> 2.0.0"])
|
78
|
-
s.add_dependency(%q<database_cleaner>, ["~> 0.6.0"])
|
79
78
|
s.add_dependency(%q<rspec>, ["~> 2.5.0"])
|
80
79
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
81
80
|
end
|
82
81
|
else
|
83
82
|
s.add_dependency(%q<mongoid>, ["~> 2.0.0"])
|
84
|
-
s.add_dependency(%q<database_cleaner>, ["~> 0.6.0"])
|
85
83
|
s.add_dependency(%q<rspec>, ["~> 2.5.0"])
|
86
84
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
87
85
|
end
|
@@ -16,6 +16,7 @@ module Mongoid
|
|
16
16
|
end
|
17
17
|
|
18
18
|
end
|
19
|
+
|
19
20
|
context "with default settings" do
|
20
21
|
|
21
22
|
let!(:flower_myth) { BasicArtwork.create(:title => 'Flower Myth') }
|
@@ -125,6 +126,7 @@ module Mongoid
|
|
125
126
|
end
|
126
127
|
|
127
128
|
end
|
129
|
+
|
128
130
|
context "with an index name specified" do
|
129
131
|
let!(:pablo_picasso) { ExternalArtist.create(:full_name => 'Pablo Picasso') }
|
130
132
|
let!(:portrait_of_picasso) { ExternalArtwork.create(:title => 'Portrait of Picasso') }
|
@@ -188,6 +190,7 @@ module Mongoid
|
|
188
190
|
end
|
189
191
|
|
190
192
|
end
|
193
|
+
|
191
194
|
context "with an index name specified" do
|
192
195
|
|
193
196
|
let!(:andy_warhol) { ExternalArtist.create(:full_name => 'Andy Warhol') }
|
@@ -202,6 +205,7 @@ module Mongoid
|
|
202
205
|
end
|
203
206
|
|
204
207
|
end
|
208
|
+
|
205
209
|
context "with an index name specified" do
|
206
210
|
|
207
211
|
let!(:pop) { ExternalArtwork.create(:title => 'Pop') }
|
@@ -237,6 +241,7 @@ module Mongoid
|
|
237
241
|
end
|
238
242
|
|
239
243
|
end
|
244
|
+
|
240
245
|
context "with an index name specified" do
|
241
246
|
|
242
247
|
it "cleans up item from the index after they're destroyed" do
|
@@ -250,6 +255,7 @@ module Mongoid
|
|
250
255
|
end
|
251
256
|
|
252
257
|
end
|
258
|
+
|
253
259
|
context "with an index name specified and no fields provided to index" do
|
254
260
|
|
255
261
|
let!(:big_bang) { ExternalArtworkNoFieldsSupplied.create(:title => 'Big Bang', :artist => 'David Poppie', :year => '2009') }
|
@@ -261,6 +267,7 @@ module Mongoid
|
|
261
267
|
end
|
262
268
|
|
263
269
|
end
|
270
|
+
|
264
271
|
context "with multiple indexes defined" do
|
265
272
|
|
266
273
|
let!(:pop) { MultiExternalArtwork.create(:title => 'Pop', :year => '1970', :artist => 'Joe Schmoe') }
|
@@ -282,6 +289,7 @@ module Mongoid
|
|
282
289
|
end
|
283
290
|
|
284
291
|
end
|
292
|
+
|
285
293
|
context "with multiple fields indexed and the same index used by multiple models" do
|
286
294
|
|
287
295
|
let!(:andy_warhol) { MultiFieldArtist.create(:full_name => 'Andy Warhol', :birth_year => '1928') }
|
@@ -338,6 +346,9 @@ module Mongoid
|
|
338
346
|
# fields as well as the union of all the filter fields to allow for efficient lookups.
|
339
347
|
|
340
348
|
it "creates a proper index for searching efficiently" do
|
349
|
+
[ FilteredArtwork, FilteredArtist, FilteredOther].each do |klass|
|
350
|
+
klass.create_indexes
|
351
|
+
end
|
341
352
|
index_collection = FilteredArtwork.collection.db.collection('mongoid_fulltext.artworks_and_artists')
|
342
353
|
ngram_indexes = index_collection.index_information.find_all{ |name, definition| definition['key'].has_key?('ngram') }
|
343
354
|
ngram_indexes.length.should == 1
|
@@ -431,7 +442,37 @@ module Mongoid
|
|
431
442
|
|
432
443
|
end
|
433
444
|
|
445
|
+
context "mongoid indexes" do
|
446
|
+
it "can re-create dropped indexes" do
|
447
|
+
# there're no indexes by default as Mongoid.autocreate_indexes is set to false
|
448
|
+
# but mongo will automatically attempt to index _id in the background
|
449
|
+
Mongoid.master["mongoid_fulltext.index_basicartwork_0"].index_information.size.should <= 1
|
450
|
+
BasicArtwork.create_indexes
|
451
|
+
Mongoid.master["mongoid_fulltext.index_basicartwork_0"].index_information.should ==
|
452
|
+
{
|
453
|
+
"_id_" => {
|
454
|
+
"name" => "_id_",
|
455
|
+
"ns" => "mongoid_fulltext_test.mongoid_fulltext.index_basicartwork_0",
|
456
|
+
"key" => { "_id" => 1 },
|
457
|
+
"v" => 0
|
458
|
+
},
|
459
|
+
"fts_index" => {
|
460
|
+
"name" => "fts_index",
|
461
|
+
"ns" => "mongoid_fulltext_test.mongoid_fulltext.index_basicartwork_0",
|
462
|
+
"key" => { "ngram" => 1, "score" => -1 },
|
463
|
+
"v" => 0
|
464
|
+
},
|
465
|
+
"document_id_1" => {
|
466
|
+
"name" => "document_id_1",
|
467
|
+
"ns" => "mongoid_fulltext_test.mongoid_fulltext.index_basicartwork_0",
|
468
|
+
"key" => { "document_id" => 1 },
|
469
|
+
"v"=>0
|
470
|
+
}
|
471
|
+
}
|
472
|
+
end
|
473
|
+
|
474
|
+
end
|
475
|
+
|
434
476
|
end
|
435
|
-
|
436
477
|
end
|
437
478
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,7 +3,6 @@ require 'bundler/setup'
|
|
3
3
|
require 'rspec'
|
4
4
|
|
5
5
|
require 'mongoid'
|
6
|
-
require 'database_cleaner'
|
7
6
|
|
8
7
|
Mongoid.configure do |config|
|
9
8
|
name = "mongoid_fulltext_test"
|
@@ -15,8 +14,11 @@ require File.expand_path("../../lib/mongoid_fulltext", __FILE__)
|
|
15
14
|
Dir["#{File.dirname(__FILE__)}/models/**/*.rb"].each { |f| require f }
|
16
15
|
|
17
16
|
Rspec.configure do |c|
|
18
|
-
c.before(:
|
19
|
-
|
20
|
-
|
17
|
+
c.before(:each) do
|
18
|
+
Mongoid.master.collections.select {|c| c.name !~ /system/ }.each(&:drop)
|
19
|
+
end
|
20
|
+
c.after(:all) do
|
21
|
+
Mongoid.master.command({'dropDatabase' => 1})
|
22
|
+
end
|
21
23
|
end
|
22
24
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_fulltext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-07-
|
12
|
+
date: 2011-07-28 00:00:00.000000000 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: mongoid
|
17
|
-
requirement: &
|
17
|
+
requirement: &86604030 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,21 +22,10 @@ dependencies:
|
|
22
22
|
version: 2.0.0
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
26
|
-
- !ruby/object:Gem::Dependency
|
27
|
-
name: database_cleaner
|
28
|
-
requirement: &75049790 !ruby/object:Gem::Requirement
|
29
|
-
none: false
|
30
|
-
requirements:
|
31
|
-
- - ~>
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.6.0
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: *75049790
|
25
|
+
version_requirements: *86604030
|
37
26
|
- !ruby/object:Gem::Dependency
|
38
27
|
name: rspec
|
39
|
-
requirement: &
|
28
|
+
requirement: &86603130 !ruby/object:Gem::Requirement
|
40
29
|
none: false
|
41
30
|
requirements:
|
42
31
|
- - ~>
|
@@ -44,10 +33,10 @@ dependencies:
|
|
44
33
|
version: 2.5.0
|
45
34
|
type: :development
|
46
35
|
prerelease: false
|
47
|
-
version_requirements: *
|
36
|
+
version_requirements: *86603130
|
48
37
|
- !ruby/object:Gem::Dependency
|
49
38
|
name: jeweler
|
50
|
-
requirement: &
|
39
|
+
requirement: &86602120 !ruby/object:Gem::Requirement
|
51
40
|
none: false
|
52
41
|
requirements:
|
53
42
|
- - ~>
|
@@ -55,7 +44,7 @@ dependencies:
|
|
55
44
|
version: 1.5.2
|
56
45
|
type: :development
|
57
46
|
prerelease: false
|
58
|
-
version_requirements: *
|
47
|
+
version_requirements: *86602120
|
59
48
|
description: Full-text search for the Mongoid ORM, using n-grams extracted from text
|
60
49
|
email: aaron.windsor@gmail.com
|
61
50
|
executables: []
|
@@ -72,6 +61,7 @@ files:
|
|
72
61
|
- Rakefile
|
73
62
|
- VERSION
|
74
63
|
- lib/mongoid_fulltext.rb
|
64
|
+
- lib/mongoid_indexes.rb
|
75
65
|
- mongoid_fulltext.gemspec
|
76
66
|
- spec/models/advanced_artwork.rb
|
77
67
|
- spec/models/basic_artwork.rb
|
@@ -104,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
104
94
|
version: '0'
|
105
95
|
segments:
|
106
96
|
- 0
|
107
|
-
hash:
|
97
|
+
hash: 229668173
|
108
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
99
|
none: false
|
110
100
|
requirements:
|