From 7891bdbeacef28cd1ff2d7af6b95cfb7eb1d5d28 Mon Sep 17 00:00:00 2001 From: Kleissner Date: Sun, 10 Oct 2021 16:07:44 +0200 Subject: [PATCH] webapi search: Provide option to embed statistics into /search/result response --- webapi/Search Job.go | 20 ++++++++------------ webapi/Search.go | 21 +++++++++++++++++---- webapi/readme.md | 37 +++++++++++++++++++++++++++---------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/webapi/Search Job.go b/webapi/Search Job.go index 0445ded..562f994 100644 --- a/webapi/Search Job.go +++ b/webapi/Search Job.go @@ -384,18 +384,16 @@ type SearchStatisticRecord struct { Count int `json:"count"` // Count of files for the given key } -// SearchStatistic contains statistics on search results. Statistics are always calculated over all results, regardless if runtime filters change. -type SearchStatistic struct { - Date []SearchStatisticRecordDay `json:"date"` // Files per date - FileType []SearchStatisticRecord `json:"filetype"` // Files per file type - FileFormat []SearchStatisticRecord `json:"fileformat"` // Files per file format - Total int `json:"total"` // Total count of files - Status int `json:"status"` // Status: 0 = Success - IsTerminated bool `json:"terminated"` // Whether the search is terminated, meaning that statistics won't change +// SearchStatisticData contains statistics on search results. +type SearchStatisticData struct { + Date []SearchStatisticRecordDay `json:"date"` // Files per date + FileType []SearchStatisticRecord `json:"filetype"` // Files per file type + FileFormat []SearchStatisticRecord `json:"fileformat"` // Files per file format + Total int `json:"total"` // Total count of files } -// Statistics generates statistics on results -func (job *SearchJob) Statistics() (result SearchStatistic) { +// Statistics generates statistics on all results, regardless of runtime filters. +func (job *SearchJob) Statistics() (result SearchStatisticData) { job.stats.RLock() defer job.stats.RUnlock() @@ -415,8 +413,6 @@ func (job *SearchJob) Statistics() (result SearchStatistic) { result.FileFormat = append(result.FileFormat, SearchStatisticRecord{Key: int(key), Count: value}) } - result.IsTerminated = job.IsTerminated() - return } diff --git a/webapi/Search.go b/webapi/Search.go index f46e185..13fefd5 100644 --- a/webapi/Search.go +++ b/webapi/Search.go @@ -61,8 +61,16 @@ type SearchRequestResponse struct { // SearchResult contains the search results. type SearchResult struct { - Status int `json:"status"` // Status: 0 = Success with results, 1 = No more results available, 2 = Search ID not found, 3 = No results yet available keep trying - Files []apiFile `json:"files"` // List of files found + Status int `json:"status"` // Status: 0 = Success with results, 1 = No more results available, 2 = Search ID not found, 3 = No results yet available keep trying + Files []apiFile `json:"files"` // List of files found + Statistic interface{} `json:"statistic"` // Statistics of all results (independent from applied filters), if requested. Only set if files are returned (= if statistics changed). See SearchStatisticData. +} + +// SearchStatistic contains statistics on search results. Statistics are always calculated over all results, regardless of any applied runtime filters. +type SearchStatistic struct { + SearchStatisticData + Status int `json:"status"` // Status: 0 = Success + IsTerminated bool `json:"terminated"` // Whether the search is terminated, meaning that statistics won't change } const apiDateFormat = "2006-01-02 15:04:05" @@ -168,6 +176,11 @@ func apiSearchResult(w http.ResponseWriter, r *http.Request) { //if !job.IsSearchResults() { // if no fresh results to be expected result.Status = 1 // No more results to expect + // embedded statistics? + if returnStats, _ := strconv.ParseBool(r.Form.Get("stats")); returnStats && len(result.Files) > 0 { + result.Statistic = job.Statistics() + } + EncodeJSON(w, r, result) } @@ -263,7 +276,7 @@ func apiSearchTerminate(w http.ResponseWriter, r *http.Request) { } /* -apiSearchStatistic returns search result statistics. Statistics are always calculated over all results, regardless if runtime filters change. +apiSearchStatistic returns search result statistics. Statistics are always calculated over all results, regardless of any applied runtime filters. Request: GET /search/result?id=[UUID] Result: 200 with JSON structure SearchStatistic. Check the field status (0 = Success, 2 = ID not found). @@ -285,7 +298,7 @@ func apiSearchStatistic(w http.ResponseWriter, r *http.Request) { stats := job.Statistics() - EncodeJSON(w, r, stats) + EncodeJSON(w, r, SearchStatistic{SearchStatisticData: stats, Status: 0, IsTerminated: job.IsTerminated()}) } /* diff --git a/webapi/readme.md b/webapi/readme.md index f35a574..85ca8ae 100644 --- a/webapi/readme.md +++ b/webapi/readme.md @@ -580,6 +580,8 @@ This function returns search results. The default limit is 100. If reset is set, all results will be filtered and sorted according to the provided parameters. This means that the new first result will be returned again and internal result offset is set to 0. Note that most filters must be set to -1 if they are not used (see the field comments in the `SearchRequest` structure in `/search` above). +The statistics of all results (regardless of applied runtime filters) can be returned immediately in the `statistics` field by specifying `&stats=1`. If will be only provided if the statistics change, i.e. if at least one file is returned. The returned statistics is the `SearchStatisticData` structure and matches with what is returned by `/search/statistic`. + ``` Request: GET /search/result?id=[UUID]&limit=[max records] Optional parameters: @@ -595,8 +597,9 @@ Result: 200 with JSON structure SearchResult. Check the field status. ```go type SearchResult struct { - Status int `json:"status"` // Status: 0 = Success with results, 1 = No more results available, 2 = Search ID not found, 3 = No results yet available keep trying - Files []apiFile `json:"files"` // List of files found + Status int `json:"status"` // Status: 0 = Success with results, 1 = No more results available, 2 = Search ID not found, 3 = No results yet available keep trying + Files []apiFile `json:"files"` // List of files found + Statistic interface{} `json:"statistic"` // Statistics of all results (independent from applied filters), if requested. Only set if files are returned (= if statistics changed). See SearchStatisticData. } ``` @@ -639,21 +642,35 @@ Example response with dummy data: ### Search Result Statistics -This returns search result statistics. Statistics are always calculated over all results, regardless if runtime filters change. +This returns search result statistics. Statistics are always calculated over all results, regardless of any applied runtime filters. ``` -Request: GET /search/result?id=[UUID] +Request: GET /search/statistic?id=[UUID] Result: 200 with JSON structure SearchStatistic. Check the field status (0 = Success, 2 = ID not found). ``` ```go type SearchStatistic struct { - Date []SearchStatisticRecordDay `json:"date"` // Files per date - FileType []SearchStatisticRecord `json:"filetype"` // Files per file type - FileFormat []SearchStatisticRecord `json:"fileformat"` // Files per file format - Total int `json:"total"` // Total count of files - Status int `json:"status"` // Status: 0 = Success - IsTerminated bool `json:"terminated"` // Whether the search is terminated, meaning that statistics won't change + SearchStatisticData + Status int `json:"status"` // Status: 0 = Success + IsTerminated bool `json:"terminated"` // Whether the search is terminated, meaning that statistics won't change +} + +type SearchStatisticData struct { + Date []SearchStatisticRecordDay `json:"date"` // Files per date + FileType []SearchStatisticRecord `json:"filetype"` // Files per file type + FileFormat []SearchStatisticRecord `json:"fileformat"` // Files per file format + Total int `json:"total"` // Total count of files +} + +type SearchStatisticRecordDay struct { + Date time.Time `json:"date"` // The day (which covers the full 24 hours). Always rounded down to midnight. + Count int `json:"count"` // Count of files. +} + +type SearchStatisticRecord struct { + Key int `json:"key"` // Key index. The exact meaning depends on where this structure is used. + Count int `json:"count"` // Count of files for the given key } ```