From c5ed44143c0309916c0093c19bb1b1eb59fbcc7d Mon Sep 17 00:00:00 2001 From: Daniil Forshev Date: Tue, 18 Aug 2026 14:58:00 +0500 Subject: [PATCH 1/4] feat(stream search): serve ComplexSearch through stream search --- cmd/seq-db/seq-db.go | 1 + config/config.go | 2 + proxyapi/grpc_complex_search.go | 213 ++++++++++++++++++++ proxyapi/grpc_complex_search_stream_test.go | 149 ++++++++++++++ proxyapi/ingestor_config.go | 2 + 5 files changed, 367 insertions(+) create mode 100644 proxyapi/grpc_complex_search_stream_test.go diff --git a/cmd/seq-db/seq-db.go b/cmd/seq-db/seq-db.go index 7fbf26533..faa42d1a7 100644 --- a/cmd/seq-db/seq-db.go +++ b/cmd/seq-db/seq-db.go @@ -188,6 +188,7 @@ func startProxy( EsVersion: cfg.API.ESVersion, GatewayAddr: cfg.Address.GRPC, AsyncSearchMaxDocumentsPerRequest: cfg.AsyncSearch.MaxDocumentsPerRequest, + TryStreamSearch: cfg.Experimental.TryStreamSearch, }, Search: search.Config{ HotStores: hotStores, diff --git a/config/config.go b/config/config.go index db512c7c1..ae965e80f 100644 --- a/config/config.go +++ b/config/config.go @@ -341,6 +341,8 @@ type Config struct { // Specify how many tokens can be checked using regular expressions. // If zero then there is no limit. MaxRegexTokensCheck int `config:"max_regex_tokens_check" default:"0"` + // If true, suitable ComplexSearch queries will be served through stream search implementation. + TryStreamSearch bool `config:"try_stream_search"` } `config:"experimental"` } diff --git a/proxyapi/grpc_complex_search.go b/proxyapi/grpc_complex_search.go index 7dbb6fe71..ffce184d7 100644 --- a/proxyapi/grpc_complex_search.go +++ b/proxyapi/grpc_complex_search.go @@ -1,12 +1,23 @@ package proxyapi import ( + "cmp" "context" + "errors" + "fmt" + "slices" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" + "github.com/ozontech/seq-db/consts" + "github.com/ozontech/seq-db/metric" + "github.com/ozontech/seq-db/parser" "github.com/ozontech/seq-db/pkg/seqproxyapi/v1" + "github.com/ozontech/seq-db/pkg/storeapi" + "github.com/ozontech/seq-db/proxy/search" + "github.com/ozontech/seq-db/query" "github.com/ozontech/seq-db/querytracer" "github.com/ozontech/seq-db/seq" ) @@ -22,6 +33,11 @@ func (g *grpcV1) ComplexSearch( } tr := querytracer.New(req.Query.Explain, "proxy/ComplexSearch") + + if shouldTryStreamSearch(g.config.TryStreamSearch, req) { + return g.emulateStreamSearch(ctx, req, tr) + } + sResp, err := g.doSearch(ctx, req, true, true, tr) if err != nil { return nil, err @@ -73,3 +89,200 @@ func aggregationArgsFromProto(aggs []*seqproxyapi.AggQuery) []seq.AggregateArgs } return args } + +func (g *grpcV1) emulateStreamSearch( + ctx context.Context, + req *seqproxyapi.ComplexSearchRequest, + tr *querytracer.Tracer, +) (*seqproxyapi.ComplexSearchResponse, error) { + metric.SearchOverall.Add(1) + tr.Printf("making stream search request") + + streamSearchReq, err := buildStreamSearchReqFromComplexSearchReq(req) + if err != nil { + return nil, status.Error(codes.InvalidArgument, `can't build stream search request`) + } + + var partialErr error + storesStream, broadcaster, err := g.searchIngestor.StreamSearch(ctx, streamSearchReq, tr) + if err != nil { + // The stores were not opened or failed to open, cancel any that may have started before propagating the error. + if broadcaster != nil { + broadcaster.SendControl(storeapi.ControlAction_CANCEL) + } + if errors.Is(err, consts.ErrPartialResponse) { + if shouldFailPartialResponse(ctx) { + return nil, status.Error(codes.Internal, "partial response: not all shards returned results") + } + partialErr = err + metric.SearchPartial.Inc() + } else { + return nil, status.Error(codes.Internal, err.Error()) + } + } + + var docs []*seqproxyapi.Document + var aggs []*seqproxyapi.Aggregation + if streamSearchReq.Agg != nil { + aggs = readAggregations(storesStream) + } else { + docs = readDocuments(storesStream) + } + + // finalize to get summary + broadcaster.SendControl(storeapi.ControlAction_FINALIZE) + + summary := storesStream.Finalize() + if summary == nil { + summary = &query.Summary{} + } + if partialErr != nil && summary.Err == nil { + summary.Err = partialErr + } + + if req.Query.Explain { + tr.Done() + } + + resp := &seqproxyapi.ComplexSearchResponse{ + Total: int64(summary.Total), + Docs: docs, + Aggs: aggs, + Explain: tracerSpanToExplainEntry(tr.ToSpan()), + Error: &seqproxyapi.Error{ + Code: seqproxyapi.ErrorCode_ERROR_CODE_NO, + }, + } + if summary.Err != nil { + resp.Error = &seqproxyapi.Error{ + Code: mapProxyErrorCode(summary.Err), + Message: summary.Err.Error(), + } + if !shouldHaveResponse(resp.Error.Code) { + resp.Docs = nil + resp.Aggs = nil + } + } + + return resp, nil +} + +func readDocuments(storesStream query.RecordProducer) []*seqproxyapi.Document { + var docs []*seqproxyapi.Document + for r := storesStream.Next(); r != nil; r = storesStream.Next() { + id := r.Vals[0].Decoded().(seq.ID) + docs = append(docs, &seqproxyapi.Document{ + Id: id.String(), + Time: timestamppb.New(id.MID.Time()), + Data: r.Vals[1].RawData(), + }) + } + return docs +} + +func readAggregations(storesStream query.RecordProducer) []*seqproxyapi.Aggregation { + buckets := make([]*seqproxyapi.Aggregation_Bucket, 0) + for r := storesStream.Next(); r != nil; r = storesStream.Next() { + bucket := &seqproxyapi.Aggregation_Bucket{ + Key: r.Vals[0].Decoded().(string), + Value: r.Vals[1].Decoded().(float64), + } + if ts := r.Vals[2].Decoded().(uint64); ts != consts.DummyMID { + bucket.Ts = timestamppb.New(seq.MID(ts).Time()) + } + buckets = append(buckets, bucket) + } + return []*seqproxyapi.Aggregation{{Buckets: buckets}} +} + +func shouldTryStreamSearch(tryStreamSearch bool, req *seqproxyapi.ComplexSearchRequest) bool { + if !tryStreamSearch { + return false + } + if req.Hist != nil || len(req.Aggs) > 1 { + return false + } + if len(req.Aggs) == 1 && (req.Aggs[0].Func == seq.AggFuncQuantile || req.Aggs[0].Func == seq.AggFuncUniqueCount) { + return false + } + return true +} + +func buildStreamSearchReqFromComplexSearchReq( + req *seqproxyapi.ComplexSearchRequest, +) (*search.StreamSearchRequest, error) { + seqql, err := parser.ParseSeqQL(req.Query.Query, nil) + if err != nil { + return nil, fmt.Errorf("parse query: %w", err) + } + + streamSearchReq := &search.StreamSearchRequest{ + Query: req.Query.Query, + From: seq.TimeToMID(req.Query.From.AsTime()), + To: seq.TimeToMID(req.Query.To.AsTime()), + Explain: req.Query.Explain, + WithTotal: req.WithTotal, + OffsetId: req.OffsetId, + Order: req.Order.MustDocsOrder(), + Size: int(req.Size), + Offset: int(req.Offset), + } + + // stream search serves either documents or a single agg. + // shouldTryStreamSearch guarantees single agg and no histogram. + if len(req.Aggs) == 1 { + aggQuery, err := convertAggsQuery(req.Aggs) + if err != nil { + return nil, err + } + streamSearchReq.Agg = &aggQuery[0] + seqql.Pipes = append(seqql.Pipes, statsPipeFromProto(req.Aggs[0])) + } else { + if req.Size > 0 { + seqql.Pipes = append(seqql.Pipes, &parser.PipeLimit{Limit: int(req.Size)}) + } + if req.Offset > 0 { + seqql.Pipes = append(seqql.Pipes, &parser.PipeOffset{Offset: int(req.Offset)}) + } + seqql.Pipes = append(seqql.Pipes, &parser.PipeSort{Order: orderToPipeString(req.Order)}) + } + + // pipes order is important + slices.SortFunc(seqql.Pipes, func(a, b parser.Pipe) int { + return cmp.Compare(pipeOrder[a.Name()], pipeOrder[b.Name()]) + }) + + // we need to modify query with pipes because stores extracts parameters from it. + streamSearchReq.Query = seqql.SeqQLString() + + return streamSearchReq, nil +} + +var pipeOrder = map[string]int{ + "stats": 0, + "filter": 1, + "fields": 2, + "sort": 3, + "limit": 4, + "offset": 5, +} + +func orderToPipeString(order seqproxyapi.Order) string { + if order == seqproxyapi.Order_ORDER_ASC { + return "asc" + } + return "desc" +} + +func statsPipeFromProto(agg *seqproxyapi.AggQuery) *parser.PipeStats { + statsAgg := parser.StatsAgg{ + Func: agg.Func.MustAggFunc().String(), + Field: agg.Field, + GroupBy: agg.GroupBy, + Quantiles: agg.Quantiles, + } + if agg.Interval != nil { + statsAgg.Interval = *agg.Interval + } + return &parser.PipeStats{Agg: statsAgg} +} diff --git a/proxyapi/grpc_complex_search_stream_test.go b/proxyapi/grpc_complex_search_stream_test.go new file mode 100644 index 000000000..95501487f --- /dev/null +++ b/proxyapi/grpc_complex_search_stream_test.go @@ -0,0 +1,149 @@ +package proxyapi + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/ozontech/seq-db/pkg/seqproxyapi/v1" + "github.com/ozontech/seq-db/proxy/search" + "github.com/ozontech/seq-db/seq" +) + +var interval = "1m" + +func TestBuildStreamSearchReqFromComplexSearchReq(t *testing.T) { + now := time.Now() + + tests := []struct { + name string + req *seqproxyapi.ComplexSearchRequest + want *search.StreamSearchRequest + wantErr bool + }{ + { + name: "docs", + req: &seqproxyapi.ComplexSearchRequest{ + Query: &seqproxyapi.SearchQuery{ + Query: "message:ok", + From: timestamppb.New(now), + To: timestamppb.New(now.Add(time.Hour)), + }, + Size: 10, + Offset: 5, + Order: seqproxyapi.Order_ORDER_ASC, + WithTotal: true, + }, + want: &search.StreamSearchRequest{ + Query: "message:ok | sort asc | limit 10 | offset 5", + From: seq.TimeToMID(now), + To: seq.TimeToMID(now.Add(time.Hour)), + Size: 10, + Offset: 5, + Order: seq.DocsOrderAsc, + WithTotal: true, + }, + }, + { + name: "docs_with_existing_fields_pipe", + req: &seqproxyapi.ComplexSearchRequest{ + Query: &seqproxyapi.SearchQuery{ + Query: "message:ok | fields service, level", + From: timestamppb.New(now), + To: timestamppb.New(now.Add(time.Hour)), + }, + Size: 10, + Offset: 5, + Order: seqproxyapi.Order_ORDER_DESC, + }, + want: &search.StreamSearchRequest{ + Query: "message:ok | fields service, level | sort desc | limit 10 | offset 5", + From: seq.TimeToMID(now), + To: seq.TimeToMID(now.Add(time.Hour)), + Size: 10, + Offset: 5, + Order: seq.DocsOrderDesc, + }, + }, + { + name: "aggregation", + req: &seqproxyapi.ComplexSearchRequest{ + Query: &seqproxyapi.SearchQuery{ + Query: "message:ok", + From: timestamppb.New(now), + To: timestamppb.New(now.Add(time.Hour)), + }, + Aggs: []*seqproxyapi.AggQuery{{ + Field: "duration", + GroupBy: "service", + Func: seqproxyapi.AggFunc_AGG_FUNC_SUM, + }}, + }, + want: &search.StreamSearchRequest{ + Query: "message:ok | stats sum(duration) by (service)", + From: seq.TimeToMID(now), + To: seq.TimeToMID(now.Add(time.Hour)), + Agg: &search.AggQuery{ + Field: "duration", + GroupBy: "service", + Func: seq.AggFuncSum, + }, + }, + }, + { + name: "aggregation_with_interval", + req: &seqproxyapi.ComplexSearchRequest{ + Query: &seqproxyapi.SearchQuery{ + Query: "message:ok", + From: timestamppb.New(now), + To: timestamppb.New(now.Add(time.Hour)), + }, + Aggs: []*seqproxyapi.AggQuery{{ + Field: "duration", + GroupBy: "service", + Func: seqproxyapi.AggFunc_AGG_FUNC_AVG, + Interval: &interval, + }}, + }, + want: &search.StreamSearchRequest{ + Query: "message:ok | stats avg(duration) by (service) interval(1m)", + From: seq.TimeToMID(now), + To: seq.TimeToMID(now.Add(time.Hour)), + Agg: &search.AggQuery{ + Field: "duration", + GroupBy: "service", + Func: seq.AggFuncAvg, + Interval: seq.DurationToMID(1 * time.Minute), + }, + }, + }, + { + name: "invalid_query", + req: &seqproxyapi.ComplexSearchRequest{ + Query: &seqproxyapi.SearchQuery{ + Query: "message:)", + From: timestamppb.New(now), + To: timestamppb.New(now.Add(time.Hour)), + }, + Size: 10, + }, + wantErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + got, err := buildStreamSearchReqFromComplexSearchReq(tc.req) + require.Equal(t, tc.wantErr, err != nil) + if tc.wantErr { + return + } + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } +} diff --git a/proxyapi/ingestor_config.go b/proxyapi/ingestor_config.go index ed00552fe..960b57690 100644 --- a/proxyapi/ingestor_config.go +++ b/proxyapi/ingestor_config.go @@ -19,6 +19,8 @@ type APIConfig struct { // GatewayAddr is grpc-gateway client address. Used for debugging purposes. GatewayAddr string AsyncSearchMaxDocumentsPerRequest int64 + // If true, suitable ComplexSearch queries will be served through stream search implementation. + TryStreamSearch bool } type IngestorConfig struct { From 0a3b18e5c6f824c484fbe29cf0d1c18626071c2b Mon Sep 17 00:00:00 2001 From: Daniil Forshev Date: Wed, 19 Aug 2026 12:15:09 +0500 Subject: [PATCH 2/4] feat(stream search): support quantile agg func --- api/seqproxyapi/v1/seq_proxy_api.proto | 3 +- api/storeapi/store_api.proto | 3 +- pkg/seqproxyapi/v1/marshaler.go | 108 ++++---- pkg/seqproxyapi/v1/marshaler_test.go | 20 +- pkg/seqproxyapi/v1/seq_proxy_api.pb.go | 290 ++++++++++---------- pkg/storeapi/store_api.pb.go | 156 ++++++----- proxy/search/stream_search.go | 2 +- proxyapi/grpc_complex_search.go | 5 +- proxyapi/grpc_stream_search.go | 4 +- query/encoding/encoding.go | 25 ++ query/encoding/encoding_test.go | 21 ++ query/exec/aggregator.go | 43 ++- query/exec/aggregator_test.go | 112 +++++--- query/exec/datasource.go | 1 + query/record.go | 5 +- storeapi/grpc_stream_search.go | 1 + tests/integration_tests/integration_test.go | 51 +++- 17 files changed, 511 insertions(+), 339 deletions(-) diff --git a/api/seqproxyapi/v1/seq_proxy_api.proto b/api/seqproxyapi/v1/seq_proxy_api.proto index fe1f8f7d3..1f3a90464 100644 --- a/api/seqproxyapi/v1/seq_proxy_api.proto +++ b/api/seqproxyapi/v1/seq_proxy_api.proto @@ -497,8 +497,7 @@ enum DataType { INT32 = 6; INT64 = 7; FLOAT64 = 8; - // TODO: later we will need array data types, such as: - // StringArray, Uin64Array, Float64Array etc. + FLOAT64_ARRAY = 9; } message ResponseData { diff --git a/api/storeapi/store_api.proto b/api/storeapi/store_api.proto index d388442b9..a1a8aba37 100644 --- a/api/storeapi/store_api.proto +++ b/api/storeapi/store_api.proto @@ -321,8 +321,7 @@ enum DataType { INT32 = 6; INT64 = 7; FLOAT64 = 8; - // TODO: later we will need array data types, such as: - // StringArray, Uin64Array, Float64Array etc. + FLOAT64_ARRAY = 9; } message ResponseData { diff --git a/pkg/seqproxyapi/v1/marshaler.go b/pkg/seqproxyapi/v1/marshaler.go index b670a134a..61fb8d3ed 100644 --- a/pkg/seqproxyapi/v1/marshaler.go +++ b/pkg/seqproxyapi/v1/marshaler.go @@ -262,71 +262,75 @@ func (i *AsyncSearchesListItem) MarshalJSON() ([]byte, error) { return pbMarshaller.Marshal(i) } -// streamSearchColumns is the number of columns carried by a record produced by -// StreamSearch. Both document and aggregation records use 3 cells, so the -// layout is distinguished by the third cell's content rather than its count: -// - documents: [id, time(uint64 nanoseconds), data] — data is a JSON document; -// - aggregation buckets: [key, value(float64), ts(uint64 nanoseconds)] — ts is -// a little-endian uint64, never valid JSON. -const streamSearchColumns = 3 +// streamSearchDocColumns is the number of columns carried by a document record +// produced by StreamSearch: [id, time, data]. +const streamSearchDocColumns = 3 + +// streamSearchAggColumns is the number of columns carried by an aggregation +// record: [key, value, ts, quantiles]. quantiles holds the computed quantile +// values (a little-endian float64 array); it is empty for non-quantile +// aggregations. The record kind is told from the column count, so documents +// (3 cells) and aggregations (4 cells) never collide. +const streamSearchAggColumns = 4 // MarshalJSON formats a StreamSearch record into a human-readable JSON array. +// The record kind is distinguished by the column count: // -// Document and aggregation records share the same 3-cell width, so the record -// kind is inferred from the third cell: when it holds a valid JSON document the -// record is treated as a document, otherwise as an aggregation bucket. -// -// - documents: [id, time(nanoseconds, little-endian uint64), data] where data -// is inlined as a json.RawMessage and time is rendered as an RFC3339Nano -// string; -// - aggregation buckets: [key, value(little-endian float64), -// ts(nanoseconds, little-endian uint64)] where value is rendered as a number -// (NaN/Inf become quoted strings) and ts is rendered as an RFC3339Nano -// string (empty when the bucket has no timestamp). +// - documents (3 cells): [id, time(nanoseconds, little-endian uint64), data] +// where data is inlined as a json.RawMessage and time is rendered as an +// RFC3339Nano string; +// - aggregation buckets (4 cells): [key, value(little-endian float64), +// ts(nanoseconds, little-endian uint64), quantiles(little-endian float64 +// array)] where value is rendered as a number (NaN/Inf become quoted +// strings), ts is rendered as an RFC3339Nano string (empty when the bucket +// has no timestamp) and quantiles is rendered as an array of numbers +// (empty when no quantiles were requested). // // For any other layout the raw cells are emitted as-is (base64 for bytes). func (r *Record) MarshalJSON() ([]byte, error) { cells := r.GetRawData() switch len(cells) { - case streamSearchColumns: - // Both layouts use 3 cells. A document's third cell is a JSON document; - // an aggregation bucket's third cell is an 8-byte uint64 timestamp, - // which is never valid JSON. - if json.Valid(cells[2]) { - // cells[1] is a little-endian uint64 storing the document MID (nanoseconds). - var ts time.Time - if len(cells[1]) == 8 { - ts = seq.MID(encoding.Uint64FromBytes(cells[1])).Time() - } - return json.Marshal([]any{ - string(cells[0]), // id - ts.UTC().Format(time.RFC3339Nano), - json.RawMessage(cells[2]), // data, inlined as JSON - }) - } - // cells[1] is a little-endian float64 storing the aggregation value. - var value float64 + case streamSearchDocColumns: + // cells[1] is a little-endian uint64 storing the document MID (nanoseconds). + var ts time.Time if len(cells[1]) == 8 { - value = encoding.Float64FromBytes(cells[1]) - } - val := json.RawMessage(strconv.FormatFloat(value, 'f', -1, 64)) - if math.IsNaN(value) || math.IsInf(value, 0) { - val = json.RawMessage(strconv.Quote(string(val))) - } - // cells[2] is a little-endian uint64 storing the bucket MID (nanoseconds). - // A zero MID (no timestamp) is rendered as an empty string. - formattedTime := "" - if len(cells[2]) == 8 { - if ns := encoding.Uint64FromBytes(cells[2]); ns != 0 { - formattedTime = time.Unix(0, int64(ns)).UTC().Format(time.RFC3339Nano) - } + ts = seq.MID(encoding.Uint64FromBytes(cells[1])).Time() } return json.Marshal([]any{ - string(cells[0]), // key - val, // value - formattedTime, // ts + string(cells[0]), // id + ts.UTC().Format(time.RFC3339Nano), + json.RawMessage(cells[2]), // data, inlined as JSON }) + case streamSearchAggColumns: + return marshalAggRecord(cells) default: return json.Marshal(cells) } } + +// marshalAggRecord renders an aggregation record: [key, value, ts, quantiles]. +func marshalAggRecord(cells [][]byte) ([]byte, error) { + // cells[1] is a little-endian float64 storing the aggregation value. + var value float64 + if len(cells[1]) == 8 { + value = encoding.Float64FromBytes(cells[1]) + } + val := json.RawMessage(strconv.FormatFloat(value, 'f', -1, 64)) + if math.IsNaN(value) || math.IsInf(value, 0) { + val = json.RawMessage(strconv.Quote(string(val))) + } + // cells[2] is a little-endian uint64 storing the bucket MID (nanoseconds). + // A zero MID (no timestamp) is rendered as an empty string. + formattedTime := "" + if len(cells[2]) == 8 { + if ns := encoding.Uint64FromBytes(cells[2]); ns != 0 { + formattedTime = time.Unix(0, int64(ns)).UTC().Format(time.RFC3339Nano) + } + } + return json.Marshal([]any{ + string(cells[0]), // key + val, // value + formattedTime, // ts + encoding.Float64ArrayFromBytes(cells[3]), // quantiles + }) +} diff --git a/pkg/seqproxyapi/v1/marshaler_test.go b/pkg/seqproxyapi/v1/marshaler_test.go index 790a74815..a1a9e370c 100644 --- a/pkg/seqproxyapi/v1/marshaler_test.go +++ b/pkg/seqproxyapi/v1/marshaler_test.go @@ -172,11 +172,26 @@ func TestRecordMarshalJSON(t *testing.T) { []byte("service-a"), encoding.Float64ToBytes(42.5), encoding.Uint64ToBytes(uint64(tsNs)), + encoding.Float64ArrayToBytes(nil), // no quantiles }} raw, err := json.Marshal(rec) r.NoError(err) - r.Equal(`["service-a",42.5,"2025-07-08T10:19:08.742Z"]`, string(raw)) + r.Equal(`["service-a",42.5,"2025-07-08T10:19:08.742Z",[]]`, string(raw)) + }) + + t.Run("aggregation bucket with quantiles", func(t *testing.T) { + tsNs := time.Date(2025, 7, 8, 10, 19, 8, 742000000, time.UTC).UnixNano() + rec := &Record{RawData: [][]byte{ + []byte("service-a"), + encoding.Float64ToBytes(42.5), + encoding.Uint64ToBytes(uint64(tsNs)), + encoding.Float64ArrayToBytes([]float64{5.5, 9.1}), + }} + + raw, err := json.Marshal(rec) + r.NoError(err) + r.Equal(`["service-a",42.5,"2025-07-08T10:19:08.742Z",[5.5,9.1]]`, string(raw)) }) t.Run("aggregation bucket with NaN", func(t *testing.T) { @@ -184,11 +199,12 @@ func TestRecordMarshalJSON(t *testing.T) { []byte("service-a"), encoding.Float64ToBytes(math.NaN()), make([]byte, 8), + encoding.Float64ArrayToBytes(nil), }} raw, err := json.Marshal(rec) r.NoError(err) - r.Equal(`["service-a","NaN",""]`, string(raw)) + r.Equal(`["service-a","NaN","",[]]`, string(raw)) }) t.Run("unknown layout falls back to raw bytes", func(t *testing.T) { diff --git a/pkg/seqproxyapi/v1/seq_proxy_api.pb.go b/pkg/seqproxyapi/v1/seq_proxy_api.pb.go index 904790ab2..3c9489236 100644 --- a/pkg/seqproxyapi/v1/seq_proxy_api.pb.go +++ b/pkg/seqproxyapi/v1/seq_proxy_api.pb.go @@ -299,15 +299,16 @@ func (ControlAction) EnumDescriptor() ([]byte, []int) { type DataType int32 const ( - DataType_BYTES DataType = 0 - DataType_SEQ_ID DataType = 1 - DataType_RAW_DOCUMENT DataType = 2 - DataType_STRING DataType = 3 - DataType_UINT32 DataType = 4 - DataType_UINT64 DataType = 5 - DataType_INT32 DataType = 6 - DataType_INT64 DataType = 7 - DataType_FLOAT64 DataType = 8 + DataType_BYTES DataType = 0 + DataType_SEQ_ID DataType = 1 + DataType_RAW_DOCUMENT DataType = 2 + DataType_STRING DataType = 3 + DataType_UINT32 DataType = 4 + DataType_UINT64 DataType = 5 + DataType_INT32 DataType = 6 + DataType_INT64 DataType = 7 + DataType_FLOAT64 DataType = 8 + DataType_FLOAT64_ARRAY DataType = 9 ) // Enum value maps for DataType. @@ -322,17 +323,19 @@ var ( 6: "INT32", 7: "INT64", 8: "FLOAT64", + 9: "FLOAT64_ARRAY", } DataType_value = map[string]int32{ - "BYTES": 0, - "SEQ_ID": 1, - "RAW_DOCUMENT": 2, - "STRING": 3, - "UINT32": 4, - "UINT64": 5, - "INT32": 6, - "INT64": 7, - "FLOAT64": 8, + "BYTES": 0, + "SEQ_ID": 1, + "RAW_DOCUMENT": 2, + "STRING": 3, + "UINT32": 4, + "UINT64": 5, + "INT32": 6, + "INT64": 7, + "FLOAT64": 8, + "FLOAT64_ARRAY": 9, } ) @@ -3906,133 +3909,134 @@ var file_seqproxyapi_v1_seq_proxy_api_proto_rawDesc = string([]byte{ 0x12, 0x1e, 0x0a, 0x1a, 0x43, 0x4f, 0x4e, 0x54, 0x52, 0x4f, 0x4c, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x10, 0x01, 0x12, 0x0a, - 0x0a, 0x06, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x02, 0x2a, 0x7a, 0x0a, 0x08, 0x44, 0x61, - 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, - 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x51, 0x5f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, - 0x0c, 0x52, 0x41, 0x57, 0x5f, 0x44, 0x4f, 0x43, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, - 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x55, - 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x49, 0x4e, 0x54, 0x36, - 0x34, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x06, 0x12, 0x09, - 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, - 0x41, 0x54, 0x36, 0x34, 0x10, 0x08, 0x32, 0x97, 0x0e, 0x0a, 0x0b, 0x53, 0x65, 0x71, 0x50, 0x72, - 0x6f, 0x78, 0x79, 0x41, 0x70, 0x69, 0x12, 0x5b, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, 0x2f, 0x73, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x12, 0x78, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x12, 0x24, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x73, 0x65, 0x71, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x63, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x76, 0x0a, - 0x0e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x25, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, - 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x70, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x23, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, - 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x65, 0x71, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, - 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f, 0x68, 0x69, - 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x54, 0x0a, 0x05, 0x46, 0x65, 0x74, 0x63, 0x68, - 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x0a, 0x06, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x02, 0x2a, 0x8d, 0x01, 0x0a, 0x08, 0x44, + 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x59, 0x54, 0x45, 0x53, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x51, 0x5f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x10, + 0x0a, 0x0c, 0x52, 0x41, 0x57, 0x5f, 0x44, 0x4f, 0x43, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, + 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, + 0x55, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x49, 0x4e, 0x54, + 0x36, 0x34, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x06, 0x12, + 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, + 0x4f, 0x41, 0x54, 0x36, 0x34, 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x41, 0x54, + 0x36, 0x34, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x09, 0x32, 0x97, 0x0e, 0x0a, 0x0b, 0x53, + 0x65, 0x71, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x41, 0x70, 0x69, 0x12, 0x5b, 0x0a, 0x06, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, + 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x78, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x24, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, - 0x3a, 0x01, 0x2a, 0x22, 0x06, 0x2f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x30, 0x01, 0x12, 0x5d, 0x0a, - 0x07, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x0b, 0x12, 0x09, 0x2f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x58, 0x0a, 0x06, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, - 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, - 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x09, 0x12, 0x07, 0x2f, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x5d, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, 0x2f, 0x65, 0x78, 0x70, - 0x6f, 0x72, 0x74, 0x30, 0x01, 0x12, 0x81, 0x01, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, - 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x27, 0x2e, 0x73, 0x65, 0x71, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, - 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x12, 0x99, 0x01, 0x0a, 0x16, 0x46, 0x65, - 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, - 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, - 0x66, 0x65, 0x74, 0x63, 0x68, 0x12, 0x94, 0x01, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, + 0x22, 0x0f, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x12, 0x76, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x73, 0x65, 0x71, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x70, 0x0a, 0x0c, 0x47, 0x65, 0x74, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x23, 0x2e, 0x73, 0x65, 0x71, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, + 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, + 0x0a, 0x2f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x54, 0x0a, 0x05, 0x46, + 0x65, 0x74, 0x63, 0x68, 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x11, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x0b, 0x3a, 0x01, 0x2a, 0x22, 0x06, 0x2f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x30, + 0x01, 0x12, 0x5d, 0x0a, 0x07, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x2e, 0x73, + 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, + 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, + 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, + 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, + 0x12, 0x58, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x09, 0x12, 0x07, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x5d, 0x0a, 0x06, 0x45, 0x78, + 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, + 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x30, 0x01, 0x12, 0x81, 0x01, 0x0a, 0x10, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x27, + 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, + 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, + 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x61, + 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x12, 0x99, 0x01, + 0x0a, 0x16, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, + 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, + 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, + 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, + 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x65, 0x73, 0x2f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x12, 0x94, 0x01, 0x0a, 0x11, 0x43, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, + 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x65, 0x71, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, + 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x22, 0x22, 0x2f, 0x61, + 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, 0x7b, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x12, 0x8d, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, + 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x29, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1d, 0x2a, 0x1b, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x7d, + 0x12, 0x92, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2b, 0x2e, 0x73, 0x65, 0x71, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, + 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, + 0x14, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, + 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x82, 0x01, 0x0a, 0x11, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x28, 0x2e, 0x73, 0x65, - 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, - 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, - 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x22, 0x22, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, - 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x8d, 0x01, 0x0a, - 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x12, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, - 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x2a, - 0x1b, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, - 0x2f, 0x7b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x92, 0x01, 0x0a, - 0x14, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, - 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2b, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, - 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x61, 0x73, - 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, 0x6c, 0x69, 0x73, - 0x74, 0x12, 0x82, 0x01, 0x0a, 0x11, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, - 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, - 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, - 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x61, - 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x30, 0x01, 0x12, 0x78, 0x0a, 0x0c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x23, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, - 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x65, - 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x28, 0x01, 0x30, 0x01, - 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, - 0x7a, 0x6f, 0x6e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x71, 0x2d, 0x64, 0x62, 0x2f, 0x70, - 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x3b, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, + 0x6f, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, 0x2a, + 0x22, 0x16, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, + 0x73, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x30, 0x01, 0x12, 0x78, 0x0a, 0x0c, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x23, 0x2e, 0x73, 0x65, 0x71, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x24, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, + 0x22, 0x0e, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x28, 0x01, 0x30, 0x01, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x71, 0x2d, + 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, + 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( diff --git a/pkg/storeapi/store_api.pb.go b/pkg/storeapi/store_api.pb.go index 83679ae92..06e6170fd 100644 --- a/pkg/storeapi/store_api.pb.go +++ b/pkg/storeapi/store_api.pb.go @@ -302,15 +302,16 @@ func (ControlAction) EnumDescriptor() ([]byte, []int) { type DataType int32 const ( - DataType_BYTES DataType = 0 - DataType_SEQ_ID DataType = 1 - DataType_RAW_DOCUMENT DataType = 2 - DataType_STRING DataType = 3 - DataType_UINT32 DataType = 4 - DataType_UINT64 DataType = 5 - DataType_INT32 DataType = 6 - DataType_INT64 DataType = 7 - DataType_FLOAT64 DataType = 8 + DataType_BYTES DataType = 0 + DataType_SEQ_ID DataType = 1 + DataType_RAW_DOCUMENT DataType = 2 + DataType_STRING DataType = 3 + DataType_UINT32 DataType = 4 + DataType_UINT64 DataType = 5 + DataType_INT32 DataType = 6 + DataType_INT64 DataType = 7 + DataType_FLOAT64 DataType = 8 + DataType_FLOAT64_ARRAY DataType = 9 ) // Enum value maps for DataType. @@ -325,17 +326,19 @@ var ( 6: "INT32", 7: "INT64", 8: "FLOAT64", + 9: "FLOAT64_ARRAY", } DataType_value = map[string]int32{ - "BYTES": 0, - "SEQ_ID": 1, - "RAW_DOCUMENT": 2, - "STRING": 3, - "UINT32": 4, - "UINT64": 5, - "INT32": 6, - "INT64": 7, - "FLOAT64": 8, + "BYTES": 0, + "SEQ_ID": 1, + "RAW_DOCUMENT": 2, + "STRING": 3, + "UINT32": 4, + "UINT64": 5, + "INT32": 6, + "INT64": 7, + "FLOAT64": 8, + "FLOAT64_ARRAY": 9, } ) @@ -3339,65 +3342,66 @@ var file_storeapi_store_api_proto_rawDesc = string([]byte{ 0x4f, 0x4c, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, - 0x02, 0x2a, 0x7a, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, - 0x05, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x51, 0x5f, - 0x49, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x41, 0x57, 0x5f, 0x44, 0x4f, 0x43, 0x55, - 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, - 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x04, 0x12, 0x0a, - 0x0a, 0x06, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, - 0x54, 0x33, 0x32, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x07, - 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x36, 0x34, 0x10, 0x08, 0x32, 0xe7, 0x05, - 0x0a, 0x08, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x41, 0x70, 0x69, 0x12, 0x32, 0x0a, 0x04, 0x42, 0x75, - 0x6c, 0x6b, 0x12, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x33, - 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, - 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x16, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, - 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, - 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x02, 0x2a, 0x8d, 0x01, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, + 0x0a, 0x05, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x51, + 0x5f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x41, 0x57, 0x5f, 0x44, 0x4f, 0x43, + 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, + 0x47, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x04, 0x12, + 0x0a, 0x0a, 0x06, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x49, + 0x4e, 0x54, 0x33, 0x32, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, + 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x36, 0x34, 0x10, 0x08, 0x12, 0x11, + 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x36, 0x34, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, + 0x09, 0x32, 0xe7, 0x05, 0x0a, 0x08, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x41, 0x70, 0x69, 0x12, 0x32, + 0x0a, 0x04, 0x42, 0x75, 0x6c, 0x6b, 0x12, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6c, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x00, 0x12, 0x33, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x12, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1c, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x16, 0x46, 0x65, + 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x11, 0x43, - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, - 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, - 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x54, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x73, - 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, - 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x05, 0x46, 0x65, 0x74, 0x63, 0x68, 0x12, - 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x44, - 0x61, 0x74, 0x61, 0x22, 0x00, 0x30, 0x01, 0x12, 0x33, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0c, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x18, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x73, - 0x65, 0x71, 0x2d, 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x61, - 0x70, 0x69, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, + 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x54, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, + 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, + 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x14, 0x47, + 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, + 0x69, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, + 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, + 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x05, 0x46, 0x65, + 0x74, 0x63, 0x68, 0x12, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x69, 0x6e, + 0x61, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x22, 0x00, 0x30, 0x01, 0x12, 0x33, 0x0a, 0x06, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x49, 0x0a, 0x0c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, + 0x63, 0x68, 0x2f, 0x73, 0x65, 0x71, 0x2d, 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x61, 0x70, 0x69, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x61, 0x70, 0x69, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( diff --git a/proxy/search/stream_search.go b/proxy/search/stream_search.go index 546a3482c..661349e65 100644 --- a/proxy/search/stream_search.go +++ b/proxy/search/stream_search.go @@ -83,7 +83,7 @@ func (si *Ingestor) StreamSearch( var mergedStream query.RecordProducer if sr.Agg != nil { - mergedStream = exec.NewDistributedAggregator(producers, sr.Agg.Func) + mergedStream = exec.NewDistributedAggregator(producers, sr.Agg.Func, sr.Agg.Quantiles) } else { const seqIdColIdx = 0 mergedDocsStream := exec.NewNMergedProducers(producers, seqIdColIdx, "", query.DataTypeSeqID, sr.Order) diff --git a/proxyapi/grpc_complex_search.go b/proxyapi/grpc_complex_search.go index ffce184d7..e46a4d69c 100644 --- a/proxyapi/grpc_complex_search.go +++ b/proxyapi/grpc_complex_search.go @@ -190,6 +190,9 @@ func readAggregations(storesStream query.RecordProducer) []*seqproxyapi.Aggregat if ts := r.Vals[2].Decoded().(uint64); ts != consts.DummyMID { bucket.Ts = timestamppb.New(seq.MID(ts).Time()) } + if quantiles := r.Vals[3].Decoded().([]float64); len(quantiles) > 0 { + bucket.Quantiles = quantiles + } buckets = append(buckets, bucket) } return []*seqproxyapi.Aggregation{{Buckets: buckets}} @@ -202,7 +205,7 @@ func shouldTryStreamSearch(tryStreamSearch bool, req *seqproxyapi.ComplexSearchR if req.Hist != nil || len(req.Aggs) > 1 { return false } - if len(req.Aggs) == 1 && (req.Aggs[0].Func == seq.AggFuncQuantile || req.Aggs[0].Func == seq.AggFuncUniqueCount) { + if len(req.Aggs) == 1 && req.Aggs[0].Func == seq.AggFuncUniqueCount { return false } return true diff --git a/proxyapi/grpc_stream_search.go b/proxyapi/grpc_stream_search.go index 34e1d9fcd..f7e1be69b 100644 --- a/proxyapi/grpc_stream_search.go +++ b/proxyapi/grpc_stream_search.go @@ -59,7 +59,7 @@ func (g *grpcV1) StreamSearch(stream seqproxyapi.SeqProxyApi_StreamSearchServer) return status.Error(codes.InvalidArgument, fmt.Sprintf("error parsing query: %s", err.Error())) } - if searchReq.Agg != nil && (searchReq.Agg.Func == seq.AggFuncQuantile || searchReq.Agg.Func == seq.AggFuncUniqueCount) { + if searchReq.Agg != nil && searchReq.Agg.Func == seq.AggFuncUniqueCount { // TODO: support all agg funcs return status.Error(codes.InvalidArgument, `unsupported aggregate function`) } @@ -285,6 +285,7 @@ func aggsTyping() []*seqproxyapi.Typing { {Title: "key", Type: seqproxyapi.DataType_STRING}, {Title: "value", Type: seqproxyapi.DataType_FLOAT64}, {Title: "ts", Type: seqproxyapi.DataType_UINT64}, + {Title: "quantiles", Type: seqproxyapi.DataType_FLOAT64_ARRAY}, } } @@ -308,6 +309,7 @@ func aggToRecord(r *query.Record) *seqproxyapi.Record { r.Vals[0].RawData(), // key r.Vals[1].RawData(), // value r.Vals[2].RawData(), // ts + r.Vals[3].RawData(), // quantiles }, } } diff --git a/query/encoding/encoding.go b/query/encoding/encoding.go index 21da3b4cc..e3c00f606 100644 --- a/query/encoding/encoding.go +++ b/query/encoding/encoding.go @@ -77,3 +77,28 @@ func Float64ToBytes(val float64) []byte { func Float64FromBytes(b []byte) float64 { return math.Float64frombits(binary.LittleEndian.Uint64(b)) } + +// Float64ArrayToBytes encodes a float64 slice as an 8-byte little-endian length +// prefix followed by the little-endian raw bytes of each element. An empty or +// nil slice is encoded as a zero length (8 zero bytes). +func Float64ArrayToBytes(v []float64) []byte { + b := make([]byte, 8+len(v)*8) + binary.LittleEndian.PutUint64(b, uint64(len(v))) + for i, f := range v { + binary.LittleEndian.PutUint64(b[8+i*8:], math.Float64bits(f)) + } + return b +} + +// Float64ArrayFromBytes is the inverse of Float64ArrayToBytes. +func Float64ArrayFromBytes(b []byte) []float64 { + if len(b) < 8 { + return nil + } + n := binary.LittleEndian.Uint64(b) + v := make([]float64, n) + for i := range n { + v[i] = math.Float64frombits(binary.LittleEndian.Uint64(b[8+i*8:])) + } + return v +} diff --git a/query/encoding/encoding_test.go b/query/encoding/encoding_test.go index fba6b8405..e663be197 100644 --- a/query/encoding/encoding_test.go +++ b/query/encoding/encoding_test.go @@ -115,3 +115,24 @@ func TestEncodedByteLengths(t *testing.T) { assert.Len(t, Int32ToBytes(1), 4, "Int32") assert.Len(t, Float64ToBytes(1), 8, "Float64") } + +func TestFloat64Array(t *testing.T) { + cases := [][]float64{ + nil, + {}, + {0}, + {1, -1, 42.5, math.Pi, math.MaxFloat64, math.SmallestNonzeroFloat64, -math.MaxFloat64}, + } + for _, v := range cases { + // nil and an empty slice both encode as a zero length and decode to an + // empty (non-nil) slice, so compare elements rather than nil-ness. + assert.ElementsMatch(t, v, Float64ArrayFromBytes(Float64ArrayToBytes(v))) + } + assert.Len(t, Float64ArrayFromBytes(Float64ArrayToBytes(nil)), 0) +} + +func TestFloat64ArrayByteLength(t *testing.T) { + assert.Len(t, Float64ArrayToBytes(nil), 8) + assert.Len(t, Float64ArrayToBytes([]float64{}), 8) + assert.Len(t, Float64ArrayToBytes([]float64{1, 2, 3}), 8+3*8) +} diff --git a/query/exec/aggregator.go b/query/exec/aggregator.go index 60f594bd3..fdb1afcfa 100644 --- a/query/exec/aggregator.go +++ b/query/exec/aggregator.go @@ -27,20 +27,14 @@ type aggKey struct { ts uint64 } -type AggSamples struct { - Min float64 - Max float64 - Sum float64 - Total uint64 -} - type DistributedAggregator struct { state ExecutorState inputs []query.RecordProducer - aggFunc seq.AggFunc + aggFunc seq.AggFunc + quantiles []float64 - buckets map[aggKey]AggSamples + buckets map[aggKey]*seq.SamplesContainer sortingBuf []*query.Record curIdx int @@ -52,11 +46,13 @@ type DistributedAggregator struct { func NewDistributedAggregator( inputs []query.RecordProducer, aggFunc seq.AggFunc, + quantiles []float64, ) *DistributedAggregator { return &DistributedAggregator{ inputs: inputs, aggFunc: aggFunc, - buckets: make(map[aggKey]AggSamples), + quantiles: quantiles, + buckets: make(map[aggKey]*seq.SamplesContainer), sortingBuf: make([]*query.Record, 0), } } @@ -75,9 +71,13 @@ func (a *DistributedAggregator) Next() *query.Record { token: r.Vals[0].Decoded().(string), ts: r.Vals[6].Decoded().(uint64), } - s := a.buckets[key] - if s.Total == 0 { + s, exists := a.buckets[key] + if !exists { + s = seq.NewSamplesContainers() + } + + if !exists { s.Min = r.Vals[1].Decoded().(float64) s.Max = r.Vals[2].Decoded().(float64) } else { @@ -86,7 +86,13 @@ func (a *DistributedAggregator) Next() *query.Record { } s.Sum += r.Vals[3].Decoded().(float64) - s.Total += r.Vals[4].Decoded().(uint64) + s.Total += int64(r.Vals[4].Decoded().(uint64)) + + if a.aggFunc == seq.AggFuncQuantile { + for _, v := range r.Vals[7].Decoded().([]float64) { + s.InsertSample(v) + } + } a.buckets[key] = s } @@ -98,6 +104,7 @@ func (a *DistributedAggregator) Next() *query.Record { if a.state == ExecutorStateProcessingData { for key, bucket := range a.buckets { var value float64 + var quantiles []float64 // TODO: support all aggregate functions switch a.aggFunc { @@ -113,6 +120,15 @@ func (a *DistributedAggregator) Next() *query.Record { if bucket.Total != 0 { value = bucket.Sum / float64(bucket.Total) } + case seq.AggFuncQuantile: + if len(a.quantiles) == 0 { + panic(fmt.Errorf("BUG: empty quantiles")) + } + quantiles = make([]float64, 0, len(a.quantiles)) + for _, q := range a.quantiles { + quantiles = append(quantiles, bucket.Quantile(q)) + } + value = quantiles[0] default: panic(fmt.Errorf("unimplemented aggregation func")) } @@ -121,6 +137,7 @@ func (a *DistributedAggregator) Next() *query.Record { query.NewRecordVals(query.DataTypeString, []byte(key.token)), query.NewRecordVals(query.DataTypeFloat64, encoding.Float64ToBytes(value)), query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(key.ts)), + query.NewRecordVals(query.DataTypeFloat64Array, encoding.Float64ArrayToBytes(quantiles)), })) } diff --git a/query/exec/aggregator_test.go b/query/exec/aggregator_test.go index fb075ea69..43b17ea47 100644 --- a/query/exec/aggregator_test.go +++ b/query/exec/aggregator_test.go @@ -12,18 +12,18 @@ import ( func TestDistributedAggregator_Count(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0), - makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0), - makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0), + makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}), } input1 := testProducer{data: records1} input2 := testProducer{data: records2} - agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncCount) + agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncCount, nil) results := collectRecords(agg) @@ -36,18 +36,18 @@ func TestDistributedAggregator_Count(t *testing.T) { func TestDistributedAggregator_Sum(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0), - makeAggInputRecord("key2", 30.0, 30.0, 30.0, 1, 0), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 30.0, 30.0, 30.0, 1, 0, []float64{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 20.0, 20.0, 20.0, 1, 0), - makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0), + makeAggInputRecord("key1", 20.0, 20.0, 20.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}), } input1 := testProducer{data: records1} input2 := testProducer{data: records2} - agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncSum) + agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncSum, nil) results := collectRecords(agg) @@ -60,18 +60,18 @@ func TestDistributedAggregator_Sum(t *testing.T) { func TestDistributedAggregator_Min(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0), - makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0), + makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0), - makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}), } input1 := testProducer{data: records1} input2 := testProducer{data: records2} - agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncMin) + agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncMin, nil) results := collectRecords(agg) @@ -84,18 +84,18 @@ func TestDistributedAggregator_Min(t *testing.T) { func TestDistributedAggregator_Max(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0), - makeAggInputRecord("key2", 30.0, 30.0, 30.0, 1, 0), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 30.0, 30.0, 30.0, 1, 0, []float64{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 50.0, 50.0, 50.0, 1, 0), - makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0), + makeAggInputRecord("key1", 50.0, 50.0, 50.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}), } input1 := testProducer{data: records1} input2 := testProducer{data: records2} - agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncMax) + agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncMax, nil) results := collectRecords(agg) @@ -108,18 +108,18 @@ func TestDistributedAggregator_Max(t *testing.T) { func TestDistributedAggregator_Avg(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0), - makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0), - makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0), + makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}), + makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}), } input1 := testProducer{data: records1} input2 := testProducer{data: records2} - agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncAvg) + agg := NewDistributedAggregator([]query.RecordProducer{&input1, &input2}, seq.AggFuncAvg, nil) results := collectRecords(agg) @@ -134,7 +134,7 @@ func TestDistributedAggregator_EmptyInput(t *testing.T) { var records []*query.Record input := testProducer{data: records} - agg := NewDistributedAggregator([]query.RecordProducer{&input}, seq.AggFuncCount) + agg := NewDistributedAggregator([]query.RecordProducer{&input}, seq.AggFuncCount, nil) results := collectRecords(agg) @@ -144,16 +144,16 @@ func TestDistributedAggregator_EmptyInput(t *testing.T) { func TestDistributedAggregatorSumTimeseries(t *testing.T) { const ts1, ts2 uint64 = 1_000_000_000, 2_000_000_000 in1 := &testProducer{data: []*query.Record{ - makeAggInputRecord("foo", 2, 2, 2, 1, ts1), - makeAggInputRecord("foo", 3, 3, 3, 1, ts2), - makeAggInputRecord("bar", 5, 5, 5, 1, ts1), + makeAggInputRecord("foo", 2, 2, 2, 1, ts1, []float64{}), + makeAggInputRecord("foo", 3, 3, 3, 1, ts2, []float64{}), + makeAggInputRecord("bar", 5, 5, 5, 1, ts1, []float64{}), }} in2 := &testProducer{data: []*query.Record{ - makeAggInputRecord("foo", 4, 4, 4, 1, ts1), // same bin as in1[0] -> merged sum 6 - makeAggInputRecord("baz", 7, 7, 7, 1, ts2), + makeAggInputRecord("foo", 4, 4, 4, 1, ts1, []float64{}), // same bin as in1[0] -> merged sum 6 + makeAggInputRecord("baz", 7, 7, 7, 1, ts2, []float64{}), }} - a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncSum) + a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncSum, nil) got := decodeAggOutputs(t, a) // Sorted by ts ASC, then value DESC, then name ASC. @@ -171,15 +171,15 @@ func TestDistributedAggregatorSumTimeseries(t *testing.T) { func TestDistributedAggregatorMinMergeAcrossShards(t *testing.T) { const ts uint64 = 0 // no interval: all samples collapse into ts=0 in1 := &testProducer{data: []*query.Record{ - makeAggInputRecord("a", 5, 50, 0, 1, ts), - makeAggInputRecord("b", 1, 10, 0, 1, ts), + makeAggInputRecord("a", 5, 50, 0, 1, ts, []float64{}), + makeAggInputRecord("b", 1, 10, 0, 1, ts, []float64{}), }} in2 := &testProducer{data: []*query.Record{ - makeAggInputRecord("a", 2, 60, 0, 1, ts), // min(5,2)=2, max(50,60)=60 - makeAggInputRecord("c", 9, 9, 0, 1, ts), + makeAggInputRecord("a", 2, 60, 0, 1, ts, []float64{}), // min(5,2)=2, max(50,60)=60 + makeAggInputRecord("c", 9, 9, 0, 1, ts, []float64{}), }} - a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncMin) + a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncMin, nil) got := decodeAggOutputs(t, a) // Same ts (0); Min sorts by value ASC, then name ASC. @@ -195,13 +195,13 @@ func TestDistributedAggregatorMinMergeAcrossShards(t *testing.T) { // interval (ts=0 for every input) aggregation merges solely by token. func TestDistributedAggregatorNoIntervalCollapsesByToken(t *testing.T) { in1 := &testProducer{data: []*query.Record{ - makeAggInputRecord("foo", 0, 0, 10, 2, 0), + makeAggInputRecord("foo", 0, 0, 10, 2, 0, []float64{}), }} in2 := &testProducer{data: []*query.Record{ - makeAggInputRecord("foo", 0, 0, 5, 3, 0), + makeAggInputRecord("foo", 0, 0, 5, 3, 0, []float64{}), }} - a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncCount) + a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncCount, nil) got := decodeAggOutputs(t, a) // count = total = 2 + 3 = 5. @@ -211,10 +211,37 @@ func TestDistributedAggregatorNoIntervalCollapsesByToken(t *testing.T) { assert.Equal(t, want, got) } +func TestDistributedAggregator_Quantile(t *testing.T) { + const ts uint64 = 0 + in1 := &testProducer{data: []*query.Record{ + makeAggInputRecord("key", 1, 5, 0, 0, ts, []float64{1, 2, 3, 4, 5}), + }} + in2 := &testProducer{data: []*query.Record{ + makeAggInputRecord("key", 6, 10, 0, 0, ts, []float64{6, 7, 8, 9, 10}), + }} + + quantiles := []float64{0, 0.5, 0.9, 1} + agg := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncQuantile, quantiles) + + results := collectRecords(agg) + assert.Len(t, results, 1) + assert.Equal(t, "key", results[0].Vals[0].Decoded().(string)) + + gotValue := results[0].Vals[1].Decoded().(float64) + gotQuantiles := results[0].Vals[3].Decoded().([]float64) + assert.Len(t, gotQuantiles, len(quantiles)) + assert.Equal(t, gotQuantiles[0], gotValue) + + assert.InDelta(t, 1, gotQuantiles[0], 0.5) + assert.InDelta(t, 5.5, gotQuantiles[1], 0.5) + assert.InDelta(t, 9.1, gotQuantiles[2], 0.5) + assert.InDelta(t, 10, gotQuantiles[3], 0.5) +} + func TestDistributedAggregatorFinalize(t *testing.T) { in1 := &testProducer{data: nil, total: 40} in2 := &testProducer{data: nil, total: 60} - a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncCount) + a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncCount, nil) for r := a.Next(); r != nil; r = a.Next() { t.Fatalf("unexpected record: %v", r) } @@ -224,7 +251,7 @@ func TestDistributedAggregatorFinalize(t *testing.T) { assert.Nil(t, summary.Err) } -func makeAggInputRecord(token string, mn, mx, sum float64, total, ts uint64) *query.Record { +func makeAggInputRecord(token string, mn, mx, sum float64, total, ts uint64, samples []float64) *query.Record { return query.NewRecord([]*query.RecordVals{ query.NewRecordVals(query.DataTypeString, []byte(token)), query.NewRecordVals(query.DataTypeFloat64, encoding.Float64ToBytes(mn)), @@ -233,6 +260,7 @@ func makeAggInputRecord(token string, mn, mx, sum float64, total, ts uint64) *qu query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(total)), query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(0)), // not_exists, unused by aggregator query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(ts)), + query.NewRecordVals(query.DataTypeFloat64Array, encoding.Float64ArrayToBytes(samples)), }) } diff --git a/query/exec/datasource.go b/query/exec/datasource.go index 95347f75b..cf4c40a08 100644 --- a/query/exec/datasource.go +++ b/query/exec/datasource.go @@ -288,6 +288,7 @@ func makeAggRecord(bin *storeapi.SearchResponse_Bin) *query.Record { query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(uint64(bin.Hist.Total))), query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(uint64(bin.Hist.NotExists))), query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(uint64(bin.Ts.AsTime().UnixNano()))), + query.NewRecordVals(query.DataTypeFloat64Array, encoding.Float64ArrayToBytes(bin.Hist.Samples)), }, } } diff --git a/query/record.go b/query/record.go index ea985ba90..1f2fdd5dc 100644 --- a/query/record.go +++ b/query/record.go @@ -31,8 +31,7 @@ const ( DataTypeInt32 DataTypeInt64 DataTypeFloat64 - // later we will need array data types, such as: - // StringArray, Uin64Array, Float64Array etc. + DataTypeFloat64Array ) // Executors make use of val's index. the plan knows which executors use which col indexes @@ -112,6 +111,8 @@ func (rv *RecordVals) ensureDecoded() { rv.decoded = encoding.Int64FromBytes(rv.rawData) case DataTypeFloat64: rv.decoded = encoding.Float64FromBytes(rv.rawData) + case DataTypeFloat64Array: + rv.decoded = encoding.Float64ArrayFromBytes(rv.rawData) default: panic("BUG: unknown data type") } diff --git a/storeapi/grpc_stream_search.go b/storeapi/grpc_stream_search.go index 0b9e3e152..a08d3498b 100644 --- a/storeapi/grpc_stream_search.go +++ b/storeapi/grpc_stream_search.go @@ -395,6 +395,7 @@ func aggsTyping() []*storeapi.Typing { {Title: "total", Type: storeapi.DataType_UINT64}, {Title: "not_exists", Type: storeapi.DataType_UINT64}, {Title: "ts", Type: storeapi.DataType_UINT64}, + {Title: "samples", Type: storeapi.DataType_FLOAT64_ARRAY}, } } diff --git a/tests/integration_tests/integration_test.go b/tests/integration_tests/integration_test.go index 395f8d204..4ba5f5a24 100644 --- a/tests/integration_tests/integration_test.go +++ b/tests/integration_tests/integration_test.go @@ -35,6 +35,7 @@ import ( "github.com/ozontech/seq-db/pkg/seqproxyapi/v1" "github.com/ozontech/seq-db/pkg/storeapi" "github.com/ozontech/seq-db/proxy/search" + "github.com/ozontech/seq-db/query/encoding" "github.com/ozontech/seq-db/seq" "github.com/ozontech/seq-db/skipmaskmanager" "github.com/ozontech/seq-db/tests/common" @@ -2186,8 +2187,8 @@ func (s *IntegrationTestSuite) TestStreamSearch() { case *seqproxyapi.StreamSearchResponse_Data: for _, rec := range v.Data.GetBatch().GetRecords() { raw := rec.GetRawData() - // [key:STRING, value:FLOAT64, ts:UINT64] — proxy agg schema. - r.Len(raw, 3) + // [key:STRING, value:FLOAT64, ts:UINT64, quantiles:FLOAT64_ARRAY] — proxy agg schema. + r.Len(raw, 4) value := math.Float64frombits(binary.LittleEndian.Uint64(raw[1])) ts := binary.LittleEndian.Uint64(raw[2]) got[ts] += value @@ -2210,6 +2211,52 @@ func (s *IntegrationTestSuite) TestStreamSearch() { } }) + t.Run("quantile aggregation stream", func(t *testing.T) { + const quantDocs = 10 + qDocs := make([]string, 0, quantDocs) + for i := range quantDocs { + qDocs = append(qDocs, fmt.Sprintf(`{"service":"q","level":%d}`, i)) + } + setup.Bulk(t, env.IngestorBulkAddr(), qDocs) + env.WaitIdle() + + stream, conn, _, cancel := newStreamSearchClient(t, env) + defer cancel() + defer conn.Close() + + sendStreamSearchQuery(t, stream, `service:q | stats quantile(level, 0, 0.5, 1) by (service)`) + + var gotRecords int + var value float64 + var quantiles []float64 + for { + resp, err := stream.Recv() + if err != nil { + break + } + switch v := resp.ResponseType.(type) { + case *seqproxyapi.StreamSearchResponse_Data: + for _, rec := range v.Data.GetBatch().GetRecords() { + raw := rec.GetRawData() + // [key:STRING, value:FLOAT64, ts:UINT64, quantiles:FLOAT64_ARRAY]. + r.Len(raw, 4) + gotRecords++ + value = math.Float64frombits(binary.LittleEndian.Uint64(raw[1])) + quantiles = encoding.Float64ArrayFromBytes(raw[3]) + } + case *seqproxyapi.StreamSearchResponse_Summary: + r.Equal(1, gotRecords, "one bucket per `service` group") + r.Len(quantiles, 3) + r.Equal(0.0, value) + r.Equal(0.0, quantiles[0], "q=0 -> min") + r.Equal(9.0, quantiles[2], "q=1 -> max") + r.Equal(5.0, quantiles[1], "q=0.5 -> median") + return + } + } + r.Fail("expected a summary message") + }) + t.Run("missing query is rejected", func(t *testing.T) { stream, conn, _, cancel := newStreamSearchClient(t, env) defer cancel() From 947cf3c1ac4eed2c33e8b4ab58ec21156f9b681b Mon Sep 17 00:00:00 2001 From: Daniil Forshev Date: Wed, 19 Aug 2026 12:55:03 +0500 Subject: [PATCH 3/4] feat(stream search): serve GetAggregation through stream search --- proxyapi/grpc_get_aggregation.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/proxyapi/grpc_get_aggregation.go b/proxyapi/grpc_get_aggregation.go index c43c8b398..605888bb3 100644 --- a/proxyapi/grpc_get_aggregation.go +++ b/proxyapi/grpc_get_aggregation.go @@ -24,6 +24,18 @@ func (g *grpcV1) GetAggregation( Aggs: req.Aggs, } + if len(req.Aggs) == 1 && shouldTryStreamSearch(g.config.TryStreamSearch, proxyReq) { + cResp, err := g.emulateStreamSearch(ctx, proxyReq, nil) + if err != nil { + return nil, err + } + return &seqproxyapi.GetAggregationResponse{ + Aggs: cResp.Aggs, + Total: cResp.Total, + Error: cResp.Error, + }, nil + } + sResp, err := g.doSearch(ctx, proxyReq, false, true, nil) if err != nil { return nil, err From c02434ce32cf7ae0251676665f19841229d7fe1a Mon Sep 17 00:00:00 2001 From: Daniil Forshev Date: Wed, 19 Aug 2026 16:14:58 +0500 Subject: [PATCH 4/4] feat(stream search): support unique_count agg func --- api/seqproxyapi/v1/seq_proxy_api.proto | 1 + api/storeapi/store_api.proto | 1 + pkg/seqproxyapi/v1/seq_proxy_api.pb.go | 256 ++++++++++---------- pkg/storeapi/store_api.pb.go | 124 +++++----- proxyapi/grpc_complex_search.go | 3 - proxyapi/grpc_stream_search.go | 5 - query/encoding/encoding.go | 47 +++- query/encoding/encoding_test.go | 22 ++ query/exec/aggregator.go | 23 +- query/exec/aggregator_test.go | 85 ++++--- query/exec/datasource.go | 22 +- query/record.go | 3 + storeapi/grpc_stream_search.go | 1 + tests/integration_tests/integration_test.go | 42 ++++ 14 files changed, 397 insertions(+), 238 deletions(-) diff --git a/api/seqproxyapi/v1/seq_proxy_api.proto b/api/seqproxyapi/v1/seq_proxy_api.proto index 1f3a90464..2006f5b9d 100644 --- a/api/seqproxyapi/v1/seq_proxy_api.proto +++ b/api/seqproxyapi/v1/seq_proxy_api.proto @@ -498,6 +498,7 @@ enum DataType { INT64 = 7; FLOAT64 = 8; FLOAT64_ARRAY = 9; + STRING_ARRAY = 10; } message ResponseData { diff --git a/api/storeapi/store_api.proto b/api/storeapi/store_api.proto index a1a8aba37..657195923 100644 --- a/api/storeapi/store_api.proto +++ b/api/storeapi/store_api.proto @@ -322,6 +322,7 @@ enum DataType { INT64 = 7; FLOAT64 = 8; FLOAT64_ARRAY = 9; + STRING_ARRAY = 10; } message ResponseData { diff --git a/pkg/seqproxyapi/v1/seq_proxy_api.pb.go b/pkg/seqproxyapi/v1/seq_proxy_api.pb.go index 3c9489236..6624a1f6b 100644 --- a/pkg/seqproxyapi/v1/seq_proxy_api.pb.go +++ b/pkg/seqproxyapi/v1/seq_proxy_api.pb.go @@ -309,21 +309,23 @@ const ( DataType_INT64 DataType = 7 DataType_FLOAT64 DataType = 8 DataType_FLOAT64_ARRAY DataType = 9 + DataType_STRING_ARRAY DataType = 10 ) // Enum value maps for DataType. var ( DataType_name = map[int32]string{ - 0: "BYTES", - 1: "SEQ_ID", - 2: "RAW_DOCUMENT", - 3: "STRING", - 4: "UINT32", - 5: "UINT64", - 6: "INT32", - 7: "INT64", - 8: "FLOAT64", - 9: "FLOAT64_ARRAY", + 0: "BYTES", + 1: "SEQ_ID", + 2: "RAW_DOCUMENT", + 3: "STRING", + 4: "UINT32", + 5: "UINT64", + 6: "INT32", + 7: "INT64", + 8: "FLOAT64", + 9: "FLOAT64_ARRAY", + 10: "STRING_ARRAY", } DataType_value = map[string]int32{ "BYTES": 0, @@ -336,6 +338,7 @@ var ( "INT64": 7, "FLOAT64": 8, "FLOAT64_ARRAY": 9, + "STRING_ARRAY": 10, } ) @@ -3909,7 +3912,7 @@ var file_seqproxyapi_v1_seq_proxy_api_proto_rawDesc = string([]byte{ 0x12, 0x1e, 0x0a, 0x1a, 0x43, 0x4f, 0x4e, 0x54, 0x52, 0x4f, 0x4c, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x10, 0x01, 0x12, 0x0a, - 0x0a, 0x06, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x02, 0x2a, 0x8d, 0x01, 0x0a, 0x08, 0x44, + 0x0a, 0x06, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x02, 0x2a, 0x9f, 0x01, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x51, 0x5f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x41, 0x57, 0x5f, 0x44, 0x4f, 0x43, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, @@ -3918,125 +3921,126 @@ var file_seqproxyapi_v1_seq_proxy_api_proto_rawDesc = string([]byte{ 0x36, 0x34, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x36, 0x34, 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x41, 0x54, - 0x36, 0x34, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x09, 0x32, 0x97, 0x0e, 0x0a, 0x0b, 0x53, - 0x65, 0x71, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x41, 0x70, 0x69, 0x12, 0x5b, 0x0a, 0x06, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, - 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x78, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x24, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, - 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, - 0x22, 0x0f, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x12, 0x76, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x73, 0x65, 0x71, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x70, 0x0a, 0x0c, 0x47, 0x65, 0x74, - 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x23, 0x2e, 0x73, 0x65, 0x71, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, - 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x36, 0x34, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, + 0x52, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x0a, 0x32, 0x97, 0x0e, 0x0a, + 0x0b, 0x53, 0x65, 0x71, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x41, 0x70, 0x69, 0x12, 0x5b, 0x0a, 0x06, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, + 0x22, 0x07, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x78, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x24, 0x2e, 0x73, 0x65, 0x71, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x25, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, + 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x2d, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x12, 0x76, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x73, + 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, - 0x0a, 0x2f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x54, 0x0a, 0x05, 0x46, - 0x65, 0x74, 0x63, 0x68, 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x11, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x0b, 0x3a, 0x01, 0x2a, 0x22, 0x06, 0x2f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x30, - 0x01, 0x12, 0x5d, 0x0a, 0x07, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x2e, 0x73, - 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, - 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, - 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, - 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, - 0x12, 0x58, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x09, 0x12, 0x07, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x5d, 0x0a, 0x06, 0x45, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, - 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x30, 0x01, 0x12, 0x81, 0x01, 0x0a, 0x10, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x27, + 0x0a, 0x2f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x70, 0x0a, 0x0c, 0x47, + 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x23, 0x2e, 0x73, 0x65, + 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x24, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, + 0x2a, 0x22, 0x0a, 0x2f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x54, 0x0a, + 0x05, 0x46, 0x65, 0x74, 0x63, 0x68, 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x11, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x3a, 0x01, 0x2a, 0x22, 0x06, 0x2f, 0x66, 0x65, 0x74, 0x63, + 0x68, 0x30, 0x01, 0x12, 0x5d, 0x0a, 0x07, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, - 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, - 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x61, - 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x12, 0x99, 0x01, - 0x0a, 0x16, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, - 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, - 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, - 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, - 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x65, 0x73, 0x2f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x12, 0x94, 0x01, 0x0a, 0x11, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, - 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x65, 0x71, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x22, 0x22, 0x2f, 0x61, - 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, 0x7b, 0x73, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x12, 0x8d, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, - 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, - 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x29, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1d, 0x2a, 0x1b, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x7d, - 0x12, 0x92, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2b, 0x2e, 0x73, 0x65, 0x71, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, - 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, - 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, - 0x14, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, - 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x82, 0x01, 0x0a, 0x11, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x28, 0x2e, 0x73, 0x65, - 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, - 0x6f, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, + 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, + 0x67, 0x73, 0x12, 0x58, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, + 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, + 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x09, 0x12, 0x07, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x5d, 0x0a, 0x06, + 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, 0x2a, - 0x22, 0x16, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, - 0x73, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x30, 0x01, 0x12, 0x78, 0x0a, 0x0c, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x23, 0x2e, 0x73, 0x65, 0x71, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x24, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, - 0x22, 0x0e, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x28, 0x01, 0x30, 0x01, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x71, 0x2d, - 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, - 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, + 0x22, 0x07, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x30, 0x01, 0x12, 0x81, 0x01, 0x0a, 0x10, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x12, 0x27, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, + 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x12, + 0x99, 0x01, 0x0a, 0x16, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2d, 0x2e, 0x73, 0x65, 0x71, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, + 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x73, 0x65, 0x71, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x12, 0x94, 0x01, 0x0a, 0x11, + 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x12, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x65, + 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x22, 0x22, + 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, + 0x7b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x12, 0x8d, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, + 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x28, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x2a, 0x1b, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x69, + 0x64, 0x7d, 0x12, 0x92, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2b, 0x2e, 0x73, 0x65, + 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, + 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, + 0x2a, 0x22, 0x14, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x65, 0x73, 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x82, 0x01, 0x0a, 0x11, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x28, 0x2e, + 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, + 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, + 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x65, 0x73, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x30, 0x01, 0x12, 0x78, 0x0a, 0x0c, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x23, 0x2e, 0x73, + 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, + 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2d, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x28, 0x01, 0x30, 0x01, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x73, 0x65, + 0x71, 0x2d, 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x73, 0x65, 0x71, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( diff --git a/pkg/storeapi/store_api.pb.go b/pkg/storeapi/store_api.pb.go index 06e6170fd..d7a78c8de 100644 --- a/pkg/storeapi/store_api.pb.go +++ b/pkg/storeapi/store_api.pb.go @@ -312,21 +312,23 @@ const ( DataType_INT64 DataType = 7 DataType_FLOAT64 DataType = 8 DataType_FLOAT64_ARRAY DataType = 9 + DataType_STRING_ARRAY DataType = 10 ) // Enum value maps for DataType. var ( DataType_name = map[int32]string{ - 0: "BYTES", - 1: "SEQ_ID", - 2: "RAW_DOCUMENT", - 3: "STRING", - 4: "UINT32", - 5: "UINT64", - 6: "INT32", - 7: "INT64", - 8: "FLOAT64", - 9: "FLOAT64_ARRAY", + 0: "BYTES", + 1: "SEQ_ID", + 2: "RAW_DOCUMENT", + 3: "STRING", + 4: "UINT32", + 5: "UINT64", + 6: "INT32", + 7: "INT64", + 8: "FLOAT64", + 9: "FLOAT64_ARRAY", + 10: "STRING_ARRAY", } DataType_value = map[string]int32{ "BYTES": 0, @@ -339,6 +341,7 @@ var ( "INT64": 7, "FLOAT64": 8, "FLOAT64_ARRAY": 9, + "STRING_ARRAY": 10, } ) @@ -3342,7 +3345,7 @@ var file_storeapi_store_api_proto_rawDesc = string([]byte{ 0x4f, 0x4c, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, - 0x02, 0x2a, 0x8d, 0x01, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, + 0x02, 0x2a, 0x9f, 0x01, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x51, 0x5f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x41, 0x57, 0x5f, 0x44, 0x4f, 0x43, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, @@ -3351,57 +3354,58 @@ var file_storeapi_store_api_proto_rawDesc = string([]byte{ 0x4e, 0x54, 0x33, 0x32, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x36, 0x34, 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x36, 0x34, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, - 0x09, 0x32, 0xe7, 0x05, 0x0a, 0x08, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x41, 0x70, 0x69, 0x12, 0x32, - 0x0a, 0x04, 0x42, 0x75, 0x6c, 0x6b, 0x12, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6c, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x22, 0x00, 0x12, 0x33, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x12, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1c, 0x2e, 0x61, 0x70, + 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x52, 0x52, 0x41, + 0x59, 0x10, 0x0a, 0x32, 0xe7, 0x05, 0x0a, 0x08, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x41, 0x70, 0x69, + 0x12, 0x32, 0x0a, 0x04, 0x42, 0x75, 0x6c, 0x6b, 0x12, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, + 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x12, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x10, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1c, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x16, 0x46, 0x65, - 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, - 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, - 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x54, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, - 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x14, 0x47, - 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, - 0x69, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, - 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, + 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x16, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, + 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x54, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1d, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, + 0x14, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, + 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x05, 0x46, 0x65, - 0x74, 0x63, 0x68, 0x12, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x69, 0x6e, - 0x61, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x22, 0x00, 0x30, 0x01, 0x12, 0x33, 0x0a, 0x06, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x49, 0x0a, 0x0c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, - 0x63, 0x68, 0x2f, 0x73, 0x65, 0x71, 0x2d, 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x61, 0x70, 0x69, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x61, 0x70, 0x69, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, + 0x74, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x05, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x12, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x65, 0x74, 0x63, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, + 0x69, 0x6e, 0x61, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x22, 0x00, 0x30, 0x01, 0x12, 0x33, 0x0a, + 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x32, 0x5a, + 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, + 0x74, 0x65, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x71, 0x2d, 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x61, 0x70, 0x69, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x61, 0x70, + 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( diff --git a/proxyapi/grpc_complex_search.go b/proxyapi/grpc_complex_search.go index e46a4d69c..131962632 100644 --- a/proxyapi/grpc_complex_search.go +++ b/proxyapi/grpc_complex_search.go @@ -205,9 +205,6 @@ func shouldTryStreamSearch(tryStreamSearch bool, req *seqproxyapi.ComplexSearchR if req.Hist != nil || len(req.Aggs) > 1 { return false } - if len(req.Aggs) == 1 && req.Aggs[0].Func == seq.AggFuncUniqueCount { - return false - } return true } diff --git a/proxyapi/grpc_stream_search.go b/proxyapi/grpc_stream_search.go index f7e1be69b..86bf704b3 100644 --- a/proxyapi/grpc_stream_search.go +++ b/proxyapi/grpc_stream_search.go @@ -59,11 +59,6 @@ func (g *grpcV1) StreamSearch(stream seqproxyapi.SeqProxyApi_StreamSearchServer) return status.Error(codes.InvalidArgument, fmt.Sprintf("error parsing query: %s", err.Error())) } - if searchReq.Agg != nil && searchReq.Agg.Func == seq.AggFuncUniqueCount { - // TODO: support all agg funcs - return status.Error(codes.InvalidArgument, `unsupported aggregate function`) - } - tr := querytracer.New(q.Explain, "proxy/StreamSearch") var partialErr error diff --git a/query/encoding/encoding.go b/query/encoding/encoding.go index e3c00f606..0828359c3 100644 --- a/query/encoding/encoding.go +++ b/query/encoding/encoding.go @@ -81,16 +81,15 @@ func Float64FromBytes(b []byte) float64 { // Float64ArrayToBytes encodes a float64 slice as an 8-byte little-endian length // prefix followed by the little-endian raw bytes of each element. An empty or // nil slice is encoded as a zero length (8 zero bytes). -func Float64ArrayToBytes(v []float64) []byte { - b := make([]byte, 8+len(v)*8) - binary.LittleEndian.PutUint64(b, uint64(len(v))) - for i, f := range v { +func Float64ArrayToBytes(val []float64) []byte { + b := make([]byte, 8+len(val)*8) + binary.LittleEndian.PutUint64(b, uint64(len(val))) + for i, f := range val { binary.LittleEndian.PutUint64(b[8+i*8:], math.Float64bits(f)) } return b } -// Float64ArrayFromBytes is the inverse of Float64ArrayToBytes. func Float64ArrayFromBytes(b []byte) []float64 { if len(b) < 8 { return nil @@ -102,3 +101,41 @@ func Float64ArrayFromBytes(b []byte) []float64 { } return v } + +// StringArrayToBytes encodes a string slice as an 8-byte little-endian length +// prefix (number of strings) followed by each string prefixed with its own +// 8-byte little-endian length. An empty or nil slice is encoded as a zero +// length (8 zero bytes). +func StringArrayToBytes(val []string) []byte { + // 8 bytes for the count, plus 8 bytes + len(s) per string. + size := 8 + for _, s := range val { + size += 8 + len(s) + } + b := make([]byte, size) + binary.LittleEndian.PutUint64(b, uint64(len(val))) + offset := 8 + for _, s := range val { + binary.LittleEndian.PutUint64(b[offset:], uint64(len(s))) + offset += 8 + copy(b[offset:], s) + offset += len(s) + } + return b +} + +func StringArrayFromBytes(b []byte) []string { + if len(b) < 8 { + return nil + } + n := binary.LittleEndian.Uint64(b) + v := make([]string, n) + offset := 8 + for i := range n { + slen := binary.LittleEndian.Uint64(b[offset:]) + offset += 8 + v[i] = string(b[offset : offset+int(slen)]) + offset += int(slen) + } + return v +} diff --git a/query/encoding/encoding_test.go b/query/encoding/encoding_test.go index e663be197..b8f7ff17a 100644 --- a/query/encoding/encoding_test.go +++ b/query/encoding/encoding_test.go @@ -136,3 +136,25 @@ func TestFloat64ArrayByteLength(t *testing.T) { assert.Len(t, Float64ArrayToBytes([]float64{}), 8) assert.Len(t, Float64ArrayToBytes([]float64{1, 2, 3}), 8+3*8) } + +func TestStringArray(t *testing.T) { + cases := [][]string{ + nil, + {}, + {""}, + {"a"}, + {"a", "b", "", "hello", "мир"}, + } + for _, v := range cases { + // nil and an empty slice both encode as a zero length and decode to an + // empty (non-nil) slice, so compare elements rather than nil-ness. + assert.ElementsMatch(t, v, StringArrayFromBytes(StringArrayToBytes(v))) + } + assert.Len(t, StringArrayFromBytes(StringArrayToBytes(nil)), 0) +} + +func TestStringArrayByteLength(t *testing.T) { + assert.Len(t, StringArrayToBytes(nil), 8) + assert.Len(t, StringArrayToBytes([]string{}), 8) + assert.Len(t, StringArrayToBytes([]string{"a", "bc"}), 8+(8+1)+(8+2)) +} diff --git a/query/exec/aggregator.go b/query/exec/aggregator.go index fdb1afcfa..4b4167279 100644 --- a/query/exec/aggregator.go +++ b/query/exec/aggregator.go @@ -37,9 +37,11 @@ type DistributedAggregator struct { buckets map[aggKey]*seq.SamplesContainer sortingBuf []*query.Record + // values holds the unique field-value sets per bucket for unique count. + values map[aggKey]map[string]struct{} + curIdx int - // err holds the first error encountered while reading the inputs. It is - // reported via Finalize. + // err holds the first error encountered while reading the inputs. It is reported via Finalize. err error } @@ -94,6 +96,20 @@ func (a *DistributedAggregator) Next() *query.Record { } } + if a.aggFunc == seq.AggFuncUniqueCount { + if a.values == nil { + a.values = make(map[aggKey]map[string]struct{}) + } + m, ok := a.values[key] + if !ok { + m = make(map[string]struct{}) + a.values[key] = m + } + for _, v := range r.Vals[8].Decoded().([]string) { + m[v] = struct{}{} + } + } + a.buckets[key] = s } } @@ -106,10 +122,11 @@ func (a *DistributedAggregator) Next() *query.Record { var value float64 var quantiles []float64 - // TODO: support all aggregate functions switch a.aggFunc { case seq.AggFuncCount, seq.AggFuncUnique: value = float64(bucket.Total) + case seq.AggFuncUniqueCount: + value = float64(len(a.values[key])) case seq.AggFuncSum: value = bucket.Sum case seq.AggFuncMin: diff --git a/query/exec/aggregator_test.go b/query/exec/aggregator_test.go index 43b17ea47..6d42bc94a 100644 --- a/query/exec/aggregator_test.go +++ b/query/exec/aggregator_test.go @@ -12,13 +12,13 @@ import ( func TestDistributedAggregator_Count(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}, []string{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}, []string{}), } input1 := testProducer{data: records1} @@ -36,13 +36,13 @@ func TestDistributedAggregator_Count(t *testing.T) { func TestDistributedAggregator_Sum(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 30.0, 30.0, 30.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 30.0, 30.0, 30.0, 1, 0, []float64{}, []string{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 20.0, 20.0, 20.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 20.0, 20.0, 20.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}, []string{}), } input1 := testProducer{data: records1} @@ -60,13 +60,13 @@ func TestDistributedAggregator_Sum(t *testing.T) { func TestDistributedAggregator_Min(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}, []string{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}, []string{}), } input1 := testProducer{data: records1} @@ -84,13 +84,13 @@ func TestDistributedAggregator_Min(t *testing.T) { func TestDistributedAggregator_Max(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 30.0, 30.0, 30.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 30.0, 30.0, 30.0, 1, 0, []float64{}, []string{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 50.0, 50.0, 50.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 50.0, 50.0, 50.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}, []string{}), } input1 := testProducer{data: records1} @@ -108,13 +108,13 @@ func TestDistributedAggregator_Max(t *testing.T) { func TestDistributedAggregator_Avg(t *testing.T) { records1 := []*query.Record{ - makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 10.0, 10.0, 10.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 20.0, 20.0, 20.0, 1, 0, []float64{}, []string{}), } records2 := []*query.Record{ - makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}), - makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}), + makeAggInputRecord("key1", 30.0, 30.0, 30.0, 1, 0, []float64{}, []string{}), + makeAggInputRecord("key2", 40.0, 40.0, 40.0, 1, 0, []float64{}, []string{}), } input1 := testProducer{data: records1} @@ -144,13 +144,13 @@ func TestDistributedAggregator_EmptyInput(t *testing.T) { func TestDistributedAggregatorSumTimeseries(t *testing.T) { const ts1, ts2 uint64 = 1_000_000_000, 2_000_000_000 in1 := &testProducer{data: []*query.Record{ - makeAggInputRecord("foo", 2, 2, 2, 1, ts1, []float64{}), - makeAggInputRecord("foo", 3, 3, 3, 1, ts2, []float64{}), - makeAggInputRecord("bar", 5, 5, 5, 1, ts1, []float64{}), + makeAggInputRecord("foo", 2, 2, 2, 1, ts1, []float64{}, []string{}), + makeAggInputRecord("foo", 3, 3, 3, 1, ts2, []float64{}, []string{}), + makeAggInputRecord("bar", 5, 5, 5, 1, ts1, []float64{}, []string{}), }} in2 := &testProducer{data: []*query.Record{ - makeAggInputRecord("foo", 4, 4, 4, 1, ts1, []float64{}), // same bin as in1[0] -> merged sum 6 - makeAggInputRecord("baz", 7, 7, 7, 1, ts2, []float64{}), + makeAggInputRecord("foo", 4, 4, 4, 1, ts1, []float64{}, []string{}), // same bin as in1[0] -> merged sum 6 + makeAggInputRecord("baz", 7, 7, 7, 1, ts2, []float64{}, []string{}), }} a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncSum, nil) @@ -171,12 +171,12 @@ func TestDistributedAggregatorSumTimeseries(t *testing.T) { func TestDistributedAggregatorMinMergeAcrossShards(t *testing.T) { const ts uint64 = 0 // no interval: all samples collapse into ts=0 in1 := &testProducer{data: []*query.Record{ - makeAggInputRecord("a", 5, 50, 0, 1, ts, []float64{}), - makeAggInputRecord("b", 1, 10, 0, 1, ts, []float64{}), + makeAggInputRecord("a", 5, 50, 0, 1, ts, []float64{}, []string{}), + makeAggInputRecord("b", 1, 10, 0, 1, ts, []float64{}, []string{}), }} in2 := &testProducer{data: []*query.Record{ - makeAggInputRecord("a", 2, 60, 0, 1, ts, []float64{}), // min(5,2)=2, max(50,60)=60 - makeAggInputRecord("c", 9, 9, 0, 1, ts, []float64{}), + makeAggInputRecord("a", 2, 60, 0, 1, ts, []float64{}, []string{}), // min(5,2)=2, max(50,60)=60 + makeAggInputRecord("c", 9, 9, 0, 1, ts, []float64{}, []string{}), }} a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncMin, nil) @@ -195,10 +195,10 @@ func TestDistributedAggregatorMinMergeAcrossShards(t *testing.T) { // interval (ts=0 for every input) aggregation merges solely by token. func TestDistributedAggregatorNoIntervalCollapsesByToken(t *testing.T) { in1 := &testProducer{data: []*query.Record{ - makeAggInputRecord("foo", 0, 0, 10, 2, 0, []float64{}), + makeAggInputRecord("foo", 0, 0, 10, 2, 0, []float64{}, []string{}), }} in2 := &testProducer{data: []*query.Record{ - makeAggInputRecord("foo", 0, 0, 5, 3, 0, []float64{}), + makeAggInputRecord("foo", 0, 0, 5, 3, 0, []float64{}, []string{}), }} a := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncCount, nil) @@ -214,10 +214,10 @@ func TestDistributedAggregatorNoIntervalCollapsesByToken(t *testing.T) { func TestDistributedAggregator_Quantile(t *testing.T) { const ts uint64 = 0 in1 := &testProducer{data: []*query.Record{ - makeAggInputRecord("key", 1, 5, 0, 0, ts, []float64{1, 2, 3, 4, 5}), + makeAggInputRecord("key", 1, 5, 0, 0, ts, []float64{1, 2, 3, 4, 5}, []string{}), }} in2 := &testProducer{data: []*query.Record{ - makeAggInputRecord("key", 6, 10, 0, 0, ts, []float64{6, 7, 8, 9, 10}), + makeAggInputRecord("key", 6, 10, 0, 0, ts, []float64{6, 7, 8, 9, 10}, []string{}), }} quantiles := []float64{0, 0.5, 0.9, 1} @@ -238,6 +238,22 @@ func TestDistributedAggregator_Quantile(t *testing.T) { assert.InDelta(t, 10, gotQuantiles[3], 0.5) } +func TestDistributedAggregator_UniqueCount(t *testing.T) { + const ts uint64 = 0 + in1 := &testProducer{data: []*query.Record{ + makeAggInputRecord("key", 0, 0, 0, 0, ts, []float64{}, []string{"a", "b", "c"}), + }} + in2 := &testProducer{data: []*query.Record{ + makeAggInputRecord("key", 0, 0, 0, 0, ts, []float64{}, []string{"b", "c", "d"}), + }} + agg := NewDistributedAggregator([]query.RecordProducer{in1, in2}, seq.AggFuncUniqueCount, nil) + + results := collectRecords(agg) + assert.Len(t, results, 1) + assert.Equal(t, "key", results[0].Vals[0].Decoded().(string)) + assert.Equal(t, float64(4), results[0].Vals[1].Decoded().(float64)) +} + func TestDistributedAggregatorFinalize(t *testing.T) { in1 := &testProducer{data: nil, total: 40} in2 := &testProducer{data: nil, total: 60} @@ -251,7 +267,7 @@ func TestDistributedAggregatorFinalize(t *testing.T) { assert.Nil(t, summary.Err) } -func makeAggInputRecord(token string, mn, mx, sum float64, total, ts uint64, samples []float64) *query.Record { +func makeAggInputRecord(token string, mn, mx, sum float64, total, ts uint64, samples []float64, values []string) *query.Record { return query.NewRecord([]*query.RecordVals{ query.NewRecordVals(query.DataTypeString, []byte(token)), query.NewRecordVals(query.DataTypeFloat64, encoding.Float64ToBytes(mn)), @@ -261,6 +277,7 @@ func makeAggInputRecord(token string, mn, mx, sum float64, total, ts uint64, sam query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(0)), // not_exists, unused by aggregator query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(ts)), query.NewRecordVals(query.DataTypeFloat64Array, encoding.Float64ArrayToBytes(samples)), + query.NewRecordVals(query.DataTypeStringArray, encoding.StringArrayToBytes(values)), }) } diff --git a/query/exec/datasource.go b/query/exec/datasource.go index cf4c40a08..588133758 100644 --- a/query/exec/datasource.go +++ b/query/exec/datasource.go @@ -138,7 +138,7 @@ func (s *SearcherDataSource) nextAgg() *query.Record { return nil } - record := makeAggRecord(agg.Timeseries[s.curIdx]) + record := makeAggRecord(agg.Timeseries[s.curIdx], agg.ValuesPool) s.curIdx++ @@ -249,6 +249,13 @@ func buildAggs(qpr *seq.QPR) []*storeapi.SearchResponse_Agg { NotExists: hist.NotExists, } + if len(hist.Values) > 0 { + pbhist.Values = make([]uint32, 0, len(hist.Values)) + for idx := range hist.Values { + pbhist.Values = append(pbhist.Values, idx) + } + } + curAgg.Timeseries = append(curAgg.Timeseries, &storeapi.SearchResponse_Bin{ Label: bin.Token, @@ -262,6 +269,7 @@ func buildAggs(qpr *seq.QPR) []*storeapi.SearchResponse_Agg { curAgg.NotExists = fromAgg.NotExists curAgg.AggHistogram = to + curAgg.ValuesPool = fromAgg.ValuesPool aggs[i] = curAgg } @@ -278,7 +286,16 @@ func makeDocumentRecord(id seq.ID, payload []byte) *query.Record { } } -func makeAggRecord(bin *storeapi.SearchResponse_Bin) *query.Record { +func makeAggRecord(bin *storeapi.SearchResponse_Bin, valuesPool []string) *query.Record { + // For unique_count, the store holds unique field values as indices into the per-agg ValuesPool. + // Resolve them to strings here so each record is self-contained, no shared pool. + var values []string + if len(bin.Hist.Values) > 0 && len(valuesPool) > 0 { + values = make([]string, 0, len(bin.Hist.Values)) + for _, idx := range bin.Hist.Values { + values = append(values, valuesPool[idx]) + } + } return &query.Record{ Vals: []*query.RecordVals{ query.NewRecordVals(query.DataTypeBytes, []byte(bin.Label)), @@ -289,6 +306,7 @@ func makeAggRecord(bin *storeapi.SearchResponse_Bin) *query.Record { query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(uint64(bin.Hist.NotExists))), query.NewRecordVals(query.DataTypeUint64, encoding.Uint64ToBytes(uint64(bin.Ts.AsTime().UnixNano()))), query.NewRecordVals(query.DataTypeFloat64Array, encoding.Float64ArrayToBytes(bin.Hist.Samples)), + query.NewRecordVals(query.DataTypeStringArray, encoding.StringArrayToBytes(values)), }, } } diff --git a/query/record.go b/query/record.go index 1f2fdd5dc..467b8e6ed 100644 --- a/query/record.go +++ b/query/record.go @@ -32,6 +32,7 @@ const ( DataTypeInt64 DataTypeFloat64 DataTypeFloat64Array + DataTypeStringArray ) // Executors make use of val's index. the plan knows which executors use which col indexes @@ -113,6 +114,8 @@ func (rv *RecordVals) ensureDecoded() { rv.decoded = encoding.Float64FromBytes(rv.rawData) case DataTypeFloat64Array: rv.decoded = encoding.Float64ArrayFromBytes(rv.rawData) + case DataTypeStringArray: + rv.decoded = encoding.StringArrayFromBytes(rv.rawData) default: panic("BUG: unknown data type") } diff --git a/storeapi/grpc_stream_search.go b/storeapi/grpc_stream_search.go index a08d3498b..5a373f4a6 100644 --- a/storeapi/grpc_stream_search.go +++ b/storeapi/grpc_stream_search.go @@ -396,6 +396,7 @@ func aggsTyping() []*storeapi.Typing { {Title: "not_exists", Type: storeapi.DataType_UINT64}, {Title: "ts", Type: storeapi.DataType_UINT64}, {Title: "samples", Type: storeapi.DataType_FLOAT64_ARRAY}, + {Title: "values", Type: storeapi.DataType_STRING_ARRAY}, } } diff --git a/tests/integration_tests/integration_test.go b/tests/integration_tests/integration_test.go index 4ba5f5a24..001e3b711 100644 --- a/tests/integration_tests/integration_test.go +++ b/tests/integration_tests/integration_test.go @@ -2257,6 +2257,48 @@ func (s *IntegrationTestSuite) TestStreamSearch() { r.Fail("expected a summary message") }) + t.Run("unique_count aggregation stream", func(t *testing.T) { + const uniqLevels = 5 + const reps = 2 + uDocs := make([]string, 0, uniqLevels*reps) + for i := range uniqLevels { + for range reps { + uDocs = append(uDocs, fmt.Sprintf(`{"service":"uc","level":%d}`, i)) + } + } + setup.Bulk(t, env.IngestorBulkAddr(), uDocs) + env.WaitIdle() + + stream, conn, _, cancel := newStreamSearchClient(t, env) + defer cancel() + defer conn.Close() + + sendStreamSearchQuery(t, stream, `service:uc | stats unique_count(level) by (service)`) + + var gotRecords int + var value float64 + for { + resp, err := stream.Recv() + if err != nil { + break + } + switch v := resp.ResponseType.(type) { + case *seqproxyapi.StreamSearchResponse_Data: + for _, rec := range v.Data.GetBatch().GetRecords() { + raw := rec.GetRawData() + r.Len(raw, 4) + gotRecords++ + value = math.Float64frombits(binary.LittleEndian.Uint64(raw[1])) + } + case *seqproxyapi.StreamSearchResponse_Summary: + r.Equal(1, gotRecords, "one bucket per `service` group") + r.Equal(float64(uniqLevels), value, "value = number of unique levels") + return + } + } + r.Fail("expected a summary message") + }) + t.Run("missing query is rejected", func(t *testing.T) { stream, conn, _, cancel := newStreamSearchClient(t, env) defer cancel()