~ubuntu-branches/ubuntu/utopic/mongodb/utopic

« back to all changes in this revision

Viewing changes to src/mongo/db/fts/fts_matcher.cpp

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-07-03 09:23:46 UTC
  • mfrom: (1.3.10) (44.1.14 sid)
  • Revision ID: package-import@ubuntu.com-20140703092346-c5bvt46wnzougyly
Tags: 1:2.6.3-0ubuntu1
* New upstream stable release:
  - Dropped patches, included upstream:
    + 0003-All-platforms-but-Windows-find-hash-in-std-tr1.patch
    + 0008-Use-system-libstemmer.patch
    + 0011-Use-a-signed-char-to-store-BSONType-enumerations.patch
    + 0001-SERVER-12064-Atomic-operations-for-gcc-non-Intel-arc.patch
    + 0002-SERVER-12065-Support-ARM-and-AArch64-builds.patch
  - d/p/*: Refreshed/rebased remaining patches.
  - Use system provided libyaml-cpp:
    + d/control: Add libyaml-cpp-dev to BD's.
    + d/rules: Enable --with-system-yaml option.
    + d/p/fix-yaml-detection.patch: Fix detection of libyaml-cpp library.
  - d/mongodb-server.mongodb.upstart: Sync changes from upstream.
  - d/control,mongodb-dev.*: Drop mongodb-dev package; it has no reverse
    dependencies and upstream no longer install header files.
  - d/NEWS: Point users to upstream upgrade documentation for upgrades
    from 2.4 to 2.6.
* Merge from Debian unstable.
* d/control: BD on libv8-3.14-dev to ensure that transitioning to new v8
  versions is a explicit action due to changes in behaviour in >= 3.25
  (LP: #1295723).
* d/mongodb-server.prerm: Dropped debug echo call from maintainer script
  (LP: #1294455).

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
*
15
15
*    You should have received a copy of the GNU Affero General Public License
16
16
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
*
 
18
*    As a special exception, the copyright holders give permission to link the
 
19
*    code of portions of this program with the OpenSSL library under certain
 
20
*    conditions as described in each individual source file and distribute
 
21
*    linked combinations including the program with the OpenSSL library. You
 
22
*    must comply with the GNU Affero General Public License in all respects for
 
23
*    all of the code used other than as permitted herein. If you modify file(s)
 
24
*    with this exception, you may extend this exception to your version of the
 
25
*    file(s), but you are not obligated to do so. If you do not wish to do so,
 
26
*    delete this exception statement from your version. If you delete this
 
27
*    exception statement from all source files in the program, then also delete
 
28
*    it in the license file.
17
29
*/
18
30
 
19
31
#include "mongo/pch.h"
20
32
 
21
33
#include "mongo/db/fts/fts_matcher.h"
 
34
#include "mongo/db/fts/fts_element_iterator.h"
22
35
#include "mongo/platform/strcasestr.h"
23
36
 
24
37
namespace mongo {
25
38
 
26
39
    namespace fts {
27
40
 
28
 
 
29
41
        FTSMatcher::FTSMatcher( const FTSQuery& query, const FTSSpec& spec )
30
42
            : _query( query ),
31
 
              _spec( spec ),
32
 
