Example #1
0
func (pages *Pages) QueryMatchPhrase(field string, phrase string) *Pages {
	q := bleve.NewMatchPhraseQuery(phrase)
	q.SetField(field)
	pages.queries = append(pages.queries, q)
	pages.clear()
	return pages
}
Example #2
0
func TestQuerySyntaxParserValid(t *testing.T) {
	fivePointOh := 5.0
	onePointOh := 1.0
	theTruth := true
	theFalsehood := false

	jan_01_2015 := numeric_util.Int64ToFloat64(time.Date(2015, time.January, 01, 0, 0, 0, 0, time.UTC).UnixNano())
	jan_02_2015 := numeric_util.Int64ToFloat64(time.Date(2015, time.January, 02, 0, 0, 0, 0, time.UTC).UnixNano())
	mar_15_2015 := numeric_util.Int64ToFloat64(time.Date(2015, time.March, 15, 0, 0, 0, 0, time.UTC).UnixNano())
	mar_16_2015 := numeric_util.Int64ToFloat64(time.Date(2015, time.March, 16, 0, 0, 0, 0, time.UTC).UnixNano())

	tests := []struct {
		input   string
		result  bleve.Query
		mapping *bleve.IndexMapping
	}{
		{
			input:   "test",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("test"),
		},
		{
			input:   `"test phrase 1"`,
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("test phrase 1"),
		},
		{
			input:   "field:test",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("test").SetField("field"),
		},
		// - is allowed inside a term, just not the start
		{
			input:   "field:t-est",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("t-est").SetField("field"),
		},
		// + is allowed inside a term, just not the start
		{
			input:   "field:t+est",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("t+est").SetField("field"),
		},
		// > is allowed inside a term, just not the start
		{
			input:   "field:t>est",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("t>est").SetField("field"),
		},
		// < is allowed inside a term, just not the start
		{
			input:   "field:t<est",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("t<est").SetField("field"),
		},
		// = is allowed inside a term, just not the start
		{
			input:   "field:t=est",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("t=est").SetField("field"),
		},
		{
			input:   "+field1:test1",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("test1").SetField("field1"),
		},
		{
			input:   "-field2:test2",
			mapping: NewIndexMapping(),
			result: bleve.NewBooleanQuery(
				nil,
				nil,
				[]bleve.Query{
					bleve.NewMatchPhraseQuery("test2").SetField("field2"),
				}),
		},
		{
			input:   `field3:"test phrase 2"`,
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("test phrase 2").SetField("field3"),
		},
		{
			input:   `+field4:"test phrase 1"`,
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("test phrase 1").SetField("field4"),
		},
		{
			input:   `-field5:"test phrase 2"`,
			mapping: NewIndexMapping(),
			result: bleve.NewBooleanQuery(
				nil,
				nil,
				[]bleve.Query{
					bleve.NewMatchPhraseQuery("test phrase 2").SetField("field5"),
				}),
		},
		{
			input:   `+field6:test3 -field7:test4 field8:test5`,
			mapping: NewIndexMapping(),
			result: bleve.NewBooleanQuery(
				[]bleve.Query{
					bleve.NewMatchPhraseQuery("test3").SetField("field6"),
				},
				[]bleve.Query{
					bleve.NewMatchPhraseQuery("test5").SetField("field8"),
				},
				[]bleve.Query{
					bleve.NewMatchPhraseQuery("test4").SetField("field7"),
				}),
		},
		{
			input:   "test^3",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("test").SetBoost(3.0),
		},
		{
			input:   "test^3 other^6",
			mapping: NewIndexMapping(),
			result: bleve.NewBooleanQuery(
				nil,
				[]bleve.Query{
					bleve.NewMatchPhraseQuery("test").SetBoost(3.0),
					bleve.NewMatchPhraseQuery("other").SetBoost(6.0),
				},
				nil,
			),
		},
		{
			input:   "33",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("33"),
		},
		{
			input:   "field:33",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("33").SetField("field"),
		},
		{
			input:   "cat-dog",
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("cat-dog"),
		},
		/*
			        // TODO: MatchPhraseQuery doesn't handle fuzziness...
					{
						input:   "watex~",
						mapping: NewIndexMapping(),
						result:  bleve.NewMatchPhraseQuery("watex").SetFuzziness(1),
					},

				{
					input:   "watex~2",
					mapping: NewIndexMapping(),
					result: bleve.NewBooleanQuery(
						nil,
						[]bleve.Query{
							bleve.NewMatchQuery("watex").SetFuzziness(2),
						},
						nil),
				},
				{
					input:   "watex~ 2",
					mapping: NewIndexMapping(),
					result: bleve.NewBooleanQuery(
						nil,
						[]bleve.Query{
							bleve.NewMatchQuery("watex").SetFuzziness(1),
							bleve.NewMatchQuery("2"),
						},
						nil),
				},
				{
					input:   "field:watex~",
					mapping: NewIndexMapping(),
					result: bleve.NewBooleanQuery(
						nil,
						[]bleve.Query{
							bleve.NewMatchQuery("watex").SetFuzziness(1).SetField("field"),
						},
						nil),
				},
				{
					input:   "field:watex~2",
					mapping: NewIndexMapping(),
					result: bleve.NewBooleanQuery(
						nil,
						[]bleve.Query{
							bleve.NewMatchQuery("watex").SetFuzziness(2).SetField("field"),
						},
						nil),
				},
		*/
		{
			input:   `field:555c3bb06f7a127cda000005`,
			mapping: NewIndexMapping(),
			result:  bleve.NewMatchPhraseQuery("555c3bb06f7a127cda000005").SetField("field"),
		},
		{
			input:   `field:>5`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&fivePointOh, nil, &theFalsehood, nil).SetField("field"),
		},
		{
			input:   `field:>=5`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&fivePointOh, nil, &theTruth, nil).SetField("field"),
		},
		{
			input:   `field:<5`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(nil, &fivePointOh, nil, &theFalsehood).SetField("field"),
		},
		{
			input:   `field:<=5`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(nil, &fivePointOh, nil, &theTruth).SetField("field"),
		},
		{
			input:   `grapefruit AND lemon`,
			mapping: NewIndexMapping(),
			result: bleve.NewConjunctionQuery([]bleve.Query{
				bleve.NewMatchPhraseQuery("grapefruit"),
				bleve.NewMatchPhraseQuery("lemon"),
			}),
		},
		{
			input:   `grapefruit OR lemon`,
			mapping: NewIndexMapping(),
			result: bleve.NewDisjunctionQuery([]bleve.Query{
				bleve.NewMatchPhraseQuery("grapefruit"),
				bleve.NewMatchPhraseQuery("lemon"),
			}),
		},
		{
			// default operator is OR
			input:   `grapefruit lemon`,
			mapping: NewIndexMapping(),
			result: bleve.NewBooleanQuery(
				nil,
				[]bleve.Query{
					bleve.NewMatchPhraseQuery("grapefruit"),
					bleve.NewMatchPhraseQuery("lemon"),
				},
				nil,
			),
		},
		{
			input:   `grapefruit AND NOT lemon`,
			mapping: NewIndexMapping(),
			result: bleve.NewConjunctionQuery([]bleve.Query{
				bleve.NewMatchPhraseQuery("grapefruit"),
				bleve.NewBooleanQuery(nil, nil, []bleve.Query{bleve.NewMatchPhraseQuery("lemon")}),
			}),
		},
		{
			input:   `field:(grapefruit AND lemon)`,
			mapping: NewIndexMapping(),
			result: bleve.NewConjunctionQuery([]bleve.Query{
				bleve.NewMatchPhraseQuery("grapefruit").SetField("field"),
				bleve.NewMatchPhraseQuery("lemon").SetField("field"),
			}),
		},
		{
			input:   `-field:(grapefruit AND lemon)`,
			mapping: NewIndexMapping(),
			result: bleve.NewBooleanQuery(nil, nil, []bleve.Query{
				bleve.NewConjunctionQuery([]bleve.Query{
					bleve.NewMatchPhraseQuery("grapefruit").SetField("field"),
					bleve.NewMatchPhraseQuery("lemon").SetField("field"),
				}),
			}),
		},
		{
			input:   `shoesize:[1 TO 5]`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&onePointOh, &fivePointOh, &theTruth, &theTruth).SetField("shoesize"),
		},
		{
			input:   `shoesize:{1 TO 5}`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&onePointOh, &fivePointOh, &theFalsehood, &theFalsehood).SetField("shoesize"),
		},
		{
			input:   `shoesize:[1 TO 5}`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&onePointOh, &fivePointOh, &theTruth, &theFalsehood).SetField("shoesize"),
		},
		{
			input:   `shoesize:{1 TO 5]`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&onePointOh, &fivePointOh, &theFalsehood, &theTruth).SetField("shoesize"),
		},
		{
			input:   `shoesize:[ TO 5]`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(nil, &fivePointOh, nil, &theTruth).SetField("shoesize"),
		},
		{
			input:   `shoesize:[1 TO ]`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&onePointOh, nil, &theTruth, nil).SetField("shoesize"),
		},
		// date ranges (note that endpoints and inclusivity might be modified by the parser)
		{
			input:   `when:[2015-01-01 TO 2015-03-15]`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&jan_01_2015, &mar_16_2015, &theTruth, &theFalsehood).SetField("when"),
		},
		{
			input:   `when:{2015-01-01 TO 2015-03-15]`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&jan_02_2015, &mar_16_2015, &theTruth, &theFalsehood).SetField("when"),
		},
		{
			input:   `when:[2015-01-01 TO 2015-03-15}`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&jan_01_2015, &mar_15_2015, &theTruth, &theFalsehood).SetField("when"),
		},
		{
			input:   `when:>2015-03-15`,
			mapping: NewIndexMapping(),
			result:  bleve.NewNumericRangeInclusiveQuery(&mar_16_2015, nil, &theTruth, nil).SetField("when"),
		},
	}

	for _, test := range tests {

		q, err := Parse(test.input)
		if err != nil {
			t.Error(err)
		}
		if !reflect.DeepEqual(q, test.result) {
			t.Errorf("Expected %#v, got %#v: for `%s`", test.result, q, test.input)
			//			t.Errorf("Expected %#v, got %#v: for %s", test.result.(*booleanQuery).Should.(*disjunctionQuery).Disjuncts[0], q.(*booleanQuery).Should.(*disjunctionQuery).Disjuncts[0], test.input)
		}
	}
}
Example #3
0
func resultsHandler(w http.ResponseWriter, r *http.Request) {
	var (
		pageHTML    = "results-search.html"
		pageInclude = "results-search.include"
	)

	urlQuery := r.URL.Query()
	err := r.ParseForm()
	if err != nil {
		responseLogger(r, http.StatusBadRequest, err)
		w.Header().Set("Content-Type", "text/plain")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(fmt.Sprintf("error in POST: %s", err)))
		return
	}

	// Collect the submissions fields.
	submission := make(map[string]interface{})
	// Basic Search results
	if r.Method == "GET" {
		for k, v := range urlQuery {
			if k == "all_ids" {
				if b, err := strconv.ParseBool(strings.Join(v, "")); err == nil {
					submission[k] = b
				}
			} else if k == "from" || k == "size" || k == "total" {
				if i, err := strconv.Atoi(strings.Join(v, "")); err == nil {
					submission[k] = i
				}
			} else if k == "q" || k == "q_exact" || k == "q_excluded" || k == "q_required" {
				submission[k] = strings.Join(v, "")
			}
		}
	}

	// Advanced Search results
	if r.Method == "POST" {
		for k, v := range r.Form {
			if k == "all_ids" {
				if b, err := strconv.ParseBool(strings.Join(v, "")); err == nil {
					submission[k] = b
				}
			} else if k == "from" || k == "size" || k == "total" {
				if i, err := strconv.Atoi(strings.Join(v, "")); err == nil {
					submission[k] = i
				}
			} else if k == "q" || k == "q_exact" || k == "q_excluded" || k == "q_required" {
				submission[k] = strings.Join(v, "")
			}
		}
	}

	q, err := mapToSearchQuery(submission)
	if err != nil {
		responseLogger(r, http.StatusBadRequest, err)
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(fmt.Sprintf("%s", err)))
		return
	}

	//
	// Note: Add logic to handle basic and advanced search...
	//
	// q           NewQueryStringQuery
	// q_required  NewQueryStringQuery with a + prefix for each strings.Fields(q_required) value
	// q_exact     NewMatchPhraseQuery
	// q_excluded NewQueryStringQuery with a - prefix for each strings.Feilds(q_excluded) value
	//
	var conQry []bleve.Query

	if q.Q != "" {
		conQry = append(conQry, bleve.NewQueryStringQuery(q.Q))
	}
	if q.QExact != "" {
		conQry = append(conQry, bleve.NewMatchPhraseQuery(q.QExact))
	}
	var terms []string
	for _, s := range strings.Fields(q.QRequired) {
		terms = append(terms, fmt.Sprintf("+%s", strings.TrimSpace(s)))
	}
	for _, s := range strings.Fields(q.QExcluded) {
		terms = append(terms, fmt.Sprintf("-%s", strings.TrimSpace(s)))
	}
	if len(terms) > 0 {
		qString := strings.Join(terms, " ")
		conQry = append(conQry, bleve.NewQueryStringQuery(qString))
	}

	qry := bleve.NewConjunctionQuery(conQry)
	if q.Size == 0 {
		q.Size = 10
	}
	searchRequest := bleve.NewSearchRequestOptions(qry, q.Size, q.From, q.Explain)
	if searchRequest == nil {
		responseLogger(r, http.StatusBadRequest, fmt.Errorf("Can't build new search request options %+v, %s", qry, err))
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(fmt.Sprintf("%s", err)))
		return
	}

	searchRequest.Highlight = bleve.NewHighlight()
	searchRequest.Highlight.AddField("title")
	searchRequest.Highlight.AddField("content_description")
	searchRequest.Highlight.AddField("subjects")
	searchRequest.Highlight.AddField("subjects_function")
	searchRequest.Highlight.AddField("subjects_topical")
	searchRequest.Highlight.AddField("extents")

	subjectFacet := bleve.NewFacetRequest("subjects", 3)
	searchRequest.AddFacet("subjects", subjectFacet)

	subjectTopicalFacet := bleve.NewFacetRequest("subjects_topical", 3)
	searchRequest.AddFacet("subjects_topical", subjectTopicalFacet)

	subjectFunctionFacet := bleve.NewFacetRequest("subjects_function", 3)
	searchRequest.AddFacet("subjects_function", subjectFunctionFacet)

	// Return all fields
	searchRequest.Fields = []string{
		"title",
		"identifier",
		"content_description",
		"content_condition",
		"resource_type",
		"access_restrictions",
		"access_restrictions_note",
		"use_restrictins",
		"use_restrictons_note",
		"dates",
		"date_expression",
		"extents",
		"subjects",
		"subjects_function",
		"subjects_topical",
		"linked_agents_creators",
		"linked_agents_subjects",
		"link_agents_sources",
		"digital_objects.title",
		"digital_objects.file_uris",
		"related_resources",
		"deaccessions",
		"accession_date",
		"created",
	}

	searchResults, err := index.Search(searchRequest)
	if err != nil {
		responseLogger(r, http.StatusInternalServerError, fmt.Errorf("Bleve results error %v, %s", qry, err))
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(fmt.Sprintf("%s", err)))
		return
	}

	// q (ciat.SearchQuery) performs double duty as both the structure for query submission as well
	// as carring the results to support paging and other types of navigation through
	// the query set. Results are a query with the bleve.SearchReults merged
	q.AttachSearchResults(searchResults)
	pageHTML = "results-search.html"
	pageInclude = "results-search.include"

	// Load my templates and setup to execute them
	tmpl, err := tmplfn.Assemble(tmplFuncs, path.Join(templatesDir, pageHTML), path.Join(templatesDir, pageInclude))
	if err != nil {
		responseLogger(r, http.StatusInternalServerError, fmt.Errorf("Template Errors: %s, %s, %s\n", pageHTML, pageInclude, err))
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(fmt.Sprintf("Template errors: %s", err)))
		return
	}
	// Render the page
	w.Header().Set("Content-Type", "text/html")
	var buf bytes.Buffer
	err = tmpl.Execute(&buf, q)
	//err = tmpl.Execute(w, q)
	if err != nil {
		responseLogger(r, http.StatusInternalServerError, fmt.Errorf("Can't render %s, %s/%s, %s", templatesDir, pageHTML, pageInclude, err))
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Template error"))
		return
	}
	//NOTE: This bit of ugliness is here because I need to allow <mark> elements and ellipis in the results fragments
	w.Write(bytes.Replace(bytes.Replace(bytes.Replace(buf.Bytes(), []byte("&lt;mark&gt;"), []byte("<mark>"), -1), []byte("&lt;/mark&gt;"), []byte("</mark>"), -1), []byte(`…`), []byte(`&hellip;`), -1))
}
Example #4
0
func TestBeerSearchAll(t *testing.T) {
	defer os.RemoveAll("beer-search-test.bleve")

	mapping, err := buildIndexMapping()
	if err != nil {
		t.Fatal(err)
	}
	index, err := bleve.New("beer-search-test.bleve", mapping)
	if err != nil {
		t.Fatal(err)
	}
	defer index.Close()

	for jf := range walkDirectory("data/", t) {
		docId := jf.filename[0:strings.LastIndex(jf.filename, ".")]
		err = index.Index(docId, jf.contents)
		if err != nil {
			t.Error(err)
		}
	}

	expectedCount := uint64(7303)
	actualCount := index.DocCount()
	if actualCount != expectedCount {
		t.Errorf("expected %d documents, got %d", expectedCount, actualCount)
	}

	// run a term search
	termQuery := bleve.NewTermQuery("shock").SetField("name")
	termSearchRequest := bleve.NewSearchRequest(termQuery)
	termSearchResult, err := index.Search(termSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount := uint64(1)
	if termSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, termSearchResult.Total)
	} else {
		expectedResultId := "anheuser_busch-shock_top"
		if termSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, termSearchResult.Hits[0].ID)
		}
	}

	// run a match phrase search
	matchPhraseQuery := bleve.NewMatchPhraseQuery("spicy mexican food")
	matchPhraseSearchRequest := bleve.NewSearchRequest(matchPhraseQuery)
	matchPhraseSearchResult, err := index.Search(matchPhraseSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(1)
	if matchPhraseSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, matchPhraseSearchResult.Total)
	} else {
		expectedResultId := "great_divide_brewing-wild_raspberry_ale"
		if matchPhraseSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, matchPhraseSearchResult.Hits[0].ID)
		}
	}

	// run a syntax query
	syntaxQuery := bleve.NewQueryStringQuery("+name:light +description:water -description:barley")
	syntaxSearchRequest := bleve.NewSearchRequest(syntaxQuery)
	syntaxSearchResult, err := index.Search(syntaxSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(1)
	if syntaxSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, syntaxSearchResult.Total)
	} else {
		expectedResultId := "iron_city_brewing_co-ic_light"
		if syntaxSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, syntaxSearchResult.Hits[0].ID)
		}
	}

	// run a numeric range search
	queryMin := 50.0
	numericRangeQuery := bleve.NewNumericRangeQuery(&queryMin, nil).SetField("abv")
	numericSearchRequest := bleve.NewSearchRequest(numericRangeQuery)
	numericSearchResult, err := index.Search(numericSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(1)
	if numericSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, numericSearchResult.Total)
	} else {
		expectedResultId := "woodforde_s_norfolk_ales-norfolk_nog_old_dark_ale"
		if numericSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, numericSearchResult.Hits[0].ID)
		}
	}

	// run a date range search
	queryStartDate := "2011-10-04"
	dateRangeQuery := bleve.NewDateRangeQuery(&queryStartDate, nil).SetField("updated")
	dateSearchRequest := bleve.NewSearchRequest(dateRangeQuery)
	dateSearchResult, err := index.Search(dateSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(2)
	if dateSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, dateSearchResult.Total)
	} else {
		expectedResultId := "brasserie_du_bouffay-ambr"
		if dateSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, dateSearchResult.Hits[0].ID)
		}
	}

	// run a prefix search
	prefixQuery := bleve.NewPrefixQuery("adir").SetField("name")
	prefixSearchRequest := bleve.NewSearchRequest(prefixQuery)
	prefixSearchResult, err := index.Search(prefixSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(1)
	if prefixSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, prefixSearchResult.Total)
	} else {
		expectedResultId := "f_x_matt_brewing-saranac_adirondack_lager"
		if prefixSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, prefixSearchResult.Hits[0].ID)
		}
	}
}
Example #5
0
func TestBeerSearchAll(t *testing.T) {
	defer os.RemoveAll("beer-search-test.bleve")

	mapping, err := buildIndexMapping()
	if err != nil {
		t.Fatal(err)
	}
	index, err := bleve.New("beer-search-test.bleve", mapping)
	if err != nil {
		t.Fatal(err)
	}
	defer index.Close()

	// open the directory
	dirEntries, err := ioutil.ReadDir("data/")
	if err != nil {
		t.Fatal(err)
	}

	indexBatchSize := 100
	batch := index.NewBatch()
	batchCount := 0
	for _, dirEntry := range dirEntries {
		filename := dirEntry.Name()
		// read the bytes
		jsonBytes, err := ioutil.ReadFile("data/" + filename)
		if err != nil {
			t.Fatal(err)
		}
		// // shred them into a document
		ext := filepath.Ext(filename)
		docId := filename[:(len(filename) - len(ext))]
		batch.Index(docId, jsonBytes)
		batchCount++

		if batchCount >= indexBatchSize {
			err = index.Batch(batch)
			if err != nil {
				t.Fatal(err)
			}
			batch = index.NewBatch()
			batchCount = 0
		}
	}
	// flush the last batch
	if batchCount > 0 {
		err = index.Batch(batch)
		if err != nil {
			t.Fatal(err)
		}
	}

	expectedCount := uint64(7303)
	actualCount, err := index.DocCount()
	if err != nil {
		t.Error(err)
	}
	if actualCount != expectedCount {
		t.Errorf("expected %d documents, got %d", expectedCount, actualCount)
	}

	// run a term search
	termQuery := bleve.NewTermQuery("shock").SetField("name")
	termSearchRequest := bleve.NewSearchRequest(termQuery)
	termSearchResult, err := index.Search(termSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount := uint64(1)
	if termSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, termSearchResult.Total)
	} else {
		expectedResultId := "anheuser_busch-shock_top"
		if termSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, termSearchResult.Hits[0].ID)
		}
	}

	// run a match phrase search
	matchPhraseQuery := bleve.NewMatchPhraseQuery("spicy mexican food")
	matchPhraseSearchRequest := bleve.NewSearchRequest(matchPhraseQuery)
	matchPhraseSearchResult, err := index.Search(matchPhraseSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(1)
	if matchPhraseSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, matchPhraseSearchResult.Total)
	} else {
		expectedResultId := "great_divide_brewing-wild_raspberry_ale"
		if matchPhraseSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, matchPhraseSearchResult.Hits[0].ID)
		}
	}

	// run a syntax query
	syntaxQuery := bleve.NewQueryStringQuery("+name:light +description:water -description:barley")
	syntaxSearchRequest := bleve.NewSearchRequest(syntaxQuery)
	syntaxSearchResult, err := index.Search(syntaxSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(1)
	if syntaxSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, syntaxSearchResult.Total)
	} else {
		expectedResultId := "iron_city_brewing_co-ic_light"
		if syntaxSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, syntaxSearchResult.Hits[0].ID)
		}
	}

	// run a numeric range search
	queryMin := 50.0
	numericRangeQuery := bleve.NewNumericRangeQuery(&queryMin, nil).SetField("abv")
	numericSearchRequest := bleve.NewSearchRequest(numericRangeQuery)
	numericSearchResult, err := index.Search(numericSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(1)
	if numericSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, numericSearchResult.Total)
	} else {
		expectedResultId := "woodforde_s_norfolk_ales-norfolk_nog_old_dark_ale"
		if numericSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, numericSearchResult.Hits[0].ID)
		}
	}

	// run a date range search
	queryStartDate := "2011-10-04"
	dateRangeQuery := bleve.NewDateRangeQuery(&queryStartDate, nil).SetField("updated")
	dateSearchRequest := bleve.NewSearchRequest(dateRangeQuery)
	dateSearchResult, err := index.Search(dateSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(2)
	if dateSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, dateSearchResult.Total)
	} else {
		expectedResultId := "brasserie_du_bouffay-ambr"
		if dateSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, dateSearchResult.Hits[0].ID)
		}
	}

	// run a prefix search
	prefixQuery := bleve.NewPrefixQuery("adir").SetField("name")
	prefixSearchRequest := bleve.NewSearchRequest(prefixQuery)
	prefixSearchResult, err := index.Search(prefixSearchRequest)
	if err != nil {
		t.Error(err)
	}
	expectedResultCount = uint64(1)
	if prefixSearchResult.Total != expectedResultCount {
		t.Errorf("expected %d hits, got %d", expectedResultCount, prefixSearchResult.Total)
	} else {
		expectedResultId := "f_x_matt_brewing-saranac_adirondack_lager"
		if prefixSearchResult.Hits[0].ID != expectedResultId {
			t.Errorf("expected top hit ID: %s, got %s", expectedResultId, prefixSearchResult.Hits[0].ID)
		}
	}
}
Example #6
0
//   part = lit {"~" number} | range | "(" exprList ")"
func (p *Parser) parsePart(ctx context) (query.Query, error) {

	tok := p.next()

	//   lit
	if tok.typ == tLITERAL {
		var q query.Query
		if strings.ContainsAny(tok.val, "*?") {
			q = bleve.NewWildcardQuery(tok.val)
		} else {
			if p.peek().typ == tFUZZY {
				fuzziness, err := p.parseFuzzySuffix()
				if err != nil {
					return nil, err
				}
				fuzz := bleve.NewFuzzyQuery(tok.val)
				fuzz.SetFuzziness(fuzziness)
				q = fuzz
			} else {
				q = bleve.NewMatchPhraseQuery(tok.val)
			}
		}
		if ctx.field != "" {
			if fieldable, ok := q.(query.FieldableQuery); ok {
				fieldable.SetField(ctx.field)
			} else {
				return nil, ParseError{ctx.fieldPos, "unexpected field"}
			}
		}
		return q, nil
	}
	if tok.typ == tQUOTED {
		// strip quotes (ugh)
		txt := string(tok.val[1 : len(tok.val)-1])
		/*
			if strings.ContainsAny(txt, "*?") {
				return nil, ParseError{tok.pos, "wildcards not supported in phrases"}
			}
		*/
		q := bleve.NewMatchPhraseQuery(txt)
		if ctx.field != "" {
			q.SetField(ctx.field)
		}
		return q, nil
	}

	//   | "(" exprList ")"
	if tok.typ == tLPAREN {
		q, err := p.parseExprList(ctx)
		if err != nil {
			return nil, err
		}
		tok = p.next()
		if tok.typ != tRPAREN {
			return nil, ParseError{tok.pos, "missing )"}
		}
		return q, nil
	}

	//   | range
	if tok.typ == tLSQUARE || tok.typ == tLBRACE {
		p.backup()
		q, err := p.parseRange(ctx)
		if err != nil {
			return nil, err
		}
		return q, nil
	}

	//   | relational
	if tok.typ == tGREATER || tok.typ == tLESS {
		p.backup()
		q, err := p.parseRelational(ctx)
		if err != nil {
			return nil, err
		}
		return q, nil
	}

	if tok.typ == tERROR {
		return nil, ParseError{tok.pos, tok.val}
	}

	return nil, ParseError{tok.pos, fmt.Sprintf("unexpected %s", tok.val)}
}
Example #7
0
File: parse.go Project: deoxxa/qs
//   part = lit | range | "(" exprList ")"
func (p *Parser) parsePart(ctx context) (bleve.Query, error) {

	tok := p.next()

	//   lit
	if tok.typ == tLITERAL {
		q := bleve.NewMatchPhraseQuery(tok.val)
		if ctx.field != "" {
			q.SetField(ctx.field)
		}
		return q, nil
	}
	if tok.typ == tQUOTED {
		// strip quotes (ugh)
		txt := string(tok.val[1 : len(tok.val)-1])
		q := bleve.NewMatchPhraseQuery(txt)
		if ctx.field != "" {
			q.SetField(ctx.field)
		}
		return q, nil
	}

	//   | "(" exprList ")"
	if tok.typ == tLPAREN {
		q, err := p.parseExprList(ctx)
		if err != nil {
			return nil, err
		}
		tok = p.next()
		if tok.typ != tRPAREN {
			return nil, ParseError{tok.pos, "missing )"}
		}
		return q, nil
	}

	//   | range
	if tok.typ == tLSQUARE || tok.typ == tLBRACE {
		p.backup()
		q, err := p.parseRange(ctx)
		if err != nil {
			return nil, err
		}
		return q, nil
	}

	//   | relational
	if tok.typ == tGREATER || tok.typ == tLESS {
		p.backup()
		q, err := p.parseRelational(ctx)
		if err != nil {
			return nil, err
		}
		return q, nil
	}

	if tok.typ == tERROR {
		return nil, ParseError{tok.pos, tok.val}
	}

	return nil, ParseError{tok.pos, fmt.Sprintf("unexpected %s", tok.val)}
}