[search] title phrase (#99753)

[search] rename title_sort to title_phrase
This commit is contained in:
Scott Lepper 2025-01-29 17:31:59 -05:00 committed by GitHub
parent cf177776bf
commit 8e9e3b8362
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 62 additions and 51 deletions

View File

@ -240,9 +240,9 @@ func (s *Service) getFolderByTitleFromApiServer(ctx context.Context, orgID int64
Key: folderkey,
Fields: []*resource.Requirement{
{
Key: resource.SEARCH_FIELD_TITLE_SORT,
Key: resource.SEARCH_FIELD_TITLE_PHRASE,
Operator: string(selection.In),
Values: []string{strings.ToLower(title)},
Values: []string{title},
},
},
Labels: []*resource.Requirement{},

View File

@ -567,7 +567,7 @@ func (r resourceClientMock) Search(ctx context.Context, in *resource.ResourceSea
}
if len(in.Options.Fields) > 0 &&
in.Options.Fields[0].Key == resource.SEARCH_FIELD_TITLE_SORT &&
in.Options.Fields[0].Key == resource.SEARCH_FIELD_TITLE_PHRASE &&
in.Options.Fields[0].Operator == "in" &&
len(in.Options.Fields[0].Values) > 0 &&
in.Options.Fields[0].Values[0] == "foo" {

View File

@ -63,7 +63,7 @@ type IndexableDocument struct {
Title string `json:"title,omitempty"`
// internal sort field for title ( don't set this directly )
TitleSort string `json:"title_sort,omitempty"`
TitlePhrase string `json:"title_phrase,omitempty"`
// A generic description -- helpful in global search
Description string `json:"description,omitempty"`
@ -163,15 +163,15 @@ func NewIndexableDocument(key *ResourceKey, rv int64, obj utils.GrafanaMetaAcces
}
}
doc := &IndexableDocument{
Key: key,
RV: rv,
Name: key.Name,
Title: title, // We always want *something* to display
TitleSort: strings.ToLower(title), // Lowercase for case-insensitive sorting
Labels: obj.GetLabels(),
Folder: obj.GetFolder(),
CreatedBy: obj.GetCreatedBy(),
UpdatedBy: obj.GetUpdatedBy(),
Key: key,
RV: rv,
Name: key.Name,
Title: title, // We always want *something* to display
TitlePhrase: strings.ToLower(title), // Lowercase for case-insensitive sorting
Labels: obj.GetLabels(),
Folder: obj.GetFolder(),
CreatedBy: obj.GetCreatedBy(),
UpdatedBy: obj.GetUpdatedBy(),
}
doc.RepoInfo, _ = obj.GetRepositoryInfo()
ts := obj.GetCreationTimestamp()
@ -253,7 +253,7 @@ const SEARCH_FIELD_NAMESPACE = "namespace"
const SEARCH_FIELD_NAME = "name"
const SEARCH_FIELD_RV = "rv"
const SEARCH_FIELD_TITLE = "title"
const SEARCH_FIELD_TITLE_SORT = "title_sort"
const SEARCH_FIELD_TITLE_PHRASE = "title_phrase" // filtering/sorting on title by full phrase
const SEARCH_FIELD_DESCRIPTION = "description"
const SEARCH_FIELD_TAGS = "tags"
const SEARCH_FIELD_LABELS = "labels" // All labels, not a specific one

View File

@ -35,7 +35,7 @@ func TestStandardDocumentBuilder(t *testing.T) {
},
"rv": 10,
"title": "test playlist unified storage",
"title_sort": "test playlist unified storage",
"title_phrase": "test playlist unified storage",
"created": 1717236672000,
"createdBy": "user:ABC",
"updatedBy": "user:XYZ",

View File

@ -1284,12 +1284,12 @@ type ListOptions struct {
// Group+Namespace+Resource (not name)
Key *ResourceKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
// (best effort) Match label
// Allowed to send more results than actually match because the filter will be appled
// to the resutls agin in the client. That time with the full field selector
// Allowed to send more results than actually match because the filter will be applied
// to the results again in the client. That time with the full field selector
Labels []*Requirement `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty"`
// (best effort) fields matcher
// Allowed to send more results than actually match because the filter will be appled
// to the resutls agin in the client. That time with the full field selector
// Allowed to send more results than actually match because the filter will be applied
// to the results again in the client. That time with the full field selector
Fields []*Requirement `protobuf:"bytes,3,rep,name=fields,proto3" json:"fields,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache

View File

@ -209,13 +209,13 @@ message ListOptions {
ResourceKey key = 1;
// (best effort) Match label
// Allowed to send more results than actually match because the filter will be appled
// to the resutls agin in the client. That time with the full field selector
// Allowed to send more results than actually match because the filter will be applied
// to the results again in the client. That time with the full field selector
repeated Requirement labels = 2;
// (best effort) fields matcher
// Allowed to send more results than actually match because the filter will be appled
// to the resutls agin in the client. That time with the full field selector
// Allowed to send more results than actually match because the filter will be applied
// to the results again in the client. That time with the full field selector
repeated Requirement fields = 3;
}

View File

@ -684,9 +684,11 @@ func getSortFields(req *resource.ResourceSearchRequest) []string {
// fields that we went to sort by the full text
var textSortFields = map[string]string{
resource.SEARCH_FIELD_TITLE: resource.SEARCH_FIELD_TITLE + "_sort",
resource.SEARCH_FIELD_TITLE: resource.SEARCH_FIELD_TITLE_PHRASE,
}
const lowerCase = "phrase"
// Convert a "requirement" into a bleve query
func requirementQuery(req *resource.Requirement, prefix string) (query.Query, *resource.ErrorResult) {
switch selection.Operator(req.Operator) {
@ -696,14 +698,14 @@ func requirementQuery(req *resource.Requirement, prefix string) (query.Query, *r
}
if len(req.Values[0]) == 1 {
q := query.NewMatchQuery(req.Values[0])
q := query.NewMatchQuery(filterValue(req.Key, req.Values[0]))
q.FieldVal = prefix + req.Key
return q, nil
}
conjuncts := []query.Query{}
for _, v := range req.Values {
q := query.NewMatchQuery(v)
q := query.NewMatchQuery(filterValue(req.Key, v))
q.FieldVal = prefix + req.Key
conjuncts = append(conjuncts, q)
}
@ -720,14 +722,14 @@ func requirementQuery(req *resource.Requirement, prefix string) (query.Query, *r
return query.NewMatchAllQuery(), nil
}
if len(req.Values) == 1 {
q := query.NewMatchQuery(req.Values[0])
q := query.NewMatchQuery(filterValue(req.Key, req.Values[0]))
q.FieldVal = prefix + req.Key
return q, nil
}
disjuncts := []query.Query{}
for _, v := range req.Values {
q := query.NewMatchQuery(v)
q := query.NewMatchQuery(filterValue(req.Key, v))
q.FieldVal = prefix + req.Key
disjuncts = append(disjuncts, q)
}
@ -739,7 +741,7 @@ func requirementQuery(req *resource.Requirement, prefix string) (query.Query, *r
var mustNotQueries []query.Query
for _, value := range req.Values {
mustNotQueries = append(mustNotQueries, bleve.NewMatchQuery(value))
mustNotQueries = append(mustNotQueries, bleve.NewMatchQuery(filterValue(req.Key, value)))
}
boolQuery.AddMustNot(mustNotQueries...)
@ -754,6 +756,14 @@ func requirementQuery(req *resource.Requirement, prefix string) (query.Query, *r
)
}
// filterValue will convert the value to lower case if the field is a phrase field
func filterValue(field string, v string) string {
if strings.HasSuffix(field, lowerCase) {
return strings.ToLower(v)
}
return v
}
func (b *bleveIndex) hitsToTable(ctx context.Context, selectFields []string, hits search.DocumentMatchCollection, explain bool) (*resource.ResourceTable, error) {
_, span := b.tracing.Start(ctx, tracingPrexfixBleve+"hitsToTable")
defer span.End()

View File

@ -24,11 +24,12 @@ func getBleveDocMappings(_ resource.SearchableDocumentFields) *mapping.DocumentM
}
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_NAME, nameMapping)
// for sorting by title
titleSortMapping := bleve.NewKeywordFieldMapping()
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_TITLE_SORT, titleSortMapping)
// for filtering/sorting by title full phrase
titlePhraseMapping := bleve.NewKeywordFieldMapping()
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_TITLE_PHRASE, titlePhraseMapping)
// for searching by title
// TODO: do we still need this since we have SEARCH_FIELD_TITLE_PHRASE?
titleSearchMapping := bleve.NewTextFieldMapping()
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_TITLE, titleSearchMapping)

View File

@ -78,9 +78,9 @@ func TestBleveBackend(t *testing.T) {
Group: "dashboard.grafana.app",
Resource: "dashboards",
},
Title: "aaa (dash)",
TitleSort: "aaa (dash)",
Folder: "xxx",
Title: "aaa (dash)",
TitlePhrase: "aaa (dash)",
Folder: "xxx",
Fields: map[string]any{
DASHBOARD_PANEL_TYPES: []string{"timeseries", "table"},
DASHBOARD_ERRORS_TODAY: 25,
@ -106,9 +106,9 @@ func TestBleveBackend(t *testing.T) {
Group: "dashboard.grafana.app",
Resource: "dashboards",
},
Title: "bbb (dash)",
TitleSort: "bbb (dash)",
Folder: "xxx",
Title: "bbb (dash)",
TitlePhrase: "bbb (dash)",
Folder: "xxx",
Fields: map[string]any{
DASHBOARD_PANEL_TYPES: []string{"timeseries"},
DASHBOARD_ERRORS_TODAY: 40,
@ -134,10 +134,10 @@ func TestBleveBackend(t *testing.T) {
Group: "dashboard.grafana.app",
Resource: "dashboards",
},
Name: "ccc",
Title: "ccc (dash)",
TitleSort: "ccc (dash)",
Folder: "zzz",
Name: "ccc",
Title: "ccc (dash)",
TitlePhrase: "ccc (dash)",
Folder: "zzz",
RepoInfo: &utils.ResourceRepositoryInfo{
Name: "repo2",
Path: "path/in/repo2.yaml",
@ -332,8 +332,8 @@ func TestBleveBackend(t *testing.T) {
Group: "folder.grafana.app",
Resource: "folders",
},
Title: "zzz (folder)",
TitleSort: "zzz (folder)",
Title: "zzz (folder)",
TitlePhrase: "zzz (folder)",
RepoInfo: &utils.ResourceRepositoryInfo{
Name: "repo-1",
Path: "path/to/folder.json",
@ -349,8 +349,8 @@ func TestBleveBackend(t *testing.T) {
Group: "folder.grafana.app",
Resource: "folders",
},
Title: "yyy (folder)",
TitleSort: "yyy (folder)",
Title: "yyy (folder)",
TitlePhrase: "yyy (folder)",
Labels: map[string]string{
"region": "west",
},

View File

@ -8,7 +8,7 @@
"name": "aaa",
"rv": 1234,
"title": "Test title",
"title_sort": "test title",
"title_phrase": "test title",
"description": "test description",
"tags": [
"a",

View File

@ -8,7 +8,7 @@
"name": "aaa",
"rv": 1234,
"title": "test-aaa",
"title_sort": "test-aaa",
"title_phrase": "test-aaa",
"created": 1730490142000,
"createdBy": "user:1",
"repo": {

View File

@ -8,7 +8,7 @@
"name": "bbb",
"rv": 1234,
"title": "test-bbb",
"title_sort": "test-bbb",
"title_phrase": "test-bbb",
"created": 1730490142000,
"createdBy": "user:1",
"repo": {

View File

@ -8,7 +8,7 @@
"name": "aaa",
"rv": 1234,
"title": "Test AAA",
"title_sort": "test aaa",
"title_phrase": "test aaa",
"created": 1731336353000,
"createdBy": "user:t000000001",
"repo": {

View File

@ -8,7 +8,7 @@
"name": "aaa",
"rv": 1234,
"title": "Test AAA",
"title_sort": "test aaa",
"title_phrase": "test aaa",
"labels": {
"grafana.app/deprecatedInternalID": "123"
},