feat: improve search relevance by boosting keyword matches
Alan Pearce alan@alanpearce.eu
Wed, 29 May 2024 11:56:51 +0200
2 files changed, 46 insertions(+), 4 deletions(-)
M internal/index/indexer.go → internal/index/indexer.go
@@ -101,7 +101,7 @@ locFieldMapping.Store = false optionMapping := bleve.NewDocumentStaticMapping() - optionMapping.AddFieldMappingsAt("Name", keywordFieldMapping) + optionMapping.AddFieldMappingsAt("Name", nameMapping) optionMapping.AddFieldMappingsAt("Source", keywordFieldMapping) optionMapping.AddFieldMappingsAt("Loc", locFieldMapping) optionMapping.AddFieldMappingsAt("RelatedPackages", textFieldMapping) @@ -112,6 +112,7 @@ optionMapping.AddSubDocumentMapping("Example", nixValueMapping) packageMapping := bleve.NewDocumentStaticMapping() + packageMapping.AddFieldMappingsAt("Name", nameMapping) packageMapping.AddFieldMappingsAt("Attribute", keywordFieldMapping) packageMapping.AddFieldMappingsAt("Source", keywordFieldMapping) packageMapping.AddFieldMappingsAt("Description", textFieldMapping)
M internal/index/search.go → internal/index/search.go
@@ -8,7 +8,9 @@ "searchix/internal/config" "searchix/internal/nix" "github.com/blevesearch/bleve/v2" + "github.com/blevesearch/bleve/v2/analysis/analyzer/standard" "github.com/blevesearch/bleve/v2/search" + "github.com/blevesearch/bleve/v2/search/query" "github.com/pkg/errors" ) @@ -71,18 +73,57 @@ return result, nil } +func setField( + q query.FieldableQuery, + field string, +) query.FieldableQuery { + q.SetField(field) + + return q +} + func (index *ReadIndex) Search( ctx context.Context, source *config.Source, keyword string, from uint64, ) (*Result, error) { - sourceQuery := bleve.NewTermQuery(source.Key) - sourceQuery.SetField("Source") + query := bleve.NewBooleanQuery() + + // match the user's query in any field ... userQuery := bleve.NewMatchQuery(keyword) userQuery.Analyzer = "option_name" - query := bleve.NewConjunctionQuery(sourceQuery, userQuery) + query.AddMust( + setField(bleve.NewTermQuery(source.Key), "Source"), + userQuery, + ) + + switch source.Importer { + case config.Packages: + // ...and boost it if it matches any of these + query.AddShould( + setField(bleve.NewMatchQuery(keyword), "MainProgram"), + setField(bleve.NewMatchQuery(keyword), "Name"), + setField(bleve.NewMatchQuery(keyword), "Attribute"), + ) + case config.Options: + query.AddShould( + setField(bleve.NewMatchQuery(keyword), "Loc"), + setField(bleve.NewMatchQuery(keyword), "Name"), + ) + nameLiteralQuery := bleve.NewMatchQuery(keyword) + nameLiteralQuery.SetField("Name") + nameLiteralQuery.Analyzer = standard.Name + query.AddShould( + nameLiteralQuery, + ) + default: + return nil, errors.Errorf( + "unsupported source type for search: %s", + source.Importer.String(), + ) + } search := bleve.NewSearchRequest(query) search.Size = ResultsPerPage