1// Copyright (c) 2014 Couchbase, Inc. 2// 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 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 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. 14 15package query 16 17import ( 18 "regexp" 19 "strings" 20 21 "github.com/blevesearch/bleve/index" 22 "github.com/blevesearch/bleve/mapping" 23 "github.com/blevesearch/bleve/search" 24 "github.com/blevesearch/bleve/search/searcher" 25) 26 27type RegexpQuery struct { 28 Regexp string `json:"regexp"` 29 FieldVal string `json:"field,omitempty"` 30 BoostVal *Boost `json:"boost,omitempty"` 31 compiled *regexp.Regexp 32} 33 34// NewRegexpQuery creates a new Query which finds 35// documents containing terms that match the 36// specified regular expression. The regexp pattern 37// SHOULD NOT include ^ or $ modifiers, the search 38// will only match entire terms even without them. 39func NewRegexpQuery(regexp string) *RegexpQuery { 40 return &RegexpQuery{ 41 Regexp: regexp, 42 } 43} 44 45func (q *RegexpQuery) SetBoost(b float64) { 46 boost := Boost(b) 47 q.BoostVal = &boost 48} 49 50func (q *RegexpQuery) Boost() float64 { 51 return q.BoostVal.Value() 52} 53 54func (q *RegexpQuery) SetField(f string) { 55 q.FieldVal = f 56} 57 58func (q *RegexpQuery) Field() string { 59 return q.FieldVal 60} 61 62func (q *RegexpQuery) Searcher(i index.IndexReader, m mapping.IndexMapping, options search.SearcherOptions) (search.Searcher, error) { 63 field := q.FieldVal 64 if q.FieldVal == "" { 65 field = m.DefaultSearchField() 66 } 67 err := q.compile() 68 if err != nil { 69 return nil, err 70 } 71 72 return searcher.NewRegexpSearcher(i, q.compiled, field, q.BoostVal.Value(), options) 73} 74 75func (q *RegexpQuery) Validate() error { 76 return q.compile() 77} 78 79func (q *RegexpQuery) compile() error { 80 if q.compiled == nil { 81 // require that pattern NOT be anchored to start and end of term 82 actualRegexp := q.Regexp 83 if strings.HasPrefix(actualRegexp, "^") { 84 actualRegexp = actualRegexp[1:] // remove leading ^ 85 } 86 // do not attempt to remove trailing $, it's presence is not 87 // known to interfere with LiteralPrefix() the way ^ does 88 // and removing $ introduces possible ambiguities with escaped \$, \\$, etc 89 var err error 90 q.compiled, err = regexp.Compile(actualRegexp) 91 if err != nil { 92 return err 93 } 94 } 95 return nil 96} 97