search_test.go 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596
  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 bleve
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "os"
  19. "reflect"
  20. "strconv"
  21. "strings"
  22. "testing"
  23. "time"
  24. "github.com/blevesearch/bleve/analysis"
  25. "github.com/blevesearch/bleve/analysis/analyzer/custom"
  26. "github.com/blevesearch/bleve/analysis/analyzer/keyword"
  27. "github.com/blevesearch/bleve/analysis/analyzer/standard"
  28. "github.com/blevesearch/bleve/analysis/token/length"
  29. "github.com/blevesearch/bleve/analysis/token/lowercase"
  30. "github.com/blevesearch/bleve/analysis/token/shingle"
  31. "github.com/blevesearch/bleve/analysis/tokenizer/single"
  32. "github.com/blevesearch/bleve/analysis/tokenizer/whitespace"
  33. "github.com/blevesearch/bleve/document"
  34. "github.com/blevesearch/bleve/index/scorch"
  35. "github.com/blevesearch/bleve/index/upsidedown"
  36. "github.com/blevesearch/bleve/mapping"
  37. "github.com/blevesearch/bleve/search"
  38. "github.com/blevesearch/bleve/search/highlight/highlighter/html"
  39. "github.com/blevesearch/bleve/search/query"
  40. )
  41. func TestSearchResultString(t *testing.T) {
  42. tests := []struct {
  43. result *SearchResult
  44. str string
  45. }{
  46. {
  47. result: &SearchResult{
  48. Request: &SearchRequest{
  49. Size: 10,
  50. },
  51. Total: 5,
  52. Took: 1 * time.Second,
  53. Hits: search.DocumentMatchCollection{
  54. &search.DocumentMatch{},
  55. &search.DocumentMatch{},
  56. &search.DocumentMatch{},
  57. &search.DocumentMatch{},
  58. &search.DocumentMatch{},
  59. },
  60. },
  61. str: "5 matches, showing 1 through 5, took 1s",
  62. },
  63. {
  64. result: &SearchResult{
  65. Request: &SearchRequest{
  66. Size: 0,
  67. },
  68. Total: 5,
  69. Hits: search.DocumentMatchCollection{},
  70. },
  71. str: "5 matches",
  72. },
  73. {
  74. result: &SearchResult{
  75. Request: &SearchRequest{
  76. Size: 10,
  77. },
  78. Total: 0,
  79. Hits: search.DocumentMatchCollection{},
  80. },
  81. str: "No matches",
  82. },
  83. }
  84. for _, test := range tests {
  85. srstring := test.result.String()
  86. if !strings.HasPrefix(srstring, test.str) {
  87. t.Errorf("expected to start %s, got %s", test.str, srstring)
  88. }
  89. }
  90. }
  91. func TestSearchResultMerge(t *testing.T) {
  92. l := &SearchResult{
  93. Status: &SearchStatus{
  94. Total: 1,
  95. Successful: 1,
  96. Errors: make(map[string]error),
  97. },
  98. Total: 1,
  99. MaxScore: 1,
  100. Hits: search.DocumentMatchCollection{
  101. &search.DocumentMatch{
  102. ID: "a",
  103. Score: 1,
  104. },
  105. },
  106. }
  107. r := &SearchResult{
  108. Status: &SearchStatus{
  109. Total: 1,
  110. Successful: 1,
  111. Errors: make(map[string]error),
  112. },
  113. Total: 1,
  114. MaxScore: 2,
  115. Hits: search.DocumentMatchCollection{
  116. &search.DocumentMatch{
  117. ID: "b",
  118. Score: 2,
  119. },
  120. },
  121. }
  122. expected := &SearchResult{
  123. Status: &SearchStatus{
  124. Total: 2,
  125. Successful: 2,
  126. Errors: make(map[string]error),
  127. },
  128. Total: 2,
  129. MaxScore: 2,
  130. Hits: search.DocumentMatchCollection{
  131. &search.DocumentMatch{
  132. ID: "a",
  133. Score: 1,
  134. },
  135. &search.DocumentMatch{
  136. ID: "b",
  137. Score: 2,
  138. },
  139. },
  140. }
  141. l.Merge(r)
  142. if !reflect.DeepEqual(l, expected) {
  143. t.Errorf("expected %#v, got %#v", expected, l)
  144. }
  145. }
  146. func TestUnmarshalingSearchResult(t *testing.T) {
  147. searchResponse := []byte(`{
  148. "status":{
  149. "total":1,
  150. "failed":1,
  151. "successful":0,
  152. "errors":{
  153. "default_index_362ce020b3d62b13_348f5c3c":"context deadline exceeded"
  154. }
  155. },
  156. "request":{
  157. "query":{
  158. "match":"emp",
  159. "field":"type",
  160. "boost":1,
  161. "prefix_length":0,
  162. "fuzziness":0
  163. },
  164. "size":10000000,
  165. "from":0,
  166. "highlight":null,
  167. "fields":[],
  168. "facets":null,
  169. "explain":false
  170. },
  171. "hits":null,
  172. "total_hits":0,
  173. "max_score":0,
  174. "took":0,
  175. "facets":null
  176. }`)
  177. rv := &SearchResult{
  178. Status: &SearchStatus{
  179. Errors: make(map[string]error),
  180. },
  181. }
  182. err = json.Unmarshal(searchResponse, rv)
  183. if err != nil {
  184. t.Error(err)
  185. }
  186. if len(rv.Status.Errors) != 1 {
  187. t.Errorf("expected 1 error, got %d", len(rv.Status.Errors))
  188. }
  189. }
  190. func TestFacetNumericDateRangeRequests(t *testing.T) {
  191. var drMissingErr = fmt.Errorf("date range query must specify either start, end or both for range name 'testName'")
  192. var nrMissingErr = fmt.Errorf("numeric range query must specify either min, max or both for range name 'testName'")
  193. var drNrErr = fmt.Errorf("facet can only conain numeric ranges or date ranges, not both")
  194. var drNameDupErr = fmt.Errorf("date ranges contains duplicate name 'testName'")
  195. var nrNameDupErr = fmt.Errorf("numeric ranges contains duplicate name 'testName'")
  196. value := float64(5)
  197. tests := []struct {
  198. facet *FacetRequest
  199. result error
  200. }{
  201. {
  202. facet: &FacetRequest{
  203. Field: "Date_Range_Success_With_StartEnd",
  204. Size: 1,
  205. DateTimeRanges: []*dateTimeRange{
  206. &dateTimeRange{Name: "testName", Start: time.Unix(0, 0), End: time.Now()},
  207. },
  208. },
  209. result: nil,
  210. },
  211. {
  212. facet: &FacetRequest{
  213. Field: "Date_Range_Success_With_Start",
  214. Size: 1,
  215. DateTimeRanges: []*dateTimeRange{
  216. &dateTimeRange{Name: "testName", Start: time.Unix(0, 0)},
  217. },
  218. },
  219. result: nil,
  220. },
  221. {
  222. facet: &FacetRequest{
  223. Field: "Date_Range_Success_With_End",
  224. Size: 1,
  225. DateTimeRanges: []*dateTimeRange{
  226. &dateTimeRange{Name: "testName", End: time.Now()},
  227. },
  228. },
  229. result: nil,
  230. },
  231. {
  232. facet: &FacetRequest{
  233. Field: "Numeric_Range_Success_With_MinMax",
  234. Size: 1,
  235. NumericRanges: []*numericRange{
  236. &numericRange{Name: "testName", Min: &value, Max: &value},
  237. },
  238. },
  239. result: nil,
  240. },
  241. {
  242. facet: &FacetRequest{
  243. Field: "Numeric_Range_Success_With_Min",
  244. Size: 1,
  245. NumericRanges: []*numericRange{
  246. &numericRange{Name: "testName", Min: &value},
  247. },
  248. },
  249. result: nil,
  250. },
  251. {
  252. facet: &FacetRequest{
  253. Field: "Numeric_Range_Success_With_Max",
  254. Size: 1,
  255. NumericRanges: []*numericRange{
  256. &numericRange{Name: "testName", Max: &value},
  257. },
  258. },
  259. result: nil,
  260. },
  261. {
  262. facet: &FacetRequest{
  263. Field: "Date_Range_Missing_Failure",
  264. Size: 1,
  265. DateTimeRanges: []*dateTimeRange{
  266. &dateTimeRange{Name: "testName2", Start: time.Unix(0, 0)},
  267. &dateTimeRange{Name: "testName1", End: time.Now()},
  268. &dateTimeRange{Name: "testName"},
  269. },
  270. },
  271. result: drMissingErr,
  272. },
  273. {
  274. facet: &FacetRequest{
  275. Field: "Numeric_Range_Missing_Failure",
  276. Size: 1,
  277. NumericRanges: []*numericRange{
  278. &numericRange{Name: "testName2", Min: &value},
  279. &numericRange{Name: "testName1", Max: &value},
  280. &numericRange{Name: "testName"},
  281. },
  282. },
  283. result: nrMissingErr,
  284. },
  285. {
  286. facet: &FacetRequest{
  287. Field: "Numeric_And_DateRanges_Failure",
  288. Size: 1,
  289. NumericRanges: []*numericRange{
  290. &numericRange{Name: "testName", Max: &value},
  291. },
  292. DateTimeRanges: []*dateTimeRange{
  293. &dateTimeRange{Name: "testName", End: time.Now()},
  294. },
  295. },
  296. result: drNrErr,
  297. },
  298. {
  299. facet: &FacetRequest{
  300. Field: "Numeric_Range_Name_Repeat_Failure",
  301. Size: 1,
  302. NumericRanges: []*numericRange{
  303. &numericRange{Name: "testName", Min: &value},
  304. &numericRange{Name: "testName", Max: &value},
  305. },
  306. },
  307. result: nrNameDupErr,
  308. },
  309. {
  310. facet: &FacetRequest{
  311. Field: "Date_Range_Name_Repeat_Failure",
  312. Size: 1,
  313. DateTimeRanges: []*dateTimeRange{
  314. &dateTimeRange{Name: "testName", Start: time.Unix(0, 0)},
  315. &dateTimeRange{Name: "testName", End: time.Now()},
  316. },
  317. },
  318. result: drNameDupErr,
  319. },
  320. }
  321. for _, test := range tests {
  322. result := test.facet.Validate()
  323. if !reflect.DeepEqual(result, test.result) {
  324. t.Errorf("expected %#v, got %#v", test.result, result)
  325. }
  326. }
  327. }
  328. func TestSearchResultFacetsMerge(t *testing.T) {
  329. lowmed := "2010-01-01"
  330. medhi := "2011-01-01"
  331. hihigher := "2012-01-01"
  332. fr := &search.FacetResult{
  333. Field: "birthday",
  334. Total: 100,
  335. Missing: 25,
  336. Other: 25,
  337. DateRanges: []*search.DateRangeFacet{
  338. {
  339. Name: "low",
  340. End: &lowmed,
  341. Count: 25,
  342. },
  343. {
  344. Name: "med",
  345. Count: 24,
  346. Start: &lowmed,
  347. End: &medhi,
  348. },
  349. {
  350. Name: "hi",
  351. Count: 1,
  352. Start: &medhi,
  353. End: &hihigher,
  354. },
  355. },
  356. }
  357. frs := search.FacetResults{
  358. "birthdays": fr,
  359. }
  360. l := &SearchResult{
  361. Status: &SearchStatus{
  362. Total: 10,
  363. Successful: 1,
  364. Errors: make(map[string]error),
  365. },
  366. Total: 10,
  367. MaxScore: 1,
  368. }
  369. r := &SearchResult{
  370. Status: &SearchStatus{
  371. Total: 1,
  372. Successful: 1,
  373. Errors: make(map[string]error),
  374. },
  375. Total: 1,
  376. MaxScore: 2,
  377. Facets: frs,
  378. }
  379. expected := &SearchResult{
  380. Status: &SearchStatus{
  381. Total: 11,
  382. Successful: 2,
  383. Errors: make(map[string]error),
  384. },
  385. Total: 11,
  386. MaxScore: 2,
  387. Facets: frs,
  388. }
  389. l.Merge(r)
  390. if !reflect.DeepEqual(l, expected) {
  391. t.Errorf("expected %#v, got %#v", expected, l)
  392. }
  393. }
  394. func TestMemoryNeededForSearchResult(t *testing.T) {
  395. query := NewTermQuery("blah")
  396. req := NewSearchRequest(query)
  397. var sr SearchResult
  398. expect := sr.Size()
  399. var dm search.DocumentMatch
  400. expect += 10 * dm.Size()
  401. estimate := MemoryNeededForSearchResult(req)
  402. if estimate != uint64(expect) {
  403. t.Errorf("estimate not what is expected: %v != %v", estimate, expect)
  404. }
  405. }
  406. // https://github.com/blevesearch/bleve/issues/954
  407. func TestNestedBooleanSearchers(t *testing.T) {
  408. // create an index with a custom analyzer
  409. idxMapping := NewIndexMapping()
  410. if err := idxMapping.AddCustomAnalyzer("3xbla", map[string]interface{}{
  411. "type": custom.Name,
  412. "tokenizer": whitespace.Name,
  413. "token_filters": []interface{}{lowercase.Name, "stop_en"},
  414. }); err != nil {
  415. t.Fatal(err)
  416. }
  417. idxMapping.DefaultAnalyzer = "3xbla"
  418. idx, err := New("testidx", idxMapping)
  419. if err != nil {
  420. t.Fatal(err)
  421. }
  422. defer func() {
  423. err = idx.Close()
  424. if err != nil {
  425. t.Fatal(err)
  426. }
  427. err = os.RemoveAll("testidx")
  428. if err != nil {
  429. t.Fatal(err)
  430. }
  431. }()
  432. // create and insert documents as a batch
  433. batch := idx.NewBatch()
  434. matches := 0
  435. for i := 0; i < 100; i++ {
  436. hostname := fmt.Sprintf("planner_hostname_%d", i%5)
  437. metadata := map[string]string{"region": fmt.Sprintf("planner_us-east-%d", i%5)}
  438. // Expected matches
  439. if (hostname == "planner_hostname_1" || hostname == "planner_hostname_2") &&
  440. metadata["region"] == "planner_us-east-1" {
  441. matches++
  442. }
  443. doc := document.NewDocument(strconv.Itoa(i))
  444. doc.Fields = []document.Field{
  445. document.NewTextFieldCustom("hostname", []uint64{}, []byte(hostname),
  446. document.IndexField,
  447. &analysis.Analyzer{
  448. Tokenizer: single.NewSingleTokenTokenizer(),
  449. TokenFilters: []analysis.TokenFilter{
  450. lowercase.NewLowerCaseFilter(),
  451. },
  452. },
  453. ),
  454. }
  455. for k, v := range metadata {
  456. doc.AddField(document.NewTextFieldWithIndexingOptions(
  457. fmt.Sprintf("metadata.%s", k), []uint64{}, []byte(v), document.IndexField))
  458. }
  459. doc.CompositeFields = []*document.CompositeField{
  460. document.NewCompositeFieldWithIndexingOptions(
  461. "_all", true, []string{"text"}, []string{},
  462. document.IndexField|document.IncludeTermVectors),
  463. }
  464. if err = batch.IndexAdvanced(doc); err != nil {
  465. t.Fatal(err)
  466. }
  467. }
  468. if err = idx.Batch(batch); err != nil {
  469. t.Fatal(err)
  470. }
  471. que, err := query.ParseQuery([]byte(
  472. `{
  473. "conjuncts": [
  474. {
  475. "must": {
  476. "conjuncts": [
  477. {
  478. "disjuncts": [
  479. {
  480. "match": "planner_hostname_1",
  481. "field": "hostname"
  482. },
  483. {
  484. "match": "planner_hostname_2",
  485. "field": "hostname"
  486. }
  487. ]
  488. }
  489. ]
  490. }
  491. },
  492. {
  493. "must": {
  494. "conjuncts": [
  495. {
  496. "match": "planner_us-east-1",
  497. "field": "metadata.region"
  498. }
  499. ]
  500. }
  501. }
  502. ]
  503. }`,
  504. ))
  505. if err != nil {
  506. t.Fatal(err)
  507. }
  508. req := NewSearchRequest(que)
  509. req.Size = 100
  510. req.Fields = []string{"hostname", "metadata.region"}
  511. searchResults, err := idx.Search(req)
  512. if err != nil {
  513. t.Fatal(err)
  514. }
  515. if matches != len(searchResults.Hits) {
  516. t.Fatalf("Unexpected result set, %v != %v", matches, len(searchResults.Hits))
  517. }
  518. }
  519. func TestNestedBooleanMustNotSearcherUpsidedown(t *testing.T) {
  520. // create an index with default settings
  521. idxMapping := NewIndexMapping()
  522. idx, err := New("testidx", idxMapping)
  523. if err != nil {
  524. t.Fatal(err)
  525. }
  526. defer func() {
  527. err = idx.Close()
  528. if err != nil {
  529. t.Fatal(err)
  530. }
  531. err = os.RemoveAll("testidx")
  532. if err != nil {
  533. t.Fatal(err)
  534. }
  535. }()
  536. // create and insert documents as a batch
  537. batch := idx.NewBatch()
  538. docs := []struct {
  539. id string
  540. hasRole bool
  541. investigationId string
  542. }{
  543. {
  544. id: "1@1",
  545. hasRole: true,
  546. investigationId: "1",
  547. },
  548. {
  549. id: "1@2",
  550. hasRole: false,
  551. investigationId: "2",
  552. },
  553. {
  554. id: "2@1",
  555. hasRole: true,
  556. investigationId: "1",
  557. },
  558. {
  559. id: "2@2",
  560. hasRole: false,
  561. investigationId: "2",
  562. },
  563. {
  564. id: "3@1",
  565. hasRole: true,
  566. investigationId: "1",
  567. },
  568. {
  569. id: "3@2",
  570. hasRole: false,
  571. investigationId: "2",
  572. },
  573. {
  574. id: "4@1",
  575. hasRole: true,
  576. investigationId: "1",
  577. },
  578. {
  579. id: "5@1",
  580. hasRole: true,
  581. investigationId: "1",
  582. },
  583. {
  584. id: "6@1",
  585. hasRole: true,
  586. investigationId: "1",
  587. },
  588. {
  589. id: "7@1",
  590. hasRole: true,
  591. investigationId: "1",
  592. },
  593. }
  594. for i := 0; i < len(docs); i++ {
  595. doc := document.NewDocument(docs[i].id)
  596. doc.Fields = []document.Field{
  597. document.NewTextField("id", []uint64{}, []byte(docs[i].id)),
  598. document.NewBooleanField("hasRole", []uint64{}, docs[i].hasRole),
  599. document.NewTextField("investigationId", []uint64{}, []byte(docs[i].investigationId)),
  600. }
  601. doc.CompositeFields = []*document.CompositeField{
  602. document.NewCompositeFieldWithIndexingOptions(
  603. "_all", true, []string{"text"}, []string{},
  604. document.IndexField|document.IncludeTermVectors),
  605. }
  606. if err = batch.IndexAdvanced(doc); err != nil {
  607. t.Fatal(err)
  608. }
  609. }
  610. if err = idx.Batch(batch); err != nil {
  611. t.Fatal(err)
  612. }
  613. tq := NewTermQuery("1")
  614. tq.SetField("investigationId")
  615. // using must not, for cases that the field did not exists at all
  616. hasRole := NewBoolFieldQuery(true)
  617. hasRole.SetField("hasRole")
  618. noRole := NewBooleanQuery()
  619. noRole.AddMustNot(hasRole)
  620. oneRolesOrNoRoles := NewBooleanQuery()
  621. oneRolesOrNoRoles.AddShould(noRole)
  622. oneRolesOrNoRoles.SetMinShould(1)
  623. q := NewConjunctionQuery(tq, oneRolesOrNoRoles)
  624. sr := NewSearchRequestOptions(q, 100, 0, false)
  625. sr.Fields = []string{"hasRole"}
  626. sr.Highlight = NewHighlight()
  627. res, err := idx.Search(sr)
  628. if err != nil {
  629. t.Fatal(err)
  630. }
  631. if res.Total != 0 {
  632. t.Fatalf("Unexpected result, %v != 0", res.Total)
  633. }
  634. }
  635. func TestSearchScorchOverEmptyKeyword(t *testing.T) {
  636. defaultIndexType := Config.DefaultIndexType
  637. Config.DefaultIndexType = scorch.Name
  638. dmap := mapping.NewDocumentMapping()
  639. dmap.DefaultAnalyzer = standard.Name
  640. fm := mapping.NewTextFieldMapping()
  641. fm.Analyzer = keyword.Name
  642. fm1 := mapping.NewTextFieldMapping()
  643. fm1.Analyzer = standard.Name
  644. dmap.AddFieldMappingsAt("id", fm)
  645. dmap.AddFieldMappingsAt("name", fm1)
  646. imap := mapping.NewIndexMapping()
  647. imap.DefaultMapping = dmap
  648. imap.DefaultAnalyzer = standard.Name
  649. idx, err := New("testidx", imap)
  650. if err != nil {
  651. t.Fatal(err)
  652. }
  653. defer func() {
  654. err = idx.Close()
  655. if err != nil {
  656. t.Fatal(err)
  657. }
  658. err = os.RemoveAll("testidx")
  659. if err != nil {
  660. t.Fatal(err)
  661. }
  662. Config.DefaultIndexType = defaultIndexType
  663. }()
  664. for i := 0; i < 10; i++ {
  665. err = idx.Index(fmt.Sprint(i), map[string]string{"name": fmt.Sprintf("test%d", i), "id": ""})
  666. if err != nil {
  667. t.Fatal(err)
  668. }
  669. }
  670. count, err := idx.DocCount()
  671. if err != nil {
  672. t.Fatal(err)
  673. }
  674. if count != 10 {
  675. t.Fatalf("Unexpected doc count: %v, expected 10", count)
  676. }
  677. q := query.NewWildcardQuery("test*")
  678. sr := NewSearchRequestOptions(q, 40, 0, false)
  679. res, err := idx.Search(sr)
  680. if err != nil {
  681. t.Fatal(err)
  682. }
  683. if res.Total != 10 {
  684. t.Fatalf("Unexpected search hits: %v, expected 10", res.Total)
  685. }
  686. }
  687. func TestMultipleNestedBooleanMustNotSearchersOnScorch(t *testing.T) {
  688. defaultIndexType := Config.DefaultIndexType
  689. Config.DefaultIndexType = scorch.Name
  690. // create an index with default settings
  691. idxMapping := NewIndexMapping()
  692. idx, err := New("testidx", idxMapping)
  693. if err != nil {
  694. t.Fatal(err)
  695. }
  696. defer func() {
  697. err = idx.Close()
  698. if err != nil {
  699. t.Fatal(err)
  700. }
  701. err = os.RemoveAll("testidx")
  702. if err != nil {
  703. t.Fatal(err)
  704. }
  705. Config.DefaultIndexType = defaultIndexType
  706. }()
  707. // create and insert documents as a batch
  708. batch := idx.NewBatch()
  709. doc := document.NewDocument("1-child-0")
  710. doc.Fields = []document.Field{
  711. document.NewTextField("id", []uint64{}, []byte("1-child-0")),
  712. document.NewBooleanField("hasRole", []uint64{}, false),
  713. document.NewTextField("roles", []uint64{}, []byte("R1")),
  714. document.NewNumericField("type", []uint64{}, 0),
  715. }
  716. doc.CompositeFields = []*document.CompositeField{
  717. document.NewCompositeFieldWithIndexingOptions(
  718. "_all", true, []string{"text"}, []string{},
  719. document.IndexField|document.IncludeTermVectors),
  720. }
  721. if err = batch.IndexAdvanced(doc); err != nil {
  722. t.Fatal(err)
  723. }
  724. docs := []struct {
  725. id string
  726. hasRole bool
  727. typ int
  728. }{
  729. {
  730. id: "16d6fa37-48fd-4dea-8b3d-a52bddf73951",
  731. hasRole: false,
  732. typ: 9,
  733. },
  734. {
  735. id: "18fa9eb2-8b1f-46f0-8b56-b4c551213f78",
  736. hasRole: false,
  737. typ: 9,
  738. },
  739. {
  740. id: "3085855b-d74b-474a-86c3-9bf3e4504382",
  741. hasRole: false,
  742. typ: 9,
  743. },
  744. {
  745. id: "38ef5d28-0f85-4fb0-8a94-dd20751c3364",
  746. hasRole: false,
  747. typ: 9,
  748. },
  749. }
  750. for i := 0; i < len(docs); i++ {
  751. doc := document.NewDocument(docs[i].id)
  752. doc.Fields = []document.Field{
  753. document.NewTextField("id", []uint64{}, []byte(docs[i].id)),
  754. document.NewBooleanField("hasRole", []uint64{}, docs[i].hasRole),
  755. document.NewNumericField("type", []uint64{}, float64(docs[i].typ)),
  756. }
  757. doc.CompositeFields = []*document.CompositeField{
  758. document.NewCompositeFieldWithIndexingOptions(
  759. "_all", true, []string{"text"}, []string{},
  760. document.IndexField|document.IncludeTermVectors),
  761. }
  762. if err = batch.IndexAdvanced(doc); err != nil {
  763. t.Fatal(err)
  764. }
  765. }
  766. if err = idx.Batch(batch); err != nil {
  767. t.Fatal(err)
  768. }
  769. batch = idx.NewBatch()
  770. // Update 1st doc
  771. doc = document.NewDocument("1-child-0")
  772. doc.Fields = []document.Field{
  773. document.NewTextField("id", []uint64{}, []byte("1-child-0")),
  774. document.NewBooleanField("hasRole", []uint64{}, false),
  775. document.NewNumericField("type", []uint64{}, 0),
  776. }
  777. doc.CompositeFields = []*document.CompositeField{
  778. document.NewCompositeFieldWithIndexingOptions(
  779. "_all", true, []string{"text"}, []string{},
  780. document.IndexField|document.IncludeTermVectors),
  781. }
  782. if err = batch.IndexAdvanced(doc); err != nil {
  783. t.Fatal(err)
  784. }
  785. if err = idx.Batch(batch); err != nil {
  786. t.Fatal(err)
  787. }
  788. inclusive := true
  789. val := float64(9)
  790. q := query.NewNumericRangeInclusiveQuery(&val, &val, &inclusive, &inclusive)
  791. q.SetField("type")
  792. initialQuery := query.NewBooleanQuery(nil, nil, []query.Query{q})
  793. // using must not, for cases that the field did not exists at all
  794. hasRole := NewBoolFieldQuery(true)
  795. hasRole.SetField("hasRole")
  796. noRole := NewBooleanQuery()
  797. noRole.AddMustNot(hasRole)
  798. rq := query.NewBooleanQuery([]query.Query{initialQuery, noRole}, nil, nil)
  799. sr := NewSearchRequestOptions(rq, 100, 0, false)
  800. sr.Fields = []string{"id", "hasRole", "type"}
  801. sr.Highlight = NewHighlight()
  802. res, err := idx.Search(sr)
  803. if err != nil {
  804. t.Fatal(err)
  805. }
  806. if res.Total != 1 {
  807. t.Fatalf("Unexpected result, %v != 1", res.Total)
  808. }
  809. }
  810. func testBooleanMustNotSearcher(t *testing.T, indexName string) {
  811. im := NewIndexMapping()
  812. idx, err := NewUsing("testidx", im, indexName, Config.DefaultKVStore, nil)
  813. if err != nil {
  814. t.Fatal(err)
  815. }
  816. defer func() {
  817. err = idx.Close()
  818. if err != nil {
  819. t.Fatal(err)
  820. }
  821. err := os.RemoveAll("testidx")
  822. if err != nil {
  823. t.Fatal(err)
  824. }
  825. }()
  826. docs := []struct {
  827. Name string
  828. HasRole bool
  829. }{
  830. {
  831. Name: "13900",
  832. },
  833. {
  834. Name: "13901",
  835. },
  836. {
  837. Name: "13965",
  838. },
  839. {
  840. Name: "13966",
  841. HasRole: true,
  842. },
  843. {
  844. Name: "13967",
  845. HasRole: true,
  846. },
  847. }
  848. for _, doc := range docs {
  849. err := idx.Index(doc.Name, doc)
  850. if err != nil {
  851. t.Fatal(err)
  852. }
  853. }
  854. lhs := NewDocIDQuery([]string{"13965", "13966", "13967"})
  855. hasRole := NewBoolFieldQuery(true)
  856. hasRole.SetField("HasRole")
  857. rhs := NewBooleanQuery()
  858. rhs.AddMustNot(hasRole)
  859. var compareLeftRightAndConjunction = func(idx Index, left, right query.Query) error {
  860. // left
  861. lr := NewSearchRequestOptions(left, 100, 0, false)
  862. lres, err := idx.Search(lr)
  863. if err != nil {
  864. return fmt.Errorf("error left: %v", err)
  865. }
  866. lresIds := map[string]struct{}{}
  867. for i := range lres.Hits {
  868. lresIds[lres.Hits[i].ID] = struct{}{}
  869. }
  870. // right
  871. rr := NewSearchRequestOptions(right, 100, 0, false)
  872. rres, err := idx.Search(rr)
  873. if err != nil {
  874. return fmt.Errorf("error right: %v", err)
  875. }
  876. rresIds := map[string]struct{}{}
  877. for i := range rres.Hits {
  878. rresIds[rres.Hits[i].ID] = struct{}{}
  879. }
  880. // conjunction
  881. cr := NewSearchRequestOptions(NewConjunctionQuery(left, right), 100, 0, false)
  882. cres, err := idx.Search(cr)
  883. if err != nil {
  884. return fmt.Errorf("error conjunction: %v", err)
  885. }
  886. for i := range cres.Hits {
  887. if _, ok := lresIds[cres.Hits[i].ID]; ok {
  888. if _, ok := rresIds[cres.Hits[i].ID]; !ok {
  889. return fmt.Errorf("error id %s missing from right", cres.Hits[i].ID)
  890. }
  891. } else {
  892. return fmt.Errorf("error id %s missing from left", cres.Hits[i].ID)
  893. }
  894. }
  895. return nil
  896. }
  897. err = compareLeftRightAndConjunction(idx, lhs, rhs)
  898. if err != nil {
  899. t.Fatal(err)
  900. }
  901. }
  902. func TestBooleanMustNotSearcherUpsidedown(t *testing.T) {
  903. testBooleanMustNotSearcher(t, upsidedown.Name)
  904. }
  905. func TestBooleanMustNotSearcherScorch(t *testing.T) {
  906. testBooleanMustNotSearcher(t, scorch.Name)
  907. }
  908. func TestQueryStringEmptyConjunctionSearcher(t *testing.T) {
  909. mapping := NewIndexMapping()
  910. mapping.DefaultAnalyzer = keyword.Name
  911. index, err := NewMemOnly(mapping)
  912. if err != nil {
  913. t.Fatal(err)
  914. }
  915. defer func() {
  916. _ = index.Close()
  917. }()
  918. query := NewQueryStringQuery("foo:bar +baz:\"\"")
  919. searchReq := NewSearchRequest(query)
  920. _, _ = index.Search(searchReq)
  921. }
  922. func TestDisjunctionQueryIncorrectMin(t *testing.T) {
  923. // create an index with default settings
  924. idxMapping := NewIndexMapping()
  925. idx, err := New("testidx", idxMapping)
  926. if err != nil {
  927. t.Fatal(err)
  928. }
  929. defer func() {
  930. err = idx.Close()
  931. if err != nil {
  932. t.Fatal(err)
  933. }
  934. err = os.RemoveAll("testidx")
  935. if err != nil {
  936. t.Fatal(err)
  937. }
  938. }()
  939. // create and insert documents as a batch
  940. batch := idx.NewBatch()
  941. docs := []struct {
  942. field1 string
  943. field2 int
  944. }{
  945. {
  946. field1: "one",
  947. field2: 1,
  948. },
  949. {
  950. field1: "two",
  951. field2: 2,
  952. },
  953. }
  954. for i := 0; i < len(docs); i++ {
  955. doc := document.NewDocument(strconv.Itoa(docs[i].field2))
  956. doc.Fields = []document.Field{
  957. document.NewTextField("field1", []uint64{}, []byte(docs[i].field1)),
  958. document.NewNumericField("field2", []uint64{}, float64(docs[i].field2)),
  959. }
  960. doc.CompositeFields = []*document.CompositeField{
  961. document.NewCompositeFieldWithIndexingOptions(
  962. "_all", true, []string{"text"}, []string{},
  963. document.IndexField|document.IncludeTermVectors),
  964. }
  965. if err = batch.IndexAdvanced(doc); err != nil {
  966. t.Fatal(err)
  967. }
  968. }
  969. if err = idx.Batch(batch); err != nil {
  970. t.Fatal(err)
  971. }
  972. tq := NewTermQuery("one")
  973. dq := NewDisjunctionQuery(tq)
  974. dq.SetMin(2)
  975. sr := NewSearchRequestOptions(dq, 1, 0, false)
  976. res, err := idx.Search(sr)
  977. if err != nil {
  978. t.Fatal(err)
  979. }
  980. if res.Total > 0 {
  981. t.Fatalf("Expected 0 matches as disjunction query contains a single clause"+
  982. " but got: %v", res.Total)
  983. }
  984. }
  985. func TestBooleanShouldMinPropagation(t *testing.T) {
  986. idx, err := New("testidx", NewIndexMapping())
  987. if err != nil {
  988. t.Fatal(err)
  989. }
  990. defer func() {
  991. err = idx.Close()
  992. if err != nil {
  993. t.Fatal(err)
  994. }
  995. err := os.RemoveAll("testidx")
  996. if err != nil {
  997. t.Fatal(err)
  998. }
  999. }()
  1000. doc1 := map[string]interface{}{
  1001. "dept": "queen",
  1002. "name": "cersei lannister",
  1003. }
  1004. doc2 := map[string]interface{}{
  1005. "dept": "kings guard",
  1006. "name": "jaime lannister",
  1007. }
  1008. batch := idx.NewBatch()
  1009. if err = batch.Index("doc1", doc1); err != nil {
  1010. t.Fatal(err)
  1011. }
  1012. if err = batch.Index("doc2", doc2); err != nil {
  1013. t.Fatal(err)
  1014. }
  1015. if err = idx.Batch(batch); err != nil {
  1016. t.Fatal(err)
  1017. }
  1018. // term dictionaries in the index for field..
  1019. // dept: queen kings guard
  1020. // name: cersei jaime lannister
  1021. // the following match query would match doc2
  1022. mq1 := NewMatchQuery("kings guard")
  1023. mq1.SetField("dept")
  1024. // the following match query would match both doc1 and doc2,
  1025. // as both docs share common lastname
  1026. mq2 := NewMatchQuery("jaime lannister")
  1027. mq2.SetField("name")
  1028. bq := NewBooleanQuery()
  1029. bq.AddShould(mq1)
  1030. bq.AddMust(mq2)
  1031. sr := NewSearchRequest(bq)
  1032. res, err := idx.Search(sr)
  1033. if err != nil {
  1034. t.Fatal(err)
  1035. }
  1036. if res.Total != 2 {
  1037. t.Errorf("Expected 2 results, but got: %v", res.Total)
  1038. }
  1039. }
  1040. func TestDisjunctionMinPropagation(t *testing.T) {
  1041. idx, err := New("testidx", NewIndexMapping())
  1042. if err != nil {
  1043. t.Fatal(err)
  1044. }
  1045. defer func() {
  1046. err = idx.Close()
  1047. if err != nil {
  1048. t.Fatal(err)
  1049. }
  1050. err := os.RemoveAll("testidx")
  1051. if err != nil {
  1052. t.Fatal(err)
  1053. }
  1054. }()
  1055. doc1 := map[string]interface{}{
  1056. "dept": "finance",
  1057. "name": "xyz",
  1058. }
  1059. doc2 := map[string]interface{}{
  1060. "dept": "marketing",
  1061. "name": "xyz",
  1062. }
  1063. doc3 := map[string]interface{}{
  1064. "dept": "engineering",
  1065. "name": "abc",
  1066. }
  1067. batch := idx.NewBatch()
  1068. if err = batch.Index("doc1", doc1); err != nil {
  1069. t.Fatal(err)
  1070. }
  1071. if err = batch.Index("doc2", doc2); err != nil {
  1072. t.Fatal(err)
  1073. }
  1074. if err = batch.Index("doc3", doc3); err != nil {
  1075. t.Fatal(err)
  1076. }
  1077. if err = idx.Batch(batch); err != nil {
  1078. t.Fatal(err)
  1079. }
  1080. mq1 := NewMatchQuery("finance")
  1081. mq2 := NewMatchQuery("marketing")
  1082. dq := NewDisjunctionQuery(mq1, mq2)
  1083. dq.SetMin(3)
  1084. dq2 := NewDisjunctionQuery(dq)
  1085. dq2.SetMin(1)
  1086. sr := NewSearchRequest(dq2)
  1087. res, err := idx.Search(sr)
  1088. if err != nil {
  1089. t.Fatal(err)
  1090. }
  1091. if res.Total != 0 {
  1092. t.Fatalf("Expect 0 results, but got: %v", res.Total)
  1093. }
  1094. }
  1095. func TestDuplicateLocationsIssue1168(t *testing.T) {
  1096. fm1 := NewTextFieldMapping()
  1097. fm1.Analyzer = keyword.Name
  1098. fm1.Name = "name1"
  1099. dm := NewDocumentStaticMapping()
  1100. dm.AddFieldMappingsAt("name", fm1)
  1101. m := NewIndexMapping()
  1102. m.DefaultMapping = dm
  1103. idx, err := NewMemOnly(m)
  1104. if err != nil {
  1105. t.Fatalf("bleve new err: %v", err)
  1106. }
  1107. err = idx.Index("x", map[string]interface{}{
  1108. "name": "marty",
  1109. })
  1110. if err != nil {
  1111. t.Fatalf("bleve index err: %v", err)
  1112. }
  1113. q1 := NewTermQuery("marty")
  1114. q2 := NewTermQuery("marty")
  1115. dq := NewDisjunctionQuery(q1, q2)
  1116. sreq := NewSearchRequest(dq)
  1117. sreq.Fields = []string{"*"}
  1118. sreq.Highlight = NewHighlightWithStyle(html.Name)
  1119. sres, err := idx.Search(sreq)
  1120. if err != nil {
  1121. t.Fatalf("bleve search err: %v", err)
  1122. }
  1123. if len(sres.Hits[0].Locations["name1"]["marty"]) != 1 {
  1124. t.Fatalf("duplicate marty")
  1125. }
  1126. }
  1127. func TestBooleanMustSingleMatchNone(t *testing.T) {
  1128. idxMapping := NewIndexMapping()
  1129. if err := idxMapping.AddCustomTokenFilter(length.Name, map[string]interface{}{
  1130. "min": 3.0,
  1131. "max": 5.0,
  1132. "type": length.Name,
  1133. }); err != nil {
  1134. t.Fatal(err)
  1135. }
  1136. if err := idxMapping.AddCustomAnalyzer("custom1", map[string]interface{}{
  1137. "type": "custom",
  1138. "tokenizer": "single",
  1139. "token_filters": []interface{}{length.Name},
  1140. }); err != nil {
  1141. t.Fatal(err)
  1142. }
  1143. idxMapping.DefaultAnalyzer = "custom1"
  1144. idx, err := New("testidx", idxMapping)
  1145. if err != nil {
  1146. t.Fatal(err)
  1147. }
  1148. defer func() {
  1149. err = idx.Close()
  1150. if err != nil {
  1151. t.Fatal(err)
  1152. }
  1153. err = os.RemoveAll("testidx")
  1154. if err != nil {
  1155. t.Fatal(err)
  1156. }
  1157. }()
  1158. doc := map[string]interface{}{
  1159. "languages_known": "Dutch",
  1160. "dept": "Sales",
  1161. }
  1162. batch := idx.NewBatch()
  1163. if err = batch.Index("doc", doc); err != nil {
  1164. t.Fatal(err)
  1165. }
  1166. if err = idx.Batch(batch); err != nil {
  1167. t.Fatal(err)
  1168. }
  1169. // this is a successful match
  1170. matchSales := NewMatchQuery("Sales")
  1171. matchSales.SetField("dept")
  1172. // this would spin off a MatchNoneSearcher as the
  1173. // token filter rules out the word "French"
  1174. matchFrench := NewMatchQuery("French")
  1175. matchFrench.SetField("languages_known")
  1176. bq := NewBooleanQuery()
  1177. bq.AddShould(matchSales)
  1178. bq.AddMust(matchFrench)
  1179. sr := NewSearchRequest(bq)
  1180. res, err := idx.Search(sr)
  1181. if err != nil {
  1182. t.Fatal(err)
  1183. }
  1184. if res.Total != 0 {
  1185. t.Fatalf("Expected 0 results but got: %v", res.Total)
  1186. }
  1187. }
  1188. func TestBooleanMustNotSingleMatchNone(t *testing.T) {
  1189. idxMapping := NewIndexMapping()
  1190. if err := idxMapping.AddCustomTokenFilter(shingle.Name, map[string]interface{}{
  1191. "min": 3.0,
  1192. "max": 5.0,
  1193. "type": shingle.Name,
  1194. }); err != nil {
  1195. t.Fatal(err)
  1196. }
  1197. if err := idxMapping.AddCustomAnalyzer("custom1", map[string]interface{}{
  1198. "type": "custom",
  1199. "tokenizer": "unicode",
  1200. "token_filters": []interface{}{shingle.Name},
  1201. }); err != nil {
  1202. t.Fatal(err)
  1203. }
  1204. idxMapping.DefaultAnalyzer = "custom1"
  1205. idx, err := New("testidx", idxMapping)
  1206. if err != nil {
  1207. t.Fatal(err)
  1208. }
  1209. defer func() {
  1210. err = idx.Close()
  1211. if err != nil {
  1212. t.Fatal(err)
  1213. }
  1214. err = os.RemoveAll("testidx")
  1215. if err != nil {
  1216. t.Fatal(err)
  1217. }
  1218. }()
  1219. doc := map[string]interface{}{
  1220. "languages_known": "Dutch",
  1221. "dept": "Sales",
  1222. }
  1223. batch := idx.NewBatch()
  1224. if err = batch.Index("doc", doc); err != nil {
  1225. t.Fatal(err)
  1226. }
  1227. if err = idx.Batch(batch); err != nil {
  1228. t.Fatal(err)
  1229. }
  1230. // this is a successful match
  1231. matchSales := NewMatchQuery("Sales")
  1232. matchSales.SetField("dept")
  1233. // this would spin off a MatchNoneSearcher as the
  1234. // token filter rules out the word "Dutch"
  1235. matchDutch := NewMatchQuery("Dutch")
  1236. matchDutch.SetField("languages_known")
  1237. matchEngineering := NewMatchQuery("Engineering")
  1238. matchEngineering.SetField("dept")
  1239. bq := NewBooleanQuery()
  1240. bq.AddShould(matchSales)
  1241. bq.AddMustNot(matchDutch, matchEngineering)
  1242. sr := NewSearchRequest(bq)
  1243. res, err := idx.Search(sr)
  1244. if err != nil {
  1245. t.Fatal(err)
  1246. }
  1247. if res.Total != 0 {
  1248. t.Fatalf("Expected 0 results but got: %v", res.Total)
  1249. }
  1250. }
  1251. func TestBooleanSearchBug1185(t *testing.T) {
  1252. defer func() {
  1253. err := os.RemoveAll("testidx")
  1254. if err != nil {
  1255. t.Fatal(err)
  1256. }
  1257. }()
  1258. of := NewTextFieldMapping()
  1259. of.Analyzer = keyword.Name
  1260. of.Name = "owner"
  1261. dm := NewDocumentMapping()
  1262. dm.AddFieldMappingsAt("owner", of)
  1263. m := NewIndexMapping()
  1264. m.DefaultMapping = dm
  1265. idx, err := NewUsing("testidx", m, "scorch", "scorch", nil)
  1266. if err != nil {
  1267. t.Fatal(err)
  1268. }
  1269. defer func() {
  1270. err := idx.Close()
  1271. if err != nil {
  1272. t.Fatal(err)
  1273. }
  1274. }()
  1275. err = idx.Index("17112", map[string]interface{}{
  1276. "owner": "marty",
  1277. "type": "A Demo Type",
  1278. })
  1279. if err != nil {
  1280. t.Fatal(err)
  1281. }
  1282. err = idx.Index("17139", map[string]interface{}{
  1283. "type": "A Demo Type",
  1284. })
  1285. if err != nil {
  1286. t.Fatal(err)
  1287. }
  1288. err = idx.Index("177777", map[string]interface{}{
  1289. "type": "x",
  1290. })
  1291. if err != nil {
  1292. t.Fatal(err)
  1293. }
  1294. err = idx.Index("177778", map[string]interface{}{
  1295. "type": "A Demo Type",
  1296. })
  1297. if err != nil {
  1298. t.Fatal(err)
  1299. }
  1300. err = idx.Index("17140", map[string]interface{}{
  1301. "type": "A Demo Type",
  1302. })
  1303. if err != nil {
  1304. t.Fatal(err)
  1305. }
  1306. err = idx.Index("17000", map[string]interface{}{
  1307. "owner": "marty",
  1308. "type": "x",
  1309. })
  1310. if err != nil {
  1311. t.Fatal(err)
  1312. }
  1313. err = idx.Index("17141", map[string]interface{}{
  1314. "type": "A Demo Type",
  1315. })
  1316. if err != nil {
  1317. t.Fatal(err)
  1318. }
  1319. err = idx.Index("17428", map[string]interface{}{
  1320. "owner": "marty",
  1321. "type": "A Demo Type",
  1322. })
  1323. if err != nil {
  1324. t.Fatal(err)
  1325. }
  1326. err = idx.Index("17113", map[string]interface{}{
  1327. "owner": "marty",
  1328. "type": "x",
  1329. })
  1330. if err != nil {
  1331. t.Fatal(err)
  1332. }
  1333. matchTypeQ := NewMatchPhraseQuery("A Demo Type")
  1334. matchTypeQ.SetField("type")
  1335. matchAnyOwnerRegQ := NewRegexpQuery(".+")
  1336. matchAnyOwnerRegQ.SetField("owner")
  1337. matchNoOwner := NewBooleanQuery()
  1338. matchNoOwner.AddMustNot(matchAnyOwnerRegQ)
  1339. notNoOwner := NewBooleanQuery()
  1340. notNoOwner.AddMustNot(matchNoOwner)
  1341. matchTypeAndNoOwner := NewConjunctionQuery()
  1342. matchTypeAndNoOwner.AddQuery(matchTypeQ)
  1343. matchTypeAndNoOwner.AddQuery(notNoOwner)
  1344. req := NewSearchRequest(matchTypeAndNoOwner)
  1345. res, err := idx.Search(req)
  1346. if err != nil {
  1347. t.Fatal(err)
  1348. }
  1349. // query 2
  1350. matchTypeAndNoOwnerBoolean := NewBooleanQuery()
  1351. matchTypeAndNoOwnerBoolean.AddMust(matchTypeQ)
  1352. matchTypeAndNoOwnerBoolean.AddMustNot(matchNoOwner)
  1353. req2 := NewSearchRequest(matchTypeAndNoOwnerBoolean)
  1354. res2, err := idx.Search(req2)
  1355. if err != nil {
  1356. t.Fatal(err)
  1357. }
  1358. if len(res.Hits) != len(res2.Hits) {
  1359. t.Fatalf("expected same number of hits, got: %d and %d", len(res.Hits), len(res2.Hits))
  1360. }
  1361. }
  1362. func TestSearchScoreNone(t *testing.T) {
  1363. idx, err := NewUsing("testidx", NewIndexMapping(), scorch.Name, Config.DefaultKVStore, nil)
  1364. if err != nil {
  1365. t.Fatal(err)
  1366. }
  1367. defer func() {
  1368. err := os.RemoveAll("testidx")
  1369. if err != nil {
  1370. t.Fatal(err)
  1371. }
  1372. }()
  1373. doc := map[string]interface{}{
  1374. "field1": "asd fgh jkl",
  1375. "field2": "more content blah blah",
  1376. "id": "doc",
  1377. }
  1378. if err = idx.Index("doc", doc); err != nil {
  1379. t.Fatal(err)
  1380. }
  1381. q := NewQueryStringQuery("content")
  1382. sr := NewSearchRequest(q)
  1383. sr.IncludeLocations = true
  1384. sr.Score = "none"
  1385. res, err := idx.Search(sr)
  1386. if err != nil {
  1387. t.Fatal(err)
  1388. }
  1389. if len(res.Hits) != 1 {
  1390. t.Fatal("unexpected number of hits")
  1391. }
  1392. if len(res.Hits[0].Locations) != 1 {
  1393. t.Fatal("unexpected locations for the hit")
  1394. }
  1395. if res.Hits[0].Score != 0 {
  1396. t.Fatal("unexpected score for the hit")
  1397. }
  1398. }