diff --git a/internal/core/src/common/Types.h b/internal/core/src/common/Types.h index f7370a08dd..b31bc1eee0 100644 --- a/internal/core/src/common/Types.h +++ b/internal/core/src/common/Types.h @@ -113,6 +113,11 @@ using InsertRecordProto = proto::segcore::InsertRecord; using PkType = std::variant; using DefaultValueType = proto::schema::ValueField; +struct QueryIteratorCursor { + PkType last_pk; + int64_t last_element_offset = -1; +}; + inline size_t GetDataTypeSize(DataType data_type, int dim = 1) { switch (data_type) { diff --git a/internal/core/src/query/ExecPlanNodeVisitor.cpp b/internal/core/src/query/ExecPlanNodeVisitor.cpp index 16937a15ed..c408601471 100644 --- a/internal/core/src/query/ExecPlanNodeVisitor.cpp +++ b/internal/core/src/query/ExecPlanNodeVisitor.cpp @@ -346,8 +346,10 @@ ExecPlanNodeVisitor::setupRetrieveResult( "Element Level Find", tracer::GetRootSpan(), true); auto array_offsets = query_context->get_array_offsets(); auto [doc_offsets, element_indices, has_more] = - segment->find_first_n_element( - node.limit_, view, array_offsets.get()); + segment->find_first_n_element(node.limit_, + view, + array_offsets.get(), + node.query_iterator_cursor_); tmp_retrieve_result.result_offsets_ = std::move(doc_offsets); tmp_retrieve_result.element_indices_ = std::move(element_indices); tmp_retrieve_result.has_more_result = has_more; diff --git a/internal/core/src/query/PlanNode.h b/internal/core/src/query/PlanNode.h index 844e555bbd..5f9433cc52 100644 --- a/internal/core/src/query/PlanNode.h +++ b/internal/core/src/query/PlanNode.h @@ -13,11 +13,13 @@ #include #include +#include #include #include #include "common/FieldMeta.h" #include "common/QueryInfo.h" +#include "common/Types.h" namespace milvus::plan { class PlanNode; @@ -67,6 +69,7 @@ struct RetrievePlanNode : PlanNode { // Field IDs for pipeline columns in the same order as the ProjectNode output. // Used by FillOrderByResult to set field_id on DataArrays produced by the pipeline. std::vector pipeline_field_ids_; + std::optional query_iterator_cursor_; }; } // namespace milvus::query diff --git a/internal/core/src/query/PlanProto.cpp b/internal/core/src/query/PlanProto.cpp index 8158f6aab3..16b6b3d74e 100644 --- a/internal/core/src/query/PlanProto.cpp +++ b/internal/core/src/query/PlanProto.cpp @@ -755,6 +755,23 @@ ProtoParser::RetrievePlanNodeFromProto( parse_expr_to_filter_node(query.predicates()); } } + if (query.has_query_iterator_cursor()) { + AssertInfo(is_element_level, + "query iterator cursor is only supported for " + "element-level query"); + const auto& cursor_proto = query.query_iterator_cursor(); + QueryIteratorCursor cursor; + if (cursor_proto.has_last_int_pk()) { + cursor.last_pk = cursor_proto.last_int_pk(); + } else if (cursor_proto.has_last_str_pk()) { + cursor.last_pk = cursor_proto.last_str_pk(); + } else { + ThrowInfo(ErrorCode::UnexpectedError, + "query iterator cursor requires last primary key"); + } + cursor.last_element_offset = cursor_proto.last_element_offset(); + plan_node->query_iterator_cursor_ = std::move(cursor); + } // 2. Build MvccNode plannode = std::make_shared( diff --git a/internal/core/src/segcore/ChunkedSegmentSealedImpl.cpp b/internal/core/src/segcore/ChunkedSegmentSealedImpl.cpp index e152e679fd..6f69ddcc5d 100644 --- a/internal/core/src/segcore/ChunkedSegmentSealedImpl.cpp +++ b/internal/core/src/segcore/ChunkedSegmentSealedImpl.cpp @@ -2241,11 +2241,12 @@ std::tuple, std::vector>, bool> ChunkedSegmentSealedImpl::find_first_n_element( int64_t limit, const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const { + const IArrayOffsets* array_offsets, + const std::optional& cursor) const { if (!is_sorted_by_pk_) { // Not sorted by PK, use pk2offset_ to iterate in PK order return insert_record_.pk2offset_->find_first_n_element( - limit, element_bitset, array_offsets); + limit, element_bitset, array_offsets, cursor); } // Sorted by PK, element_id order = (PK, element_index) order @@ -2254,6 +2255,36 @@ ChunkedSegmentSealedImpl::find_first_n_element( limit = static_cast(element_bitset.size()); } + // We iterate matching elements by global element id, which maps back + // to (doc_offset, element_offset). The cursor, however, only tells us the + // last returned PK and element offset. Find the row for that PK first; the + // scan can then skip only elements from that row whose element offset has + // already been returned. + std::optional cursor_doc_offset; + if (cursor.has_value()) { + auto pk_field_id = + schema_->get_primary_field_id().value_or(FieldId(-1)); + AssertInfo(pk_field_id.get() != -1, "Primary key is -1"); + auto pk_column = get_column(pk_field_id); + AssertInfo(pk_column != nullptr, "primary key column not loaded"); + switch (schema_->get_fields().at(pk_field_id).get_data_type()) { + case DataType::INT64: + cursor_doc_offset = find_sorted_pk_doc_offset( + std::get(cursor->last_pk), pk_column); + break; + case DataType::VARCHAR: + cursor_doc_offset = find_sorted_pk_doc_offset( + std::get(cursor->last_pk), pk_column); + break; + default: + ThrowInfo( + DataTypeInvalid, + fmt::format( + "unsupported type {}", + schema_->get_fields().at(pk_field_id).get_data_type())); + } + } + int64_t hit_num = 0; auto element_size = static_cast(element_bitset.size()); int64_t cnt = element_size - element_bitset.count(); @@ -2268,6 +2299,12 @@ ChunkedSegmentSealedImpl::find_first_n_element( while (elem_opt.has_value() && hit_num < limit) { int64_t elem_id = static_cast(elem_opt.value()); auto [doc_id, elem_idx] = array_offsets->ElementIDToRowID(elem_id); + if (cursor_doc_offset.has_value() && + doc_id == cursor_doc_offset.value() && + elem_idx <= cursor->last_element_offset) { + elem_opt = element_bitset.find_next(elem_id, false); + continue; + } if (doc_id != current_doc_id) { // New document - start a new entry diff --git a/internal/core/src/segcore/ChunkedSegmentSealedImpl.h b/internal/core/src/segcore/ChunkedSegmentSealedImpl.h index 6b0937ab01..eb0fe34dd8 100644 --- a/internal/core/src/segcore/ChunkedSegmentSealedImpl.h +++ b/internal/core/src/segcore/ChunkedSegmentSealedImpl.h @@ -393,9 +393,11 @@ class ChunkedSegmentSealedImpl : public SegmentSealed { find_first_n(int64_t limit, const BitsetTypeView& bitset) const override; std::tuple, std::vector>, bool> - find_first_n_element(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const override; + find_first_n_element( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const override; // Calculate: output[i] = Vec[seg_offset[i]] // where Vec is determined from field_offset @@ -727,6 +729,20 @@ class ChunkedSegmentSealedImpl : public SegmentSealed { } } + template + std::optional + find_sorted_pk_doc_offset( + const PK& pk, + const std::shared_ptr& pk_column) const { + auto all_chunk_pins = pk_column->GetAllChunks(nullptr); + auto [chunk_id, in_chunk_offset, exact_match] = + this->pk_lower_bound(pk, pk_column.get(), all_chunk_pins, 0); + if (!exact_match) { + return std::nullopt; + } + return pk_column->GetNumRowsUntilChunk(chunk_id) + in_chunk_offset; + } + template void search_pks_with_two_pointers_impl( diff --git a/internal/core/src/segcore/InsertRecord.h b/internal/core/src/segcore/InsertRecord.h index 0b4bd3d1a6..d3b6ae7070 100644 --- a/internal/core/src/segcore/InsertRecord.h +++ b/internal/core/src/segcore/InsertRecord.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -279,9 +280,11 @@ class OffsetMap { // - has_more flag indicating if there are more results virtual std:: tuple, std::vector>, bool> - find_first_n_element(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const = 0; + find_first_n_element( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const = 0; virtual void clear() = 0; @@ -409,9 +412,11 @@ class OffsetOrderedMap : public OffsetMap { } std::tuple, std::vector>, bool> - find_first_n_element(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const override { + find_first_n_element( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const override { std::shared_lock lck(mtx_); if (limit == Unlimited || limit == NoLimit) { @@ -419,7 +424,7 @@ class OffsetOrderedMap : public OffsetMap { } return find_first_n_element_by_index( - limit, element_bitset, array_offsets); + limit, element_bitset, array_offsets, cursor); } void @@ -467,9 +472,11 @@ class OffsetOrderedMap : public OffsetMap { } std::tuple, std::vector>, bool> - find_first_n_element_by_index(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const { + find_first_n_element_by_index( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const { std::vector doc_offsets; std::vector> element_indices; @@ -504,6 +511,10 @@ class OffsetOrderedMap : public OffsetMap { if (elem_id >= element_size) { continue; } + if (is_skipped_by_cursor( + it->first, elem_id - first_elem, cursor)) { + continue; + } if (!element_bitset[elem_id]) { // 0 means pass filter matching_indices.push_back( static_cast(elem_id - first_elem)); @@ -518,13 +529,37 @@ class OffsetOrderedMap : public OffsetMap { // PK hit, no need to continue traversing older offsets with the same PK. break; } + if (is_cursor_pk(it->first, cursor)) { + // The cursor applies to the newest visible row for this PK. + // Do not fall through to older offsets of the same PK. + break; + } } } - bool has_more = more_hit_than_limit && (it != map_.end()); + bool has_more = more_hit_than_limit && hit_num >= limit; return {std::move(doc_offsets), std::move(element_indices), has_more}; } + bool + is_skipped_by_cursor( + const T& pk, + int64_t element_offset, + const std::optional& cursor) const { + return is_cursor_pk(pk, cursor) && + element_offset <= cursor->last_element_offset; + } + + bool + is_cursor_pk(const T& pk, + const std::optional& cursor) const { + if (!cursor.has_value()) { + return false; + } + auto last_pk = std::get_if(&cursor->last_pk); + return last_pk != nullptr && *last_pk == pk; + } + private: OrderedMap map_; mutable std::shared_mutex mtx_; @@ -663,9 +698,11 @@ class OffsetOrderedArray : public OffsetMap { } std::tuple, std::vector>, bool> - find_first_n_element(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const override { + find_first_n_element( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const override { check_search(); if (limit == Unlimited || limit == NoLimit) { @@ -673,7 +710,7 @@ class OffsetOrderedArray : public OffsetMap { } return find_first_n_element_by_index( - limit, element_bitset, array_offsets); + limit, element_bitset, array_offsets, cursor); } void @@ -714,9 +751,11 @@ class OffsetOrderedArray : public OffsetMap { } std::tuple, std::vector>, bool> - find_first_n_element_by_index(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const { + find_first_n_element_by_index( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const { std::vector doc_offsets; std::vector> element_indices; @@ -746,6 +785,10 @@ class OffsetOrderedArray : public OffsetMap { if (elem_id >= element_size) { continue; } + if (is_skipped_by_cursor( + it->first, elem_id - first_elem, cursor)) { + continue; + } if (!element_bitset[elem_id]) { // 0 means pass filter matching_indices.push_back( static_cast(elem_id - first_elem)); @@ -760,10 +803,23 @@ class OffsetOrderedArray : public OffsetMap { } } - bool has_more = more_hit_than_limit && (it != array_.end()); + bool has_more = more_hit_than_limit && hit_num >= limit; return {std::move(doc_offsets), std::move(element_indices), has_more}; } + bool + is_skipped_by_cursor( + const T& pk, + int64_t element_offset, + const std::optional& cursor) const { + if (!cursor.has_value()) { + return false; + } + auto last_pk = std::get_if(&cursor->last_pk); + return last_pk != nullptr && *last_pk == pk && + element_offset <= cursor->last_element_offset; + } + void check_search() const { AssertInfo(is_sealed, @@ -908,9 +964,11 @@ class VirtualPKOffsetMap : public OffsetMap { } std::tuple, std::vector>, bool> - find_first_n_element(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const override { + find_first_n_element( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const override { // External tables don't support array fields, but implement // the interface for completeness. auto element_size = static_cast(element_bitset.size()); @@ -931,7 +989,8 @@ class VirtualPKOffsetMap : public OffsetMap { std::vector matching; for (int64_t e = first_elem; e < last_elem && hit_num < limit; e++) { - if (e < element_size && !element_bitset[e]) { + if (e < element_size && !element_bitset[e] && + !is_skipped_by_cursor(doc, e - first_elem, cursor)) { matching.push_back(static_cast(e - first_elem)); hit_num++; } @@ -956,6 +1015,19 @@ class VirtualPKOffsetMap : public OffsetMap { return sizeof(VirtualPKOffsetMap); } + bool + is_skipped_by_cursor( + int64_t doc, + int64_t element_offset, + const std::optional& cursor) const { + if (!cursor.has_value()) { + return false; + } + auto last_pk = std::get_if(&cursor->last_pk); + return last_pk != nullptr && *last_pk == (shifted_segment_id_ | doc) && + element_offset <= cursor->last_element_offset; + } + private: int64_t truncated_segment_id_; int64_t shifted_segment_id_; diff --git a/internal/core/src/segcore/InsertRecordOffsetOrderedArrayTest.cpp b/internal/core/src/segcore/InsertRecordOffsetOrderedArrayTest.cpp index 3dcb5c6728..638a2087ce 100644 --- a/internal/core/src/segcore/InsertRecordOffsetOrderedArrayTest.cpp +++ b/internal/core/src/segcore/InsertRecordOffsetOrderedArrayTest.cpp @@ -174,7 +174,7 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element) { BitsetTypeView view(all.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); ASSERT_EQ(doc_offsets.size(), num); for (size_t i = 0; i < doc_offsets.size(); i++) { ASSERT_EQ(elem_indices[i].size(), array_len); @@ -188,7 +188,8 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element) { all.reset(); BitsetTypeView view(all.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = - this->map_.find_first_n_element(4, view, array_offsets.get()); + this->map_.find_first_n_element( + 4, view, array_offsets.get(), std::nullopt); int total = 0; for (auto& indices : elem_indices) { total += indices.size(); @@ -210,7 +211,7 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element) { BitsetTypeView view(partial.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); ASSERT_EQ(doc_offsets.size(), num); for (size_t i = 0; i < doc_offsets.size(); i++) { ASSERT_EQ(elem_indices[i].size(), 1); @@ -225,7 +226,7 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element) { BitsetTypeView view(none.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); ASSERT_EQ(doc_offsets.size(), 0); ASSERT_EQ(elem_indices.size(), 0); ASSERT_FALSE(has_more); @@ -239,7 +240,7 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element) { BitsetTypeView view(small.data(), smaller_size); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); int total = 0; for (auto& indices : elem_indices) { total += indices.size(); @@ -289,7 +290,7 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element_has_more) { BitsetTypeView view(all.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); int collected = 0; for (auto& indices : elem_indices) { collected += indices.size(); @@ -310,7 +311,8 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element_has_more) { } BitsetTypeView view(partial.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = - this->map_.find_first_n_element(num, view, array_offsets.get()); + this->map_.find_first_n_element( + num, view, array_offsets.get(), std::nullopt); int collected = 0; for (auto& indices : elem_indices) { collected += indices.size(); @@ -326,7 +328,8 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element_has_more) { all.reset(); BitsetTypeView view(all.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = - this->map_.find_first_n_element(3, view, array_offsets.get()); + this->map_.find_first_n_element( + 3, view, array_offsets.get(), std::nullopt); int collected = 0; for (auto& indices : elem_indices) { collected += indices.size(); @@ -337,10 +340,62 @@ TYPED_TEST_P(TypedOffsetOrderedArrayTest, find_first_n_element_has_more) { } } +TYPED_TEST_P(TypedOffsetOrderedArrayTest, + find_first_n_element_with_iterator_cursor) { + auto make_pk = [](int i) { + if constexpr (std::is_same_v) { + return std::to_string(i); + } else { + return static_cast(i); + } + }; + + int num = 3; + int array_len = 4; + for (int i = 0; i < num; i++) { + this->insert(make_pk(i)); + } + this->seal(); + + std::vector row_to_element_start = {0}; + for (int doc = 0; doc < num; doc++) { + row_to_element_start.push_back( + static_cast((doc + 1) * array_len)); + } + auto array_offsets = + std::make_shared(std::move(row_to_element_start)); + + BitsetType bitset(num * array_len); + bitset.reset(); + for (int e = 0; e < array_len; e++) { + bitset.set(e); // Simulate query expr pk >= 1. + } + BitsetTypeView view(bitset.data(), bitset.size()); + + QueryIteratorCursor cursor; + cursor.last_pk = make_pk(1); + cursor.last_element_offset = 1; + + auto [doc_offsets, elem_indices, has_more] = + this->map_.find_first_n_element(10, view, array_offsets.get(), cursor); + ASSERT_EQ(doc_offsets, std::vector({1, 2})); + ASSERT_EQ(elem_indices[0], std::vector({2, 3})); + ASSERT_EQ(elem_indices[1], std::vector({0, 1, 2, 3})); + ASSERT_FALSE(has_more); + + auto [limited_docs, limited_indices, limited_has_more] = + this->map_.find_first_n_element(3, view, array_offsets.get(), cursor); + ASSERT_EQ(limited_docs, std::vector({1, 2})); + ASSERT_EQ(limited_indices[0], std::vector({2, 3})); + ASSERT_EQ(limited_indices[1], std::vector({0})); + ASSERT_TRUE(limited_has_more); +} + REGISTER_TYPED_TEST_SUITE_P(TypedOffsetOrderedArrayTest, find_first_n, find_first_n_element, - find_first_n_element_has_more); + find_first_n_element_has_more, + find_first_n_element_with_iterator_cursor); INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TypedOffsetOrderedArrayTest, TypeOfPks); // ===================================================================== diff --git a/internal/core/src/segcore/InsertRecordOffsetOrderedMapTest.cpp b/internal/core/src/segcore/InsertRecordOffsetOrderedMapTest.cpp index 537c99d7bf..43bf5bb8cf 100644 --- a/internal/core/src/segcore/InsertRecordOffsetOrderedMapTest.cpp +++ b/internal/core/src/segcore/InsertRecordOffsetOrderedMapTest.cpp @@ -174,7 +174,7 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element) { BitsetTypeView view(all.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); ASSERT_EQ(doc_offsets.size(), num); for (size_t i = 0; i < doc_offsets.size(); i++) { ASSERT_EQ(elem_indices[i].size(), array_len) @@ -190,7 +190,8 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element) { BitsetTypeView view(all.data(), total_elements); // limit=4: first doc contributes 3 elements, second doc contributes 1 auto [doc_offsets, elem_indices, has_more] = - this->map_.find_first_n_element(4, view, array_offsets.get()); + this->map_.find_first_n_element( + 4, view, array_offsets.get(), std::nullopt); int total = 0; for (auto& indices : elem_indices) { total += indices.size(); @@ -212,7 +213,7 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element) { BitsetTypeView view(partial.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); ASSERT_EQ(doc_offsets.size(), num); for (size_t i = 0; i < doc_offsets.size(); i++) { ASSERT_EQ(elem_indices[i].size(), 1); @@ -227,7 +228,7 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element) { BitsetTypeView view(none.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); ASSERT_EQ(doc_offsets.size(), 0); ASSERT_EQ(elem_indices.size(), 0); } @@ -240,7 +241,7 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element) { BitsetTypeView view(small.data(), smaller_size); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); // Last doc's elements are beyond bitset, should be skipped int total = 0; for (auto& indices : elem_indices) { @@ -288,7 +289,7 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element_has_more) { BitsetTypeView view(all.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = this->map_.find_first_n_element( - total_elements, view, array_offsets.get()); + total_elements, view, array_offsets.get(), std::nullopt); int collected = 0; for (auto& indices : elem_indices) { collected += indices.size(); @@ -308,7 +309,8 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element_has_more) { } BitsetTypeView view(partial.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = - this->map_.find_first_n_element(num, view, array_offsets.get()); + this->map_.find_first_n_element( + num, view, array_offsets.get(), std::nullopt); int collected = 0; for (auto& indices : elem_indices) { collected += indices.size(); @@ -324,7 +326,8 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element_has_more) { all.reset(); BitsetTypeView view(all.data(), total_elements); auto [doc_offsets, elem_indices, has_more] = - this->map_.find_first_n_element(3, view, array_offsets.get()); + this->map_.find_first_n_element( + 3, view, array_offsets.get(), std::nullopt); int collected = 0; for (auto& indices : elem_indices) { collected += indices.size(); @@ -335,8 +338,103 @@ TYPED_TEST_P(TypedOffsetOrderedMapTest, find_first_n_element_has_more) { } } -REGISTER_TYPED_TEST_SUITE_P(TypedOffsetOrderedMapTest, - find_first_n, - find_first_n_element, - find_first_n_element_has_more); +TYPED_TEST_P(TypedOffsetOrderedMapTest, + find_first_n_element_with_iterator_cursor) { + auto make_pk = [](int i) { + if constexpr (std::is_same_v) { + return std::to_string(i); + } else { + return static_cast(i); + } + }; + + int num = 3; + int array_len = 4; + for (int i = 0; i < num; i++) { + this->insert(make_pk(i)); + } + + std::vector row_to_element_start = {0}; + for (int doc = 0; doc < num; doc++) { + row_to_element_start.push_back( + static_cast((doc + 1) * array_len)); + } + auto array_offsets = + std::make_shared(std::move(row_to_element_start)); + + BitsetType bitset(num * array_len); + bitset.reset(); + for (int e = 0; e < array_len; e++) { + bitset.set(e); // Simulate query expr pk >= 1. + } + BitsetTypeView view(bitset.data(), bitset.size()); + + QueryIteratorCursor cursor; + cursor.last_pk = make_pk(1); + cursor.last_element_offset = 1; + + auto [doc_offsets, elem_indices, has_more] = + this->map_.find_first_n_element(10, view, array_offsets.get(), cursor); + ASSERT_EQ(doc_offsets, std::vector({1, 2})); + ASSERT_EQ(elem_indices[0], std::vector({2, 3})); + ASSERT_EQ(elem_indices[1], std::vector({0, 1, 2, 3})); + ASSERT_FALSE(has_more); + + auto [limited_docs, limited_indices, limited_has_more] = + this->map_.find_first_n_element(3, view, array_offsets.get(), cursor); + ASSERT_EQ(limited_docs, std::vector({1, 2})); + ASSERT_EQ(limited_indices[0], std::vector({2, 3})); + ASSERT_EQ(limited_indices[1], std::vector({0})); + ASSERT_TRUE(limited_has_more); +} + +TYPED_TEST_P(TypedOffsetOrderedMapTest, + find_first_n_element_cursor_does_not_return_stale_pk) { + auto make_pk = [](int i) { + if constexpr (std::is_same_v) { + return std::to_string(i); + } else { + return static_cast(i); + } + }; + + int array_len = 3; + this->insert(make_pk(0)); + this->insert(make_pk(1)); // older version of pk=1 + this->insert(make_pk(1)); // newest version of pk=1 + this->insert(make_pk(2)); + + std::vector row_to_element_start = {0}; + for (int doc = 0; doc < 4; doc++) { + row_to_element_start.push_back( + static_cast((doc + 1) * array_len)); + } + auto array_offsets = + std::make_shared(std::move(row_to_element_start)); + + BitsetType bitset(4 * array_len); + bitset.reset(); + for (int e = 0; e < array_len; e++) { + bitset.set(e); // Simulate query expr pk >= 1. + } + BitsetTypeView view(bitset.data(), bitset.size()); + + QueryIteratorCursor cursor; + cursor.last_pk = make_pk(1); + cursor.last_element_offset = 2; + + auto [doc_offsets, elem_indices, has_more] = + this->map_.find_first_n_element(10, view, array_offsets.get(), cursor); + ASSERT_EQ(doc_offsets, std::vector({3})); + ASSERT_EQ(elem_indices[0], std::vector({0, 1, 2})); + ASSERT_FALSE(has_more); +} + +REGISTER_TYPED_TEST_SUITE_P( + TypedOffsetOrderedMapTest, + find_first_n, + find_first_n_element, + find_first_n_element_has_more, + find_first_n_element_with_iterator_cursor, + find_first_n_element_cursor_does_not_return_stale_pk); INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TypedOffsetOrderedMapTest, TypeOfPks); diff --git a/internal/core/src/segcore/SegmentGrowingImpl.h b/internal/core/src/segcore/SegmentGrowingImpl.h index 19f96875db..97c516980e 100644 --- a/internal/core/src/segcore/SegmentGrowingImpl.h +++ b/internal/core/src/segcore/SegmentGrowingImpl.h @@ -555,11 +555,13 @@ class SegmentGrowingImpl : public SegmentGrowing { } std::tuple, std::vector>, bool> - find_first_n_element(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const override { + find_first_n_element( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const override { return insert_record_.pk2offset_->find_first_n_element( - limit, element_bitset, array_offsets); + limit, element_bitset, array_offsets, cursor); } bool diff --git a/internal/core/src/segcore/SegmentInterface.h b/internal/core/src/segcore/SegmentInterface.h index 0e57c24f23..cc195b31a9 100644 --- a/internal/core/src/segcore/SegmentInterface.h +++ b/internal/core/src/segcore/SegmentInterface.h @@ -615,9 +615,11 @@ class SegmentInternalInterface : public SegmentInterface { */ virtual std:: tuple, std::vector>, bool> - find_first_n_element(int64_t limit, - const BitsetTypeView& element_bitset, - const IArrayOffsets* array_offsets) const = 0; + find_first_n_element( + int64_t limit, + const BitsetTypeView& element_bitset, + const IArrayOffsets* array_offsets, + const std::optional& cursor) const = 0; void FillTargetEntryDirectly( diff --git a/internal/core/unittest/test_element_filter.cpp b/internal/core/unittest/test_element_filter.cpp index db19fc5f0d..ec75b9235f 100644 --- a/internal/core/unittest/test_element_filter.cpp +++ b/internal/core/unittest/test_element_filter.cpp @@ -1849,6 +1849,197 @@ TEST(ElementFilter, RetrieveSortedByPk) { EXEC_EVAL_EXPR_BATCH_SIZE.store(saved_batch_size); } +TEST(ElementFilter, RetrieveIteratorCursorSkipsReturnedElements) { + auto saved_batch_size = EXEC_EVAL_EXPR_BATCH_SIZE.load(); + EXEC_EVAL_EXPR_BATCH_SIZE.store(100); + + int dim = 4; + auto schema = std::make_shared(); + auto vec_fid = schema->AddDebugVectorArrayField("structA[array_float_vec]", + DataType::VECTOR_FLOAT, + dim, + knowhere::metric::L2); + auto int_array_fid = schema->AddDebugArrayField( + "structA[price_array]", DataType::INT32, false); + auto int64_fid = schema->AddDebugField("id", DataType::INT64); + schema->set_primary_field_id(int64_fid); + + size_t N = 20; + int array_len = 5; + auto raw_data = DataGen(schema, N, 42, 0, 1, array_len); + + for (int i = 0; i < raw_data.raw_->fields_data_size(); i++) { + auto* field_data = raw_data.raw_->mutable_fields_data(i); + if (field_data->field_id() == int_array_fid.get()) { + field_data->mutable_scalars() + ->mutable_array_data() + ->mutable_data() + ->Clear(); + + for (int row = 0; row < N; row++) { + auto* array_data = field_data->mutable_scalars() + ->mutable_array_data() + ->mutable_data() + ->Add(); + for (int elem = 0; elem < array_len; elem++) { + array_data->mutable_int_data()->mutable_data()->Add(elem); + } + } + break; + } + } + + auto segment = CreateSealedSegment(schema, + empty_index_meta, + /*segment_id=*/0, + SegcoreConfig::default_config(), + /*is_sorted_by_pk=*/true); + LoadGeneratedDataIntoSegment(raw_data, segment.get()); + + auto build_plan = [&](int64_t limit, + std::optional min_pk, + std::optional> cursor) { + proto::plan::PlanNode plan_node; + auto* query = plan_node.mutable_query(); + query->set_is_count(false); + query->set_limit(limit); + + auto* expr = query->mutable_predicates(); + auto* element_filter = expr->mutable_element_filter_expr(); + element_filter->set_struct_name("structA"); + + auto* element_expr = element_filter->mutable_element_expr(); + auto* element_range = element_expr->mutable_unary_range_expr(); + auto* element_column = element_range->mutable_column_info(); + element_column->set_field_id(int_array_fid.get()); + element_column->set_data_type(proto::schema::DataType::Int32); + element_column->set_element_type(proto::schema::DataType::Int32); + element_column->set_is_element_level(true); + element_range->set_op(proto::plan::OpType::GreaterEqual); + element_range->mutable_value()->set_int64_val(0); + + if (min_pk.has_value()) { + auto* predicate = element_filter->mutable_predicate(); + auto* pk_range = predicate->mutable_unary_range_expr(); + auto* pk_column = pk_range->mutable_column_info(); + pk_column->set_field_id(int64_fid.get()); + pk_column->set_data_type(proto::schema::DataType::Int64); + pk_range->set_op(proto::plan::OpType::GreaterEqual); + pk_range->mutable_value()->set_int64_val(min_pk.value()); + } + + if (cursor.has_value()) { + auto* query_cursor = query->mutable_query_iterator_cursor(); + query_cursor->set_last_int_pk(cursor->first); + query_cursor->set_last_element_offset(cursor->second); + } + + plan_node.add_output_field_ids(int64_fid.get()); + plan_node.add_output_field_ids(int_array_fid.get()); + + auto parser = ProtoParser(schema); + return parser.CreateRetrievePlan(plan_node); + }; + + auto retrieve = [&](const RetrievePlan* plan) { + return segment->Retrieve(nullptr, + plan, + 1L << 63, + INT64_MAX, + false, + folly::CancellationToken(), + 0, + 0); + }; + + auto first_plan = build_plan( + /*limit=*/8, /*min_pk=*/std::nullopt, /*cursor=*/std::nullopt); + auto first_results = retrieve(first_plan.get()); + ASSERT_NE(first_results, nullptr); + ASSERT_TRUE(first_results->element_level()); + ASSERT_TRUE(first_results->has_more_result()); + ASSERT_EQ(first_results->offset_size(), 2); + ASSERT_EQ(first_results->offset(0), 0); + ASSERT_EQ(first_results->element_indices(0).indices_size(), 5); + for (int i = 0; i < 5; i++) { + ASSERT_EQ(first_results->element_indices(0).indices(i), i); + } + ASSERT_EQ(first_results->offset(1), 1); + ASSERT_EQ(first_results->element_indices(1).indices_size(), 3); + for (int i = 0; i < 3; i++) { + ASSERT_EQ(first_results->element_indices(1).indices(i), i); + } + + auto second_plan = + build_plan(/*limit=*/8, + /*min_pk=*/std::optional(1), + /*cursor=*/std::make_pair(1, 2)); + auto second_results = retrieve(second_plan.get()); + ASSERT_NE(second_results, nullptr); + ASSERT_TRUE(second_results->element_level()); + ASSERT_TRUE(second_results->has_more_result()); + ASSERT_EQ(second_results->offset_size(), 3); + + ASSERT_EQ(second_results->offset(0), 1); + ASSERT_EQ(second_results->element_indices(0).indices_size(), 2); + ASSERT_EQ(second_results->element_indices(0).indices(0), 3); + ASSERT_EQ(second_results->element_indices(0).indices(1), 4); + + ASSERT_EQ(second_results->offset(1), 2); + ASSERT_EQ(second_results->element_indices(1).indices_size(), 5); + for (int i = 0; i < 5; i++) { + ASSERT_EQ(second_results->element_indices(1).indices(i), i); + } + + ASSERT_EQ(second_results->offset(2), 3); + ASSERT_EQ(second_results->element_indices(2).indices_size(), 1); + ASSERT_EQ(second_results->element_indices(2).indices(0), 0); + + auto last_page_plan = + build_plan(/*limit=*/2, + /*min_pk=*/std::optional(19), + /*cursor=*/std::make_pair(19, 2)); + auto last_page_results = retrieve(last_page_plan.get()); + ASSERT_NE(last_page_results, nullptr); + ASSERT_TRUE(last_page_results->element_level()); + ASSERT_FALSE(last_page_results->has_more_result()); + ASSERT_EQ(last_page_results->offset_size(), 1); + ASSERT_EQ(last_page_results->offset(0), 19); + ASSERT_EQ(last_page_results->element_indices(0).indices_size(), 2); + ASSERT_EQ(last_page_results->element_indices(0).indices(0), 3); + ASSERT_EQ(last_page_results->element_indices(0).indices(1), 4); + + EXEC_EVAL_EXPR_BATCH_SIZE.store(saved_batch_size); +} + +TEST(ElementFilter, QueryIteratorCursorRequiresElementFilter) { + auto schema = std::make_shared(); + auto int64_fid = schema->AddDebugField("id", DataType::INT64); + schema->set_primary_field_id(int64_fid); + + proto::plan::PlanNode plan_node; + auto* query = plan_node.mutable_query(); + query->set_is_count(false); + query->set_limit(10); + + auto* predicate = query->mutable_predicates(); + auto* range = predicate->mutable_unary_range_expr(); + auto* column_info = range->mutable_column_info(); + column_info->set_field_id(int64_fid.get()); + column_info->set_data_type(proto::schema::DataType::Int64); + range->set_op(proto::plan::OpType::GreaterEqual); + range->mutable_value()->set_int64_val(0); + + auto* cursor = query->mutable_query_iterator_cursor(); + cursor->set_last_int_pk(1); + cursor->set_last_element_offset(2); + + plan_node.add_output_field_ids(int64_fid.get()); + + auto parser = ProtoParser(schema); + ASSERT_ANY_THROW(parser.CreateRetrievePlan(plan_node)); +} + // Regression test for https://github.com/milvus-io/milvus/issues/49260 // ElementFilterBitsNode: when element_filter is AND-composed with a predicate // that matches 0 docs on a segment, doc_hit_ratio = 0 triggers offset_mode diff --git a/internal/proxy/task.go b/internal/proxy/task.go index 6ad338e8dc..0103fbd8cf 100644 --- a/internal/proxy/task.go +++ b/internal/proxy/task.go @@ -81,6 +81,8 @@ const ( SearchIterBatchSizeKey = "search_iter_batch_size" SearchIterLastBoundKey = "search_iter_last_bound" SearchIterIdKey = "search_iter_id" + QueryIterLastPKKey = "query_iter_last_pk" + QueryIterLastOffsetKey = "query_iter_last_element_offset" QueryGroupByFieldsKey = "group_by_fields" OrderByFieldsKey = "order_by_fields" PipelineTraceKey = "pipeline_trace" diff --git a/internal/proxy/task_query.go b/internal/proxy/task_query.go index 0fc15a539b..a274f31e6d 100644 --- a/internal/proxy/task_query.go +++ b/internal/proxy/task_query.go @@ -97,15 +97,16 @@ func (t *queryTask) getQueryLabel() string { } type queryParams struct { - limit int64 - offset int64 - reduceType reduce.IReduceType - isIterator bool - collectionID int64 - groupByFields []string - orderByFields []string // NEW: ORDER BY field specifications (e.g., "price:desc") - timezone string - extractTimeFields []string + limit int64 + offset int64 + reduceType reduce.IReduceType + isIterator bool + collectionID int64 + groupByFields []string + orderByFields []string // NEW: ORDER BY field specifications (e.g., "price:desc") + timezone string + extractTimeFields []string + queryIteratorCursor *planpb.QueryIteratorCursor } func isSupportedGroupByFieldType(dt schemapb.DataType) bool { @@ -325,7 +326,7 @@ func filterSystemFields(outputFieldIDs []UniqueID) []UniqueID { } // parseQueryParams get limit and offset from queryParamsPair, both are optional. -func parseQueryParams(queryParamsPair []*commonpb.KeyValuePair, largeTopKEnabled bool) (*queryParams, error) { +func parseQueryParams(queryParamsPair []*commonpb.KeyValuePair, largeTopKEnabled bool, pkDataType schemapb.DataType) (*queryParams, error) { var ( limit int64 offset int64 @@ -438,19 +439,76 @@ func parseQueryParams(queryParamsPair []*commonpb.KeyValuePair, largeTopKEnabled } } + queryIteratorCursor, err := parseQueryIteratorCursor(queryParamsPair, isIterator, pkDataType) + if err != nil { + return nil, err + } + return &queryParams{ - limit: limit, - offset: offset, - reduceType: reduceType, - isIterator: isIterator, - collectionID: collectionID, - groupByFields: groupByFields, - orderByFields: orderByFields, - timezone: timezone, - extractTimeFields: extractTimeFields, + limit: limit, + offset: offset, + reduceType: reduceType, + isIterator: isIterator, + collectionID: collectionID, + groupByFields: groupByFields, + orderByFields: orderByFields, + queryIteratorCursor: queryIteratorCursor, + timezone: timezone, + extractTimeFields: extractTimeFields, }, nil } +func parseQueryIteratorCursor(queryParamsPair []*commonpb.KeyValuePair, isIterator bool, pkDataType schemapb.DataType) (*planpb.QueryIteratorCursor, error) { + lastPK, hasLastPK := funcutil.TryGetAttrByKeyFromRepeatedKV(QueryIterLastPKKey, queryParamsPair) + lastOffsetStr, hasLastOffset := funcutil.TryGetAttrByKeyFromRepeatedKV(QueryIterLastOffsetKey, queryParamsPair) + if !hasLastPK && !hasLastOffset { + return nil, nil + } + if !isIterator { + return nil, merr.WrapErrAsInputError(merr.WrapErrParameterInvalidMsg( + "invalid query iterator cursor params: %s and %s can only be used when iterator=true", + QueryIterLastPKKey, QueryIterLastOffsetKey)) + } + if !hasLastPK || !hasLastOffset { + return nil, merr.WrapErrAsInputError(merr.WrapErrParameterInvalidMsg( + "incomplete query iterator cursor params: %s and %s must be provided together, has_last_pk=%t, has_last_element_offset=%t", + QueryIterLastPKKey, QueryIterLastOffsetKey, hasLastPK, hasLastOffset)) + } + + lastOffset, err := strconv.ParseInt(lastOffsetStr, 0, 64) + if err != nil || lastOffset < 0 { + return nil, merr.WrapErrParameterInvalid("non-negative int value", lastOffsetStr, + "value for query iterator last element offset is invalid") + } + + cursor := &planpb.QueryIteratorCursor{ + LastElementOffset: lastOffset, + } + switch pkDataType { + case schemapb.DataType_Int64: + lastIntPK, err := strconv.ParseInt(lastPK, 0, 64) + if err != nil { + return nil, merr.WrapErrParameterInvalid("int64 primary key", lastPK, + "value for query iterator last primary key is invalid") + } + cursor.LastIntPk = &lastIntPK + case schemapb.DataType_VarChar: + cursor.LastStrPk = &lastPK + default: + return nil, merr.WrapErrAsInputError(merr.WrapErrParameterInvalidMsg("unsupported primary key type %s for query iterator cursor", pkDataType.String())) + } + return cursor, nil +} + +func getPrimaryKeyDataType(schema *schemapb.CollectionSchema) schemapb.DataType { + for _, field := range schema.GetFields() { + if field.GetIsPrimaryKey() { + return field.GetDataType() + } + } + return schemapb.DataType_None +} + func matchCountRule(outputs []string) bool { return len(outputs) == 1 && strings.ToLower(strings.TrimSpace(outputs[0])) == "count(*)" } @@ -665,7 +723,7 @@ func (t *queryTask) PreExecute(ctx context.Context) error { if t.IgnoreGrowing, err = isIgnoreGrowing(t.request.GetQueryParams()); err != nil { return err } - queryParams, err := parseQueryParams(t.request.GetQueryParams(), colInfo.queryMode == common.QueryModeLargeTopK) + queryParams, err := parseQueryParams(t.request.GetQueryParams(), colInfo.queryMode == common.QueryModeLargeTopK, getPrimaryKeyDataType(schema.CollectionSchema)) if err != nil { return err } @@ -720,6 +778,9 @@ func (t *queryTask) PreExecute(ctx context.Context) error { return err } t.plan.GetQuery().Limit = t.Limit + if t.queryParams.queryIteratorCursor != nil { + t.plan.GetQuery().QueryIteratorCursor = t.queryParams.queryIteratorCursor + } // Aggregation queries have bounded result sizes: // - global aggregation (no GROUP BY) returns exactly one row diff --git a/internal/proxy/task_query_test.go b/internal/proxy/task_query_test.go index eca61ec4e7..3ddddd633c 100644 --- a/internal/proxy/task_query_test.go +++ b/internal/proxy/task_query_test.go @@ -746,7 +746,7 @@ func TestTaskQuery_functions(t *testing.T) { Value: test.inValue[i], }) } - ret, err := parseQueryParams(inParams, false) + ret, err := parseQueryParams(inParams, false, schemapb.DataType_Int64) if test.expectErr { assert.Error(t, err) assert.Empty(t, ret) @@ -770,7 +770,7 @@ func TestTaskQuery_functions(t *testing.T) { Key: IteratorField, Value: "True", }) - ret, err := parseQueryParams(inParams, false) + ret, err := parseQueryParams(inParams, false, schemapb.DataType_Int64) assert.NoError(t, err) assert.Equal(t, reduce.IReduceInOrderForBest, ret.reduceType) } @@ -784,7 +784,7 @@ func TestTaskQuery_functions(t *testing.T) { Key: IteratorField, Value: "TrueXXXX", }) - ret, err := parseQueryParams(inParams, false) + ret, err := parseQueryParams(inParams, false, schemapb.DataType_Int64) assert.Error(t, err) assert.Nil(t, ret) } @@ -798,7 +798,7 @@ func TestTaskQuery_functions(t *testing.T) { Key: IteratorField, Value: "True", }) - ret, err := parseQueryParams(inParams, false) + ret, err := parseQueryParams(inParams, false, schemapb.DataType_Int64) assert.Error(t, err) assert.Nil(t, ret) } @@ -809,7 +809,7 @@ func TestTaskQuery_functions(t *testing.T) { Value: "True", }) // when not setting iterator tag, ignore reduce_stop_for_best - ret, err := parseQueryParams(inParams, false) + ret, err := parseQueryParams(inParams, false, schemapb.DataType_Int64) assert.NoError(t, err) assert.Equal(t, reduce.IReduceNoOrder, ret.reduceType) } @@ -820,7 +820,7 @@ func TestTaskQuery_functions(t *testing.T) { Value: "True", }) // when not setting reduce_stop_for_best tag, reduce by keep results in order - ret, err := parseQueryParams(inParams, false) + ret, err := parseQueryParams(inParams, false, schemapb.DataType_Int64) assert.NoError(t, err) assert.Equal(t, reduce.IReduceInOrder, ret.reduceType) } @@ -834,7 +834,7 @@ func TestTaskQuery_functions(t *testing.T) { Key: IteratorField, Value: "True", }) - ret, err := parseQueryParams(inParams, false) + ret, err := parseQueryParams(inParams, false, schemapb.DataType_Int64) assert.NoError(t, err) assert.Equal(t, reduce.IReduceInOrder, ret.reduceType) } @@ -848,12 +848,169 @@ func TestTaskQuery_functions(t *testing.T) { Key: IteratorField, Value: "False", }) - ret, err := parseQueryParams(inParams, false) + ret, err := parseQueryParams(inParams, false, schemapb.DataType_Int64) assert.NoError(t, err) assert.Equal(t, reduce.IReduceNoOrder, ret.reduceType) } }) + t.Run("test parseQueryParams for query iterator cursor", func(t *testing.T) { + params := []*commonpb.KeyValuePair{ + {Key: IteratorField, Value: "true"}, + {Key: QueryIterLastPKKey, Value: "7"}, + {Key: QueryIterLastOffsetKey, Value: "2"}, + } + ret, err := parseQueryParams(params, false, schemapb.DataType_Int64) + require.NoError(t, err) + require.NotNil(t, ret.queryIteratorCursor) + require.NotNil(t, ret.queryIteratorCursor.LastIntPk) + assert.EqualValues(t, 7, ret.queryIteratorCursor.GetLastIntPk()) + assert.EqualValues(t, 2, ret.queryIteratorCursor.GetLastElementOffset()) + + params = []*commonpb.KeyValuePair{ + {Key: IteratorField, Value: "true"}, + {Key: QueryIterLastPKKey, Value: "pk-7"}, + {Key: QueryIterLastOffsetKey, Value: "2"}, + } + ret, err = parseQueryParams(params, false, schemapb.DataType_VarChar) + require.NoError(t, err) + require.NotNil(t, ret.queryIteratorCursor) + assert.Equal(t, "pk-7", ret.queryIteratorCursor.GetLastStrPk()) + + params = []*commonpb.KeyValuePair{ + {Key: QueryIterLastPKKey, Value: "7"}, + {Key: QueryIterLastOffsetKey, Value: "2"}, + } + ret, err = parseQueryParams(params, false, schemapb.DataType_Int64) + assert.Error(t, err) + assert.Nil(t, ret) + + params = []*commonpb.KeyValuePair{ + {Key: IteratorField, Value: "true"}, + {Key: QueryIterLastPKKey, Value: "7"}, + {Key: QueryIterLastOffsetKey, Value: "-1"}, + } + ret, err = parseQueryParams(params, false, schemapb.DataType_Int64) + assert.Error(t, err) + assert.Nil(t, ret) + }) + + t.Run("test parseQueryIteratorCursor", func(t *testing.T) { + tests := []struct { + name string + params []*commonpb.KeyValuePair + isIterator bool + pkDataType schemapb.DataType + wantNil bool + wantIntPK int64 + checkIntPK bool + wantStrPK string + wantOffset int64 + wantErrSubstr string + }{ + { + name: "no cursor params", + params: nil, + isIterator: true, + pkDataType: schemapb.DataType_Int64, + wantNil: true, + }, + { + name: "int64 pk with zero offset", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastPKKey, Value: "7"}, {Key: QueryIterLastOffsetKey, Value: "0"}}, + isIterator: true, + pkDataType: schemapb.DataType_Int64, + wantIntPK: 7, + checkIntPK: true, + wantOffset: 0, + }, + { + name: "varchar pk", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastPKKey, Value: "pk-7"}, {Key: QueryIterLastOffsetKey, Value: "2"}}, + isIterator: true, + pkDataType: schemapb.DataType_VarChar, + wantStrPK: "pk-7", + wantOffset: 2, + }, + { + name: "cursor params require iterator", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastPKKey, Value: "7"}, {Key: QueryIterLastOffsetKey, Value: "2"}}, + isIterator: false, + pkDataType: schemapb.DataType_Int64, + wantErrSubstr: "invalid query iterator cursor params", + }, + { + name: "missing offset", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastPKKey, Value: "7"}}, + isIterator: true, + pkDataType: schemapb.DataType_Int64, + wantErrSubstr: "incomplete query iterator cursor params", + }, + { + name: "missing pk", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastOffsetKey, Value: "2"}}, + isIterator: true, + pkDataType: schemapb.DataType_Int64, + wantErrSubstr: "incomplete query iterator cursor params", + }, + { + name: "invalid offset", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastPKKey, Value: "7"}, {Key: QueryIterLastOffsetKey, Value: "abc"}}, + isIterator: true, + pkDataType: schemapb.DataType_Int64, + wantErrSubstr: "value for query iterator last element offset is invalid", + }, + { + name: "negative offset", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastPKKey, Value: "7"}, {Key: QueryIterLastOffsetKey, Value: "-1"}}, + isIterator: true, + pkDataType: schemapb.DataType_Int64, + wantErrSubstr: "value for query iterator last element offset is invalid", + }, + { + name: "invalid int64 pk", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastPKKey, Value: "abc"}, {Key: QueryIterLastOffsetKey, Value: "2"}}, + isIterator: true, + pkDataType: schemapb.DataType_Int64, + wantErrSubstr: "value for query iterator last primary key is invalid", + }, + { + name: "unsupported pk type", + params: []*commonpb.KeyValuePair{{Key: QueryIterLastPKKey, Value: "7"}, {Key: QueryIterLastOffsetKey, Value: "2"}}, + isIterator: true, + pkDataType: schemapb.DataType_Int32, + wantErrSubstr: "unsupported primary key type", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cursor, err := parseQueryIteratorCursor(test.params, test.isIterator, test.pkDataType) + if test.wantErrSubstr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), test.wantErrSubstr) + assert.Nil(t, cursor) + return + } + require.NoError(t, err) + if test.wantNil { + assert.Nil(t, cursor) + return + } + require.NotNil(t, cursor) + assert.Equal(t, test.wantOffset, cursor.GetLastElementOffset()) + if test.checkIntPK { + require.NotNil(t, cursor.LastIntPk) + assert.Equal(t, test.wantIntPK, cursor.GetLastIntPk()) + } + if test.wantStrPK != "" { + require.NotNil(t, cursor.LastStrPk) + assert.Equal(t, test.wantStrPK, cursor.GetLastStrPk()) + } + }) + } + }) + t.Run("test reduceRetrieveResults", func(t *testing.T) { const ( Dim = 8 diff --git a/pkg/proto/plan.proto b/pkg/proto/plan.proto index c468761f50..ee814fd6e3 100644 --- a/pkg/proto/plan.proto +++ b/pkg/proto/plan.proto @@ -353,8 +353,15 @@ message QueryPlanNode { repeated int64 group_by_field_ids = 4; repeated Aggregate aggregates = 5; repeated OrderByField order_by_fields = 6; // ORDER BY specifications + optional QueryIteratorCursor query_iterator_cursor = 7; }; +message QueryIteratorCursor { + optional int64 last_int_pk = 1; + optional string last_str_pk = 2; + int64 last_element_offset = 3; +} + enum FunctionType{ FunctionTypeWeight = 0; FunctionTypeRandom = 1; diff --git a/pkg/proto/planpb/plan.pb.go b/pkg/proto/planpb/plan.pb.go index 37d3013ba4..a628637e6a 100644 --- a/pkg/proto/planpb/plan.pb.go +++ b/pkg/proto/planpb/plan.pb.go @@ -3315,12 +3315,13 @@ type QueryPlanNode struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Predicates *Expr `protobuf:"bytes,1,opt,name=predicates,proto3" json:"predicates,omitempty"` - IsCount bool `protobuf:"varint,2,opt,name=is_count,json=isCount,proto3" json:"is_count,omitempty"` - Limit int64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` - GroupByFieldIds []int64 `protobuf:"varint,4,rep,packed,name=group_by_field_ids,json=groupByFieldIds,proto3" json:"group_by_field_ids,omitempty"` - Aggregates []*Aggregate `protobuf:"bytes,5,rep,name=aggregates,proto3" json:"aggregates,omitempty"` - OrderByFields []*OrderByField `protobuf:"bytes,6,rep,name=order_by_fields,json=orderByFields,proto3" json:"order_by_fields,omitempty"` // ORDER BY specifications + Predicates *Expr `protobuf:"bytes,1,opt,name=predicates,proto3" json:"predicates,omitempty"` + IsCount bool `protobuf:"varint,2,opt,name=is_count,json=isCount,proto3" json:"is_count,omitempty"` + Limit int64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + GroupByFieldIds []int64 `protobuf:"varint,4,rep,packed,name=group_by_field_ids,json=groupByFieldIds,proto3" json:"group_by_field_ids,omitempty"` + Aggregates []*Aggregate `protobuf:"bytes,5,rep,name=aggregates,proto3" json:"aggregates,omitempty"` + OrderByFields []*OrderByField `protobuf:"bytes,6,rep,name=order_by_fields,json=orderByFields,proto3" json:"order_by_fields,omitempty"` // ORDER BY specifications + QueryIteratorCursor *QueryIteratorCursor `protobuf:"bytes,7,opt,name=query_iterator_cursor,json=queryIteratorCursor,proto3,oneof" json:"query_iterator_cursor,omitempty"` } func (x *QueryPlanNode) Reset() { @@ -3397,6 +3398,76 @@ func (x *QueryPlanNode) GetOrderByFields() []*OrderByField { return nil } +func (x *QueryPlanNode) GetQueryIteratorCursor() *QueryIteratorCursor { + if x != nil { + return x.QueryIteratorCursor + } + return nil +} + +type QueryIteratorCursor struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LastIntPk *int64 `protobuf:"varint,1,opt,name=last_int_pk,json=lastIntPk,proto3,oneof" json:"last_int_pk,omitempty"` + LastStrPk *string `protobuf:"bytes,2,opt,name=last_str_pk,json=lastStrPk,proto3,oneof" json:"last_str_pk,omitempty"` + LastElementOffset int64 `protobuf:"varint,3,opt,name=last_element_offset,json=lastElementOffset,proto3" json:"last_element_offset,omitempty"` +} + +func (x *QueryIteratorCursor) Reset() { + *x = QueryIteratorCursor{} + if protoimpl.UnsafeEnabled { + mi := &file_plan_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryIteratorCursor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryIteratorCursor) ProtoMessage() {} + +func (x *QueryIteratorCursor) ProtoReflect() protoreflect.Message { + mi := &file_plan_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryIteratorCursor.ProtoReflect.Descriptor instead. +func (*QueryIteratorCursor) Descriptor() ([]byte, []int) { + return file_plan_proto_rawDescGZIP(), []int{32} +} + +func (x *QueryIteratorCursor) GetLastIntPk() int64 { + if x != nil && x.LastIntPk != nil { + return *x.LastIntPk + } + return 0 +} + +func (x *QueryIteratorCursor) GetLastStrPk() string { + if x != nil && x.LastStrPk != nil { + return *x.LastStrPk + } + return "" +} + +func (x *QueryIteratorCursor) GetLastElementOffset() int64 { + if x != nil { + return x.LastElementOffset + } + return 0 +} + type ScoreFunction struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3411,7 +3482,7 @@ type ScoreFunction struct { func (x *ScoreFunction) Reset() { *x = ScoreFunction{} if protoimpl.UnsafeEnabled { - mi := &file_plan_proto_msgTypes[32] + mi := &file_plan_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3424,7 +3495,7 @@ func (x *ScoreFunction) String() string { func (*ScoreFunction) ProtoMessage() {} func (x *ScoreFunction) ProtoReflect() protoreflect.Message { - mi := &file_plan_proto_msgTypes[32] + mi := &file_plan_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3437,7 +3508,7 @@ func (x *ScoreFunction) ProtoReflect() protoreflect.Message { // Deprecated: Use ScoreFunction.ProtoReflect.Descriptor instead. func (*ScoreFunction) Descriptor() ([]byte, []int) { - return file_plan_proto_rawDescGZIP(), []int{32} + return file_plan_proto_rawDescGZIP(), []int{33} } func (x *ScoreFunction) GetFilter() *Expr { @@ -3480,7 +3551,7 @@ type ScoreOption struct { func (x *ScoreOption) Reset() { *x = ScoreOption{} if protoimpl.UnsafeEnabled { - mi := &file_plan_proto_msgTypes[33] + mi := &file_plan_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3493,7 +3564,7 @@ func (x *ScoreOption) String() string { func (*ScoreOption) ProtoMessage() {} func (x *ScoreOption) ProtoReflect() protoreflect.Message { - mi := &file_plan_proto_msgTypes[33] + mi := &file_plan_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3506,7 +3577,7 @@ func (x *ScoreOption) ProtoReflect() protoreflect.Message { // Deprecated: Use ScoreOption.ProtoReflect.Descriptor instead. func (*ScoreOption) Descriptor() ([]byte, []int) { - return file_plan_proto_rawDescGZIP(), []int{33} + return file_plan_proto_rawDescGZIP(), []int{34} } func (x *ScoreOption) GetBoostMode() BoostMode { @@ -3534,7 +3605,7 @@ type PlanOption struct { func (x *PlanOption) Reset() { *x = PlanOption{} if protoimpl.UnsafeEnabled { - mi := &file_plan_proto_msgTypes[34] + mi := &file_plan_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3547,7 +3618,7 @@ func (x *PlanOption) String() string { func (*PlanOption) ProtoMessage() {} func (x *PlanOption) ProtoReflect() protoreflect.Message { - mi := &file_plan_proto_msgTypes[34] + mi := &file_plan_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3560,7 +3631,7 @@ func (x *PlanOption) ProtoReflect() protoreflect.Message { // Deprecated: Use PlanOption.ProtoReflect.Descriptor instead. func (*PlanOption) Descriptor() ([]byte, []int) { - return file_plan_proto_rawDescGZIP(), []int{34} + return file_plan_proto_rawDescGZIP(), []int{35} } func (x *PlanOption) GetExprUseJsonStats() bool { @@ -3592,7 +3663,7 @@ type PlanNode struct { func (x *PlanNode) Reset() { *x = PlanNode{} if protoimpl.UnsafeEnabled { - mi := &file_plan_proto_msgTypes[35] + mi := &file_plan_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3605,7 +3676,7 @@ func (x *PlanNode) String() string { func (*PlanNode) ProtoMessage() {} func (x *PlanNode) ProtoReflect() protoreflect.Message { - mi := &file_plan_proto_msgTypes[35] + mi := &file_plan_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3618,7 +3689,7 @@ func (x *PlanNode) ProtoReflect() protoreflect.Message { // Deprecated: Use PlanNode.ProtoReflect.Descriptor instead. func (*PlanNode) Descriptor() ([]byte, []int) { - return file_plan_proto_rawDescGZIP(), []int{35} + return file_plan_proto_rawDescGZIP(), []int{36} } func (m *PlanNode) GetNode() isPlanNode_Node { @@ -4245,7 +4316,7 @@ var file_plan_proto_rawDesc = []byte{ 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x6c, 0x6c, 0x73, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6e, 0x75, 0x6c, 0x6c, 0x73, 0x46, 0x69, - 0x72, 0x73, 0x74, 0x22, 0xad, 0x02, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x6c, 0x61, + 0x72, 0x73, 0x74, 0x22, 0xa8, 0x03, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x45, 0x78, @@ -4264,126 +4335,145 @@ var file_plan_proto_rawDesc = []byte{ 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x42, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x0d, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x42, 0x79, 0x46, 0x69, 0x65, - 0x6c, 0x64, 0x73, 0x22, 0xc8, 0x01, 0x0a, 0x0d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x46, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x52, 0x06, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x33, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, - 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, - 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x90, - 0x01, 0x0a, 0x0b, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, - 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, - 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x6f, 0x64, 0x65, 0x52, 0x0c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, - 0x65, 0x22, 0x3b, 0x0a, 0x0a, 0x50, 0x6c, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x2d, 0x0a, 0x13, 0x65, 0x78, 0x70, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, - 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, - 0x70, 0x72, 0x55, 0x73, 0x65, 0x4a, 0x73, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x22, 0x8c, - 0x04, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x76, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x6e, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x4e, 0x4e, 0x53, 0x48, - 0x00, 0x52, 0x0a, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x6e, 0x6e, 0x73, 0x12, 0x39, 0x0a, - 0x0a, 0x70, 0x72, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x48, 0x00, 0x52, 0x0a, 0x70, 0x72, - 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x05, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x49, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, - 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x46, 0x69, 0x65, - 0x6c, 0x64, 0x73, 0x12, 0x3a, 0x0a, 0x07, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x72, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x46, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x72, 0x73, 0x12, - 0x40, 0x0a, 0x0c, 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x6c, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x41, 0x0a, 0x0c, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x88, 0x01, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x42, - 0x0c, 0x0a, 0x0a, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2a, 0xea, 0x01, - 0x0a, 0x06, 0x4f, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x6e, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, - 0x54, 0x68, 0x61, 0x6e, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x72, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x65, 0x73, 0x73, - 0x54, 0x68, 0x61, 0x6e, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x65, 0x73, 0x73, 0x45, 0x71, - 0x75, 0x61, 0x6c, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x10, 0x05, - 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x6f, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x10, 0x06, 0x12, 0x0f, - 0x0a, 0x0b, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x07, 0x12, - 0x10, 0x0a, 0x0c, 0x50, 0x6f, 0x73, 0x74, 0x66, 0x69, 0x78, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, - 0x08, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x09, 0x12, 0x09, 0x0a, 0x05, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x10, 0x0a, 0x12, 0x06, 0x0a, 0x02, 0x49, 0x6e, 0x10, 0x0b, 0x12, - 0x09, 0x0a, 0x05, 0x4e, 0x6f, 0x74, 0x49, 0x6e, 0x10, 0x0c, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x65, - 0x78, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x0d, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x68, 0x72, - 0x61, 0x73, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x0e, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x6e, - 0x6e, 0x65, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x0f, 0x2a, 0x58, 0x0a, 0x0b, 0x41, 0x72, - 0x69, 0x74, 0x68, 0x4f, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, - 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x10, 0x01, 0x12, - 0x07, 0x0a, 0x03, 0x53, 0x75, 0x62, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x75, 0x6c, 0x10, - 0x03, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x69, 0x76, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x6f, - 0x64, 0x10, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x72, 0x72, 0x61, 0x79, 0x4c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x10, 0x06, 0x2a, 0xfa, 0x01, 0x0a, 0x0a, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x56, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x31, - 0x36, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x42, 0x46, 0x6c, - 0x6f, 0x61, 0x74, 0x31, 0x36, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x03, 0x12, 0x15, 0x0a, - 0x11, 0x53, 0x70, 0x61, 0x72, 0x73, 0x65, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x38, 0x56, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x6d, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x46, - 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, - 0x45, 0x6d, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x31, 0x36, 0x56, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x10, 0x07, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x6d, 0x62, 0x4c, 0x69, 0x73, - 0x74, 0x42, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x31, 0x36, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, - 0x08, 0x12, 0x15, 0x0a, 0x11, 0x45, 0x6d, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x38, - 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x09, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x6d, 0x62, 0x4c, - 0x69, 0x73, 0x74, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, - 0x0a, 0x2a, 0x56, 0x0a, 0x09, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, - 0x0a, 0x08, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x41, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, - 0x4d, 0x61, 0x74, 0x63, 0x68, 0x41, 0x6e, 0x79, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x61, - 0x74, 0x63, 0x68, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x4d, 0x61, - 0x74, 0x63, 0x68, 0x4d, 0x6f, 0x73, 0x74, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x61, 0x74, - 0x63, 0x68, 0x45, 0x78, 0x61, 0x63, 0x74, 0x10, 0x04, 0x2a, 0x3c, 0x0a, 0x0b, 0x41, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x12, 0x07, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x10, - 0x00, 0x12, 0x09, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, - 0x61, 0x76, 0x67, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x10, 0x03, 0x12, 0x07, - 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x10, 0x04, 0x2a, 0x3e, 0x0a, 0x0c, 0x46, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x46, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x10, 0x00, 0x12, - 0x16, 0x0a, 0x12, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x2a, 0x3d, 0x0a, 0x0c, 0x46, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x10, - 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, - 0x65, 0x53, 0x75, 0x6d, 0x10, 0x01, 0x2a, 0x34, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4d, - 0x6f, 0x64, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, - 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x42, 0x6f, - 0x6f, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x53, 0x75, 0x6d, 0x10, 0x01, 0x42, 0x31, 0x5a, 0x2f, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, - 0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, - 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x70, 0x62, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x64, 0x73, 0x12, 0x5f, 0x0a, 0x15, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x69, 0x74, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x13, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x75, 0x72, 0x73, 0x6f, + 0x72, 0x88, 0x01, 0x01, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x22, 0xaf, + 0x01, 0x0a, 0x13, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, + 0x6e, 0x74, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x09, 0x6c, + 0x61, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x50, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0b, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x01, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x74, 0x72, 0x50, 0x6b, 0x88, 0x01, 0x01, + 0x12, 0x2e, 0x0a, 0x13, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x6c, + 0x61, 0x73, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x6b, + 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x5f, 0x70, 0x6b, + 0x22, 0xc8, 0x01, 0x0a, 0x0d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x02, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x33, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, + 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x46, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x39, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, + 0x61, 0x69, 0x72, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x0b, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x0a, 0x62, + 0x6f, 0x6f, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, + 0x6c, 0x61, 0x6e, 0x2e, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x09, 0x62, + 0x6f, 0x6f, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, + 0x6c, 0x61, 0x6e, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, + 0x52, 0x0c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x3b, + 0x0a, 0x0a, 0x50, 0x6c, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x13, + 0x65, 0x78, 0x70, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x70, 0x72, 0x55, + 0x73, 0x65, 0x4a, 0x73, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x22, 0x8c, 0x04, 0x0a, 0x08, + 0x50, 0x6c, 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x76, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x5f, 0x61, 0x6e, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, + 0x6e, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x4e, 0x4e, 0x53, 0x48, 0x00, 0x52, 0x0a, + 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x6e, 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x72, + 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, + 0x61, 0x6e, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x48, 0x00, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x6c, + 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, + 0x28, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x49, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x79, 0x6e, + 0x61, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0d, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, + 0x12, 0x3a, 0x0a, 0x07, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x72, 0x73, 0x12, 0x40, 0x0a, 0x0c, + 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0b, 0x70, 0x6c, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x41, + 0x0a, 0x0c, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x21, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x88, 0x01, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x42, 0x0c, 0x0a, 0x0a, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2a, 0xea, 0x01, 0x0a, 0x06, 0x4f, + 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x54, 0x68, 0x61, + 0x6e, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x45, 0x71, + 0x75, 0x61, 0x6c, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x65, 0x73, 0x73, 0x54, 0x68, 0x61, + 0x6e, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x65, 0x73, 0x73, 0x45, 0x71, 0x75, 0x61, 0x6c, + 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x10, 0x05, 0x12, 0x0c, 0x0a, + 0x08, 0x4e, 0x6f, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x50, + 0x72, 0x65, 0x66, 0x69, 0x78, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x07, 0x12, 0x10, 0x0a, 0x0c, + 0x50, 0x6f, 0x73, 0x74, 0x66, 0x69, 0x78, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x08, 0x12, 0x09, + 0x0a, 0x05, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x09, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x61, 0x6e, + 0x67, 0x65, 0x10, 0x0a, 0x12, 0x06, 0x0a, 0x02, 0x49, 0x6e, 0x10, 0x0b, 0x12, 0x09, 0x0a, 0x05, + 0x4e, 0x6f, 0x74, 0x49, 0x6e, 0x10, 0x0c, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x65, 0x78, 0x74, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x10, 0x0d, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x68, 0x72, 0x61, 0x73, 0x65, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x0e, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x6e, 0x6e, 0x65, 0x72, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x0f, 0x2a, 0x58, 0x0a, 0x0b, 0x41, 0x72, 0x69, 0x74, 0x68, + 0x4f, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, + 0x6e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, + 0x53, 0x75, 0x62, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x75, 0x6c, 0x10, 0x03, 0x12, 0x07, + 0x0a, 0x03, 0x44, 0x69, 0x76, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x6f, 0x64, 0x10, 0x05, + 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x72, 0x72, 0x61, 0x79, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x10, + 0x06, 0x2a, 0xfa, 0x01, 0x0a, 0x0a, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x10, 0x0a, 0x0c, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x31, 0x36, 0x56, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x42, 0x46, 0x6c, 0x6f, 0x61, 0x74, + 0x31, 0x36, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x70, + 0x61, 0x72, 0x73, 0x65, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, + 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x38, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, + 0x05, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x6d, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6c, 0x6f, 0x61, + 0x74, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x45, 0x6d, 0x62, + 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x31, 0x36, 0x56, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x10, 0x07, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x6d, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x46, + 0x6c, 0x6f, 0x61, 0x74, 0x31, 0x36, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x08, 0x12, 0x15, + 0x0a, 0x11, 0x45, 0x6d, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x38, 0x56, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x10, 0x09, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x6d, 0x62, 0x4c, 0x69, 0x73, 0x74, + 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x0a, 0x2a, 0x56, + 0x0a, 0x09, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x41, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x61, 0x74, + 0x63, 0x68, 0x41, 0x6e, 0x79, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x61, 0x74, 0x63, 0x68, + 0x4c, 0x65, 0x61, 0x73, 0x74, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x4d, 0x61, 0x74, 0x63, 0x68, + 0x4d, 0x6f, 0x73, 0x74, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x45, + 0x78, 0x61, 0x63, 0x74, 0x10, 0x04, 0x2a, 0x3c, 0x0a, 0x0b, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x4f, 0x70, 0x12, 0x07, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x10, 0x00, 0x12, 0x09, + 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x61, 0x76, 0x67, + 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x6d, + 0x61, 0x78, 0x10, 0x04, 0x2a, 0x3e, 0x0a, 0x0c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x79, 0x70, 0x65, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, + 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x61, 0x6e, 0x64, + 0x6f, 0x6d, 0x10, 0x01, 0x2a, 0x3d, 0x0a, 0x0c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x4d, 0x6f, 0x64, 0x65, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x10, 0x00, 0x12, 0x13, + 0x0a, 0x0f, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x53, 0x75, + 0x6d, 0x10, 0x01, 0x2a, 0x34, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, + 0x12, 0x15, 0x0a, 0x11, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x4d, 0x75, 0x6c, + 0x74, 0x69, 0x70, 0x6c, 0x79, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x42, 0x6f, 0x6f, 0x73, 0x74, + 0x4d, 0x6f, 0x64, 0x65, 0x53, 0x75, 0x6d, 0x10, 0x01, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2d, 0x69, + 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x76, 0x32, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4399,7 +4489,7 @@ func file_plan_proto_rawDescGZIP() []byte { } var file_plan_proto_enumTypes = make([]protoimpl.EnumInfo, 13) -var file_plan_proto_msgTypes = make([]protoimpl.MessageInfo, 36) +var file_plan_proto_msgTypes = make([]protoimpl.MessageInfo, 37) var file_plan_proto_goTypes = []interface{}{ (OpType)(0), // 0: milvus.proto.plan.OpType (ArithOpType)(0), // 1: milvus.proto.plan.ArithOpType @@ -4446,21 +4536,22 @@ var file_plan_proto_goTypes = []interface{}{ (*Aggregate)(nil), // 42: milvus.proto.plan.Aggregate (*OrderByField)(nil), // 43: milvus.proto.plan.OrderByField (*QueryPlanNode)(nil), // 44: milvus.proto.plan.QueryPlanNode - (*ScoreFunction)(nil), // 45: milvus.proto.plan.ScoreFunction - (*ScoreOption)(nil), // 46: milvus.proto.plan.ScoreOption - (*PlanOption)(nil), // 47: milvus.proto.plan.PlanOption - (*PlanNode)(nil), // 48: milvus.proto.plan.PlanNode - (schemapb.DataType)(0), // 49: milvus.proto.schema.DataType - (*commonpb.KeyValuePair)(nil), // 50: milvus.proto.common.KeyValuePair + (*QueryIteratorCursor)(nil), // 45: milvus.proto.plan.QueryIteratorCursor + (*ScoreFunction)(nil), // 46: milvus.proto.plan.ScoreFunction + (*ScoreOption)(nil), // 47: milvus.proto.plan.ScoreOption + (*PlanOption)(nil), // 48: milvus.proto.plan.PlanOption + (*PlanNode)(nil), // 49: milvus.proto.plan.PlanNode + (schemapb.DataType)(0), // 50: milvus.proto.schema.DataType + (*commonpb.KeyValuePair)(nil), // 51: milvus.proto.common.KeyValuePair } var file_plan_proto_depIdxs = []int32{ 14, // 0: milvus.proto.plan.GenericValue.array_val:type_name -> milvus.proto.plan.Array 13, // 1: milvus.proto.plan.Array.array:type_name -> milvus.proto.plan.GenericValue - 49, // 2: milvus.proto.plan.Array.element_type:type_name -> milvus.proto.schema.DataType + 50, // 2: milvus.proto.plan.Array.element_type:type_name -> milvus.proto.schema.DataType 15, // 3: milvus.proto.plan.QueryInfo.search_iterator_v2_info:type_name -> milvus.proto.plan.SearchIteratorV2Info - 49, // 4: milvus.proto.plan.QueryInfo.json_type:type_name -> milvus.proto.schema.DataType - 49, // 5: milvus.proto.plan.ColumnInfo.data_type:type_name -> milvus.proto.schema.DataType - 49, // 6: milvus.proto.plan.ColumnInfo.element_type:type_name -> milvus.proto.schema.DataType + 50, // 4: milvus.proto.plan.QueryInfo.json_type:type_name -> milvus.proto.schema.DataType + 50, // 5: milvus.proto.plan.ColumnInfo.data_type:type_name -> milvus.proto.schema.DataType + 50, // 6: milvus.proto.plan.ColumnInfo.element_type:type_name -> milvus.proto.schema.DataType 17, // 7: milvus.proto.plan.ColumnExpr.info:type_name -> milvus.proto.plan.ColumnInfo 17, // 8: milvus.proto.plan.ExistsExpr.info:type_name -> milvus.proto.plan.ColumnInfo 13, // 9: milvus.proto.plan.ValueExpr.value:type_name -> milvus.proto.plan.GenericValue @@ -4537,22 +4628,23 @@ var file_plan_proto_depIdxs = []int32{ 40, // 80: milvus.proto.plan.QueryPlanNode.predicates:type_name -> milvus.proto.plan.Expr 42, // 81: milvus.proto.plan.QueryPlanNode.aggregates:type_name -> milvus.proto.plan.Aggregate 43, // 82: milvus.proto.plan.QueryPlanNode.order_by_fields:type_name -> milvus.proto.plan.OrderByField - 40, // 83: milvus.proto.plan.ScoreFunction.filter:type_name -> milvus.proto.plan.Expr - 5, // 84: milvus.proto.plan.ScoreFunction.type:type_name -> milvus.proto.plan.FunctionType - 50, // 85: milvus.proto.plan.ScoreFunction.params:type_name -> milvus.proto.common.KeyValuePair - 7, // 86: milvus.proto.plan.ScoreOption.boost_mode:type_name -> milvus.proto.plan.BoostMode - 6, // 87: milvus.proto.plan.ScoreOption.function_mode:type_name -> milvus.proto.plan.FunctionMode - 41, // 88: milvus.proto.plan.PlanNode.vector_anns:type_name -> milvus.proto.plan.VectorANNS - 40, // 89: milvus.proto.plan.PlanNode.predicates:type_name -> milvus.proto.plan.Expr - 44, // 90: milvus.proto.plan.PlanNode.query:type_name -> milvus.proto.plan.QueryPlanNode - 45, // 91: milvus.proto.plan.PlanNode.scorers:type_name -> milvus.proto.plan.ScoreFunction - 47, // 92: milvus.proto.plan.PlanNode.plan_options:type_name -> milvus.proto.plan.PlanOption - 46, // 93: milvus.proto.plan.PlanNode.score_option:type_name -> milvus.proto.plan.ScoreOption - 94, // [94:94] is the sub-list for method output_type - 94, // [94:94] is the sub-list for method input_type - 94, // [94:94] is the sub-list for extension type_name - 94, // [94:94] is the sub-list for extension extendee - 0, // [0:94] is the sub-list for field type_name + 45, // 83: milvus.proto.plan.QueryPlanNode.query_iterator_cursor:type_name -> milvus.proto.plan.QueryIteratorCursor + 40, // 84: milvus.proto.plan.ScoreFunction.filter:type_name -> milvus.proto.plan.Expr + 5, // 85: milvus.proto.plan.ScoreFunction.type:type_name -> milvus.proto.plan.FunctionType + 51, // 86: milvus.proto.plan.ScoreFunction.params:type_name -> milvus.proto.common.KeyValuePair + 7, // 87: milvus.proto.plan.ScoreOption.boost_mode:type_name -> milvus.proto.plan.BoostMode + 6, // 88: milvus.proto.plan.ScoreOption.function_mode:type_name -> milvus.proto.plan.FunctionMode + 41, // 89: milvus.proto.plan.PlanNode.vector_anns:type_name -> milvus.proto.plan.VectorANNS + 40, // 90: milvus.proto.plan.PlanNode.predicates:type_name -> milvus.proto.plan.Expr + 44, // 91: milvus.proto.plan.PlanNode.query:type_name -> milvus.proto.plan.QueryPlanNode + 46, // 92: milvus.proto.plan.PlanNode.scorers:type_name -> milvus.proto.plan.ScoreFunction + 48, // 93: milvus.proto.plan.PlanNode.plan_options:type_name -> milvus.proto.plan.PlanOption + 47, // 94: milvus.proto.plan.PlanNode.score_option:type_name -> milvus.proto.plan.ScoreOption + 95, // [95:95] is the sub-list for method output_type + 95, // [95:95] is the sub-list for method input_type + 95, // [95:95] is the sub-list for extension type_name + 95, // [95:95] is the sub-list for extension extendee + 0, // [0:95] is the sub-list for field type_name } func init() { file_plan_proto_init() } @@ -4946,7 +5038,7 @@ func file_plan_proto_init() { } } file_plan_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScoreFunction); i { + switch v := v.(*QueryIteratorCursor); i { case 0: return &v.state case 1: @@ -4958,7 +5050,7 @@ func file_plan_proto_init() { } } file_plan_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScoreOption); i { + switch v := v.(*ScoreFunction); i { case 0: return &v.state case 1: @@ -4970,7 +5062,7 @@ func file_plan_proto_init() { } } file_plan_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PlanOption); i { + switch v := v.(*ScoreOption); i { case 0: return &v.state case 1: @@ -4982,6 +5074,18 @@ func file_plan_proto_init() { } } file_plan_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlanOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plan_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PlanNode); i { case 0: return &v.state @@ -5025,7 +5129,9 @@ func file_plan_proto_init() { (*Expr_ElementFilterExpr)(nil), (*Expr_MatchExpr)(nil), } - file_plan_proto_msgTypes[35].OneofWrappers = []interface{}{ + file_plan_proto_msgTypes[31].OneofWrappers = []interface{}{} + file_plan_proto_msgTypes[32].OneofWrappers = []interface{}{} + file_plan_proto_msgTypes[36].OneofWrappers = []interface{}{ (*PlanNode_VectorAnns)(nil), (*PlanNode_Predicates)(nil), (*PlanNode_Query)(nil), @@ -5036,7 +5142,7 @@ func file_plan_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_plan_proto_rawDesc, NumEnums: 13, - NumMessages: 36, + NumMessages: 37, NumExtensions: 0, NumServices: 0, },