mongoid_fulltext 0.5.8 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -0
- data/CHANGELOG.md +133 -0
- data/Gemfile +5 -7
- data/LICENSE +2 -2
- data/README.md +203 -142
- data/VERSION +1 -1
- data/lib/mongoid_fulltext.rb +57 -52
- data/mongoid_fulltext.gemspec +19 -37
- data/spec/config/mongoid.yml +6 -0
- data/spec/models/filtered_artwork.rb +2 -2
- data/spec/models/russian_artwork.rb +10 -0
- data/spec/mongoid/fulltext_spec.rb +47 -26
- data/spec/spec_helper.rb +8 -9
- metadata +54 -45
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
0.6.0 (Next Release)
|
2
|
+
--------------------
|
3
|
+
|
4
|
+
* [#2](https://github.com/artsy/mongoid_fulltext/pull/2): Upgrade to Mongoid 3.0 - [@volmer](https://github.com/volmer).
|
5
|
+
* [#1](https://github.com/artsy/mongoid_fulltext/pull/1): Fix: downcase destroys non-latin strings - [@netoneko](https://github.com/netoneko).
|
6
|
+
|
7
|
+
0.5.8 (3/8/2012)
|
8
|
+
----------------
|
9
|
+
|
10
|
+
* Fix: do not CGI.unescape inside fulltext search - [@dblock](https://github.com/dblock).
|
11
|
+
* Refactored array filter API, allowing for overriding filter query method - [@ethul](https://github.com/ethul).
|
12
|
+
* Fix: check for the existence of the Mongoid.logger before calling it in case it was configured to false - [@AaronH](https://github.com/AaronH).
|
13
|
+
* Added install instructions to Readme - [@Nerian](https://github.com/Nerian).
|
14
|
+
|
15
|
+
0.5.7 (1/11/2012)
|
16
|
+
-----------------
|
17
|
+
|
18
|
+
* Added `reindex_immediately` option to suppress automatic reindexing - [@joeyAghion](https://github.com/joeyAghion).
|
19
|
+
* Fix: treatment of word separators, adding newlines, tabs and dashes into the set of default word separators - [@aaw](https://github.com/aaw).
|
20
|
+
|
21
|
+
0.5.4 (11/8/2011)
|
22
|
+
-----------------
|
23
|
+
|
24
|
+
* Made full word and prefix bumps inversely proportional to the length of the string - [@aaw](https://github.com/aaw).
|
25
|
+
|
26
|
+
0.5.3 (11/8/2011)
|
27
|
+
-----------------
|
28
|
+
|
29
|
+
* Added an option to index short prefixes of words - [@aaw](https://github.com/aaw).
|
30
|
+
|
31
|
+
0.5.2 (11/5/2011)
|
32
|
+
-----------------
|
33
|
+
|
34
|
+
* Added the ability to index full words that are less than the ngram length and not stop words - [@aaw](https://github.com/aaw).
|
35
|
+
|
36
|
+
0.5.1 (11/2/2011)
|
37
|
+
-----------------
|
38
|
+
|
39
|
+
* Reducing the score for a full-word match (these used to be counted multiple times for multiple occurrences) and adding a list of stopwords to the config. Stopwords aren't given a score boost when matched as full words - [@aaw](https://github.com/aaw).
|
40
|
+
* Added UTF8 downcasing - [@zepplock](https://github.com/zepplock).
|
41
|
+
|
42
|
+
0.5.0 (10/11/2011)
|
43
|
+
-----------------
|
44
|
+
|
45
|
+
* Fix: inconsistet scoring words with the same length as the ngram length - [@aaw](https://github.com/aaw).
|
46
|
+
|
47
|
+
0.4.5 (10/5/2011)
|
48
|
+
-----------------
|
49
|
+
|
50
|
+
* Added `update_if` config option to control when index updates occur - [@nickhoffman](https://github.com/nickhoffman).
|
51
|
+
|
52
|
+
0.4.4 (8/31/2011)
|
53
|
+
-----------------
|
54
|
+
|
55
|
+
* Added `remove_accents` - [@tdp2110](https://github.com/tdp2110).
|
56
|
+
|
57
|
+
0.4.3 (8/3/2011)
|
58
|
+
----------------
|
59
|
+
|
60
|
+
* Fix: including `Mongoid::FulltextSearch` and not using it causes created_indexes to fail - [@dblock](https://github.com/dblock).
|
61
|
+
|
62
|
+
0.4.2 (6/28/2011)
|
63
|
+
-----------------
|
64
|
+
|
65
|
+
* Delay-creating indexes in sync with how Mongoid creates indexes on normal collections - [@dblock](https://github.com/dblock).
|
66
|
+
|
67
|
+
0.4.1 (6/27/2011)
|
68
|
+
-----------------
|
69
|
+
|
70
|
+
* Using `Mongoid.logger` for logging - [@dblock](https://github.com/dblock).
|
71
|
+
* Changed `ensure_index` to index in the background, avoid blocking booting app - [@dblock](https://github.com/dblock).
|
72
|
+
|
73
|
+
0.4.0 (6/19/2011)
|
74
|
+
-----------------
|
75
|
+
|
76
|
+
* Removing all use of map-reduce - [@aaw](https://github.com/aaw).
|
77
|
+
* Support class name with module for example (Module::ClassConstantName) - [@steverandy](https://github.com/steverandy).
|
78
|
+
|
79
|
+
0.3.7 (6/7/2011)
|
80
|
+
----------------
|
81
|
+
|
82
|
+
* Added support for updating model indexes in bulk - [@dblock](https://github.com/dblock).
|
83
|
+
|
84
|
+
0.3.6 (5/27/2011)
|
85
|
+
-----------------
|
86
|
+
|
87
|
+
* Skipping words that are shorter than the n-gram - [@dblock](https://github.com/dblock).
|
88
|
+
* Added `index_full_words` - [@dblock](https://github.com/dblock).
|
89
|
+
* Keeping max score of ngram in the ngram hash - [@dblock](https://github.com/dblock).
|
90
|
+
|
91
|
+
0.3.5 (5/25/2011)
|
92
|
+
-----------------
|
93
|
+
|
94
|
+
* Added index on document_id for faster remove - [@dblock](https://github.com/dblock).
|
95
|
+
* Addeda way to return scored results - [@dblock](https://github.com/dblock).
|
96
|
+
|
97
|
+
0.3.4 (5/16/2011)
|
98
|
+
-----------------
|
99
|
+
|
100
|
+
* Added support for array filters - [@dblock](https://github.com/dblock).
|
101
|
+
* Added support for Ruby 1.8.7 - [@dbussink](https://github.com/dbussink).
|
102
|
+
|
103
|
+
0.3.2 (4/19/2011)
|
104
|
+
-----------------
|
105
|
+
|
106
|
+
Exposing `update_ngram_index` and `remove_from_ngram_index` for fast bulk-updating the index - [@aaw](https://github.com/aaw).
|
107
|
+
|
108
|
+
0.3.1 (4/14/2011)
|
109
|
+
-----------------
|
110
|
+
|
111
|
+
* Support for mongo versions >= 1.7.4 - [@aaw](https://github.com/aaw).
|
112
|
+
|
113
|
+
0.3.0 (4/13/2011)
|
114
|
+
-----------------
|
115
|
+
|
116
|
+
* Adding the ability to define filters on an index - [@aaw](https://github.com/aaw).
|
117
|
+
|
118
|
+
0.2.0 (4/13/2011)
|
119
|
+
-----------------
|
120
|
+
|
121
|
+
* Multiple indexes per model, removing internal indexes entirely - [@aaw](https://github.com/aaw).
|
122
|
+
|
123
|
+
0.1.1 (4/11/2011)
|
124
|
+
-----------------
|
125
|
+
|
126
|
+
* Keep garbage in the index from blowing up `fulltext_search` - [@aaw](https://github.com/aaw).
|
127
|
+
* Indexing the results of `to_s` if no fields are provided - [@aaw](https://github.com/aaw).
|
128
|
+
* Adding a `before_destroy` callback for external indexes - [@aaw](https://github.com/aaw).
|
129
|
+
|
130
|
+
0.1.0 (4/7/2011)
|
131
|
+
----------------
|
132
|
+
|
133
|
+
* Initial public release - [@aaw](https://github.com/aaw).
|
data/Gemfile
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
+
gem "mongoid", "~> 3.0.1"
|
3
4
|
gem "unicode_utils", "~> 1.0.0"
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
gem "
|
9
|
-
gem "bson_ext", "~> 1.5.2"
|
10
|
-
gem "rspec", "~> 2.5.0"
|
11
|
-
gem "jeweler", "~> 1.5.2"
|
6
|
+
group :development, :test do
|
7
|
+
gem "bundler"
|
8
|
+
gem "rspec", "~> 2.10.0"
|
9
|
+
gem "jeweler", "~> 1.8.3"
|
12
10
|
end
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2011 by Artsy, Inc.
|
1
|
+
Copyright (c) 2011-2012 by Artsy, Inc.
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
16
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
THE SOFTWARE.
|
19
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Mongoid Fulltext Search
|
1
|
+
Mongoid Fulltext Search [![Build Status](https://secure.travis-ci.org/artsy/mongoid_fulltext.png)](http://travis-ci.org/artsy/mongoid_fulltext)
|
2
2
|
=======================
|
3
3
|
|
4
4
|
Full-text search using n-gram matching for the Mongoid ODM. Tested on MongoDB 1.6 and above, but
|
@@ -7,61 +7,78 @@ probably works on earlier versions as well.
|
|
7
7
|
MongoDB currently has no native full-text search capabilities, so this gem is a good fit for cases
|
8
8
|
where you want something a little less than a full-blown indexing service like Solr. mongoid_fulltext
|
9
9
|
lets you do a fuzzy string search across relatively short strings, which makes it good for populating
|
10
|
-
autocomplete boxes based on the display names of your Rails models but not appropriate for, say,
|
10
|
+
autocomplete boxes based on the display names of your Rails models but not appropriate for, say,
|
11
11
|
indexing hundreds of thousands of HTML documents.
|
12
12
|
|
13
13
|
Install
|
14
14
|
--------------
|
15
15
|
|
16
|
-
|
16
|
+
Version 0.6.0 or newer of this gem requires Ruby 1.9.3 and Mongoid 3.0.
|
17
|
+
Use version 0.5.x for Mongoid 2.4.x and Ruby 1.8.7, 1.9.2 or 1.9.3.
|
18
|
+
|
19
|
+
For Ruby 1.8.7 and/or Mongoid 2.x use [mongoid_fulltext 0.5.x](https://github.com/artsy/mongoid_fulltext/tree/0.5-stable).
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
gem 'mongoid_fulltext'
|
23
|
+
```
|
17
24
|
|
18
25
|
Some examples:
|
19
26
|
--------------
|
20
|
-
|
27
|
+
|
21
28
|
Suppose you have an `Artist` model and want to index each artist's name:
|
22
29
|
|
23
|
-
|
24
|
-
|
25
|
-
|
30
|
+
``` ruby
|
31
|
+
class Artist
|
32
|
+
include Mongoid::Document
|
33
|
+
include Mongoid::FullTextSearch
|
26
34
|
|
27
|
-
|
28
|
-
|
35
|
+
field :first_name
|
36
|
+
field :last_name
|
29
37
|
|
30
|
-
|
31
|
-
|
32
|
-
|
38
|
+
def name
|
39
|
+
[first_name, last_name].join(' ')
|
40
|
+
end
|
33
41
|
|
34
|
-
|
35
|
-
|
42
|
+
fulltext_search_in :name
|
43
|
+
end
|
44
|
+
```
|
36
45
|
|
37
46
|
The `fulltext_search_in` directive will index the full name of the artist, so now
|
38
47
|
you can call:
|
39
48
|
|
40
|
-
|
49
|
+
``` ruby
|
50
|
+
Artist.fulltext_search("vince vangogh")
|
51
|
+
```
|
41
52
|
|
42
53
|
which will return an array of the Artist instances that best match the search string. Most likely,
|
43
54
|
Vincent van Gogh will be included in the results. You can index multiple fields with the same
|
44
55
|
index, so we can get the same effect of our Artist index above using:
|
45
56
|
|
46
|
-
|
47
|
-
|
48
|
-
|
57
|
+
``` ruby
|
58
|
+
class Artist
|
59
|
+
include Mongoid::Document
|
60
|
+
include Mongoid::FullTextSearch
|
49
61
|
|
50
|
-
|
51
|
-
|
62
|
+
field :first_name
|
63
|
+
field :last_name
|
52
64
|
|
53
|
-
|
54
|
-
|
65
|
+
fulltext_search_in :first_name, :last_name
|
66
|
+
end
|
67
|
+
```
|
55
68
|
|
56
69
|
To restrict the number of results returned, pass the `:max_results` parameter to `fulltext_search`:
|
57
70
|
|
58
|
-
|
71
|
+
``` ruby
|
72
|
+
Artist.fulltext_search("vince vangogh", { :max_results => 5 })
|
73
|
+
```
|
59
74
|
|
60
75
|
To return a pair of `[ result, score ]` instead of an array of results, pass the `:return_scores` parameter to `fulltext_search`:
|
61
76
|
|
62
|
-
|
77
|
+
``` ruby
|
78
|
+
Artist.fulltext_search("vince vangogh", { :return_scores => true })
|
79
|
+
```
|
63
80
|
|
64
|
-
The larger a score is, the better mongoid_fulltext thinks the match is. The scores have the following rough
|
81
|
+
The larger a score is, the better mongoid_fulltext thinks the match is. The scores have the following rough
|
65
82
|
interpretation that you can use to make decisions about whether the match is good enough:
|
66
83
|
|
67
84
|
* If a prefix of your query matches something indexed, or if your query matches a prefix of something
|
@@ -74,86 +91,98 @@ interpretation that you can use to make decisions about whether the match is goo
|
|
74
91
|
If you don't specify a field to index, the default is the result of `to_s` called on the object.
|
75
92
|
The following definition will index the first and last name of an artist:
|
76
93
|
|
77
|
-
|
78
|
-
|
79
|
-
|
94
|
+
``` ruby
|
95
|
+
class Artist
|
96
|
+
include Mongoid::Document
|
97
|
+
include Mongoid::FullTextSearch
|
80
98
|
|
81
|
-
|
82
|
-
|
99
|
+
field :first_name
|
100
|
+
field :last_name
|
83
101
|
|
84
|
-
|
85
|
-
|
86
|
-
|
102
|
+
def to_s
|
103
|
+
'%s %s' % [first_name, last_name]
|
104
|
+
end
|
87
105
|
|
88
|
-
|
89
|
-
|
106
|
+
fulltext_search_in
|
107
|
+
end
|
108
|
+
```
|
90
109
|
|
91
110
|
The full-text index is stored in a separate MongoDB collection in the same database as the
|
92
111
|
models you're indexing. By default, the name of this collection is generated for you. Above,
|
93
112
|
a collection named something like `mongoid_fulltext.index_artist_0` will be created to
|
94
|
-
hold the index data. You can override this naming and provide your own collection name with
|
113
|
+
hold the index data. You can override this naming and provide your own collection name with
|
95
114
|
the :index_name parameter:
|
96
115
|
|
97
|
-
|
98
|
-
|
99
|
-
|
116
|
+
``` ruby
|
117
|
+
class Artwork
|
118
|
+
include Mongoid::Document
|
119
|
+
include Mongoid::FullTextSearch
|
100
120
|
|
101
|
-
|
102
|
-
|
103
|
-
|
121
|
+
field :title
|
122
|
+
fulltext_search_in :title, :index_name => 'mongoid_fulltext.foobar'
|
123
|
+
end
|
124
|
+
```
|
104
125
|
|
105
126
|
You can also create multiple indexes on a single model, in which case you'll want to
|
106
127
|
provide index names:
|
107
128
|
|
108
|
-
|
109
|
-
|
110
|
-
|
129
|
+
``` ruby
|
130
|
+
class Artwork
|
131
|
+
include Mongoid::Document
|
132
|
+
include Mongoid::FullTextSearch
|
111
133
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
134
|
+
field :title
|
135
|
+
field :artist_name
|
136
|
+
field :gallery_name
|
137
|
+
filed :gallery_address
|
116
138
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
139
|
+
fulltext_search_in :title, :index_name => 'title_index'
|
140
|
+
fulltext_search_in :artist_name, :index_name => 'artist_name_index'
|
141
|
+
fulltext_search_in :gallery_name, :gallery_address, :index_name => 'gallery_index'
|
142
|
+
end
|
143
|
+
```
|
121
144
|
|
122
145
|
The index names are helpful now because you'll have to specify which one you want to use when you
|
123
146
|
call `fulltext_search`:
|
124
147
|
|
125
|
-
|
148
|
+
``` ruby
|
149
|
+
Artwork.fulltext_search('warhol', :index => 'artist_name_index')
|
150
|
+
```
|
126
151
|
|
127
152
|
If you have multiple indexes specified and you don't supply a name to `fulltext_search`, the
|
128
153
|
method call will raise an exception.
|
129
154
|
|
130
155
|
If you're indexing multiple models, you may find that you need to combine results to create
|
131
156
|
a single result set. For example, if both the `Artist` model and the `Artwork` model are
|
132
|
-
indexed for full-text search, then to get results from both, you'd have to call
|
157
|
+
indexed for full-text search, then to get results from both, you'd have to call
|
133
158
|
`Artist.fulltext_search` and `Artwork.fulltext_search` and combine the results yourself. If
|
134
159
|
your intention is instead to get the top k results from both Artists and Artworks, you can
|
135
160
|
merge both into a single index by using the same `:external_index` parameter:
|
136
161
|
|
137
|
-
|
138
|
-
|
139
|
-
|
162
|
+
``` ruby
|
163
|
+
class Artwork
|
164
|
+
include Mongoid::Document
|
165
|
+
include Mongoid::FullTextSearch
|
140
166
|
|
141
|
-
|
142
|
-
|
143
|
-
|
167
|
+
field :title
|
168
|
+
fulltext_search_in :title, :index_name => 'artwork_and_artists'
|
169
|
+
end
|
144
170
|
|
145
|
-
|
146
|
-
|
147
|
-
|
171
|
+
class Artist
|
172
|
+
include Mongoid::Document
|
173
|
+
include Mongoid::FullTextSearch
|
148
174
|
|
149
|
-
|
150
|
-
|
151
|
-
|
175
|
+
field :name
|
176
|
+
fulltext_search_in :name, :index_name => 'artwork_and_artists'
|
177
|
+
end
|
178
|
+
```
|
152
179
|
|
153
180
|
Now that these two models share the same external index collection, we can search them both through
|
154
181
|
either model's `fulltext_search` method:
|
155
182
|
|
156
|
-
|
183
|
+
``` ruby
|
184
|
+
Artwork.fulltext_search('picasso') # returns same results as Artist.fulltext_search('picasso')
|
185
|
+
```
|
157
186
|
|
158
187
|
If you want to filter the results from full-text search, you set up filters when the indexes are
|
159
188
|
defined. For example, suppose that in addition to wanting to use the `artwork_and_artists` index
|
@@ -162,59 +191,63 @@ for artists only and for artworks priced above $10,000. Instead of creating two
|
|
162
191
|
attempting to filter the results after the query is run, we can specify the filter predicates
|
163
192
|
at the time of index definition:
|
164
193
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
194
|
+
``` ruby
|
195
|
+
class Artwork
|
196
|
+
include Mongoid::Document
|
197
|
+
include Mongoid::FullTextSearch
|
198
|
+
|
199
|
+
field :title
|
200
|
+
field :price
|
201
|
+
fulltext_search_in :title, :index_name => 'artwork_and_artists',
|
202
|
+
:filters => { :is_expensive => lambda { |x| x.price > 10000 },
|
203
|
+
:has_long_name => lambda { |x| x.title.length > 20 }}
|
204
|
+
end
|
205
|
+
|
206
|
+
class Artist
|
207
|
+
include Mongoid::Document
|
208
|
+
include Mongoid::FullTextSearch
|
209
|
+
|
210
|
+
field :name
|
211
|
+
field :birth_year
|
212
|
+
fulltext_search_in :name, :index_name => 'artwork_and_artists',
|
213
|
+
:filters => { :born_before_1900 => lambda { |x| x.birth_year < 1900 },
|
214
|
+
:has_long_name => lambda { |x| x.name.length > 20}}
|
215
|
+
end
|
216
|
+
```
|
186
217
|
|
187
218
|
After defining filters, you can query for results that match particular values of filters:
|
188
219
|
|
189
|
-
|
190
|
-
|
220
|
+
``` ruby
|
221
|
+
# Only return artists born before 1900 that match 'foobar'
|
222
|
+
Artist.fulltext_search('foobar', :born_before_1900 => true)
|
191
223
|
|
192
|
-
|
193
|
-
|
224
|
+
# Return artists or artworks that match 'foobar' and have short names
|
225
|
+
Artist.fulltext_search('foobar', :has_long_name => false)
|
194
226
|
|
195
|
-
|
196
|
-
|
227
|
+
# Only return artworks with prices over 10000 that match 'mona lisa'
|
228
|
+
Artwork.fulltext_search('mona lisa', :is_expensive => true)
|
197
229
|
|
198
|
-
|
199
|
-
|
230
|
+
# Only return artworks with prices less than 10000 that match 'mona lisa'
|
231
|
+
Artwork.fulltext_search('mona lisa', :is_expensive => false)
|
232
|
+
```
|
200
233
|
|
201
|
-
Note that in all of the example queries above, supplying a filter that is defined on exactly
|
234
|
+
Note that in all of the example queries above, supplying a filter that is defined on exactly
|
202
235
|
one of the models will restrict the search to results from that model only. For example,
|
203
236
|
since `:is_expensive` is defined only on `Artwork`s, a call to `fulltext_search` with either
|
204
237
|
`:is_expensive => true` or `:is_expensive => false` will return only `Artwork` results.
|
205
238
|
|
206
|
-
You can specify multiple filters per index and per model. Each filter is a predicate that will
|
207
|
-
be called on objects as they're inserted into the full-text index (any time the model is saved.)
|
208
|
-
Filters are only called on instances of models they're defined on, so in the example above, the
|
209
|
-
`is_expensive` filter is only applied to instances of `Artwork` and the `born_before_1900` filter
|
210
|
-
is only applied to instances of `Artist`, although both filters can be used when querying from
|
211
|
-
either model. The `has_long_name` filter, on the other hand, will return instances of both
|
239
|
+
You can specify multiple filters per index and per model. Each filter is a predicate that will
|
240
|
+
be called on objects as they're inserted into the full-text index (any time the model is saved.)
|
241
|
+
Filters are only called on instances of models they're defined on, so in the example above, the
|
242
|
+
`is_expensive` filter is only applied to instances of `Artwork` and the `born_before_1900` filter
|
243
|
+
is only applied to instances of `Artist`, although both filters can be used when querying from
|
244
|
+
either model. The `has_long_name` filter, on the other hand, will return instances of both
|
212
245
|
`Artwork` and `Artist` since it's defined on each model.
|
213
246
|
|
214
247
|
Filters shouldn't ever throw, but if they do, the filter is just ignored. If you apply filters to
|
215
248
|
indexes that are on multiple fields, the filter is applied to each field and the filter result is
|
216
|
-
the AND of all of the individual results for each of the fields. Finally, if a filter is defined
|
217
|
-
but criteria for that filter aren't passed to `fulltext_search`, the result is as if the filter
|
249
|
+
the AND of all of the individual results for each of the fields. Finally, if a filter is defined
|
250
|
+
but criteria for that filter aren't passed to `fulltext_search`, the result is as if the filter
|
218
251
|
had never been defined - you see both models that both pass and fail the filter in the results.
|
219
252
|
|
220
253
|
Indexing Options
|
@@ -236,7 +269,7 @@ Additional indexing/query options can be used as parameters to `fulltext_search_
|
|
236
269
|
Defaults to 1000. If you're seeing poor results, you can try increasing this value to consider
|
237
270
|
more ngrams per query (changing this parameter does not require a re-index.) The amount of time
|
238
271
|
a search takes is directly proportional to this parameter's value.
|
239
|
-
* `remove_accents`: remove accents on accented characters, default is `true`.
|
272
|
+
* `remove_accents`: remove accents on accented characters, default is `true`.
|
240
273
|
We strip the accents using [NFKD normalization](http://unicode-utils.rubyforge.org/UnicodeUtils.html#method-c-compatibility_decomposition)
|
241
274
|
using an external library, `unicode_utils`.
|
242
275
|
* `update_if`: controls whether or not the index will be updated. This can be set to a symbol,
|
@@ -247,46 +280,54 @@ Additional indexing/query options can be used as parameters to `fulltext_search_
|
|
247
280
|
* When set to any other type of object, the document's index will not be updated.
|
248
281
|
* `reindex_immediately`: whether models will be reindexed automatically upon saves or updates. Defaults to true. When set to false, the class-level `update_ngram_index` method can be called to perform reindexing.
|
249
282
|
|
283
|
+
If you work with Cyrillic texts, use this option: `:alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789абвгдежзиклмнопрстуфхцчшщъыьэюя'`.
|
284
|
+
|
250
285
|
Array filters
|
251
286
|
-------------
|
252
287
|
|
253
288
|
A filter may also return an Array. Consider the following example.
|
254
289
|
|
255
|
-
|
256
|
-
|
257
|
-
|
290
|
+
``` ruby
|
291
|
+
class Artist
|
292
|
+
include Mongoid::Document
|
293
|
+
include Mongoid::FullTextSearch
|
258
294
|
|
259
|
-
|
260
|
-
|
295
|
+
field :name
|
296
|
+
field :exhibitions, as: Array, default: []
|
261
297
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
298
|
+
fulltext_search_in :name, :index_name => 'exhibited_artist',
|
299
|
+
:filters => {
|
300
|
+
:exhibitions => lambda { |artist| artist.exhibitions }
|
301
|
+
}
|
302
|
+
end
|
303
|
+
```
|
267
304
|
|
268
305
|
You can now find all artists that are at the Art Basel exhibition or all artists that have exhibited
|
269
306
|
at both the Art Basel and the New York Armory exhibition.
|
270
307
|
|
271
|
-
|
272
|
-
|
308
|
+
``` ruby
|
309
|
+
# All artists
|
310
|
+
Artist.fulltext_search('foobar')
|
273
311
|
|
274
|
-
|
275
|
-
|
312
|
+
# Artists at the Art Basel exhibition only
|
313
|
+
Artist.fulltext_search('foobar', :exhibitions => [ "Art Basel" ])
|
276
314
|
|
277
|
-
|
278
|
-
|
315
|
+
# Artists at both the Art Basel and the New York Armory exhibition
|
316
|
+
Artist.fulltext_search('foobar', :exhibitions => [ "Art Basel", "New York Armory" ])
|
279
317
|
|
280
|
-
|
281
|
-
|
282
|
-
|
318
|
+
# Note that the following explicit syntax may be used to achieve the
|
319
|
+
# same result as above
|
320
|
+
Artist.fulltext_search('foobar', :exhibitions => {:all => [ "Art Basel", "New York Armory" ]})
|
321
|
+
```
|
283
322
|
|
284
323
|
If you want to find all artists that are at either the Art Basel or the
|
285
324
|
New York Armory exhibition, then you may specify the `:any` operator in
|
286
325
|
the filter.
|
287
326
|
|
288
|
-
|
289
|
-
|
327
|
+
``` ruby
|
328
|
+
# Artists at either the Art Basel or the New York Armory exhibition
|
329
|
+
Artist.fulltext_search('foobar', :exhibitions => {:any => [ "Art Basel", "New York Armory" ]})
|
330
|
+
```
|
290
331
|
|
291
332
|
Note that `:all` and `:any` are currently the only supported operators
|
292
333
|
for the array filters.
|
@@ -294,47 +335,67 @@ for the array filters.
|
|
294
335
|
Building the index
|
295
336
|
------------------
|
296
337
|
|
297
|
-
The fulltext index is built and maintained incrementally by hooking into `before_save` and
|
338
|
+
The fulltext index is built and maintained incrementally by hooking into `before_save` and
|
298
339
|
`before_destroy` callbacks on each model that's being indexed. If you want to build an index
|
299
340
|
on existing models, you can call the `update_ngram_index` method on the class or each instance:
|
300
341
|
|
301
|
-
|
302
|
-
|
342
|
+
``` ruby
|
343
|
+
Artwork.update_ngram_index
|
344
|
+
Artwork.find(id).update_ngram_index
|
345
|
+
```
|
303
346
|
|
304
347
|
You can remove all or individual instances from the index with the `remove_from_ngram_index`
|
305
348
|
method:
|
306
349
|
|
307
|
-
|
308
|
-
|
350
|
+
``` ruby
|
351
|
+
Artwork.remove_from_ngram_index
|
352
|
+
Artwork.find(id).remove_from_ngram_index
|
353
|
+
```
|
309
354
|
|
310
|
-
The methods on the model level perform bulk removal operations and are therefore faster that
|
355
|
+
The methods on the model level perform bulk removal operations and are therefore faster that
|
311
356
|
updating or removing records individually.
|
312
357
|
|
313
358
|
If you need to control when the index is updated, provide the `update_if` option to
|
314
359
|
`fulltext_search_in`, and set it to a symbol, string, or proc. Eg:
|
315
360
|
|
316
|
-
|
317
|
-
|
361
|
+
``` ruby
|
362
|
+
# Only update the "age" index if the "age" field has changed.
|
363
|
+
fulltext_search_in :age, :update_if => :age_changed?
|
318
364
|
|
319
|
-
|
320
|
-
|
365
|
+
# Only update the "names" index if the "firstname" or "lastname" field has changed.
|
366
|
+
fulltext_search_in :names, :update_if => "firstname_changed? || lastname_changed?"
|
321
367
|
|
322
|
-
|
323
|
-
|
368
|
+
# Only update the "email" index if the "email" field ends with "gmail.com".
|
369
|
+
fulltext_search_in :email, :update_if => Proc.new { |doc| doc.email.match /gmail.com\Z/ }
|
370
|
+
```
|
324
371
|
|
325
372
|
Mongo Database Indexes
|
326
373
|
----------------------
|
327
374
|
|
328
375
|
Mongoid provides an indexing mechanism on its models triggered by the `create_indexes` method.
|
329
376
|
Mongoid_fulltext will hook into that behavior and create appropriate database indexes on its
|
330
|
-
collections. These indexes are required for an efficient full text search.
|
377
|
+
collections. These indexes are required for an efficient full text search.
|
331
378
|
|
332
379
|
Creating database indexes is typically done with the `db:mongoid:create_indexes` task.
|
333
380
|
|
334
|
-
|
381
|
+
``` bash
|
382
|
+
rake db:mongoid:create_indexes
|
383
|
+
```
|
335
384
|
|
336
385
|
Running the specs
|
337
386
|
-----------------
|
338
387
|
|
339
388
|
To run the specs, execute `rake spec`. You need a local MongoDB instance to run the specs.
|
340
389
|
|
390
|
+
Contributing
|
391
|
+
------------
|
392
|
+
|
393
|
+
Fork the project. Make your feature addition or bug fix with tests. Send a pull request. Bonus points for topic branches.
|
394
|
+
|
395
|
+
Copyright and License
|
396
|
+
---------------------
|
397
|
+
|
398
|
+
MIT License, see [LICENSE](https://github.com/aaw/mongoid_fulltext/blob/master/LICENSE) for details.
|
399
|
+
|
400
|
+
(c) 2011-2012 [Art.sy Inc.](http://artsy.github.com)
|
401
|
+
|