              _stemmer( query.getLanguage() ){
 
43
              _spec( spec ) {
33
44
        }
34
45
 
35
46
        /*
41
52
            // flagged for exclusion, i.e. "hello -world" we want to remove all
42
53
            // results that include "world"
43
54
 
44
 
            if ( _query.getNegatedTerms().size() == 0 )
 
55
            if ( _query.getNegatedTerms().size() == 0 ) {
45
56
                return false;
46
 
 
47
 
            if ( _spec.wildcard() ) {
48
 
                return _hasNegativeTerm_recurse(obj);
49
 
            }
50
 
 
51
 
            /* otherwise look at fields where weights are defined */
52
 
            for ( Weights::const_iterator i = _spec.weights().begin();
53
 
                  i != _spec.weights().end();
54
 
                  i++ ) {
55
 
                const char * leftOverName = i->first.c_str();
56
 
                BSONElement e = obj.getFieldDottedOrArray(leftOverName);
57
 
 
58
 
                if ( e.type() == Array ) {
59
 
                    BSONObjIterator j( e.Obj() );
60
 
                    while ( j.more() ) {
61
 
                        BSONElement x = j.next();
62
 
                        if ( leftOverName[0] && x.isABSONObj() )
63
 
                            x = x.Obj().getFieldDotted( leftOverName );
64
 
                        if ( x.type() == String )
65
 
                            if ( _hasNegativeTerm_string( x.String() ) )
66
 
                                return true;
67
 
                    }
68
 
                }
69
 
                else if ( e.type() == String ) {
70
 
                    if ( _hasNegativeTerm_string( e.String() ) )
71
 
                        return true;
72
 
                }
73
 
            }
74
 
            return false;
75
 
        }
76
 
 
77
 
        bool FTSMatcher::_hasNegativeTerm_recurse(const BSONObj& obj ) const {
78
 
            BSONObjIterator j( obj );
79
 
            while ( j.more() ) {
80
 
                BSONElement x = j.next();
81
 
 
82
 
                if ( _spec.languageOverrideField() == x.fieldName())
83
 
                    continue;
84
 
 
85
 
                if (x.type() == String) {
86
 
                    if ( _hasNegativeTerm_string( x.String() ) )
87
 
                        return true;
88
 
                }
89
 
                else if ( x.isABSONObj() ) {
90
 
                    BSONObjIterator k( x.Obj() );
91
 
                    while ( k.more() ) {
92
 
                        // check if k.next() is a obj/array or not
93
 
                        BSONElement y = k.next();
94
 
                        if ( y.type() == String ) {
95
 
                            if ( _hasNegativeTerm_string( y.String() ) )
96
 
                                return true;
97
 
                        }
98
 
                        else if ( y.isABSONObj() ) {
99
 
                            if ( _hasNegativeTerm_recurse( y.Obj() ) )
100
 
                                return true;
101
 
                        }
102
 
                    }
103
 
                }
104
 
            }
 
57
            }
 
58
 
 
59
            FTSElementIterator it( _spec, obj);
 
60
 
 
61
            while ( it.more() ) {
 
62
                FTSIteratorValue val = it.next();
 
63
                if (_hasNegativeTerm_string( val._language, val._text )) {
 
64
                    return true;
 
65
                }
 
66
            }
 
67
 
105
68
            return false;
106
69
        }
107
70
 
109
72
         * Checks if any of the negTerms is in the tokenized string
110
73
         * @param raw, the raw string to be tokenized
111
74
         */
112
 
