本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
7.9KB

  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. "io/ioutil"
  19. "log"
  20. "github.com/blevesearch/bleve/index"
  21. "github.com/blevesearch/bleve/mapping"
  22. "github.com/blevesearch/bleve/search"
  23. )
  24. var logger = log.New(ioutil.Discard, "bleve mapping ", log.LstdFlags)
  25. // SetLog sets the logger used for logging
  26. // by default log messages are sent to ioutil.Discard
  27. func SetLog(l *log.Logger) {
  28. logger = l
  29. }
  30. // A Query represents a description of the type
  31. // and parameters for a query into the index.
  32. type Query interface {
  33. Searcher(i index.IndexReader, m mapping.IndexMapping,
  34. options search.SearcherOptions) (search.Searcher, error)
  35. }
  36. // A BoostableQuery represents a Query which can be boosted
  37. // relative to other queries.
  38. type BoostableQuery interface {
  39. Query
  40. SetBoost(b float64)
  41. Boost() float64
  42. }
  43. // A FieldableQuery represents a Query which can be restricted
  44. // to a single field.
  45. type FieldableQuery interface {
  46. Query
  47. SetField(f string)
  48. Field() string
  49. }
  50. // A ValidatableQuery represents a Query which can be validated
  51. // prior to execution.
  52. type ValidatableQuery interface {
  53. Query
  54. Validate() error
  55. }
  56. // ParseQuery deserializes a JSON representation of
  57. // a Query object.
  58. func ParseQuery(input []byte) (Query, error) {
  59. var tmp map[string]interface{}
  60. err := json.Unmarshal(input, &tmp)
  61. if err != nil {
  62. return nil, err
  63. }
  64. _, isMatchQuery := tmp["match"]
  65. _, hasFuzziness := tmp["fuzziness"]
  66. if hasFuzziness && !isMatchQuery {
  67. var rv FuzzyQuery
  68. err := json.Unmarshal(input, &rv)
  69. if err != nil {
  70. return nil, err
  71. }
  72. return &rv, nil
  73. }
  74. _, isTermQuery := tmp["term"]
  75. if isTermQuery {
  76. var rv TermQuery
  77. err := json.Unmarshal(input, &rv)
  78. if err != nil {
  79. return nil, err
  80. }
  81. return &rv, nil
  82. }
  83. if isMatchQuery {
  84. var rv MatchQuery
  85. err := json.Unmarshal(input, &rv)
  86. if err != nil {
  87. return nil, err
  88. }
  89. return &rv, nil
  90. }
  91. _, isMatchPhraseQuery := tmp["match_phrase"]
  92. if isMatchPhraseQuery {
  93. var rv MatchPhraseQuery
  94. err := json.Unmarshal(input, &rv)
  95. if err != nil {
  96. return nil, err
  97. }
  98. return &rv, nil
  99. }
  100. _, hasMust := tmp["must"]
  101. _, hasShould := tmp["should"]
  102. _, hasMustNot := tmp["must_not"]
  103. if hasMust || hasShould || hasMustNot {
  104. var rv BooleanQuery
  105. err := json.Unmarshal(input, &rv)
  106. if err != nil {
  107. return nil, err
  108. }
  109. return &rv, nil
  110. }
  111. _, hasTerms := tmp["terms"]
  112. if hasTerms {
  113. var rv PhraseQuery
  114. err := json.Unmarshal(input, &rv)
  115. if err != nil {
  116. // now try multi-phrase
  117. var rv2 MultiPhraseQuery
  118. err = json.Unmarshal(input, &rv2)
  119. if err != nil {
  120. return nil, err
  121. }
  122. return &rv2, nil
  123. }
  124. return &rv, nil
  125. }
  126. _, hasConjuncts := tmp["conjuncts"]
  127. if hasConjuncts {
  128. var rv ConjunctionQuery
  129. err := json.Unmarshal(input, &rv)
  130. if err != nil {
  131. return nil, err
  132. }
  133. return &rv, nil
  134. }
  135. _, hasDisjuncts := tmp["disjuncts"]
  136. if hasDisjuncts {
  137. var rv DisjunctionQuery
  138. err := json.Unmarshal(input, &rv)
  139. if err != nil {
  140. return nil, err
  141. }
  142. return &rv, nil
  143. }
  144. _, hasSyntaxQuery := tmp["query"]
  145. if hasSyntaxQuery {
  146. var rv QueryStringQuery
  147. err := json.Unmarshal(input, &rv)
  148. if err != nil {
  149. return nil, err
  150. }
  151. return &rv, nil
  152. }
  153. _, hasMin := tmp["min"].(float64)
  154. _, hasMax := tmp["max"].(float64)
  155. if hasMin || hasMax {
  156. var rv NumericRangeQuery
  157. err := json.Unmarshal(input, &rv)
  158. if err != nil {
  159. return nil, err
  160. }
  161. return &rv, nil
  162. }
  163. _, hasMinStr := tmp["min"].(string)
  164. _, hasMaxStr := tmp["max"].(string)
  165. if hasMinStr || hasMaxStr {
  166. var rv TermRangeQuery
  167. err := json.Unmarshal(input, &rv)
  168. if err != nil {
  169. return nil, err
  170. }
  171. return &rv, nil
  172. }
  173. _, hasStart := tmp["start"]
  174. _, hasEnd := tmp["end"]
  175. if hasStart || hasEnd {
  176. var rv DateRangeQuery
  177. err := json.Unmarshal(input, &rv)
  178. if err != nil {
  179. return nil, err
  180. }
  181. return &rv, nil
  182. }
  183. _, hasPrefix := tmp["prefix"]
  184. if hasPrefix {
  185. var rv PrefixQuery
  186. err := json.Unmarshal(input, &rv)
  187. if err != nil {
  188. return nil, err
  189. }
  190. return &rv, nil
  191. }
  192. _, hasRegexp := tmp["regexp"]
  193. if hasRegexp {
  194. var rv RegexpQuery
  195. err := json.Unmarshal(input, &rv)
  196. if err != nil {
  197. return nil, err
  198. }
  199. return &rv, nil
  200. }
  201. _, hasWildcard := tmp["wildcard"]
  202. if hasWildcard {
  203. var rv WildcardQuery
  204. err := json.Unmarshal(input, &rv)
  205. if err != nil {
  206. return nil, err
  207. }
  208. return &rv, nil
  209. }
  210. _, hasMatchAll := tmp["match_all"]
  211. if hasMatchAll {
  212. var rv MatchAllQuery
  213. err := json.Unmarshal(input, &rv)
  214. if err != nil {
  215. return nil, err
  216. }
  217. return &rv, nil
  218. }
  219. _, hasMatchNone := tmp["match_none"]
  220. if hasMatchNone {
  221. var rv MatchNoneQuery
  222. err := json.Unmarshal(input, &rv)
  223. if err != nil {
  224. return nil, err
  225. }
  226. return &rv, nil
  227. }
  228. _, hasDocIds := tmp["ids"]
  229. if hasDocIds {
  230. var rv DocIDQuery
  231. err := json.Unmarshal(input, &rv)
  232. if err != nil {
  233. return nil, err
  234. }
  235. return &rv, nil
  236. }
  237. _, hasBool := tmp["bool"]
  238. if hasBool {
  239. var rv BoolFieldQuery
  240. err := json.Unmarshal(input, &rv)
  241. if err != nil {
  242. return nil, err
  243. }
  244. return &rv, nil
  245. }
  246. _, hasTopLeft := tmp["top_left"]
  247. _, hasBottomRight := tmp["bottom_right"]
  248. if hasTopLeft && hasBottomRight {
  249. var rv GeoBoundingBoxQuery
  250. err := json.Unmarshal(input, &rv)
  251. if err != nil {
  252. return nil, err
  253. }
  254. return &rv, nil
  255. }
  256. _, hasDistance := tmp["distance"]
  257. if hasDistance {
  258. var rv GeoDistanceQuery
  259. err := json.Unmarshal(input, &rv)
  260. if err != nil {
  261. return nil, err
  262. }
  263. return &rv, nil
  264. }
  265. return nil, fmt.Errorf("unknown query type")
  266. }
  267. // expandQuery traverses the input query tree and returns a new tree where
  268. // query string queries have been expanded into base queries. Returned tree may
  269. // reference queries from the input tree or new queries.
  270. func expandQuery(m mapping.IndexMapping, query Query) (Query, error) {
  271. var expand func(query Query) (Query, error)
  272. var expandSlice func(queries []Query) ([]Query, error)
  273. expandSlice = func(queries []Query) ([]Query, error) {
  274. expanded := []Query{}
  275. for _, q := range queries {
  276. exp, err := expand(q)
  277. if err != nil {
  278. return nil, err
  279. }
  280. expanded = append(expanded, exp)
  281. }
  282. return expanded, nil
  283. }
  284. expand = func(query Query) (Query, error) {
  285. switch q := query.(type) {
  286. case *QueryStringQuery:
  287. parsed, err := parseQuerySyntax(q.Query)
  288. if err != nil {
  289. return nil, fmt.Errorf("could not parse '%s': %s", q.Query, err)
  290. }
  291. return expand(parsed)
  292. case *ConjunctionQuery:
  293. children, err := expandSlice(q.Conjuncts)
  294. if err != nil {
  295. return nil, err
  296. }
  297. q.Conjuncts = children
  298. return q, nil
  299. case *DisjunctionQuery:
  300. children, err := expandSlice(q.Disjuncts)
  301. if err != nil {
  302. return nil, err
  303. }
  304. q.Disjuncts = children
  305. return q, nil
  306. case *BooleanQuery:
  307. var err error
  308. q.Must, err = expand(q.Must)
  309. if err != nil {
  310. return nil, err
  311. }
  312. q.Should, err = expand(q.Should)
  313. if err != nil {
  314. return nil, err
  315. }
  316. q.MustNot, err = expand(q.MustNot)
  317. if err != nil {
  318. return nil, err
  319. }
  320. return q, nil
  321. default:
  322. return query, nil
  323. }
  324. }
  325. return expand(query)
  326. }
  327. // DumpQuery returns a string representation of the query tree, where query
  328. // string queries have been expanded into base queries. The output format is
  329. // meant for debugging purpose and may change in the future.
  330. func DumpQuery(m mapping.IndexMapping, query Query) (string, error) {
  331. q, err := expandQuery(m, query)
  332. if err != nil {
  333. return "", err
  334. }
  335. data, err := json.MarshalIndent(q, "", " ")
  336. return string(data), err
  337. }
上海开阖软件有限公司 沪ICP备12045867号-1