From 7ad2bb14a8463c52ef5a168e79764704171ce19b Mon Sep 17 00:00:00 2001 From: CascadingRadium Date: Fri, 15 Nov 2024 18:50:54 +0530 Subject: [PATCH] unit test --- mapping/index.go | 8 ++ mapping/synonym.go | 7 ++ search_test.go | 181 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) diff --git a/mapping/index.go b/mapping/index.go index d6d355b11..ae17a3da5 100644 --- a/mapping/index.go +++ b/mapping/index.go @@ -146,6 +146,14 @@ func (im *IndexMappingImpl) AddCustomDateTimeParser(name string, config map[stri return nil } +func (im *IndexMappingImpl) AddSynonymSource(name, collection, analyzer string) error { + if im.SynonymSources == nil { + im.SynonymSources = make(map[string]*SynonymSource) + } + im.SynonymSources[name] = NewSynonymSource(collection, analyzer) + return nil +} + // NewIndexMapping creates a new IndexMapping that will use all the default indexing rules func NewIndexMapping() *IndexMappingImpl { return &IndexMappingImpl{ diff --git a/mapping/synonym.go b/mapping/synonym.go index 5065b3b2a..597539bf0 100644 --- a/mapping/synonym.go +++ b/mapping/synonym.go @@ -25,6 +25,13 @@ type SynonymSource struct { AnalyzerName string `json:"analyzer"` } +func NewSynonymSource(collection, analyzer string) *SynonymSource { + return &SynonymSource{ + CollectionName: collection, + AnalyzerName: analyzer, + } +} + func (s *SynonymSource) Collection() string { return s.CollectionName } diff --git a/search_test.go b/search_test.go index 3d14c9254..3235bbc6c 100644 --- a/search_test.go +++ b/search_test.go @@ -15,10 +15,12 @@ package bleve import ( + "context" "encoding/json" "fmt" "math" "reflect" + "sort" "strconv" "strings" "testing" @@ -3562,5 +3564,184 @@ func TestScoreBreakdown(t *testing.T) { } } } +} + +func TestSynonymSearch(t *testing.T) { + tmpIndexPath := createTmpIndexPath(t) + defer cleanupTmpIndexPath(t, tmpIndexPath) + + synonymCollection := "collection1" + + synonymSourceName := "english" + + synonymAnalyzer := "simple" + + imap := mapping.NewIndexMapping() + textField := mapping.NewTextFieldMapping() + textField.Analyzer = simple.Name + imap.DefaultMapping.AddFieldMappingsAt("text", textField) + imap.AddSynonymSource(synonymSourceName, synonymCollection, synonymAnalyzer) + + err := imap.Validate() + if err != nil { + t.Fatal(err) + } + + idx, err := New(tmpIndexPath, imap) + if err != nil { + t.Fatal(err) + } + defer func() { + err = idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + documents := map[string]map[string]interface{}{ + "doc1": { + "text": "quick brown fox eats", + }, + "doc2": { + "text": "fast red wolf jumps", + }, + "doc3": { + "text": "quick red cat runs", + }, + "doc4": { + "text": "speedy brown dog barks", + }, + "doc5": { + "text": "fast green rabbit hops", + }, + } + + batch := idx.NewBatch() + for docID, doc := range documents { + err := batch.Index(docID, doc) + if err != nil { + t.Fatal(err) + } + } + + synonymDocuments := map[string]*SynonymDefinition{ + "synDoc1": { + Synonyms: []string{"quick", "fast", "speedy"}, + }, + "synDoc2": { + Input: []string{"color", "colour"}, + Synonyms: []string{"red", "green", "blue", "yellow", "brown"}, + }, + "synDoc3": { + Input: []string{"animal", "creature"}, + Synonyms: []string{"fox", "wolf", "cat", "dog", "rabbit"}, + }, + "synDoc4": { + Synonyms: []string{"eats", "jumps", "runs", "barks", "hops"}, + }, + } + + for synName, synDef := range synonymDocuments { + err := batch.IndexSynonym(synName, "collection1", synDef) + if err != nil { + t.Fatal(err) + } + } + err = idx.Batch(batch) + if err != nil { + t.Fatal(err) + } + sco, err := idx.Advanced() + if err != nil { + t.Fatal(err) + } + + reader, err := sco.Reader() + if err != nil { + t.Fatal(err) + } + defer func() { + err = reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + synReader, ok := reader.(index.ThesaurusReader) + if !ok { + t.Fatal("expected thesaurus reader") + } + + type testStruct struct { + queryTerm string + expectedSynonyms []string + } + + testQueries := []testStruct{ + { + queryTerm: "quick", + expectedSynonyms: []string{"fast", "speedy"}, + }, + { + queryTerm: "red", + expectedSynonyms: []string{}, + }, + { + queryTerm: "color", + expectedSynonyms: []string{"red", "green", "blue", "yellow", "brown"}, + }, + { + queryTerm: "colour", + expectedSynonyms: []string{"red", "green", "blue", "yellow", "brown"}, + }, + { + queryTerm: "animal", + expectedSynonyms: []string{"fox", "wolf", "cat", "dog", "rabbit"}, + }, + { + queryTerm: "creature", + expectedSynonyms: []string{"fox", "wolf", "cat", "dog", "rabbit"}, + }, + { + queryTerm: "fox", + expectedSynonyms: []string{}, + }, + { + queryTerm: "eats", + expectedSynonyms: []string{"jumps", "runs", "barks", "hops"}, + }, + { + queryTerm: "jumps", + expectedSynonyms: []string{"eats", "runs", "barks", "hops"}, + }, + } + + for _, test := range testQueries { + str, err := synReader.SynonymTermReader(context.Background(), synonymSourceName, []byte(test.queryTerm)) + if err != nil { + t.Fatal(err) + } + var gotSynonyms []string + for { + synonym, err := str.Next() + if err != nil { + t.Fatal(err) + } + if synonym == "" { + break + } + gotSynonyms = append(gotSynonyms, string(synonym)) + } + if len(gotSynonyms) != len(test.expectedSynonyms) { + t.Fatalf("expected %d synonyms, got %d", len(test.expectedSynonyms), len(gotSynonyms)) + } + sort.Strings(gotSynonyms) + sort.Strings(test.expectedSynonyms) + for i, syn := range gotSynonyms { + if syn != test.expectedSynonyms[i] { + t.Fatalf("expected synonym %s, got %s", test.expectedSynonyms[i], syn) + } + } + } }