1// Copyright 2019 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15syntax = "proto2"; 16 17package icing.lib; 18 19import "icing/proto/document.proto"; 20import "icing/proto/logging.proto"; 21import "icing/proto/scoring.proto"; 22import "icing/proto/status.proto"; 23import "icing/proto/term.proto"; 24 25option java_package = "com.google.android.icing.proto"; 26option java_multiple_files = true; 27option objc_class_prefix = "ICNG"; 28 29// Client-supplied specifications on what documents to retrieve. 30// Next tag: 15 31message SearchSpecProto { 32 // REQUIRED: The "raw" query string that users may type. For example, "cat" 33 // will search for documents with the term cat in it. 34 optional string query = 1; 35 36 // Indicates how the query terms should match terms in the index. 37 // 38 // TermMatchType.Code=UNKNOWN 39 // Should never purposely be set and may lead to undefined behavior. This is 40 // used for backwards compatibility reasons. 41 // 42 // TermMatchType.Code=EXACT_ONLY 43 // Query terms will only match exact tokens in the index. 44 // Ex. A query term "foo" will only match indexed token "foo", and not "foot" 45 // or "football" 46 // 47 // TermMatchType.Code=PREFIX 48 // Query terms will match indexed tokens when the query term is a prefix of 49 // the token. 50 // Ex. A query term "foo" will match indexed tokens like "foo", "foot", and 51 // "football". 52 // 53 // TermMatchType.Code=STEMMING 54 // Query terms will match indexed tokens when the query term is a stem of 55 // the token, or relates to the token via the same stem. 56 // Ex. A query term "dance" will match indexed tokens like "dance", "dances", 57 // and "dancing". 58 // 59 // TODO: b/344915547 - Refactor this to be a repeated field so that clients 60 // can choose multiple fuzzy match types. 61 optional TermMatchType.Code term_match_type = 2; 62 63 // OPTIONAL: Only search for documents that have the specified namespaces. If 64 // unset, the query will search over all namespaces. Note that this applies to 65 // the entire 'query'. To issue different queries for different namespaces, 66 // separate Search()'s will need to be made. 67 repeated string namespace_filters = 3; 68 69 // OPTIONAL: Only search for documents that have the specified schema types. 70 // If unset, the query will search over all schema types. Note that this 71 // applies to the entire 'query'. To issue different queries for different 72 // schema types, separate Search()'s will need to be made. Also note that 73 // schema filters will not be expanded for polymorphism. 74 repeated string schema_type_filters = 4; 75 76 // OPTIONAL: Only search for documents under the specified namespaces and 77 // uris. If unset, all documents will be searched. 78 // 79 // All given NamespaceDocumentUriGroup must specify at least one 80 // document_uri. To exclude a namespace, use namespace_filters instead. 81 repeated NamespaceDocumentUriGroup document_uri_filters = 14; 82 83 // Timestamp taken just before sending proto across the JNI boundary from java 84 // to native side. 85 optional int64 java_to_native_start_timestamp_ms = 5; 86 87 // OPTIONAL: If this field is present, join documents based on a nested 88 // SearchSpec. 89 optional JoinSpecProto join_spec = 7; 90 91 // Features enabled in this search spec. 92 repeated string enabled_features = 8; 93 94 // OPTIONAL: Whether to use the read-only implementation of 95 // IcingSearchEngine::Search. 96 // The read-only version enables multiple queries to be performed concurrently 97 // as it only acquires the read lock at IcingSearchEngine's level. 98 // Finer-grained locks are implemented around code paths that write changes to 99 // Icing during Search. 100 optional bool use_read_only_search = 9 [default = true]; 101 102 // TODO(b/294266822): Handle multiple property filter lists for same schema 103 // type. 104 // How to specify a subset of properties to be searched. If no type property 105 // filter has been specified for a schema type (no TypePropertyMask for the 106 // given schema type), then *all* properties of that schema type will be 107 // searched. If an empty property filter is specified for a given schema type 108 // (TypePropertyMask for the given schema type has empty paths field), no 109 // properties of that schema type will be searched. 110 repeated TypePropertyMask type_property_filters = 10; 111 112 // The vectors to be used in embedding queries. 113 repeated PropertyProto.VectorProto embedding_query_vectors = 11; 114 115 message EmbeddingQueryMetricType { 116 enum Code { 117 UNKNOWN = 0; 118 COSINE = 1; 119 DOT_PRODUCT = 2; 120 EUCLIDEAN = 3; 121 } 122 } 123 124 // The default metric type used to calculate the scores for embedding 125 // queries. 126 optional EmbeddingQueryMetricType.Code embedding_query_metric_type = 12; 127 128 // Strings to be used as parameters in the query. The strings will be treated 129 // as pure TEXT and will be normalized and tokenized. 130 repeated string query_parameter_strings = 13; 131 132 reserved 6; 133} 134 135// Client-supplied specifications on what to include/how to format the search 136// results. 137// Next tag: 10 138message ResultSpecProto { 139 // The results will be returned in pages, and num_per_page specifies the 140 // number of documents in one page. 141 optional int32 num_per_page = 1 [default = 10]; 142 143 // Whether to collect and return debug_info in the SearchResultProto. 144 optional bool debug_info = 2; 145 146 // How to provide snippeting information in the SearchResultProto. 147 // Next tag: 5 148 message SnippetSpecProto { 149 // Only the first num_to_snippet documents will have snippet information 150 // provided. If set to 0, snippeting is disabled. 151 optional int32 num_to_snippet = 1; 152 153 // Only the first num_matches_per_property matches for a single section will 154 // have snippet information provided. If set to 0, snippeting is disabled. 155 optional int32 num_matches_per_property = 2; 156 157 // How large of a window to provide. Windows start at 158 // max_window_utf32_length / 2 bytes before the middle of the matching token 159 // and end at max_window_utf32_length / 2 bytes after the middle of the 160 // matching token. Windowing respects token boundaries. Therefore, the 161 // returned window may be smaller than requested. Setting 162 // max_window_utf32_length to 0 will disable windowing information. If 163 // matches enabled is also set to false, then snippeting is disabled. Ex. 164 // max_window_utf32_length = 16. "foo bar baz bat rat" with a query of "baz" 165 // will return a window of "bar baz bat" which is only 11 bytes long. 166 optional int32 max_window_utf32_length = 3; 167 168 // Whether to get match info for embedding semantic search. Embedding match 169 // info is returned in 170 // ResultProto.SnippetProto.EntryProto.EmbeddingMatchSnippetProto and 171 // contains the following information: 172 // - The score of the matched embedding vector. 173 // - The index of the embedding query for this vector match. 174 // - The metric type of the embedding query for this vector match. 175 optional bool get_embedding_match_info = 4; 176 } 177 optional SnippetSpecProto snippet_spec = 3; 178 179 // How to specify a subset of properties to retrieve. If no type property mask 180 // has been specified for a schema type, then *all* properties of that schema 181 // type will be retrieved. 182 repeated TypePropertyMask type_property_masks = 4; 183 184 // Groupings of namespaces and schema types whose total returned results 185 // should be limited together. 186 // Next tag: 3 187 message ResultGrouping { 188 // Grouping of namespace and schema type. 189 // Next tag: 3 190 message Entry { 191 // The namespace in this grouping that should be returned. 192 // This field should be empty if ResultGroupingType is SCHEMA_TYPE 193 optional string namespace = 1; 194 195 // The schema in this grouping that should be returned. 196 // This field should be empty if ResultGroupingType is NAMESPACE 197 optional string schema = 2; 198 } 199 200 // Identifier for namespace and schema type pairs. 201 repeated Entry entry_groupings = 1; 202 203 // The maximum number of results in this grouping that should be returned. 204 optional int32 max_results = 2; 205 } 206 207 // How to limit the number of results returned per set of namespaces or schema 208 // type. If results match for a namespace or schema type that is not present 209 // in any result groupings, then those results will be returned without limit. 210 // 211 // Non-existent namespaces and/or schema type will be ignored. 212 // 213 // Example : Suppose that there are four namespaces each with three results 214 // matching the query for "foo". Without any result groupings, Icing would 215 // return the following results: 216 // ["ns0doc0", "ns0doc1", "ns1doc0", "ns3doc0", "ns0doc2", "ns3doc1", 217 // "ns2doc1", "ns3doc2", "ns2doc0", "ns1doc1", "ns2doc2", "ns1doc1"]. 218 // 219 // The following result groupings will be returned if that the 220 // ResultGroupingType is set to NAMESPACE: 221 // [ { [ {"namespace0"} ], 2 }, { [ {"namespace1"}, {"namespace2"} ], 2} ] 222 // 223 // The following results will be returned: 224 // ["ns0doc0", "ns0doc1", "ns1doc0", "ns3doc0", "ns3doc1", "ns2doc1", 225 // "ns3doc2"]. 226 repeated ResultGrouping result_groupings = 5; 227 228 // The threshold of total bytes of all documents to cutoff, in order to limit 229 // # of bytes in a single page. 230 // Note that it doesn't guarantee the result # of bytes will be smaller, equal 231 // to, or larger than the threshold. Instead, it is just a threshold to 232 // cutoff, and only guarantees total bytes of search results will exceed the 233 // threshold by less than the size of the final search result. 234 optional int32 num_total_bytes_per_page_threshold = 6 235 [default = 2147483647]; // INT_MAX 236 237 // The value by which the search results will get grouped by. 238 // Can get grouped by schema type, namespace (default), or by namespace and 239 // schema type. 240 enum ResultGroupingType { 241 NONE = 0; 242 SCHEMA_TYPE = 1; 243 NAMESPACE = 2; 244 NAMESPACE_AND_SCHEMA_TYPE = 3; 245 } 246 optional ResultGroupingType result_group_type = 7; 247 248 // The max # of child documents will be attached and returned in the result 249 // for each parent. It is only used for join API. 250 optional int32 max_joined_children_per_parent_to_return = 8; 251 252 // The max # of results being scored and ranked. 253 // Running time of ScoringProcessor and Ranker is O(num_to_score) according to 254 // results of //icing/scoring:score-and-rank_benchmark. Note that 255 // the process includes scoring, building a heap, and popping results from the 256 // heap. 257 // 258 // 30000 results can be scored and ranked within 3 ms on a Pixel 3 XL 259 // according to results of 260 // //icing/scoring:score-and-rank_benchmark, so set it as the 261 // default value. 262 optional int32 num_to_score = 9 [default = 30000]; 263} 264 265// The representation of a single match within a DocumentProto property. 266// 267// Example : A document whose content is "Necesito comprar comida mañana." and a 268// query for "mana" with window=15 269// Next tag: 12 270message SnippetMatchProto { 271 // The index of the byte in the string at which the match begins and the 272 // length in bytes of the match. 273 // 274 // For the example above, the values of these fields would be 275 // exact_match_byte_position=24, exact_match_byte_length=7 "mañana" 276 optional int32 exact_match_byte_position = 2; 277 optional int32 exact_match_byte_length = 3; 278 279 // The length in bytes of the subterm that matches the query. The beginning of 280 // the submatch is the same as exact_match_byte_position. 281 // 282 // For the example above, the value of this field would be 5. With 283 // exact_match_byte_position=24 above, it would produce the substring "maña" 284 optional int32 submatch_byte_length = 10; 285 286 // The index of the UTF-16 code unit in the string at which the match begins 287 // and the length in UTF-16 code units of the match. This is for use with 288 // UTF-16 encoded strings like Java.lang.String. 289 // 290 // For the example above, the values of these fields would be 291 // exact_match_utf16_position=24, exact_match_utf16_length=6 "mañana" 292 optional int32 exact_match_utf16_position = 6; 293 optional int32 exact_match_utf16_length = 7; 294 295 // The length in UTF-16 code units of the subterm that matches the query. The 296 // beginning of the submatch is the same as exact_match_utf16_position. This 297 // is for use with UTF-16 encoded strings like Java.lang.String. 298 // 299 // For the example above, the value of this field would be 4. With 300 // exact_match_utf16_position=24 above, it would produce the substring "maña" 301 optional int32 submatch_utf16_length = 11; 302 303 // The index of the byte in the string at which the suggested snippet window 304 // begins and the length in bytes of the window. 305 // 306 // For the example above, the values of these fields would be 307 // window_byte_position=17, window_byte_length=15 "comida mañana." 308 optional int32 window_byte_position = 4; 309 optional int32 window_byte_length = 5; 310 311 // The index of the UTF-16 code unit in the string at which the suggested 312 // snippet window begins and the length in UTF-16 code units of the window. 313 // This is for use with UTF-16 encoded strings like Java.lang.String. 314 // 315 // For the example above, the values of these fields would be 316 // window_utf16_position=17, window_utf16_length=14 "comida mañana." 317 optional int32 window_utf16_position = 8; 318 optional int32 window_utf16_length = 9; 319 320 reserved 1; 321} 322 323// The representation of a single embedding vector match within a DocumentProto 324// property. 325// 326// Next tag: 4 327message EmbeddingMatchSnippetProto { 328 // Semantic score of the matched embedding vector. 329 optional double semantic_score = 1; 330 331 // Index of the embedding query for this vector match. 332 optional int32 embedding_query_vector_index = 2; 333 334 // The metric type of the embedding query for this vector match. 335 optional SearchSpecProto.EmbeddingQueryMetricType.Code 336 embedding_query_metric_type = 3; 337} 338 339// A Proto representing all snippets for a single DocumentProto. 340// Next tag: 2 341message SnippetProto { 342 // A pair of property name and all snippet matches that correspond to the 343 // property values in the corresponding DocumentProto. 344 // Next tag: 4 345 message EntryProto { 346 // A property path indicating which property in the DocumentProto these 347 // snippets correspond to. Property paths will contain 1) property names, 348 // 2) the property separator character '.' used to represent nested property 349 // and 3) indices surrounded by brackets to represent a specific value in 350 // that property. 351 // 352 // Example properties: 353 // - 'body' : the first and only string value of a top-level 354 // property called 'body'. 355 // - 'sender.name' : the first and only string value of a property 356 // called 'name' that is a subproperty of a 357 // property called 'sender'. 358 // - 'bcc[1].emailaddress': the first and only string value of a property 359 // called 'emailaddress' that is a subproperty of 360 // the second document value of a property called 361 // 'bcc'. 362 // - 'attachments[0]' : the first (of more than one) string value of a 363 // property called 'attachments'. 364 // NOTE: If there is only a single value for a property (like 365 // 'sender.name'), then no value index will be added to the property path. 366 // An index of [0] is implied. If there is more than one value for a 367 // property, then the value index will be added to the property path (like 368 // 'attachements[0]'). 369 optional string property_name = 1; 370 371 // The term-match info for this property. Only populated if the property is 372 // a string. 373 repeated SnippetMatchProto snippet_matches = 2; 374 375 // The embedding-match info for this property. Only populated if the 376 // property is an embedding vector and get_embedding_match_info is set to 377 // true in the ResultSpecProto. 378 repeated EmbeddingMatchSnippetProto embedding_matches = 3; 379 } 380 // Properties that do not appear in entries do not contain any matches. 381 repeated EntryProto entries = 1; 382} 383 384// Icing lib-supplied results from a search results. 385// Next tag: 6 386message SearchResultProto { 387 // Status code can be one of: 388 // OK 389 // FAILED_PRECONDITION 390 // INVALID_ARGUMENT 391 // ABORTED 392 // INTERNAL 393 // 394 // See status.proto for more details. 395 // 396 // TODO(b/147699081): Fix error codes: +ABORTED. 397 // go/icing-library-apis. 398 optional StatusProto status = 1; 399 400 // The Results that matched the query. Empty if there was an error. 401 // Next tag: 6 402 message ResultProto { 403 // Document that matches the SearchSpecProto. 404 optional DocumentProto document = 1; 405 406 // Snippeting information for the document if requested in the 407 // ResultSpecProto. A default instance, if not requested. 408 optional SnippetProto snippet = 2; 409 410 // The score that the document was ranked by. The meaning of this score is 411 // determined by ScoringSpecProto.rank_by. 412 optional double score = 3; 413 414 // The child documents that were joined to a parent document. 415 repeated ResultProto joined_results = 4; 416 417 // Extra helpful scores as specified by 418 // ScoringSpecProto.additional_advanced_scoring_expressions. The scores will 419 // not be used for ranking. 420 repeated double additional_scores = 5 [packed = true]; 421 } 422 repeated ResultProto results = 2; 423 424 // Various debug fields. Not populated if ResultSpecProto.debug_info = false. 425 // Next tag: 4 426 message DebugInfoProto { 427 // The internal representation of the actual query string that was executed. 428 // This may be different from the SearchSpecProto.query if the original 429 // query was malformed. 430 optional string executed_query = 3; 431 432 reserved 1, 2; 433 } 434 optional DebugInfoProto debug_info = 3; 435 436 // An opaque token used internally to keep track of information needed for 437 // pagination. A valid pagination token is required to fetch other pages of 438 // results. A value 0 means that there're no more pages. 439 // LINT.IfChange(next_page_token) 440 optional uint64 next_page_token = 4; 441 // LINT.ThenChange(//depot/google3/icing/result/result-state-manager.h:kInvalidNextPageToken) 442 443 // Stats for query execution performance. 444 optional QueryStatsProto query_stats = 5; 445} 446 447// Next tag: 3 448message TypePropertyMask { 449 // The schema type to which these property masks should apply. 450 // If the schema type is the wildcard ("*"), then the type property masks 451 // will apply to all results of types that don't have their own, specific 452 // type property mask entry. 453 optional string schema_type = 1; 454 455 // The property masks specifying the property to be retrieved. Property 456 // masks must be composed only of property names, property separators (the 457 // '.' character). For example, "subject", "recipients.name". Specifying no 458 // property masks will result in *no* properties being retrieved. 459 repeated string paths = 2; 460} 461 462// Next tag: 5 463// TODO(b/394875109): Rename it to GetRequestProto to be consistent with the 464// name in AppSearch. 465message GetResultSpecProto { 466 optional string namespace_requested = 2; 467 repeated string ids = 3; 468 469 // How to specify a subset of properties to retrieve. If no type property mask 470 // has been specified for a schema type, then *all* properties of that schema 471 // type will be retrieved. 472 repeated TypePropertyMask type_property_masks = 1; 473 474 // The maximum number of accumulated bytes for the documents to return in the 475 // result. This limit is to prevent the result from being too large, and we 476 // can't send it over VM boundary, which has transaction limit 600KB. 477 optional int32 num_total_document_bytes_to_return = 4 478 [default = 2147483647]; // INT_MAX 479} 480 481// Next tag: 12 482message SuggestionSpecProto { 483 // REQUIRED: The "raw" prefix string that users may type. For example, "f" 484 // will search for suggested query that start with "f" like "foo", "fool". 485 optional string prefix = 1; 486 487 // OPTIONAL: Only search for suggestions that under the specified namespaces. 488 // If unset, the suggestion will search over all namespaces. Note that this 489 // applies to the entire 'prefix'. To issue different suggestions for 490 // different namespaces, separate RunSuggestion()'s will need to be made. 491 repeated string namespace_filters = 2; 492 493 // REQUIRED: The number of suggestions to be returned. 494 optional int32 num_to_return = 3; 495 496 // Indicates how the suggestion terms should be scored and ranked. 497 optional SuggestionScoringSpecProto scoring_spec = 4; 498 499 // OPTIONAL: Only search for suggestions that under the specified 500 // DocumentUris. If unset, the suggestion will search over all Documents. 501 // 502 // All namespace in the given NamespaceDocumentUriGroup should match the 503 // namespace_filters. i.e. appears in the namespace_filter or namespace_filter 504 // is empty. 505 // 506 // All given NamespaceDocumentUriGroup cannot have empty. Please use the 507 // namespace_filter to exclude a namespace. 508 // 509 // Note that this applies to the entire 'prefix'. To issue different 510 // suggestions for different DocumentIds, separate RunSuggestion()'s will need 511 // to be made. 512 repeated NamespaceDocumentUriGroup document_uri_filters = 5; 513 514 // OPTIONAL: Only search for suggestions that under the specified schemas. 515 // If unset, the suggestion will search over all schema types. Note that this 516 // applies to the entire 'prefix'. To issue different suggestions for 517 // different schema typs, separate RunSuggestion()'s will need to be made. 518 // Also note that schema filters will not be expanded for polymorphism. 519 repeated string schema_type_filters = 6; 520 521 // OPTIONAL: Only search for suggestions that under the specified types and 522 // properties. 523 // 524 // If unset, the suggestion will search over all types. 525 // If the TypePropertyMask.paths is unset, the suggestion will search over all 526 // properties under the TypePropertyMask.schema_type. 527 // 528 // Note that this applies to the entire 'prefix'. To issue different 529 // suggestions for different types, separate RunSuggestion()'s will need to be 530 // made. 531 repeated TypePropertyMask type_property_filters = 7; 532 533 // The vectors to be used in embedding queries. 534 repeated PropertyProto.VectorProto embedding_query_vectors = 8; 535 536 // The default metric type used to calculate the scores for embedding 537 // queries. 538 optional SearchSpecProto.EmbeddingQueryMetricType.Code 539 embedding_query_metric_type = 9; 540 541 // Strings to be used as parameters in the query. The strings will be treated 542 // as pure TEXT and will be normalized and tokenized. 543 repeated string query_parameter_strings = 10; 544 545 // Features enabled in this suggestion spec. 546 repeated string enabled_features = 11; 547} 548 549// A group that holds namespace and document_uris under it. 550message NamespaceDocumentUriGroup { 551 optional string namespace_ = 1; 552 repeated string document_uris = 2; 553} 554 555// Next tag: 3 556message SuggestionResponse { 557 message Suggestion { 558 // The suggested query string for client to search for. 559 optional string query = 1; 560 } 561 562 // Status code can be one of: 563 // OK 564 // FAILED_PRECONDITION 565 // INTERNAL 566 // 567 // See status.proto for more details. 568 optional StatusProto status = 1; 569 570 repeated Suggestion suggestions = 2; 571} 572 573// Specification for a left outer join. 574// 575// Next tag: 7 576message JoinSpecProto { 577 // Collection of several specs that will be used for searching and joining 578 // child documents. 579 // 580 // Next tag: 4 581 message NestedSpecProto { 582 // A nested SearchSpec that will be used to retrieve child documents. If you 583 // are only looking to join on a specific type documents, you could set a 584 // schema filter in this SearchSpec. This includes the nested search query. 585 // See SearchSpecProto. 586 optional SearchSpecProto search_spec = 1; 587 588 // A nested ScoringSpec that will be used to score child documents. 589 // See ScoringSpecProto. 590 optional ScoringSpecProto scoring_spec = 2; 591 592 // A nested ResultSpec that will be used to format child documents in the 593 // result joined documents, e.g. snippeting, projection. 594 // See ResultSpecProto. 595 optional ResultSpecProto result_spec = 3; 596 } 597 optional NestedSpecProto nested_spec = 1; 598 599 // The equivalent of a primary key in SQL. This is an expression that will be 600 // used to match child documents from the nested search to this document. One 601 // such expression is qualifiedId(). When used, it means the contents of 602 // child_property_expression property in the child documents must be equal to 603 // the qualified id. 604 // TODO(b/256022027) allow for parent_property_expression to be any property 605 // of the parent document. 606 optional string parent_property_expression = 2; 607 608 // The equivalent of a foreign key in SQL. This defines an equality constraint 609 // between a property in a child document and a property in the parent 610 // document. For example, if you want to join child documents which an 611 // entityId property containing a fully qualified document id, 612 // child_property_expression can be set to "entityId". 613 // TODO(b/256022027) figure out how to allow this to refer to documents 614 // outside of same pkg+db+ns. 615 optional string child_property_expression = 3; 616 617 // The max number of child documents to join to a parent document. 618 // DEPRECATED: use ResultSpecProto.max_joined_children_per_parent_to_return to 619 // control the number of children that are returned. There is no supported 620 // control for the number of children being scored at this time. 621 optional int32 max_joined_child_count = 4 [deprecated = true]; 622 623 // The strategy by which to score the aggregation of child documents. For 624 // example, you might want to know which entity document has the most actions 625 // taken on it. If JOIN_AGGREGATE_SCORE is used in the base SearchSpecProto, 626 // the COUNT value will rank entity documents based on the number of child 627 // documents. 628 message AggregationScoringStrategy { 629 enum Code { 630 NONE = 0; // No aggregation strategy for child documents and use parent 631 // document score. 632 COUNT = 1; 633 MIN = 2; 634 AVG = 3; 635 MAX = 4; 636 SUM = 5; 637 } 638 } 639 optional AggregationScoringStrategy.Code aggregation_scoring_strategy = 5; 640} 641