mongoid_fulltext 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|