        bool FTSMatcher::_hasNegativeTerm_string( const string& raw ) const {
 
75
        bool FTSMatcher::_hasNegativeTerm_string( const FTSLanguage* language,
 
76
                                                  const string& raw ) const {
113
77
 
114
 
            Tokenizer i( _query.getLanguage(), raw );
 
78
            Tokenizer i( *language, raw );
 
79
            Stemmer stemmer( *language );
115
80
            while ( i.more() ) {
116
81
                Token t = i.next();
117
82
                if ( t.type != Token::TEXT )
118
83
                    continue;
119
 
                string word = tolowerString( _stemmer.stem( t.data ) );
 
84
                string word = stemmer.stem( tolowerString( t.data ) );
120
85
                if ( _query.getNegatedTerms().count( word ) > 0 )
121
86
                    return true;
122
87
            }
123
88
            return false;
124
89
        }
125
90
 
126
 
 
127
91
        bool FTSMatcher::phrasesMatch( const BSONObj& obj ) const {
128
92
            for (unsigned i = 0; i < _query.getPhr().size(); i++ ) {
129
93
                if ( !phraseMatch( _query.getPhr()[i], obj ) ) {
140
104
            return true;
141
105
        }
142
106
 
143
 
 
144
107
        /**
145
108
         * Checks if phrase is exactly matched in obj, returns true if so, false otherwise
146
109
         * @param phrase, the string to be matched
147
110
         * @param obj, document in the collection to match against
148
111
         */
149
112
        bool FTSMatcher::phraseMatch( const string& phrase, const BSONObj& obj ) const {
150
 
 
151
 
            if ( _spec.wildcard() ) {
152
 
                // case where everything is indexed (all fields)
153
 
                return _phraseRecurse( phrase, obj );
154
 
            }
155
 
 
156
 
            for ( Weights::const_iterator i = _spec.weights().begin();
157
 
                  i != _spec.weights().end();
158
 
                  ++i ) {
159
 
 
160
 
                //  figure out what the indexed field is.. ie. is it "field" or "field.subfield" etc.
161
 
                const char * leftOverName = i->first.c_str();
162
 
                BSONElement e = obj.getFieldDottedOrArray(leftOverName);
163
 
 
164
 
                if ( e.type() == Array ) {
165
 
                    BSONObjIterator j( e.Obj() );
166
 
                    while ( j.more() ) {
167
 
                        BSONElement x = j.next();
168
 
 
169
 
                        if ( leftOverName[0] && x.isABSONObj() )
170
 
                            x = x.Obj().getFieldDotted( leftOverName );
171
 
 
172
 
                        if ( x.type() == String )
173
 
                            if ( _phraseMatches( phrase, x.String() ) )
174
 
                                return true;
175
 
                    }
176
 
                }
177
 
                else if ( e.type() == String ) {
178
 
                    if ( _phraseMatches( phrase, e.String() ) )
179
 
                        return true;
180
 
                }
181
 
            }
182
 
            return false;
183
 
        }
184
 
 
185
 
 
186
 
        /*
187
 
         * Recurses over all fields in the obj to match against phrase
188
 
         * @param phrase, string to be matched
189
 
         * @param obj, object to matched against
190
 
         */
191
 
        bool FTSMatcher::_phraseRecurse( const string& phrase, const BSONObj& obj ) const {
192
 
            BSONObjIterator j( obj );
193
 
            while ( j.more() ) {
194
 
                BSONElement x = j.next();
195
 
 
196
 
                if ( _spec.languageOverrideField() == x.fieldName() )
197
 
                    continue;
198
 
 
199
 
                if ( x.type() == String ) {
200
 
                    if ( _phraseMatches( phrase, x.String() ) )
201
 
                        return true;
202
 
                } 
203
 
                else if ( x.isABSONObj() ) {
204
 
                    BSONObjIterator k( x.Obj() );
205
 
 
206
 
                    while ( k.more() ) {
207
 
 
208
 
                        BSONElement y = k.next();
209
 
 
210
 
                        if ( y.type() == mongo::String ) {
211
 
                            if ( _phraseMatches( phrase, y.String() ) )
212
 
                                return true;
213
 
                        }
214
 
                        else if ( y.isABSONObj() ) {
215
 
                            if ( _phraseRecurse( phrase, y.Obj() ) )
216
 
                                return true;
217
 
                        }
218
 
                    }
219
 
 
220
 
                }
221
 
            }
222
 
 
223
 
            return false;
224
 
        }
225
 
 
 
113
            FTSElementIterator it( _spec, obj);
 
114
 
 
115
            while ( it.more() ) {
 
116
                FTSIteratorValue val = it.next();
 
117
                if (_phraseMatches( phrase, val._text )) {
 
118
                    return true;
 
119
                }
 
120
            }
 
121
 
 
122
            return false;
 
123
        }
226
124
 
227
125
        /*
228
126
         * Looks for phrase in a raw string
232
130
        bool FTSMatcher::_phraseMatches( const string& phrase, const string& haystack ) const {
233
131
            return strcasestr( haystack.c_str(), phrase.c_str() ) > 0;
234
132
        }
235
 
 
236
 
 
237
133
    }
238
134
}