Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. package query
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "github.com/blevesearch/bleve/index"
  19. "github.com/blevesearch/bleve/mapping"
  20. "github.com/blevesearch/bleve/search"
  21. "github.com/blevesearch/bleve/search/searcher"
  22. )
  23. type BooleanQuery struct {
  24. Must Query `json:"must,omitempty"`
  25. Should Query `json:"should,omitempty"`
  26. MustNot Query `json:"must_not,omitempty"`
  27. BoostVal *Boost `json:"boost,omitempty"`
  28. queryStringMode bool
  29. }
  30. // NewBooleanQuery creates a compound Query composed
  31. // of several other Query objects.
  32. // Result documents must satisfy ALL of the
  33. // must Queries.
  34. // Result documents must satisfy NONE of the must not
  35. // Queries.
  36. // Result documents that ALSO satisfy any of the should
  37. // Queries will score higher.
  38. func NewBooleanQuery(must []Query, should []Query, mustNot []Query) *BooleanQuery {
  39. rv := BooleanQuery{}
  40. if len(must) > 0 {
  41. rv.Must = NewConjunctionQuery(must)
  42. }
  43. if len(should) > 0 {
  44. rv.Should = NewDisjunctionQuery(should)
  45. }
  46. if len(mustNot) > 0 {
  47. rv.MustNot = NewDisjunctionQuery(mustNot)
  48. }
  49. return &rv
  50. }
  51. func NewBooleanQueryForQueryString(must []Query, should []Query, mustNot []Query) *BooleanQuery {
  52. rv := NewBooleanQuery(nil, nil, nil)
  53. rv.queryStringMode = true
  54. rv.AddMust(must...)
  55. rv.AddShould(should...)
  56. rv.AddMustNot(mustNot...)
  57. return rv
  58. }
  59. // SetMinShould requires that at least minShould of the
  60. // should Queries must be satisfied.
  61. func (q *BooleanQuery) SetMinShould(minShould float64) {
  62. q.Should.(*DisjunctionQuery).SetMin(minShould)
  63. }
  64. func (q *BooleanQuery) AddMust(m ...Query) {
  65. if q.Must == nil {
  66. tmp := NewConjunctionQuery([]Query{})
  67. tmp.queryStringMode = q.queryStringMode
  68. q.Must = tmp
  69. }
  70. for _, mq := range m {
  71. q.Must.(*ConjunctionQuery).AddQuery(mq)
  72. }
  73. }
  74. func (q *BooleanQuery) AddShould(m ...Query) {
  75. if q.Should == nil {
  76. tmp := NewDisjunctionQuery([]Query{})
  77. tmp.queryStringMode = q.queryStringMode
  78. q.Should = tmp
  79. }
  80. for _, mq := range m {
  81. q.Should.(*DisjunctionQuery).AddQuery(mq)
  82. }
  83. }
  84. func (q *BooleanQuery) AddMustNot(m ...Query) {
  85. if q.MustNot == nil {
  86. tmp := NewDisjunctionQuery([]Query{})
  87. tmp.queryStringMode = q.queryStringMode
  88. q.MustNot = tmp
  89. }
  90. for _, mq := range m {
  91. q.MustNot.(*DisjunctionQuery).AddQuery(mq)
  92. }
  93. }
  94. func (q *BooleanQuery) SetBoost(b float64) {
  95. boost := Boost(b)
  96. q.BoostVal = &boost
  97. }
  98. func (q *BooleanQuery) Boost() float64 {
  99. return q.BoostVal.Value()
  100. }
  101. func (q *BooleanQuery) Searcher(i index.IndexReader, m mapping.IndexMapping, options search.SearcherOptions) (search.Searcher, error) {
  102. var err error
  103. var mustNotSearcher search.Searcher
  104. if q.MustNot != nil {
  105. mustNotSearcher, err = q.MustNot.Searcher(i, m, options)
  106. if err != nil {
  107. return nil, err
  108. }
  109. // if must not is MatchNone, reset it to nil
  110. if _, ok := mustNotSearcher.(*searcher.MatchNoneSearcher); ok {
  111. mustNotSearcher = nil
  112. }
  113. }
  114. var mustSearcher search.Searcher
  115. if q.Must != nil {
  116. mustSearcher, err = q.Must.Searcher(i, m, options)
  117. if err != nil {
  118. return nil, err
  119. }
  120. // if must searcher is MatchNone, reset it to nil
  121. if _, ok := mustSearcher.(*searcher.MatchNoneSearcher); ok {
  122. mustSearcher = nil
  123. }
  124. }
  125. var shouldSearcher search.Searcher
  126. if q.Should != nil {
  127. shouldSearcher, err = q.Should.Searcher(i, m, options)
  128. if err != nil {
  129. return nil, err
  130. }
  131. // if should searcher is MatchNone, reset it to nil
  132. if _, ok := shouldSearcher.(*searcher.MatchNoneSearcher); ok {
  133. shouldSearcher = nil
  134. }
  135. }
  136. // if all 3 are nil, return MatchNone
  137. if mustSearcher == nil && shouldSearcher == nil && mustNotSearcher == nil {
  138. return searcher.NewMatchNoneSearcher(i)
  139. }
  140. // if only mustNotSearcher, start with MatchAll
  141. if mustSearcher == nil && shouldSearcher == nil && mustNotSearcher != nil {
  142. mustSearcher, err = searcher.NewMatchAllSearcher(i, 1.0, options)
  143. if err != nil {
  144. return nil, err
  145. }
  146. }
  147. // optimization, if only should searcher, just return it instead
  148. if mustSearcher == nil && shouldSearcher != nil && mustNotSearcher == nil {
  149. return shouldSearcher, nil
  150. }
  151. return searcher.NewBooleanSearcher(i, mustSearcher, shouldSearcher, mustNotSearcher, options)
  152. }
  153. func (q *BooleanQuery) Validate() error {
  154. if qm, ok := q.Must.(ValidatableQuery); ok {
  155. err := qm.Validate()
  156. if err != nil {
  157. return err
  158. }
  159. }
  160. if qs, ok := q.Should.(ValidatableQuery); ok {
  161. err := qs.Validate()
  162. if err != nil {
  163. return err
  164. }
  165. }
  166. if qmn, ok := q.MustNot.(ValidatableQuery); ok {
  167. err := qmn.Validate()
  168. if err != nil {
  169. return err
  170. }
  171. }
  172. if q.Must == nil && q.Should == nil && q.MustNot == nil {
  173. return fmt.Errorf("boolean query must contain at least one must or should or not must clause")
  174. }
  175. return nil
  176. }
  177. func (q *BooleanQuery) UnmarshalJSON(data []byte) error {
  178. tmp := struct {
  179. Must json.RawMessage `json:"must,omitempty"`
  180. Should json.RawMessage `json:"should,omitempty"`
  181. MustNot json.RawMessage `json:"must_not,omitempty"`
  182. Boost *Boost `json:"boost,omitempty"`
  183. }{}
  184. err := json.Unmarshal(data, &tmp)
  185. if err != nil {
  186. return err
  187. }
  188. if tmp.Must != nil {
  189. q.Must, err = ParseQuery(tmp.Must)
  190. if err != nil {
  191. return err
  192. }
  193. _, isConjunctionQuery := q.Must.(*ConjunctionQuery)
  194. if !isConjunctionQuery {
  195. return fmt.Errorf("must clause must be conjunction")
  196. }
  197. }
  198. if tmp.Should != nil {
  199. q.Should, err = ParseQuery(tmp.Should)
  200. if err != nil {
  201. return err
  202. }
  203. _, isDisjunctionQuery := q.Should.(*DisjunctionQuery)
  204. if !isDisjunctionQuery {
  205. return fmt.Errorf("should clause must be disjunction")
  206. }
  207. }
  208. if tmp.MustNot != nil {
  209. q.MustNot, err = ParseQuery(tmp.MustNot)
  210. if err != nil {
  211. return err
  212. }
  213. _, isDisjunctionQuery := q.MustNot.(*DisjunctionQuery)
  214. if !isDisjunctionQuery {
  215. return fmt.Errorf("must not clause must be disjunction")
  216. }
  217. }
  218. q.BoostVal = tmp.Boost
  219. return nil
  220. }