github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/m3ninx/search/query/disjunction.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package query 22 23 import ( 24 "sort" 25 "strings" 26 27 "github.com/m3db/m3/src/m3ninx/generated/proto/querypb" 28 "github.com/m3db/m3/src/m3ninx/search" 29 "github.com/m3db/m3/src/m3ninx/search/searcher" 30 ) 31 32 // DisjuctionQuery finds documents which match at least one of the given queries. 33 type DisjuctionQuery struct { 34 str string 35 queries []search.Query 36 } 37 38 // NewDisjunctionQuery constructs a new query which matches documents that match any 39 // of the given queries. 40 func NewDisjunctionQuery(queries []search.Query) search.Query { 41 qs := make([]search.Query, 0, len(queries)) 42 for _, query := range queries { 43 // Merge disjunction queries into slice of top-level queries. 44 q, ok := query.(*DisjuctionQuery) 45 if ok { 46 qs = append(qs, q.queries...) 47 continue 48 } 49 50 qs = append(qs, query) 51 } 52 // Cause a sort of the queries/negations for deterministic cache key. 53 sort.Slice(qs, func(i, j int) bool { 54 return qs[i].String() < qs[j].String() 55 }) 56 q := &DisjuctionQuery{ 57 queries: qs, 58 } 59 // NB(r): Calculate string value up front so 60 // not allocated every time String() is called to determine 61 // the cache key. 62 q.str = q.string() 63 return q 64 } 65 66 // Searcher returns a searcher over the provided readers. 67 func (q *DisjuctionQuery) Searcher() (search.Searcher, error) { 68 switch len(q.queries) { 69 case 0: 70 return searcher.NewEmptySearcher(), nil 71 72 case 1: 73 return q.queries[0].Searcher() 74 } 75 76 srs := make(search.Searchers, 0, len(q.queries)) 77 for _, q := range q.queries { 78 sr, err := q.Searcher() 79 if err != nil { 80 return nil, err 81 } 82 srs = append(srs, sr) 83 } 84 85 return searcher.NewDisjunctionSearcher(srs) 86 } 87 88 // Equal reports whether q is equivalent to o. 89 func (q *DisjuctionQuery) Equal(o search.Query) bool { 90 if len(q.queries) == 1 { 91 return q.queries[0].Equal(o) 92 } 93 94 inner, ok := o.(*DisjuctionQuery) 95 if !ok { 96 return false 97 } 98 99 if len(q.queries) != len(inner.queries) { 100 return false 101 } 102 103 // TODO: Should order matter? 104 for i := range q.queries { 105 if !q.queries[i].Equal(inner.queries[i]) { 106 return false 107 } 108 } 109 return true 110 } 111 112 // ToProto returns the Protobuf query struct corresponding to the disjunction query. 113 func (q *DisjuctionQuery) ToProto() *querypb.Query { 114 qs := make([]*querypb.Query, 0, len(q.queries)) 115 for _, qry := range q.queries { 116 qs = append(qs, qry.ToProto()) 117 } 118 disj := querypb.DisjunctionQuery{Queries: qs} 119 120 return &querypb.Query{ 121 Query: &querypb.Query_Disjunction{Disjunction: &disj}, 122 } 123 } 124 125 func (q *DisjuctionQuery) String() string { 126 return q.str 127 } 128 129 func (q *DisjuctionQuery) string() string { 130 var str strings.Builder 131 str.WriteString("disjunction(") 132 join(&str, q.queries) 133 str.WriteRune(')') 134 return str.String() 135 }