1
// Copyright (c) 2014 Couchbase, Inc.
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
20
"github.com/blevesearch/bleve/index"
21
"github.com/blevesearch/bleve/search"
24
func TestBooleanSearch(t *testing.T) {
26
if twoDocIndex == nil {
29
twoDocIndexReader, err := twoDocIndex.Reader()
34
err := twoDocIndexReader.Close()
40
explainTrue := search.SearcherOptions{Explain: true}
43
beerTermSearcher, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, explainTrue)
47
mustSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher}, explainTrue)
51
martyTermSearcher, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, explainTrue)
55
dustinTermSearcher, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, explainTrue)
59
shouldSearcher, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher, dustinTermSearcher}, 0, explainTrue)
63
steveTermSearcher, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, explainTrue)
67
mustNotSearcher, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher}, 0, explainTrue)
71
booleanSearcher, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher, shouldSearcher, mustNotSearcher, explainTrue)
77
martyTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, explainTrue)
81
dustinTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, explainTrue)
85
shouldSearcher2, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher2, dustinTermSearcher2}, 0, explainTrue)
89
steveTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, explainTrue)
93
mustNotSearcher2, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher2}, 0, explainTrue)
97
booleanSearcher2, err := NewBooleanSearcher(twoDocIndexReader, nil, shouldSearcher2, mustNotSearcher2, explainTrue)
103
steveTermSearcher3, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, explainTrue)
107
mustNotSearcher3, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher3}, 0, explainTrue)
111
booleanSearcher3, err := NewBooleanSearcher(twoDocIndexReader, nil, nil, mustNotSearcher3, explainTrue)
117
beerTermSearcher4, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, explainTrue)
121
mustSearcher4, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher4}, explainTrue)
125
steveTermSearcher4, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, explainTrue)
129
mustNotSearcher4, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher4}, 0, explainTrue)
133
booleanSearcher4, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher4, nil, mustNotSearcher4, explainTrue)
139
beerTermSearcher5, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, explainTrue)
143
mustSearcher5, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher5}, explainTrue)
147
steveTermSearcher5, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, explainTrue)
151
martyTermSearcher5, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, explainTrue)
155
mustNotSearcher5, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher5, martyTermSearcher5}, 0, explainTrue)
159
booleanSearcher5, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher5, nil, mustNotSearcher5, explainTrue)
165
beerTermSearcher6, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, explainTrue)
169
mustSearcher6, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher6}, explainTrue)
173
martyTermSearcher6, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, explainTrue)
177
dustinTermSearcher6, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, explainTrue)
181
shouldSearcher6, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher6, dustinTermSearcher6}, 2, explainTrue)
185
booleanSearcher6, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher6, shouldSearcher6, nil, explainTrue)
191
beerTermSearcher7, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, explainTrue)
195
mustSearcher7, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher7}, explainTrue)
199
booleanSearcher7, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher7, nil, nil, explainTrue)
203
martyTermSearcher7, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 5.0, explainTrue)
207
conjunctionSearcher7, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher7, booleanSearcher7}, explainTrue)
210
beerTermSearcher8, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, explainTrue)
214
mustSearcher8, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher8}, explainTrue)
218
martyTermSearcher8, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, explainTrue)
222
dustinTermSearcher8, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, explainTrue)
226
shouldSearcher8, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher8, dustinTermSearcher8}, 0, explainTrue)
230
steveTermSearcher8, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, explainTrue)
234
mustNotSearcher8, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher8}, 0, explainTrue)
238
booleanSearcher8, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher8, shouldSearcher8, mustNotSearcher8, explainTrue)
242
dustinTermSearcher8a, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 5.0, explainTrue)
246
conjunctionSearcher8, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{booleanSearcher8, dustinTermSearcher8a}, explainTrue)
252
searcher search.Searcher
253
results []*search.DocumentMatch
256
searcher: booleanSearcher,
257
results: []*search.DocumentMatch{
259
IndexInternalID: index.IndexInternalID("1"),
260
Score: 0.9818005051949021,
263
IndexInternalID: index.IndexInternalID("3"),
264
Score: 0.808709699395535,
267
IndexInternalID: index.IndexInternalID("4"),
268
Score: 0.34618161159873423,
273
searcher: booleanSearcher2,
274
results: []*search.DocumentMatch{
276
IndexInternalID: index.IndexInternalID("1"),
277
Score: 0.6775110856165737,
280
IndexInternalID: index.IndexInternalID("3"),
281
Score: 0.6775110856165737,
285
// no MUST or SHOULD clauses yields no results
287
searcher: booleanSearcher3,
288
results: []*search.DocumentMatch{},
291
searcher: booleanSearcher4,
292
results: []*search.DocumentMatch{
294
IndexInternalID: index.IndexInternalID("1"),
298
IndexInternalID: index.IndexInternalID("3"),
302
IndexInternalID: index.IndexInternalID("4"),
308
searcher: booleanSearcher5,
309
results: []*search.DocumentMatch{
311
IndexInternalID: index.IndexInternalID("3"),
315
IndexInternalID: index.IndexInternalID("4"),
321
searcher: booleanSearcher6,
322
results: []*search.DocumentMatch{},
324
// test a conjunction query with a nested boolean
326
searcher: conjunctionSearcher7,
327
results: []*search.DocumentMatch{
329
IndexInternalID: index.IndexInternalID("1"),
330
Score: 2.0097428702814377,
335
searcher: conjunctionSearcher8,
336
results: []*search.DocumentMatch{
338
IndexInternalID: index.IndexInternalID("3"),
339
Score: 2.0681575785068107,
345
for testIndex, test := range tests {
347
err := test.searcher.Close()
353
ctx := &search.SearchContext{
354
DocumentMatchPool: search.NewDocumentMatchPool(test.searcher.DocumentMatchPoolSize(), 0),
356
next, err := test.searcher.Next(ctx)
358
for err == nil && next != nil {
359
if i < len(test.results) {
360
if !next.IndexInternalID.Equals(test.results[i].IndexInternalID) {
361
t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].IndexInternalID, next.IndexInternalID, testIndex)
363
if !scoresCloseEnough(next.Score, test.results[i].Score) {
364
t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex)
365
t.Logf("scoring explanation: %s", next.Expl)
368
ctx.DocumentMatchPool.Put(next)
369
next, err = test.searcher.Next(ctx)
373
t.Fatalf("error iterating searcher: %v for test %d", err, testIndex)
375
if len(test.results) != i {
376
t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex)