From f8a77bc42f8043ae09035292f3d302eed1346a71 Mon Sep 17 00:00:00 2001 From: LaurentiuNiculae Date: Wed, 22 Mar 2023 19:31:53 +0200 Subject: [PATCH] feat(search): update search pattern matching rules (#1257) Signed-off-by: Laurentiu Niculae --- pkg/api/controller_test.go | 2 - pkg/extensions/search/common/common_test.go | 12 +- pkg/extensions/search/common/model.go | 2 - pkg/extensions/search/common/oci_layout.go | 3 - pkg/extensions/search/convert/repodb.go | 4 - .../search/gql_generated/generated.go | 193 ------------------ .../search/gql_generated/models_gen.go | 6 - pkg/extensions/search/schema.graphql | 12 -- pkg/extensions/search/search.md | 1 - .../repodb/boltdb-wrapper/boltdb_wrapper.go | 4 +- pkg/meta/repodb/common.go | 4 +- pkg/meta/repodb/common/common.go | 73 +++++-- .../repodb/dynamodb-wrapper/dynamo_wrapper.go | 4 +- pkg/meta/repodb/repodb_test.go | 27 ++- 14 files changed, 83 insertions(+), 264 deletions(-) diff --git a/pkg/api/controller_test.go b/pkg/api/controller_test.go index a3a0a9ce..55f94e2a 100644 --- a/pkg/api/controller_test.go +++ b/pkg/api/controller_test.go @@ -6674,7 +6674,6 @@ func TestSearchRoutes(t *testing.T) { GlobalSearch(query:"testrepo"){ Repos { Name - Score NewestImage { RepoName Tag @@ -6808,7 +6807,6 @@ func TestSearchRoutes(t *testing.T) { GlobalSearch(query:"testrepo"){ Repos { Name - Score NewestImage { RepoName Tag diff --git a/pkg/extensions/search/common/common_test.go b/pkg/extensions/search/common/common_test.go index b732e36f..5e39486d 100644 --- a/pkg/extensions/search/common/common_test.go +++ b/pkg/extensions/search/common/common_test.go @@ -3150,7 +3150,7 @@ func TestGlobalSearchImageAuthor(t *testing.T) { Repos { Name LastUpdated Size Platforms { Os Arch } - Vendors Score + Vendors NewestImage { RepoName Tag LastUpdated Size IsSigned Authors @@ -3213,7 +3213,7 @@ func TestGlobalSearchImageAuthor(t *testing.T) { Repos { Name LastUpdated Size Platforms { Os Arch } - Vendors Score + Vendors NewestImage { RepoName Tag LastUpdated Size IsSigned Authors @@ -3427,7 +3427,7 @@ func TestGlobalSearch(t *testing.T) { Repos { Name LastUpdated Size Platforms { Os Arch } - Vendors Score + Vendors NewestImage { RepoName Tag LastUpdated Size Manifests{ @@ -3516,7 +3516,7 @@ func TestGlobalSearch(t *testing.T) { Repos { Name LastUpdated Size Platforms { Os Arch } - Vendors Score + Vendors NewestImage { RepoName Tag LastUpdated Size Manifests { @@ -3753,7 +3753,7 @@ func TestGlobalSearch(t *testing.T) { Repos { Name LastUpdated Size Platforms { Os Arch } - Vendors Score + Vendors NewestImage { RepoName Tag LastUpdated Size Manifests { @@ -3843,7 +3843,7 @@ func TestGlobalSearch(t *testing.T) { Repos { Name LastUpdated Size Platforms { Os Arch } - Vendors Score + Vendors NewestImage { RepoName Tag LastUpdated Size Manifests { diff --git a/pkg/extensions/search/common/model.go b/pkg/extensions/search/common/model.go index 38ed750f..320dd100 100644 --- a/pkg/extensions/search/common/model.go +++ b/pkg/extensions/search/common/model.go @@ -15,7 +15,6 @@ type RepoSummary struct { Size string `json:"size"` Platforms []Platform `json:"platforms"` Vendors []string `json:"vendors"` - Score int `json:"score"` NewestImage ImageSummary `json:"newestImage"` } @@ -33,7 +32,6 @@ type ImageSummary struct { Licenses string `json:"licenses"` Labels string `json:"labels"` Title string `json:"title"` - Score int `json:"score"` Source string `json:"source"` Documentation string `json:"documentation"` Authors string `json:"authors"` diff --git a/pkg/extensions/search/common/oci_layout.go b/pkg/extensions/search/common/oci_layout.go index fdf9f995..6671426e 100644 --- a/pkg/extensions/search/common/oci_layout.go +++ b/pkg/extensions/search/common/oci_layout.go @@ -482,7 +482,6 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er manifestDigest := man.Digest.String() configDigest := manifest.Config.Digest.String() lastUpdated := GetImageLastUpdated(imageConfigInfo) - score := 0 imageSummary := ImageSummary{ RepoName: repoName, @@ -501,7 +500,6 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er LastUpdated: lastUpdated, IsSigned: isSigned, Size: size, - Score: score, Description: annotations.Description, Title: annotations.Title, Documentation: annotations.Documentation, @@ -546,7 +544,6 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er Platforms: repoPlatforms, NewestImage: lastUpdatedImageSummary, Vendors: repoVendors, - Score: -1, } repo.Summary = summary diff --git a/pkg/extensions/search/convert/repodb.go b/pkg/extensions/search/convert/repodb.go index c7742c87..b6fcba0b 100644 --- a/pkg/extensions/search/convert/repodb.go +++ b/pkg/extensions/search/convert/repodb.go @@ -86,7 +86,6 @@ func RepoMeta2RepoSummary(ctx context.Context, repoMeta repodb.RepoMetadata, } repoSize := strconv.FormatInt(size, 10) - score := 0 repoPlatforms := make([]*gql_generated.Platform, 0, len(repoPlatformsSet)) for _, platform := range repoPlatformsSet { @@ -127,7 +126,6 @@ func RepoMeta2RepoSummary(ctx context.Context, repoMeta repodb.RepoMetadata, Size: &repoSize, Platforms: repoPlatforms, Vendors: repoVendors, - Score: &score, NewestImage: lastUpdatedImageSummary, DownloadCount: &repoDownloadCount, StarCount: &repoStarCount, @@ -632,7 +630,6 @@ func RepoMeta2ExpandedRepoInfo(ctx context.Context, repoMeta repodb.RepoMetadata } repoSize := strconv.FormatInt(size, 10) - score := 0 repoPlatforms := make([]*gql_generated.Platform, 0, len(repoPlatformsSet)) for _, platform := range repoPlatformsSet { @@ -672,7 +669,6 @@ func RepoMeta2ExpandedRepoInfo(ctx context.Context, repoMeta repodb.RepoMetadata Size: &repoSize, Platforms: repoPlatforms, Vendors: repoVendors, - Score: &score, NewestImage: lastUpdatedImageSummary, DownloadCount: &repoDownloadCount, StarCount: &repoStarCount, diff --git a/pkg/extensions/search/gql_generated/generated.go b/pkg/extensions/search/gql_generated/generated.go index c91c34f3..f2f54f40 100644 --- a/pkg/extensions/search/gql_generated/generated.go +++ b/pkg/extensions/search/gql_generated/generated.go @@ -90,7 +90,6 @@ type ComplexityRoot struct { MediaType func(childComplexity int) int Referrers func(childComplexity int) int RepoName func(childComplexity int) int - Score func(childComplexity int) int Size func(childComplexity int) int Source func(childComplexity int) int Tag func(childComplexity int) int @@ -111,7 +110,6 @@ type ComplexityRoot struct { LayerSummary struct { Digest func(childComplexity int) int - Score func(childComplexity int) int Size func(childComplexity int) int } @@ -191,7 +189,6 @@ type ComplexityRoot struct { Name func(childComplexity int) int NewestImage func(childComplexity int) int Platforms func(childComplexity int) int - Score func(childComplexity int) int Size func(childComplexity int) int StarCount func(childComplexity int) int Vendors func(childComplexity int) int @@ -452,13 +449,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ImageSummary.RepoName(childComplexity), true - case "ImageSummary.Score": - if e.complexity.ImageSummary.Score == nil { - break - } - - return e.complexity.ImageSummary.Score(childComplexity), true - case "ImageSummary.Size": if e.complexity.ImageSummary.Size == nil { break @@ -536,13 +526,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.LayerSummary.Digest(childComplexity), true - case "LayerSummary.Score": - if e.complexity.LayerSummary.Score == nil { - break - } - - return e.complexity.LayerSummary.Score(childComplexity), true - case "LayerSummary.Size": if e.complexity.LayerSummary.Size == nil { break @@ -946,13 +929,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.RepoSummary.Platforms(childComplexity), true - case "RepoSummary.Score": - if e.complexity.RepoSummary.Score == nil { - break - } - - return e.complexity.RepoSummary.Score(childComplexity), true - case "RepoSummary.Size": if e.complexity.RepoSummary.Size == nil { break @@ -1200,10 +1176,6 @@ type ImageSummary { """ Title: String """ - Integer used to rank search results by relevance - """ - Score: Int - """ URL to get source code for building the image """ Source: String @@ -1318,10 +1290,6 @@ type RepoSummary { """ Vendors: [String] """ - Integer used to rank search results by relevance - """ - Score: Int - """ Details of the newest image inside the repository NOTE: not the image with the ` + "`" + `latest` + "`" + ` tag, the one with the most recent created timestamp """ @@ -1356,10 +1324,6 @@ type LayerSummary { Digest of the layer content """ Digest: String - """ - Integer used to rank search results by relevance - """ - Score: Int } """ @@ -2645,8 +2609,6 @@ func (ec *executionContext) fieldContext_GlobalSearchResult_Images(ctx context.C return ec.fieldContext_ImageSummary_Labels(ctx, field) case "Title": return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) case "Source": return ec.fieldContext_ImageSummary_Source(ctx, field) case "Documentation": @@ -2712,8 +2674,6 @@ func (ec *executionContext) fieldContext_GlobalSearchResult_Repos(ctx context.Co return ec.fieldContext_RepoSummary_Platforms(ctx, field) case "Vendors": return ec.fieldContext_RepoSummary_Vendors(ctx, field) - case "Score": - return ec.fieldContext_RepoSummary_Score(ctx, field) case "NewestImage": return ec.fieldContext_RepoSummary_NewestImage(ctx, field) case "DownloadCount": @@ -2771,8 +2731,6 @@ func (ec *executionContext) fieldContext_GlobalSearchResult_Layers(ctx context.C return ec.fieldContext_LayerSummary_Size(ctx, field) case "Digest": return ec.fieldContext_LayerSummary_Digest(ctx, field) - case "Score": - return ec.fieldContext_LayerSummary_Score(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type LayerSummary", field.Name) }, @@ -3542,47 +3500,6 @@ func (ec *executionContext) fieldContext_ImageSummary_Title(ctx context.Context, return fc, nil } -func (ec *executionContext) _ImageSummary_Score(ctx context.Context, field graphql.CollectedField, obj *ImageSummary) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_ImageSummary_Score(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Score, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*int) - fc.Result = res - return ec.marshalOInt2ᚖint(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_ImageSummary_Score(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "ImageSummary", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _ImageSummary_Source(ctx context.Context, field graphql.CollectedField, obj *ImageSummary) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ImageSummary_Source(ctx, field) if err != nil { @@ -3969,8 +3886,6 @@ func (ec *executionContext) fieldContext_LayerHistory_Layer(ctx context.Context, return ec.fieldContext_LayerSummary_Size(ctx, field) case "Digest": return ec.fieldContext_LayerSummary_Digest(ctx, field) - case "Score": - return ec.fieldContext_LayerSummary_Score(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type LayerSummary", field.Name) }, @@ -4113,47 +4028,6 @@ func (ec *executionContext) fieldContext_LayerSummary_Digest(ctx context.Context return fc, nil } -func (ec *executionContext) _LayerSummary_Score(ctx context.Context, field graphql.CollectedField, obj *LayerSummary) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_LayerSummary_Score(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Score, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*int) - fc.Result = res - return ec.marshalOInt2ᚖint(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_LayerSummary_Score(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "LayerSummary", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _ManifestSummary_Digest(ctx context.Context, field graphql.CollectedField, obj *ManifestSummary) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ManifestSummary_Digest(ctx, field) if err != nil { @@ -4487,8 +4361,6 @@ func (ec *executionContext) fieldContext_ManifestSummary_Layers(ctx context.Cont return ec.fieldContext_LayerSummary_Size(ctx, field) case "Digest": return ec.fieldContext_LayerSummary_Digest(ctx, field) - case "Score": - return ec.fieldContext_LayerSummary_Score(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type LayerSummary", field.Name) }, @@ -4966,8 +4838,6 @@ func (ec *executionContext) fieldContext_PaginatedImagesResult_Results(ctx conte return ec.fieldContext_ImageSummary_Labels(ctx, field) case "Title": return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) case "Source": return ec.fieldContext_ImageSummary_Source(ctx, field) case "Documentation": @@ -5083,8 +4953,6 @@ func (ec *executionContext) fieldContext_PaginatedReposResult_Results(ctx contex return ec.fieldContext_RepoSummary_Platforms(ctx, field) case "Vendors": return ec.fieldContext_RepoSummary_Vendors(ctx, field) - case "Score": - return ec.fieldContext_RepoSummary_Score(ctx, field) case "NewestImage": return ec.fieldContext_RepoSummary_NewestImage(ctx, field) case "DownloadCount": @@ -5854,8 +5722,6 @@ func (ec *executionContext) fieldContext_Query_Image(ctx context.Context, field return ec.fieldContext_ImageSummary_Labels(ctx, field) case "Title": return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) case "Source": return ec.fieldContext_ImageSummary_Source(ctx, field) case "Documentation": @@ -6355,8 +6221,6 @@ func (ec *executionContext) fieldContext_RepoInfo_Images(ctx context.Context, fi return ec.fieldContext_ImageSummary_Labels(ctx, field) case "Title": return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) case "Source": return ec.fieldContext_ImageSummary_Source(ctx, field) case "Documentation": @@ -6422,8 +6286,6 @@ func (ec *executionContext) fieldContext_RepoInfo_Summary(ctx context.Context, f return ec.fieldContext_RepoSummary_Platforms(ctx, field) case "Vendors": return ec.fieldContext_RepoSummary_Vendors(ctx, field) - case "Score": - return ec.fieldContext_RepoSummary_Score(ctx, field) case "NewestImage": return ec.fieldContext_RepoSummary_NewestImage(ctx, field) case "DownloadCount": @@ -6652,47 +6514,6 @@ func (ec *executionContext) fieldContext_RepoSummary_Vendors(ctx context.Context return fc, nil } -func (ec *executionContext) _RepoSummary_Score(ctx context.Context, field graphql.CollectedField, obj *RepoSummary) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_RepoSummary_Score(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Score, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*int) - fc.Result = res - return ec.marshalOInt2ᚖint(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_RepoSummary_Score(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "RepoSummary", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _RepoSummary_NewestImage(ctx context.Context, field graphql.CollectedField, obj *RepoSummary) (ret graphql.Marshaler) { fc, err := ec.fieldContext_RepoSummary_NewestImage(ctx, field) if err != nil { @@ -6755,8 +6576,6 @@ func (ec *executionContext) fieldContext_RepoSummary_NewestImage(ctx context.Con return ec.fieldContext_ImageSummary_Labels(ctx, field) case "Title": return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) case "Source": return ec.fieldContext_ImageSummary_Source(ctx, field) case "Documentation": @@ -9052,10 +8871,6 @@ func (ec *executionContext) _ImageSummary(ctx context.Context, sel ast.Selection out.Values[i] = ec._ImageSummary_Title(ctx, field, obj) - case "Score": - - out.Values[i] = ec._ImageSummary_Score(ctx, field, obj) - case "Source": out.Values[i] = ec._ImageSummary_Source(ctx, field, obj) @@ -9167,10 +8982,6 @@ func (ec *executionContext) _LayerSummary(ctx context.Context, sel ast.Selection out.Values[i] = ec._LayerSummary_Digest(ctx, field, obj) - case "Score": - - out.Values[i] = ec._LayerSummary_Score(ctx, field, obj) - default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -9789,10 +9600,6 @@ func (ec *executionContext) _RepoSummary(ctx context.Context, sel ast.SelectionS out.Values[i] = ec._RepoSummary_Vendors(ctx, field, obj) - case "Score": - - out.Values[i] = ec._RepoSummary_Score(ctx, field, obj) - case "NewestImage": out.Values[i] = ec._RepoSummary_NewestImage(ctx, field, obj) diff --git a/pkg/extensions/search/gql_generated/models_gen.go b/pkg/extensions/search/gql_generated/models_gen.go index 02f9b829..a9d842c2 100644 --- a/pkg/extensions/search/gql_generated/models_gen.go +++ b/pkg/extensions/search/gql_generated/models_gen.go @@ -114,8 +114,6 @@ type ImageSummary struct { Labels *string `json:"Labels"` // Human-readable title of the image Title *string `json:"Title"` - // Integer used to rank search results by relevance - Score *int `json:"Score"` // URL to get source code for building the image Source *string `json:"Source"` // URL to get documentation on the image @@ -152,8 +150,6 @@ type LayerSummary struct { Size *string `json:"Size"` // Digest of the layer content Digest *string `json:"Digest"` - // Integer used to rank search results by relevance - Score *int `json:"Score"` } // Details about a specific version of an image for a certain operating system and architecture. @@ -276,8 +272,6 @@ type RepoSummary struct { Platforms []*Platform `json:"Platforms"` // Vendors associated with this image, the distributing entities, organizations or individuals Vendors []*string `json:"Vendors"` - // Integer used to rank search results by relevance - Score *int `json:"Score"` // Details of the newest image inside the repository // NOTE: not the image with the `latest` tag, the one with the most recent created timestamp NewestImage *ImageSummary `json:"NewestImage"` diff --git a/pkg/extensions/search/schema.graphql b/pkg/extensions/search/schema.graphql index 6d61a0ea..1212f930 100644 --- a/pkg/extensions/search/schema.graphql +++ b/pkg/extensions/search/schema.graphql @@ -169,10 +169,6 @@ type ImageSummary { """ Title: String """ - Integer used to rank search results by relevance - """ - Score: Int - """ URL to get source code for building the image """ Source: String @@ -287,10 +283,6 @@ type RepoSummary { """ Vendors: [String] """ - Integer used to rank search results by relevance - """ - Score: Int - """ Details of the newest image inside the repository NOTE: not the image with the `latest` tag, the one with the most recent created timestamp """ @@ -325,10 +317,6 @@ type LayerSummary { Digest of the layer content """ Digest: String - """ - Integer used to rank search results by relevance - """ - Score: Int } """ diff --git a/pkg/extensions/search/search.md b/pkg/extensions/search/search.md index 587ec9cd..e6656f5a 100644 --- a/pkg/extensions/search/search.md +++ b/pkg/extensions/search/search.md @@ -101,7 +101,6 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList Arch } Vendor - Score DownloadCount Licenses Title diff --git a/pkg/meta/repodb/boltdb-wrapper/boltdb_wrapper.go b/pkg/meta/repodb/boltdb-wrapper/boltdb_wrapper.go index fdc007f3..60ad5d6c 100644 --- a/pkg/meta/repodb/boltdb-wrapper/boltdb_wrapper.go +++ b/pkg/meta/repodb/boltdb-wrapper/boltdb_wrapper.go @@ -897,7 +897,7 @@ func (bdw *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter return err } - if score := common.ScoreRepoName(searchText, string(repoName)); score != -1 { + if rank := common.RankRepoName(searchText, string(repoName)); rank != -1 { var ( // specific values used for sorting that need to be calculated based on all manifests from the repo repoDownloads = 0 @@ -1006,7 +1006,7 @@ func (bdw *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter pageFinder.Add(repodb.DetailedRepoMeta{ RepoMeta: repoMeta, - Score: score, + Rank: rank, Downloads: repoDownloads, UpdateTime: repoLastUpdated, }) diff --git a/pkg/meta/repodb/common.go b/pkg/meta/repodb/common.go index 43748208..db81896a 100644 --- a/pkg/meta/repodb/common.go +++ b/pkg/meta/repodb/common.go @@ -9,7 +9,7 @@ import ( // by iterating the manifests, etc.) type DetailedRepoMeta struct { RepoMeta RepoMetadata - Score int + Rank int Downloads int UpdateTime time.Time } @@ -38,7 +38,7 @@ func SortByAlphabeticDsc(pageBuffer []DetailedRepoMeta) func(i, j int) bool { func SortByRelevance(pageBuffer []DetailedRepoMeta) func(i, j int) bool { return func(i, j int) bool { - return pageBuffer[i].Score < pageBuffer[j].Score + return pageBuffer[i].Rank < pageBuffer[j].Rank } } diff --git a/pkg/meta/repodb/common/common.go b/pkg/meta/repodb/common/common.go index f0caa44a..4f07a06b 100644 --- a/pkg/meta/repodb/common/common.go +++ b/pkg/meta/repodb/common/common.go @@ -62,7 +62,21 @@ func ValidateRepoReferenceInput(repo, reference string, manifestDigest godigest. return nil } -func ScoreRepoName(searchText string, repoName string) int { +// These constants are meant used to describe how high or low in rank a match is. +// Note that the "higher rank" relates to a lower number so ranks are sorted in a +// ascending order. +const ( + lowPriority = 100 + mediumPriority = 10 + highPriority = 1 + perfectMatchPriority = 0 +) + +// RankRepoName associates a rank to a given repoName given a searchText. +// The imporance of the value grows inversly proportional to the int value it has. +// For example: rank(1) > rank(10) > rank(100)... +func RankRepoName(searchText string, repoName string) int { + searchText = strings.Trim(searchText, "/") searchTextSlice := strings.Split(searchText, "/") repoNameSlice := strings.Split(repoName, "/") @@ -70,37 +84,60 @@ func ScoreRepoName(searchText string, repoName string) int { return -1 } + if searchText == repoName { + return perfectMatchPriority + } + + // searchText containst just 1 diretory name if len(searchTextSlice) == 1 { - // check if it maches first or last name in path - if index := strings.Index(repoNameSlice[len(repoNameSlice)-1], searchTextSlice[0]); index != -1 { - return index + 1 + lastNameInRepoPath := repoNameSlice[len(repoNameSlice)-1] + + // searchText: "bar" | repoName: "foo/bar" lastNameInRepoPath: "bar" + if index := strings.Index(lastNameInRepoPath, searchText); index != -1 { + return (index + 1) * highPriority } - // we'll make repos that match the first name in path less important than matching the last name in path - if index := strings.Index(repoNameSlice[0], searchTextSlice[0]); index != -1 { - return (index + 1) * 10 + firstNameInRepoPath := repoNameSlice[0] + + // searchText: "foo" | repoName: "foo/bar" firstNameInRepoPath: "foo" + if index := strings.Index(firstNameInRepoPath, searchText); index != -1 { + return (index + 1) * mediumPriority } - - return -1 } - if len(searchTextSlice) < len(repoNameSlice) && - strings.HasPrefix(repoName, searchText) { - return 1 - } + foundPrefixInRepoName := true - // searchText and repoName match perfectly up until the last name in path + // searchText: "foo/bar/rep" | repoName: "foo/bar/baz/repo" foundPrefixInRepoName: true + // searchText: "foo/baz/rep" | repoName: "foo/bar/baz/repo" foundPrefixInRepoName: false for i := 0; i < len(searchTextSlice)-1; i++ { if searchTextSlice[i] != repoNameSlice[i] { - return -1 + foundPrefixInRepoName = false + + break } } - // check the last - if index := strings.Index(repoNameSlice[len(repoNameSlice)-1], searchTextSlice[len(searchTextSlice)-1]); index != -1 { - return (index + 1) + if foundPrefixInRepoName { + lastNameInRepoPath := repoNameSlice[len(repoNameSlice)-1] + lastNameInSearchText := searchTextSlice[len(searchTextSlice)-1] + + // searchText: "foo/bar/epo" | repoName: "foo/bar/baz/repo" -> Index(repo, epo) = 1 + if index := strings.Index(lastNameInRepoPath, lastNameInSearchText); index != -1 { + return (index + 1) * highPriority + } } + // searchText: "foo/bar/b" | repoName: "foo/bar/baz/repo" + if strings.HasPrefix(repoName, searchText) { + return mediumPriority + } + + // searchText: "bar/ba" | repoName: "foo/bar/baz/repo" + if index := strings.Index(repoName, searchText); index != -1 { + return (index + 1) * lowPriority + } + + // no match return -1 } diff --git a/pkg/meta/repodb/dynamodb-wrapper/dynamo_wrapper.go b/pkg/meta/repodb/dynamodb-wrapper/dynamo_wrapper.go index 2feaed64..53b7428a 100644 --- a/pkg/meta/repodb/dynamodb-wrapper/dynamo_wrapper.go +++ b/pkg/meta/repodb/dynamodb-wrapper/dynamo_wrapper.go @@ -829,7 +829,7 @@ func (dwr *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter continue } - if score := common.ScoreRepoName(searchText, repoMeta.Name); score != -1 { + if rank := common.RankRepoName(searchText, repoMeta.Name); rank != -1 { var ( // specific values used for sorting that need to be calculated based on all manifests from the repo repoDownloads = 0 @@ -935,7 +935,7 @@ func (dwr *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter pageFinder.Add(repodb.DetailedRepoMeta{ RepoMeta: repoMeta, - Score: score, + Rank: rank, Downloads: repoDownloads, UpdateTime: repoLastUpdated, }) diff --git a/pkg/meta/repodb/repodb_test.go b/pkg/meta/repodb/repodb_test.go index 0bf4381b..d74f562b 100644 --- a/pkg/meta/repodb/repodb_test.go +++ b/pkg/meta/repodb/repodb_test.go @@ -1962,17 +1962,22 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) { func TestRelevanceSorting(t *testing.T) { Convey("Test Relevance Sorting", t, func() { - So(common.ScoreRepoName("alpine", "alpine"), ShouldEqual, 1) - So(common.ScoreRepoName("test/alpine", "alpine"), ShouldEqual, -1) - So(common.ScoreRepoName("alpine", "test/alpine"), ShouldEqual, 1) - So(common.ScoreRepoName("test", "test/alpine"), ShouldEqual, 10) - So(common.ScoreRepoName("pine", "test/alpine"), ShouldEqual, 3) - So(common.ScoreRepoName("pine", "alpine/alpine"), ShouldEqual, 3) - So(common.ScoreRepoName("pine", "alpine/test"), ShouldEqual, 30) - So(common.ScoreRepoName("test/pine", "alpine"), ShouldEqual, -1) - So(common.ScoreRepoName("repo/test", "repo/test/alpine"), ShouldEqual, 1) - So(common.ScoreRepoName("repo/test/golang", "repo/test2/alpine"), ShouldEqual, -1) - So(common.ScoreRepoName("repo/test/pine", "repo/test/alpine"), ShouldEqual, 3) + So(common.RankRepoName("alpine", "alpine"), ShouldEqual, 0) + So(common.RankRepoName("test/alpine", "test/alpine"), ShouldEqual, 0) + So(common.RankRepoName("test/alpine", "alpine"), ShouldEqual, -1) + So(common.RankRepoName("alpine", "test/alpine"), ShouldEqual, 1) + So(common.RankRepoName("test", "test/alpine"), ShouldEqual, 10) + So(common.RankRepoName("pine", "test/alpine"), ShouldEqual, 3) + So(common.RankRepoName("pine", "alpine/alpine"), ShouldEqual, 3) + So(common.RankRepoName("pine", "alpine/test"), ShouldEqual, 30) + So(common.RankRepoName("test/pine", "alpine"), ShouldEqual, -1) + So(common.RankRepoName("repo/test", "repo/test/alpine"), ShouldEqual, 10) + So(common.RankRepoName("repo/test/golang", "repo/test2/alpine"), ShouldEqual, -1) + So(common.RankRepoName("repo/test/pine", "repo/test/alpine"), ShouldEqual, 3) + So(common.RankRepoName("debian", "c3/debian/base-amd64"), ShouldEqual, 400) + So(common.RankRepoName("debian/base-amd64", "c3/debian/base-amd64"), ShouldEqual, 400) + So(common.RankRepoName("debian/base-amd64", "c3/aux/debian/base-amd64"), ShouldEqual, 800) + So(common.RankRepoName("aux/debian", "c3/aux/debian/base-amd64"), ShouldEqual, 400) Convey("Integration", func() { filePath := path.Join(t.TempDir(), "repo.db")