mongoid_fulltext 0.5.8 → 0.6.0
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/.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 [](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
|
+
|