You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2021/11/10 04:44:57 UTC

[skywalking-banyandb] branch main updated: Add measure and topN APIs (#57)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git


The following commit(s) were added to refs/heads/main by this push:
     new d7b8833  Add measure and topN APIs (#57)
d7b8833 is described below

commit d7b8833e65cf0ca6aea07b0f16a2ac114718b8b7
Author: Gao Hongtao <ha...@gmail.com>
AuthorDate: Wed Nov 10 12:44:51 2021 +0800

    Add measure and topN APIs (#57)
---
 api/proto/banyandb/database/v1/schema.pb.go        | 870 +++++++++++++++------
 api/proto/banyandb/database/v1/schema.proto        |  62 +-
 api/proto/banyandb/measure/v1/query.pb.go          | 627 +++++++++++++++
 api/proto/banyandb/measure/v1/query.proto          |  69 ++
 api/proto/banyandb/measure/v1/rpc.pb.go            | 126 +++
 .../v1/common.proto => measure/v1/rpc.proto}       |  45 +-
 api/proto/banyandb/measure/v1/rpc_grpc.pb.go       | 207 +++++
 api/proto/banyandb/measure/v1/topn.pb.go           | 520 ++++++++++++
 api/proto/banyandb/measure/v1/topn.proto           |  66 ++
 api/proto/banyandb/measure/v1/write.pb.go          | 350 +++++++++
 api/proto/banyandb/measure/v1/write.proto          |  48 ++
 api/proto/banyandb/model/v1/common.pb.go           | 176 ++++-
 api/proto/banyandb/model/v1/common.proto           |   9 +
 api/proto/banyandb/model/v1/query.pb.go            | 412 ++++++----
 api/proto/banyandb/model/v1/query.proto            |  24 +-
 api/proto/banyandb/stream/v1/query.pb.go           | 167 ++--
 api/proto/banyandb/stream/v1/query.proto           |   8 +-
 banyand/metadata/schema/etcd_test.go               |   8 +-
 banyand/metadata/schema/testdata/stream.json       |  12 +-
 banyand/query/processor_test.go                    |   4 +-
 banyand/stream/index.go                            |   2 +-
 banyand/stream/service.go                          |   4 +-
 banyand/stream/stream.go                           |   2 +-
 banyand/stream/stream_query.go                     |   2 +-
 banyand/stream/stream_query_test.go                |   6 +-
 banyand/stream/stream_write.go                     |   2 +-
 banyand/tsdb/series_seek.go                        |  10 +-
 banyand/tsdb/series_seek_sort.go                   |  10 +-
 pkg/index/index.go                                 |   2 +-
 pkg/index/inverted/inverted.go                     |   8 +-
 pkg/index/inverted/mem.go                          |   6 +-
 pkg/index/iterator.go                              |   8 +-
 pkg/index/lsm/search.go                            |   4 +-
 pkg/index/testcases/duration.go                    |  30 +-
 pkg/pb/v1/query.go                                 |   8 +-
 pkg/query/logical/analyzer_test.go                 |  10 +-
 pkg/query/logical/common.go                        |   4 +-
 pkg/query/logical/plan_execution_test.go           |  12 +-
 pkg/query/logical/plan_orderby.go                  |  36 +-
 pkg/query/logical/schema.go                        |   2 +-
 pkg/test/testdata/stream.json                      |  12 +-
 41 files changed, 3284 insertions(+), 706 deletions(-)

diff --git a/api/proto/banyandb/database/v1/schema.pb.go b/api/proto/banyandb/database/v1/schema.pb.go
index 245fb52..57682eb 100644
--- a/api/proto/banyandb/database/v1/schema.pb.go
+++ b/api/proto/banyandb/database/v1/schema.pb.go
@@ -32,6 +32,7 @@ import (
 	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
 
 	v1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/common/v1"
+	v11 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1"
 )
 
 const (
@@ -345,7 +346,7 @@ func (x IndexRule_Type) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use IndexRule_Type.Descriptor instead.
 func (IndexRule_Type) EnumDescriptor() ([]byte, []int) {
-	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{7, 0}
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{10, 0}
 }
 
 type IndexRule_Location int32
@@ -394,7 +395,7 @@ func (x IndexRule_Location) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use IndexRule_Location.Descriptor instead.
 func (IndexRule_Location) EnumDescriptor() ([]byte, []int) {
-	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{7, 1}
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{10, 1}
 }
 
 // Duration represents the elapsed time between two instants
@@ -575,12 +576,10 @@ type Stream struct {
 	// tag_families
 	TagFamilies []*TagFamilySpec `protobuf:"bytes,2,rep,name=tag_families,json=tagFamilies,proto3" json:"tag_families,omitempty"`
 	// entity indicates how to generate a series and shard a stream
-	Entity *Entity `protobuf:"bytes,3,opt,name=entity,proto3" json:"entity,omitempty"`
-	// duration determines how long a TraceSeries keeps its data
-	ShardNum uint32    `protobuf:"varint,4,opt,name=shard_num,json=shardNum,proto3" json:"shard_num,omitempty"`
-	Duration *Duration `protobuf:"bytes,5,opt,name=duration,proto3" json:"duration,omitempty"`
-	// updated_at_nanoseconds indicates when the TraceSeries is updated
-	UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
+	Entity *Entity       `protobuf:"bytes,3,opt,name=entity,proto3" json:"entity,omitempty"`
+	Opts   *ResourceOpts `protobuf:"bytes,4,opt,name=opts,proto3" json:"opts,omitempty"`
+	// updated_at_nanoseconds indicates when the measure is updated
+	UpdatedAtNanoseconds *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=updated_at_nanoseconds,json=updatedAtNanoseconds,proto3" json:"updated_at_nanoseconds,omitempty"`
 }
 
 func (x *Stream) Reset() {
@@ -636,23 +635,16 @@ func (x *Stream) GetEntity() *Entity {
 	return nil
 }
 
-func (x *Stream) GetShardNum() uint32 {
+func (x *Stream) GetOpts() *ResourceOpts {
 	if x != nil {
-		return x.ShardNum
-	}
-	return 0
-}
-
-func (x *Stream) GetDuration() *Duration {
-	if x != nil {
-		return x.Duration
+		return x.Opts
 	}
 	return nil
 }
 
-func (x *Stream) GetUpdatedAt() *timestamppb.Timestamp {
+func (x *Stream) GetUpdatedAtNanoseconds() *timestamppb.Timestamp {
 	if x != nil {
-		return x.UpdatedAt
+		return x.UpdatedAtNanoseconds
 	}
 	return nil
 }
@@ -704,6 +696,63 @@ func (x *Entity) GetTagNames() []string {
 	return nil
 }
 
+type ResourceOpts struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// shard_num is the number of shards
+	ShardNum uint32 `protobuf:"varint,1,opt,name=shard_num,json=shardNum,proto3" json:"shard_num,omitempty"`
+	// ttl indicates time to live, how long the data will be cached
+	Ttl *Duration `protobuf:"bytes,2,opt,name=ttl,proto3" json:"ttl,omitempty"`
+}
+
+func (x *ResourceOpts) Reset() {
+	*x = ResourceOpts{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_database_v1_schema_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ResourceOpts) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ResourceOpts) ProtoMessage() {}
+
+func (x *ResourceOpts) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_database_v1_schema_proto_msgTypes[5]
+	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 ResourceOpts.ProtoReflect.Descriptor instead.
+func (*ResourceOpts) Descriptor() ([]byte, []int) {
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ResourceOpts) GetShardNum() uint32 {
+	if x != nil {
+		return x.ShardNum
+	}
+	return 0
+}
+
+func (x *ResourceOpts) GetTtl() *Duration {
+	if x != nil {
+		return x.Ttl
+	}
+	return nil
+}
+
 // FieldSpec is the specification of field
 type FieldSpec struct {
 	state         protoimpl.MessageState
@@ -723,7 +772,7 @@ type FieldSpec struct {
 func (x *FieldSpec) Reset() {
 	*x = FieldSpec{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_database_v1_schema_proto_msgTypes[5]
+		mi := &file_banyandb_database_v1_schema_proto_msgTypes[6]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -736,7 +785,7 @@ func (x *FieldSpec) String() string {
 func (*FieldSpec) ProtoMessage() {}
 
 func (x *FieldSpec) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_database_v1_schema_proto_msgTypes[5]
+	mi := &file_banyandb_database_v1_schema_proto_msgTypes[6]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -749,7 +798,7 @@ func (x *FieldSpec) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use FieldSpec.ProtoReflect.Descriptor instead.
 func (*FieldSpec) Descriptor() ([]byte, []int) {
-	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{5}
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *FieldSpec) GetName() string {
@@ -780,6 +829,107 @@ func (x *FieldSpec) GetCompressionMethod() CompressionMethod {
 	return CompressionMethod_COMPRESSION_METHOD_UNSPECIFIED
 }
 
+// IntervalRule indicates how to get the interval of a measure series.
+type IntervalRule struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// tag_name is for matching a tag
+	TagName string `protobuf:"bytes,1,opt,name=tag_name,json=tagName,proto3" json:"tag_name,omitempty"`
+	// tag_value is used by a equality matcher to match a tag
+	//
+	// Types that are assignable to TagValue:
+	//	*IntervalRule_Str
+	//	*IntervalRule_Int
+	TagValue isIntervalRule_TagValue `protobuf_oneof:"tag_value"`
+	// interval indicates how frequently to send a data point
+	Interval string `protobuf:"bytes,4,opt,name=interval,proto3" json:"interval,omitempty"`
+}
+
+func (x *IntervalRule) Reset() {
+	*x = IntervalRule{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_database_v1_schema_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *IntervalRule) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*IntervalRule) ProtoMessage() {}
+
+func (x *IntervalRule) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_database_v1_schema_proto_msgTypes[7]
+	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 IntervalRule.ProtoReflect.Descriptor instead.
+func (*IntervalRule) Descriptor() ([]byte, []int) {
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *IntervalRule) GetTagName() string {
+	if x != nil {
+		return x.TagName
+	}
+	return ""
+}
+
+func (m *IntervalRule) GetTagValue() isIntervalRule_TagValue {
+	if m != nil {
+		return m.TagValue
+	}
+	return nil
+}
+
+func (x *IntervalRule) GetStr() string {
+	if x, ok := x.GetTagValue().(*IntervalRule_Str); ok {
+		return x.Str
+	}
+	return ""
+}
+
+func (x *IntervalRule) GetInt() int64 {
+	if x, ok := x.GetTagValue().(*IntervalRule_Int); ok {
+		return x.Int
+	}
+	return 0
+}
+
+func (x *IntervalRule) GetInterval() string {
+	if x != nil {
+		return x.Interval
+	}
+	return ""
+}
+
+type isIntervalRule_TagValue interface {
+	isIntervalRule_TagValue()
+}
+
+type IntervalRule_Str struct {
+	Str string `protobuf:"bytes,2,opt,name=str,proto3,oneof"`
+}
+
+type IntervalRule_Int struct {
+	Int int64 `protobuf:"varint,3,opt,name=int,proto3,oneof"`
+}
+
+func (*IntervalRule_Str) isIntervalRule_TagValue() {}
+
+func (*IntervalRule_Int) isIntervalRule_TagValue() {}
+
 // Measure intends to store data point
 type Measure struct {
 	state         protoimpl.MessageState
@@ -794,10 +944,10 @@ type Measure struct {
 	Fields []*FieldSpec `protobuf:"bytes,3,rep,name=fields,proto3" json:"fields,omitempty"`
 	// entity indicates which tags will be to generate a series and shard a measure
 	Entity *Entity `protobuf:"bytes,4,opt,name=entity,proto3" json:"entity,omitempty"`
-	// shard_num is the number of shards
-	ShardNum uint32 `protobuf:"varint,5,opt,name=shard_num,json=shardNum,proto3" json:"shard_num,omitempty"`
-	// ttl indicates time to live, how long the data will be cached
-	Ttl *Duration `protobuf:"bytes,6,opt,name=ttl,proto3" json:"ttl,omitempty"`
+	// interval_rules define data points writing interval
+	IntervalRules []*IntervalRule `protobuf:"bytes,5,rep,name=interval_rules,json=intervalRules,proto3" json:"interval_rules,omitempty"`
+	// opts is basic resource management options
+	Opts *ResourceOpts `protobuf:"bytes,6,opt,name=opts,proto3" json:"opts,omitempty"`
 	// updated_at_nanoseconds indicates when the measure is updated
 	UpdatedAtNanoseconds *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=updated_at_nanoseconds,json=updatedAtNanoseconds,proto3" json:"updated_at_nanoseconds,omitempty"`
 }
@@ -805,7 +955,7 @@ type Measure struct {
 func (x *Measure) Reset() {
 	*x = Measure{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_database_v1_schema_proto_msgTypes[6]
+		mi := &file_banyandb_database_v1_schema_proto_msgTypes[8]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -818,7 +968,7 @@ func (x *Measure) String() string {
 func (*Measure) ProtoMessage() {}
 
 func (x *Measure) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_database_v1_schema_proto_msgTypes[6]
+	mi := &file_banyandb_database_v1_schema_proto_msgTypes[8]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -831,7 +981,7 @@ func (x *Measure) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Measure.ProtoReflect.Descriptor instead.
 func (*Measure) Descriptor() ([]byte, []int) {
-	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{6}
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *Measure) GetMetadata() *v1.Metadata {
@@ -862,16 +1012,16 @@ func (x *Measure) GetEntity() *Entity {
 	return nil
 }
 
-func (x *Measure) GetShardNum() uint32 {
+func (x *Measure) GetIntervalRules() []*IntervalRule {
 	if x != nil {
-		return x.ShardNum
+		return x.IntervalRules
 	}
-	return 0
+	return nil
 }
 
-func (x *Measure) GetTtl() *Duration {
+func (x *Measure) GetOpts() *ResourceOpts {
 	if x != nil {
-		return x.Ttl
+		return x.Opts
 	}
 	return nil
 }
@@ -883,6 +1033,130 @@ func (x *Measure) GetUpdatedAtNanoseconds() *timestamppb.Timestamp {
 	return nil
 }
 
+// TopNAggregation generates offline TopN statistics for a measure's TopN approximation
+type TopNAggregation struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// metadata is the identity of an aggregation
+	Metadata *v1.Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+	// source_measure denotes the data source of this aggregation
+	SourceMeasure *v1.Metadata `protobuf:"bytes,2,opt,name=source_measure,json=sourceMeasure,proto3" json:"source_measure,omitempty"`
+	// field_name is the name of field used for ranking
+	FieldName string `protobuf:"bytes,3,opt,name=field_name,json=fieldName,proto3" json:"field_name,omitempty"`
+	// field_value_sort indicates how to sort fields
+	// ASC: bottomN
+	// DESC: topN
+	// UNSPECIFIED: topN + bottomN
+	FieldValueSort v11.Sort `protobuf:"varint,4,opt,name=field_value_sort,json=fieldValueSort,proto3,enum=banyandb.model.v1.Sort" json:"field_value_sort,omitempty"`
+	// group_by_tag_names groups data points into statistical counters
+	GroupByTagNames []string `protobuf:"bytes,5,rep,name=group_by_tag_names,json=groupByTagNames,proto3" json:"group_by_tag_names,omitempty"`
+	// criteria select partial data points from measure
+	Criteria []*v11.Criteria `protobuf:"bytes,6,rep,name=criteria,proto3" json:"criteria,omitempty"`
+	// counters_number sets the number of counters to be tracked. The default value is 1000
+	CountersNumber int32 `protobuf:"varint,7,opt,name=counters_number,json=countersNumber,proto3" json:"counters_number,omitempty"`
+	// opts is basic resource management options
+	Opts *ResourceOpts `protobuf:"bytes,8,opt,name=opts,proto3" json:"opts,omitempty"`
+	// updated_at_nanoseconds indicates when the measure is updated
+	UpdatedAtNanoseconds *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=updated_at_nanoseconds,json=updatedAtNanoseconds,proto3" json:"updated_at_nanoseconds,omitempty"`
+}
+
+func (x *TopNAggregation) Reset() {
+	*x = TopNAggregation{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_database_v1_schema_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TopNAggregation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopNAggregation) ProtoMessage() {}
+
+func (x *TopNAggregation) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_database_v1_schema_proto_msgTypes[9]
+	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 TopNAggregation.ProtoReflect.Descriptor instead.
+func (*TopNAggregation) Descriptor() ([]byte, []int) {
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *TopNAggregation) GetMetadata() *v1.Metadata {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+func (x *TopNAggregation) GetSourceMeasure() *v1.Metadata {
+	if x != nil {
+		return x.SourceMeasure
+	}
+	return nil
+}
+
+func (x *TopNAggregation) GetFieldName() string {
+	if x != nil {
+		return x.FieldName
+	}
+	return ""
+}
+
+func (x *TopNAggregation) GetFieldValueSort() v11.Sort {
+	if x != nil {
+		return x.FieldValueSort
+	}
+	return v11.Sort(0)
+}
+
+func (x *TopNAggregation) GetGroupByTagNames() []string {
+	if x != nil {
+		return x.GroupByTagNames
+	}
+	return nil
+}
+
+func (x *TopNAggregation) GetCriteria() []*v11.Criteria {
+	if x != nil {
+		return x.Criteria
+	}
+	return nil
+}
+
+func (x *TopNAggregation) GetCountersNumber() int32 {
+	if x != nil {
+		return x.CountersNumber
+	}
+	return 0
+}
+
+func (x *TopNAggregation) GetOpts() *ResourceOpts {
+	if x != nil {
+		return x.Opts
+	}
+	return nil
+}
+
+func (x *TopNAggregation) GetUpdatedAtNanoseconds() *timestamppb.Timestamp {
+	if x != nil {
+		return x.UpdatedAtNanoseconds
+	}
+	return nil
+}
+
 // IndexRule defines how to generate indices based on tags and the index type
 // IndexRule should bind to a subject through an IndexRuleBinding to generate proper indices.
 type IndexRule struct {
@@ -907,7 +1181,7 @@ type IndexRule struct {
 func (x *IndexRule) Reset() {
 	*x = IndexRule{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_database_v1_schema_proto_msgTypes[7]
+		mi := &file_banyandb_database_v1_schema_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -920,7 +1194,7 @@ func (x *IndexRule) String() string {
 func (*IndexRule) ProtoMessage() {}
 
 func (x *IndexRule) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_database_v1_schema_proto_msgTypes[7]
+	mi := &file_banyandb_database_v1_schema_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -933,7 +1207,7 @@ func (x *IndexRule) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use IndexRule.ProtoReflect.Descriptor instead.
 func (*IndexRule) Descriptor() ([]byte, []int) {
-	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{7}
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *IndexRule) GetMetadata() *v1.Metadata {
@@ -986,7 +1260,7 @@ type Subject struct {
 func (x *Subject) Reset() {
 	*x = Subject{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_database_v1_schema_proto_msgTypes[8]
+		mi := &file_banyandb_database_v1_schema_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -999,7 +1273,7 @@ func (x *Subject) String() string {
 func (*Subject) ProtoMessage() {}
 
 func (x *Subject) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_database_v1_schema_proto_msgTypes[8]
+	mi := &file_banyandb_database_v1_schema_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1012,7 +1286,7 @@ func (x *Subject) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Subject.ProtoReflect.Descriptor instead.
 func (*Subject) Descriptor() ([]byte, []int) {
-	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{8}
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *Subject) GetCatalog() v1.Catalog {
@@ -1055,7 +1329,7 @@ type IndexRuleBinding struct {
 func (x *IndexRuleBinding) Reset() {
 	*x = IndexRuleBinding{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_database_v1_schema_proto_msgTypes[9]
+		mi := &file_banyandb_database_v1_schema_proto_msgTypes[12]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1068,7 +1342,7 @@ func (x *IndexRuleBinding) String() string {
 func (*IndexRuleBinding) ProtoMessage() {}
 
 func (x *IndexRuleBinding) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_database_v1_schema_proto_msgTypes[9]
+	mi := &file_banyandb_database_v1_schema_proto_msgTypes[12]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1081,7 +1355,7 @@ func (x *IndexRuleBinding) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use IndexRuleBinding.ProtoReflect.Descriptor instead.
 func (*IndexRuleBinding) Descriptor() ([]byte, []int) {
-	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{9}
+	return file_banyandb_database_v1_schema_proto_rawDescGZIP(), []int{12}
 }
 
 func (x *IndexRuleBinding) GetMetadata() *v1.Metadata {
@@ -1136,73 +1410,88 @@ var file_banyandb_database_v1_schema_proto_rawDesc = []byte{
 	0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73,
 	0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x62, 0x61, 0x6e, 0x79,
 	0x61, 0x6e, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63,
-	0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xed, 0x01, 0x0a, 0x08,
-	0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x76, 0x61, 0x6c, 0x12, 0x3f, 0x0a, 0x04, 0x75, 0x6e,
-	0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61,
-	0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e,
-	0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
-	0x6e, 0x55, 0x6e, 0x69, 0x74, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x22, 0x8d, 0x01, 0x0a, 0x0c,
-	0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x19,
-	0x44, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x49, 0x54, 0x5f, 0x55, 0x4e,
-	0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x44,
-	0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x49, 0x54, 0x5f, 0x48, 0x4f, 0x55,
-	0x52, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x44, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f,
-	0x55, 0x4e, 0x49, 0x54, 0x5f, 0x44, 0x41, 0x59, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x55,
-	0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x49, 0x54, 0x5f, 0x57, 0x45, 0x45, 0x4b,
-	0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x44, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55,
-	0x4e, 0x49, 0x54, 0x5f, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x10, 0x04, 0x22, 0x56, 0x0a, 0x0d, 0x54,
-	0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04,
-	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
-	0x12, 0x31, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d,
-	0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
-	0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x74,
-	0x61, 0x67, 0x73, 0x22, 0x50, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12,
-	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
-	0x6d, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e,
-	0x32, 0x1d, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61,
-	0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52,
-	0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd4, 0x02, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
-	0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f,
-	0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
-	0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x46, 0x0a, 0x0c, 0x74, 0x61,
-	0x67, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x23, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61,
-	0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c,
-	0x79, 0x53, 0x70, 0x65, 0x63, 0x52, 0x0b, 0x74, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x69,
-	0x65, 0x73, 0x12, 0x34, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61,
-	0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79,
-	0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x61, 0x72,
-	0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x68, 0x61,
-	0x72, 0x64, 0x4e, 0x75, 0x6d, 0x12, 0x3a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
-	0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
+	0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x62, 0x61, 0x6e,
+	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x71,
+	0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xed, 0x01, 0x0a, 0x08, 0x44,
+	0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x76, 0x61, 0x6c, 0x12, 0x3f, 0x0a, 0x04, 0x75, 0x6e, 0x69,
+	0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
 	0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44,
-	0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
-	0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18,
-	0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
-	0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x25, 0x0a, 0x06,
-	0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x67, 0x5f, 0x6e, 0x61,
-	0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x67, 0x4e, 0x61,
-	0x6d, 0x65, 0x73, 0x22, 0x86, 0x02, 0x0a, 0x09, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x70, 0x65,
-	0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x74,
-	0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x62, 0x61, 0x6e, 0x79,
-	0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31,
-	0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c,
-	0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4d, 0x0a, 0x0f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e,
-	0x67, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24,
-	0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
-	0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65,
-	0x74, 0x68, 0x6f, 0x64, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65,
-	0x74, 0x68, 0x6f, 0x64, 0x12, 0x56, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73,
-	0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e,
-	0x32, 0x27, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61,
-	0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73,
-	0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x11, 0x63, 0x6f, 0x6d, 0x70, 0x72,
-	0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x22, 0x9b, 0x03, 0x0a,
+	0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x55, 0x6e, 0x69, 0x74, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x22, 0x8d, 0x01, 0x0a, 0x0c, 0x44,
+	0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x19, 0x44,
+	0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x49, 0x54, 0x5f, 0x55, 0x4e, 0x53,
+	0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x55,
+	0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x49, 0x54, 0x5f, 0x48, 0x4f, 0x55, 0x52,
+	0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x44, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55,
+	0x4e, 0x49, 0x54, 0x5f, 0x44, 0x41, 0x59, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x55, 0x52,
+	0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x49, 0x54, 0x5f, 0x57, 0x45, 0x45, 0x4b, 0x10,
+	0x03, 0x12, 0x17, 0x0a, 0x13, 0x44, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e,
+	0x49, 0x54, 0x5f, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x10, 0x04, 0x22, 0x56, 0x0a, 0x0d, 0x54, 0x61,
+	0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+	0x31, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e,
+	0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x74, 0x61,
+	0x67, 0x73, 0x22, 0x50, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x12, 0x31, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x1d, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+	0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x22, 0xca, 0x02, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12,
+	0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+	0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52,
+	0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x46, 0x0a, 0x0c, 0x74, 0x61, 0x67,
+	0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x23, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+	0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79,
+	0x53, 0x70, 0x65, 0x63, 0x52, 0x0b, 0x74, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65,
+	0x73, 0x12, 0x34, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74,
+	0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52,
+	0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x36, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x12,
+	0x50, 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6e, 0x61,
+	0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+	0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x14, 0x75, 0x70, 0x64,
+	0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64,
+	0x73, 0x22, 0x25, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74,
+	0x61, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08,
+	0x74, 0x61, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x5d, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x61, 0x72,
+	0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x68, 0x61,
+	0x72, 0x64, 0x4e, 0x75, 0x6d, 0x12, 0x30, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61,
+	0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x86, 0x02, 0x0a, 0x09, 0x46, 0x69, 0x65, 0x6c,
+	0x64, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0a, 0x66, 0x69, 0x65,
+	0x6c, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e,
+	0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09,
+	0x66, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4d, 0x0a, 0x0f, 0x65, 0x6e, 0x63,
+	0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x24, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61,
+	0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69,
+	0x6e, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69,
+	0x6e, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x56, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x70,
+	0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e,
+	0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70,
+	0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x11, 0x63,
+	0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
+	0x22, 0x7a, 0x0a, 0x0c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65,
+	0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x73,
+	0x74, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x73, 0x74, 0x72, 0x12,
+	0x12, 0x0a, 0x03, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x03,
+	0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x42,
+	0x0b, 0x0a, 0x09, 0x74, 0x61, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xcf, 0x03, 0x0a,
 	0x07, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
 	0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e,
 	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
@@ -1218,104 +1507,140 @@ var file_banyandb_database_v1_schema_proto_rawDesc = []byte{
 	0x6c, 0x64, 0x73, 0x12, 0x34, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20,
 	0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64,
 	0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74,
-	0x79, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x61,
-	0x72, 0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x68,
-	0x61, 0x72, 0x64, 0x4e, 0x75, 0x6d, 0x12, 0x30, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x06, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64,
-	0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74,
-	0x69, 0x6f, 0x6e, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x50, 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61,
-	0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e,
-	0x64, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
-	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
-	0x74, 0x61, 0x6d, 0x70, 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4e,
-	0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0xa4, 0x03, 0x0a, 0x09, 0x49,
-	0x6e, 0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
-	0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e,
-	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
-	0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
-	0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
-	0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x38, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e,
-	0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x64, 0x65,
-	0x78, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
-	0x12, 0x44, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
-	0x28, 0x0e, 0x32, 0x28, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61,
-	0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52,
-	0x75, 0x6c, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f,
-	0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
-	0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
+	0x79, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x0e, 0x69, 0x6e, 0x74,
+	0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74,
+	0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61,
+	0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52,
+	0x75, 0x6c, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61,
+	0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x16,
+	0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73,
+	0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
+	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
+	0x64, 0x41, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0x8b,
+	0x04, 0x0a, 0x0f, 0x54, 0x6f, 0x70, 0x4e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
+	0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x43, 0x0a, 0x0e,
+	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
+	0x74, 0x61, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72,
+	0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x41, 0x0a, 0x10, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f,
+	0x73, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x62, 0x61, 0x6e,
+	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53,
+	0x6f, 0x72, 0x74, 0x52, 0x0e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53,
+	0x6f, 0x72, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x62, 0x79, 0x5f,
+	0x74, 0x61, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52,
+	0x0f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x54, 0x61, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x73,
+	0x12, 0x37, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x18, 0x06, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f,
+	0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x52,
+	0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x75,
+	0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x05, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x4e, 0x75, 0x6d, 0x62,
+	0x65, 0x72, 0x12, 0x36, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61,
+	0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x4f, 0x70, 0x74, 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x16, 0x75, 0x70,
+	0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63,
+	0x6f, 0x6e, 0x64, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
 	0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
-	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41,
-	0x74, 0x22, 0x3e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50,
-	0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
-	0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x45, 0x45, 0x10, 0x01, 0x12, 0x11,
-	0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x44, 0x10,
-	0x02, 0x22, 0x4e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a,
-	0x14, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
-	0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x43, 0x41, 0x54,
-	0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x45, 0x52, 0x49, 0x45, 0x53, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f,
-	0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x10,
-	0x02, 0x22, 0x54, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x35, 0x0a, 0x07,
-	0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e,
-	0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
-	0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x07, 0x63, 0x61, 0x74, 0x61,
-	0x6c, 0x6f, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xc6, 0x02, 0x0a, 0x10, 0x49, 0x6e, 0x64, 0x65,
-	0x78, 0x52, 0x75, 0x6c, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x38, 0x0a, 0x08,
-	0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
-	0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
-	0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65,
-	0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18,
-	0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x07,
-	0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e,
-	0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
-	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x73, 0x75,
-	0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x35, 0x0a, 0x08, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x61,
-	0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
-	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
-	0x61, 0x6d, 0x70, 0x52, 0x07, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x12, 0x37, 0x0a, 0x09,
-	0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, 0x70,
-	0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
-	0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41,
+	0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0xa4, 0x03, 0x0a,
+	0x09, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65,
+	0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62,
+	0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76,
+	0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61,
+	0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x38, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e,
+	0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79,
+	0x70, 0x65, 0x12, 0x44, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e,
+	0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x64, 0x65,
+	0x78, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08,
+	0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61,
+	0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
+	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
+	0x64, 0x41, 0x74, 0x22, 0x3e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54,
+	0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
+	0x00, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x45, 0x45, 0x10, 0x01,
+	0x12, 0x11, 0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x45, 0x52, 0x54, 0x45,
+	0x44, 0x10, 0x02, 0x22, 0x4e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
+	0x18, 0x0a, 0x14, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50,
+	0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x43,
+	0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x45, 0x52, 0x49, 0x45, 0x53, 0x10, 0x01, 0x12, 0x13,
+	0x0a, 0x0f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41,
+	0x4c, 0x10, 0x02, 0x22, 0x54, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x35,
+	0x0a, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x1b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+	0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x07, 0x63, 0x61,
+	0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xc6, 0x02, 0x0a, 0x10, 0x49, 0x6e,
+	0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x38,
+	0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
+	0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08,
+	0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65,
+	0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x37,
+	0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1d, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+	0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07,
+	0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x35, 0x0a, 0x08, 0x62, 0x65, 0x67, 0x69, 0x6e,
+	0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
 	0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
-	0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
-	0x2a, 0x97, 0x01, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14,
-	0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
-	0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59,
-	0x50, 0x45, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x54,
-	0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x19, 0x0a,
-	0x15, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47,
-	0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x41, 0x47, 0x5f,
-	0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x04,
-	0x12, 0x18, 0x0a, 0x14, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x41, 0x54,
-	0x41, 0x5f, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x05, 0x2a, 0x6e, 0x0a, 0x09, 0x46, 0x69,
-	0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x49, 0x45, 0x4c, 0x44,
-	0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
-	0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50,
-	0x45, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x46, 0x49,
-	0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x1a,
-	0x0a, 0x16, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x41, 0x54,
-	0x41, 0x5f, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x03, 0x2a, 0x4e, 0x0a, 0x0e, 0x45, 0x6e,
-	0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, 0x1b,
-	0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f,
-	0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a,
-	0x17, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44,
-	0x5f, 0x47, 0x4f, 0x52, 0x49, 0x4c, 0x4c, 0x41, 0x10, 0x01, 0x2a, 0x54, 0x0a, 0x11, 0x43, 0x6f,
-	0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12,
-	0x22, 0x0a, 0x1e, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d,
-	0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
-	0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49,
-	0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x5a, 0x53, 0x54, 0x44, 0x10, 0x01,
-	0x42, 0x72, 0x0a, 0x2a, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x73,
-	0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
-	0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x5a, 0x44,
-	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68,
-	0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61, 0x6e,
-	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
-	0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
-	0x65, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x12, 0x37,
+	0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65,
+	0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74,
+	0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
+	0x41, 0x74, 0x2a, 0x97, 0x01, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18,
+	0x0a, 0x14, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
+	0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x41, 0x47, 0x5f,
+	0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x10, 0x0a,
+	0x0c, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x10, 0x02, 0x12,
+	0x19, 0x0a, 0x15, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x52, 0x49,
+	0x4e, 0x47, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x41,
+	0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59,
+	0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44,
+	0x41, 0x54, 0x41, 0x5f, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x05, 0x2a, 0x6e, 0x0a, 0x09,
+	0x46, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x49, 0x45,
+	0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
+	0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54,
+	0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e,
+	0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x10, 0x02,
+	0x12, 0x1a, 0x0a, 0x16, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44,
+	0x41, 0x54, 0x41, 0x5f, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x03, 0x2a, 0x4e, 0x0a, 0x0e,
+	0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f,
+	0x0a, 0x1b, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f,
+	0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
+	0x1b, 0x0a, 0x17, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4d, 0x45, 0x54, 0x48,
+	0x4f, 0x44, 0x5f, 0x47, 0x4f, 0x52, 0x49, 0x4c, 0x4c, 0x41, 0x10, 0x01, 0x2a, 0x54, 0x0a, 0x11,
+	0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f,
+	0x64, 0x12, 0x22, 0x0a, 0x1e, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e,
+	0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
+	0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53,
+	0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x5a, 0x53, 0x54, 0x44,
+	0x10, 0x01, 0x42, 0x72, 0x0a, 0x2a, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65,
+	0x2e, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79,
+	0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31,
+	0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61,
+	0x63, 0x68, 0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62,
+	0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
+	0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -1331,7 +1656,7 @@ func file_banyandb_database_v1_schema_proto_rawDescGZIP() []byte {
 }
 
 var file_banyandb_database_v1_schema_proto_enumTypes = make([]protoimpl.EnumInfo, 7)
-var file_banyandb_database_v1_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_banyandb_database_v1_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
 var file_banyandb_database_v1_schema_proto_goTypes = []interface{}{
 	(TagType)(0),                  // 0: banyandb.database.v1.TagType
 	(FieldType)(0),                // 1: banyandb.database.v1.FieldType
@@ -1345,48 +1670,61 @@ var file_banyandb_database_v1_schema_proto_goTypes = []interface{}{
 	(*TagSpec)(nil),               // 9: banyandb.database.v1.TagSpec
 	(*Stream)(nil),                // 10: banyandb.database.v1.Stream
 	(*Entity)(nil),                // 11: banyandb.database.v1.Entity
-	(*FieldSpec)(nil),             // 12: banyandb.database.v1.FieldSpec
-	(*Measure)(nil),               // 13: banyandb.database.v1.Measure
-	(*IndexRule)(nil),             // 14: banyandb.database.v1.IndexRule
-	(*Subject)(nil),               // 15: banyandb.database.v1.Subject
-	(*IndexRuleBinding)(nil),      // 16: banyandb.database.v1.IndexRuleBinding
-	(*v1.Metadata)(nil),           // 17: banyandb.common.v1.Metadata
-	(*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp
-	(v1.Catalog)(0),               // 19: banyandb.common.v1.Catalog
+	(*ResourceOpts)(nil),          // 12: banyandb.database.v1.ResourceOpts
+	(*FieldSpec)(nil),             // 13: banyandb.database.v1.FieldSpec
+	(*IntervalRule)(nil),          // 14: banyandb.database.v1.IntervalRule
+	(*Measure)(nil),               // 15: banyandb.database.v1.Measure
+	(*TopNAggregation)(nil),       // 16: banyandb.database.v1.TopNAggregation
+	(*IndexRule)(nil),             // 17: banyandb.database.v1.IndexRule
+	(*Subject)(nil),               // 18: banyandb.database.v1.Subject
+	(*IndexRuleBinding)(nil),      // 19: banyandb.database.v1.IndexRuleBinding
+	(*v1.Metadata)(nil),           // 20: banyandb.common.v1.Metadata
+	(*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp
+	(v11.Sort)(0),                 // 22: banyandb.model.v1.Sort
+	(*v11.Criteria)(nil),          // 23: banyandb.model.v1.Criteria
+	(v1.Catalog)(0),               // 24: banyandb.common.v1.Catalog
 }
 var file_banyandb_database_v1_schema_proto_depIdxs = []int32{
 	4,  // 0: banyandb.database.v1.Duration.unit:type_name -> banyandb.database.v1.Duration.DurationUnit
 	9,  // 1: banyandb.database.v1.TagFamilySpec.tags:type_name -> banyandb.database.v1.TagSpec
 	0,  // 2: banyandb.database.v1.TagSpec.type:type_name -> banyandb.database.v1.TagType
-	17, // 3: banyandb.database.v1.Stream.metadata:type_name -> banyandb.common.v1.Metadata
+	20, // 3: banyandb.database.v1.Stream.metadata:type_name -> banyandb.common.v1.Metadata
 	8,  // 4: banyandb.database.v1.Stream.tag_families:type_name -> banyandb.database.v1.TagFamilySpec
 	11, // 5: banyandb.database.v1.Stream.entity:type_name -> banyandb.database.v1.Entity
-	7,  // 6: banyandb.database.v1.Stream.duration:type_name -> banyandb.database.v1.Duration
-	18, // 7: banyandb.database.v1.Stream.updated_at:type_name -> google.protobuf.Timestamp
-	1,  // 8: banyandb.database.v1.FieldSpec.field_type:type_name -> banyandb.database.v1.FieldType
-	2,  // 9: banyandb.database.v1.FieldSpec.encoding_method:type_name -> banyandb.database.v1.EncodingMethod
-	3,  // 10: banyandb.database.v1.FieldSpec.compression_method:type_name -> banyandb.database.v1.CompressionMethod
-	17, // 11: banyandb.database.v1.Measure.metadata:type_name -> banyandb.common.v1.Metadata
-	8,  // 12: banyandb.database.v1.Measure.tag_families:type_name -> banyandb.database.v1.TagFamilySpec
-	12, // 13: banyandb.database.v1.Measure.fields:type_name -> banyandb.database.v1.FieldSpec
-	11, // 14: banyandb.database.v1.Measure.entity:type_name -> banyandb.database.v1.Entity
-	7,  // 15: banyandb.database.v1.Measure.ttl:type_name -> banyandb.database.v1.Duration
-	18, // 16: banyandb.database.v1.Measure.updated_at_nanoseconds:type_name -> google.protobuf.Timestamp
-	17, // 17: banyandb.database.v1.IndexRule.metadata:type_name -> banyandb.common.v1.Metadata
-	5,  // 18: banyandb.database.v1.IndexRule.type:type_name -> banyandb.database.v1.IndexRule.Type
-	6,  // 19: banyandb.database.v1.IndexRule.location:type_name -> banyandb.database.v1.IndexRule.Location
-	18, // 20: banyandb.database.v1.IndexRule.updated_at:type_name -> google.protobuf.Timestamp
-	19, // 21: banyandb.database.v1.Subject.catalog:type_name -> banyandb.common.v1.Catalog
-	17, // 22: banyandb.database.v1.IndexRuleBinding.metadata:type_name -> banyandb.common.v1.Metadata
-	15, // 23: banyandb.database.v1.IndexRuleBinding.subject:type_name -> banyandb.database.v1.Subject
-	18, // 24: banyandb.database.v1.IndexRuleBinding.begin_at:type_name -> google.protobuf.Timestamp
-	18, // 25: banyandb.database.v1.IndexRuleBinding.expire_at:type_name -> google.protobuf.Timestamp
-	18, // 26: banyandb.database.v1.IndexRuleBinding.updated_at:type_name -> google.protobuf.Timestamp
-	27, // [27:27] is the sub-list for method output_type
-	27, // [27:27] is the sub-list for method input_type
-	27, // [27:27] is the sub-list for extension type_name
-	27, // [27:27] is the sub-list for extension extendee
-	0,  // [0:27] is the sub-list for field type_name
+	12, // 6: banyandb.database.v1.Stream.opts:type_name -> banyandb.database.v1.ResourceOpts
+	21, // 7: banyandb.database.v1.Stream.updated_at_nanoseconds:type_name -> google.protobuf.Timestamp
+	7,  // 8: banyandb.database.v1.ResourceOpts.ttl:type_name -> banyandb.database.v1.Duration
+	1,  // 9: banyandb.database.v1.FieldSpec.field_type:type_name -> banyandb.database.v1.FieldType
+	2,  // 10: banyandb.database.v1.FieldSpec.encoding_method:type_name -> banyandb.database.v1.EncodingMethod
+	3,  // 11: banyandb.database.v1.FieldSpec.compression_method:type_name -> banyandb.database.v1.CompressionMethod
+	20, // 12: banyandb.database.v1.Measure.metadata:type_name -> banyandb.common.v1.Metadata
+	8,  // 13: banyandb.database.v1.Measure.tag_families:type_name -> banyandb.database.v1.TagFamilySpec
+	13, // 14: banyandb.database.v1.Measure.fields:type_name -> banyandb.database.v1.FieldSpec
+	11, // 15: banyandb.database.v1.Measure.entity:type_name -> banyandb.database.v1.Entity
+	14, // 16: banyandb.database.v1.Measure.interval_rules:type_name -> banyandb.database.v1.IntervalRule
+	12, // 17: banyandb.database.v1.Measure.opts:type_name -> banyandb.database.v1.ResourceOpts
+	21, // 18: banyandb.database.v1.Measure.updated_at_nanoseconds:type_name -> google.protobuf.Timestamp
+	20, // 19: banyandb.database.v1.TopNAggregation.metadata:type_name -> banyandb.common.v1.Metadata
+	20, // 20: banyandb.database.v1.TopNAggregation.source_measure:type_name -> banyandb.common.v1.Metadata
+	22, // 21: banyandb.database.v1.TopNAggregation.field_value_sort:type_name -> banyandb.model.v1.Sort
+	23, // 22: banyandb.database.v1.TopNAggregation.criteria:type_name -> banyandb.model.v1.Criteria
+	12, // 23: banyandb.database.v1.TopNAggregation.opts:type_name -> banyandb.database.v1.ResourceOpts
+	21, // 24: banyandb.database.v1.TopNAggregation.updated_at_nanoseconds:type_name -> google.protobuf.Timestamp
+	20, // 25: banyandb.database.v1.IndexRule.metadata:type_name -> banyandb.common.v1.Metadata
+	5,  // 26: banyandb.database.v1.IndexRule.type:type_name -> banyandb.database.v1.IndexRule.Type
+	6,  // 27: banyandb.database.v1.IndexRule.location:type_name -> banyandb.database.v1.IndexRule.Location
+	21, // 28: banyandb.database.v1.IndexRule.updated_at:type_name -> google.protobuf.Timestamp
+	24, // 29: banyandb.database.v1.Subject.catalog:type_name -> banyandb.common.v1.Catalog
+	20, // 30: banyandb.database.v1.IndexRuleBinding.metadata:type_name -> banyandb.common.v1.Metadata
+	18, // 31: banyandb.database.v1.IndexRuleBinding.subject:type_name -> banyandb.database.v1.Subject
+	21, // 32: banyandb.database.v1.IndexRuleBinding.begin_at:type_name -> google.protobuf.Timestamp
+	21, // 33: banyandb.database.v1.IndexRuleBinding.expire_at:type_name -> google.protobuf.Timestamp
+	21, // 34: banyandb.database.v1.IndexRuleBinding.updated_at:type_name -> google.protobuf.Timestamp
+	35, // [35:35] is the sub-list for method output_type
+	35, // [35:35] is the sub-list for method input_type
+	35, // [35:35] is the sub-list for extension type_name
+	35, // [35:35] is the sub-list for extension extendee
+	0,  // [0:35] is the sub-list for field type_name
 }
 
 func init() { file_banyandb_database_v1_schema_proto_init() }
@@ -1456,7 +1794,7 @@ func file_banyandb_database_v1_schema_proto_init() {
 			}
 		}
 		file_banyandb_database_v1_schema_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*FieldSpec); i {
+			switch v := v.(*ResourceOpts); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1468,7 +1806,7 @@ func file_banyandb_database_v1_schema_proto_init() {
 			}
 		}
 		file_banyandb_database_v1_schema_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Measure); i {
+			switch v := v.(*FieldSpec); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1480,7 +1818,7 @@ func file_banyandb_database_v1_schema_proto_init() {
 			}
 		}
 		file_banyandb_database_v1_schema_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*IndexRule); i {
+			switch v := v.(*IntervalRule); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1492,7 +1830,7 @@ func file_banyandb_database_v1_schema_proto_init() {
 			}
 		}
 		file_banyandb_database_v1_schema_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Subject); i {
+			switch v := v.(*Measure); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1504,6 +1842,42 @@ func file_banyandb_database_v1_schema_proto_init() {
 			}
 		}
 		file_banyandb_database_v1_schema_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TopNAggregation); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_database_v1_schema_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*IndexRule); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_database_v1_schema_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Subject); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_database_v1_schema_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*IndexRuleBinding); i {
 			case 0:
 				return &v.state
@@ -1516,13 +1890,17 @@ func file_banyandb_database_v1_schema_proto_init() {
 			}
 		}
 	}
+	file_banyandb_database_v1_schema_proto_msgTypes[7].OneofWrappers = []interface{}{
+		(*IntervalRule_Str)(nil),
+		(*IntervalRule_Int)(nil),
+	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_banyandb_database_v1_schema_proto_rawDesc,
 			NumEnums:      7,
-			NumMessages:   10,
+			NumMessages:   13,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/api/proto/banyandb/database/v1/schema.proto b/api/proto/banyandb/database/v1/schema.proto
index 508966f..c5c2fb7 100644
--- a/api/proto/banyandb/database/v1/schema.proto
+++ b/api/proto/banyandb/database/v1/schema.proto
@@ -24,6 +24,7 @@ package banyandb.database.v1;
 
 import "google/protobuf/timestamp.proto";
 import "banyandb/common/v1/common.proto";
+import "banyandb/model/v1/query.proto";
 
 // Duration represents the elapsed time between two instants
 message Duration {
@@ -66,11 +67,9 @@ message Stream {
     repeated TagFamilySpec tag_families = 2;
     // entity indicates how to generate a series and shard a stream
     Entity entity = 3;
-    // duration determines how long a TraceSeries keeps its data
-    uint32 shard_num = 4;
-    Duration duration = 5;
-    // updated_at_nanoseconds indicates when the TraceSeries is updated
-    google.protobuf.Timestamp updated_at = 6;
+    ResourceOpts opts = 4;
+    // updated_at_nanoseconds indicates when the measure is updated
+    google.protobuf.Timestamp updated_at_nanoseconds = 5;
 }
 
 message Entity {
@@ -94,6 +93,13 @@ enum CompressionMethod {
     COMPRESSION_METHOD_ZSTD = 1;
 }
 
+message ResourceOpts {
+    // shard_num is the number of shards
+    uint32 shard_num = 1;
+    // ttl indicates time to live, how long the data will be cached
+    Duration ttl = 2;
+}
+
 // FieldSpec is the specification of field
 message FieldSpec {
     // name is the identity of a field
@@ -106,6 +112,19 @@ message FieldSpec {
     CompressionMethod compression_method = 4;
 }
 
+// IntervalRule indicates how to get the interval of a measure series.
+message IntervalRule {
+    // tag_name is for matching a tag
+    string tag_name = 1;
+    // tag_value is used by a equality matcher to match a tag
+    oneof tag_value {
+        string str = 2;
+        int64 int = 3;
+    }
+    // interval indicates how frequently to send a data point
+    string interval = 4;
+}
+
 // Measure intends to store data point
 message Measure {
     // metadata is the identity of a measure
@@ -116,14 +135,39 @@ message Measure {
     repeated FieldSpec fields = 3;
     // entity indicates which tags will be to generate a series and shard a measure
     Entity entity = 4;
-    // shard_num is the number of shards
-    uint32 shard_num = 5;
-    // ttl indicates time to live, how long the data will be cached
-    Duration ttl = 6;
+    // interval_rules define data points writing interval
+    repeated IntervalRule interval_rules = 5;
+    // opts is basic resource management options
+    ResourceOpts opts = 6;
     // updated_at_nanoseconds indicates when the measure is updated
     google.protobuf.Timestamp updated_at_nanoseconds = 7;
 }
 
+// TopNAggregation generates offline TopN statistics for a measure's TopN approximation
+message TopNAggregation {
+    // metadata is the identity of an aggregation
+    common.v1.Metadata metadata = 1;
+    // source_measure denotes the data source of this aggregation
+    common.v1.Metadata source_measure = 2;
+    // field_name is the name of field used for ranking
+    string field_name = 3;
+    // field_value_sort indicates how to sort fields
+    // ASC: bottomN
+    // DESC: topN
+    // UNSPECIFIED: topN + bottomN
+    model.v1.Sort field_value_sort = 4;
+    // group_by_tag_names groups data points into statistical counters
+    repeated string group_by_tag_names = 5;
+    // criteria select partial data points from measure
+    repeated model.v1.Criteria criteria = 6;
+    // counters_number sets the number of counters to be tracked. The default value is 1000
+    int32 counters_number = 7;
+    // opts is basic resource management options
+    ResourceOpts opts = 8;
+    // updated_at_nanoseconds indicates when the measure is updated
+    google.protobuf.Timestamp updated_at_nanoseconds = 9;
+}
+
 // IndexRule defines how to generate indices based on tags and the index type
 // IndexRule should bind to a subject through an IndexRuleBinding to generate proper indices.
 message IndexRule {
diff --git a/api/proto/banyandb/measure/v1/query.pb.go b/api/proto/banyandb/measure/v1/query.pb.go
new file mode 100644
index 0000000..bedbb78
--- /dev/null
+++ b/api/proto/banyandb/measure/v1/query.pb.go
@@ -0,0 +1,627 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.18.1
+// source: banyandb/measure/v1/query.proto
+
+package v1
+
+import (
+	reflect "reflect"
+	sync "sync"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+
+	v11 "github.com/apache/skywalking-banyandb/api/proto/banyandb/common/v1"
+	v1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// DataPoint is stored in Measures
+type DataPoint struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// timestamp is in the timeunit of nanoseconds.
+	Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	// tag_families contains tags selected in the projection
+	TagFamilies []*v1.TagFamily `protobuf:"bytes,2,rep,name=tag_families,json=tagFamilies,proto3" json:"tag_families,omitempty"`
+	// fields contains fields selected in the projection
+	Fields []*DataPoint_Field `protobuf:"bytes,3,rep,name=fields,proto3" json:"fields,omitempty"`
+}
+
+func (x *DataPoint) Reset() {
+	*x = DataPoint{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_query_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DataPoint) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DataPoint) ProtoMessage() {}
+
+func (x *DataPoint) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_query_proto_msgTypes[0]
+	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 DataPoint.ProtoReflect.Descriptor instead.
+func (*DataPoint) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_query_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DataPoint) GetTimestamp() *timestamppb.Timestamp {
+	if x != nil {
+		return x.Timestamp
+	}
+	return nil
+}
+
+func (x *DataPoint) GetTagFamilies() []*v1.TagFamily {
+	if x != nil {
+		return x.TagFamilies
+	}
+	return nil
+}
+
+func (x *DataPoint) GetFields() []*DataPoint_Field {
+	if x != nil {
+		return x.Fields
+	}
+	return nil
+}
+
+// QueryResponse is the response for a query to the Query module.
+type QueryResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// data_points are the actual data returned
+	DataPoints []*DataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"`
+}
+
+func (x *QueryResponse) Reset() {
+	*x = QueryResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_query_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *QueryResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryResponse) ProtoMessage() {}
+
+func (x *QueryResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_query_proto_msgTypes[1]
+	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 QueryResponse.ProtoReflect.Descriptor instead.
+func (*QueryResponse) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_query_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *QueryResponse) GetDataPoints() []*DataPoint {
+	if x != nil {
+		return x.DataPoints
+	}
+	return nil
+}
+
+// QueryRequest is the request contract for query.
+type QueryRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// metadata is required
+	Metadata *v11.Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+	// time_range is a range query with begin/end time of entities in the timeunit of nanoseconds.
+	TimeRange *v1.TimeRange `protobuf:"bytes,2,opt,name=time_range,json=timeRange,proto3" json:"time_range,omitempty"`
+	// criteria select the data points.
+	Criteria []*QueryRequest_Criteria `protobuf:"bytes,4,rep,name=criteria,proto3" json:"criteria,omitempty"`
+	// tag_projection can be used to select tags of the data points in the response
+	TagProjection *v1.TagProjection `protobuf:"bytes,5,opt,name=tag_projection,json=tagProjection,proto3" json:"tag_projection,omitempty"`
+	// field_projection can be used to select fields of the data points in the response
+	FieldProjection *QueryRequest_FieldProjection `protobuf:"bytes,6,opt,name=field_projection,json=fieldProjection,proto3" json:"field_projection,omitempty"`
+}
+
+func (x *QueryRequest) Reset() {
+	*x = QueryRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_query_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *QueryRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryRequest) ProtoMessage() {}
+
+func (x *QueryRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_query_proto_msgTypes[2]
+	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 QueryRequest.ProtoReflect.Descriptor instead.
+func (*QueryRequest) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_query_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *QueryRequest) GetMetadata() *v11.Metadata {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+func (x *QueryRequest) GetTimeRange() *v1.TimeRange {
+	if x != nil {
+		return x.TimeRange
+	}
+	return nil
+}
+
+func (x *QueryRequest) GetCriteria() []*QueryRequest_Criteria {
+	if x != nil {
+		return x.Criteria
+	}
+	return nil
+}
+
+func (x *QueryRequest) GetTagProjection() *v1.TagProjection {
+	if x != nil {
+		return x.TagProjection
+	}
+	return nil
+}
+
+func (x *QueryRequest) GetFieldProjection() *QueryRequest_FieldProjection {
+	if x != nil {
+		return x.FieldProjection
+	}
+	return nil
+}
+
+type DataPoint_Field struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name  string         `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Value *v1.FieldValue `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *DataPoint_Field) Reset() {
+	*x = DataPoint_Field{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_query_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DataPoint_Field) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DataPoint_Field) ProtoMessage() {}
+
+func (x *DataPoint_Field) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_query_proto_msgTypes[3]
+	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 DataPoint_Field.ProtoReflect.Descriptor instead.
+func (*DataPoint_Field) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_query_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *DataPoint_Field) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *DataPoint_Field) GetValue() *v1.FieldValue {
+	if x != nil {
+		return x.Value
+	}
+	return nil
+}
+
+type QueryRequest_Criteria struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TagFamilyName string          `protobuf:"bytes,1,opt,name=tag_family_name,json=tagFamilyName,proto3" json:"tag_family_name,omitempty"`
+	Conditions    []*v1.Condition `protobuf:"bytes,2,rep,name=conditions,proto3" json:"conditions,omitempty"`
+}
+
+func (x *QueryRequest_Criteria) Reset() {
+	*x = QueryRequest_Criteria{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_query_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *QueryRequest_Criteria) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryRequest_Criteria) ProtoMessage() {}
+
+func (x *QueryRequest_Criteria) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_query_proto_msgTypes[4]
+	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 QueryRequest_Criteria.ProtoReflect.Descriptor instead.
+func (*QueryRequest_Criteria) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_query_proto_rawDescGZIP(), []int{2, 0}
+}
+
+func (x *QueryRequest_Criteria) GetTagFamilyName() string {
+	if x != nil {
+		return x.TagFamilyName
+	}
+	return ""
+}
+
+func (x *QueryRequest_Criteria) GetConditions() []*v1.Condition {
+	if x != nil {
+		return x.Conditions
+	}
+	return nil
+}
+
+type QueryRequest_FieldProjection struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name []string `protobuf:"bytes,1,rep,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *QueryRequest_FieldProjection) Reset() {
+	*x = QueryRequest_FieldProjection{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_query_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *QueryRequest_FieldProjection) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryRequest_FieldProjection) ProtoMessage() {}
+
+func (x *QueryRequest_FieldProjection) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_query_proto_msgTypes[5]
+	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 QueryRequest_FieldProjection.ProtoReflect.Descriptor instead.
+func (*QueryRequest_FieldProjection) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_query_proto_rawDescGZIP(), []int{2, 1}
+}
+
+func (x *QueryRequest_FieldProjection) GetName() []string {
+	if x != nil {
+		return x.Name
+	}
+	return nil
+}
+
+var File_banyandb_measure_v1_query_proto protoreflect.FileDescriptor
+
+var file_banyandb_measure_v1_query_proto_rawDesc = []byte{
+	0x0a, 0x1f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x65, 0x61, 0x73, 0x75,
+	0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x13, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73,
+	0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+	0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
+	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
+	0x64, 0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
+	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
+	0x64, 0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, 0x72,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96, 0x02, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61,
+	0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+	0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
+	0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12,
+	0x3f, 0x0a, 0x0c, 0x74, 0x61, 0x67, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73, 0x18,
+	0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x46, 0x61, 0x6d,
+	0x69, 0x6c, 0x79, 0x52, 0x0b, 0x74, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73,
+	0x12, 0x3c, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x24, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73,
+	0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74,
+	0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x50,
+	0x0a, 0x05, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x61, 0x6e,
+	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x46,
+	0x69, 0x65, 0x6c, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x22, 0x50, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73,
+	0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74,
+	0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e,
+	0x74, 0x73, 0x22, 0x8d, 0x04, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
+	0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3b, 0x0a,
+	0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64,
+	0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52,
+	0x09, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x08, 0x63, 0x72,
+	0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x62,
+	0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e,
+	0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e,
+	0x43, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72,
+	0x69, 0x61, 0x12, 0x47, 0x0a, 0x0e, 0x74, 0x61, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x62, 0x61, 0x6e,
+	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x54,
+	0x61, 0x67, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x74, 0x61,
+	0x67, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x10, 0x66,
+	0x69, 0x65, 0x6c, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18,
+	0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72,
+	0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x50, 0x72,
+	0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x50,
+	0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x70, 0x0a, 0x08, 0x43, 0x72, 0x69,
+	0x74, 0x65, 0x72, 0x69, 0x61, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x61, 0x67, 0x5f, 0x66, 0x61, 0x6d,
+	0x69, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
+	0x74, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a,
+	0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64,
+	0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+	0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x25, 0x0a, 0x0f, 0x46,
+	0x69, 0x65, 0x6c, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12,
+	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x42, 0x70, 0x0a, 0x29, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65,
+	0x2e, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79,
+	0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x5a,
+	0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63,
+	0x68, 0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61,
+	0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72,
+	0x65, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_banyandb_measure_v1_query_proto_rawDescOnce sync.Once
+	file_banyandb_measure_v1_query_proto_rawDescData = file_banyandb_measure_v1_query_proto_rawDesc
+)
+
+func file_banyandb_measure_v1_query_proto_rawDescGZIP() []byte {
+	file_banyandb_measure_v1_query_proto_rawDescOnce.Do(func() {
+		file_banyandb_measure_v1_query_proto_rawDescData = protoimpl.X.CompressGZIP(file_banyandb_measure_v1_query_proto_rawDescData)
+	})
+	return file_banyandb_measure_v1_query_proto_rawDescData
+}
+
+var file_banyandb_measure_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
+var file_banyandb_measure_v1_query_proto_goTypes = []interface{}{
+	(*DataPoint)(nil),                    // 0: banyandb.measure.v1.DataPoint
+	(*QueryResponse)(nil),                // 1: banyandb.measure.v1.QueryResponse
+	(*QueryRequest)(nil),                 // 2: banyandb.measure.v1.QueryRequest
+	(*DataPoint_Field)(nil),              // 3: banyandb.measure.v1.DataPoint.Field
+	(*QueryRequest_Criteria)(nil),        // 4: banyandb.measure.v1.QueryRequest.Criteria
+	(*QueryRequest_FieldProjection)(nil), // 5: banyandb.measure.v1.QueryRequest.FieldProjection
+	(*timestamppb.Timestamp)(nil),        // 6: google.protobuf.Timestamp
+	(*v1.TagFamily)(nil),                 // 7: banyandb.model.v1.TagFamily
+	(*v11.Metadata)(nil),                 // 8: banyandb.common.v1.Metadata
+	(*v1.TimeRange)(nil),                 // 9: banyandb.model.v1.TimeRange
+	(*v1.TagProjection)(nil),             // 10: banyandb.model.v1.TagProjection
+	(*v1.FieldValue)(nil),                // 11: banyandb.model.v1.FieldValue
+	(*v1.Condition)(nil),                 // 12: banyandb.model.v1.Condition
+}
+var file_banyandb_measure_v1_query_proto_depIdxs = []int32{
+	6,  // 0: banyandb.measure.v1.DataPoint.timestamp:type_name -> google.protobuf.Timestamp
+	7,  // 1: banyandb.measure.v1.DataPoint.tag_families:type_name -> banyandb.model.v1.TagFamily
+	3,  // 2: banyandb.measure.v1.DataPoint.fields:type_name -> banyandb.measure.v1.DataPoint.Field
+	0,  // 3: banyandb.measure.v1.QueryResponse.data_points:type_name -> banyandb.measure.v1.DataPoint
+	8,  // 4: banyandb.measure.v1.QueryRequest.metadata:type_name -> banyandb.common.v1.Metadata
+	9,  // 5: banyandb.measure.v1.QueryRequest.time_range:type_name -> banyandb.model.v1.TimeRange
+	4,  // 6: banyandb.measure.v1.QueryRequest.criteria:type_name -> banyandb.measure.v1.QueryRequest.Criteria
+	10, // 7: banyandb.measure.v1.QueryRequest.tag_projection:type_name -> banyandb.model.v1.TagProjection
+	5,  // 8: banyandb.measure.v1.QueryRequest.field_projection:type_name -> banyandb.measure.v1.QueryRequest.FieldProjection
+	11, // 9: banyandb.measure.v1.DataPoint.Field.value:type_name -> banyandb.model.v1.FieldValue
+	12, // 10: banyandb.measure.v1.QueryRequest.Criteria.conditions:type_name -> banyandb.model.v1.Condition
+	11, // [11:11] is the sub-list for method output_type
+	11, // [11:11] is the sub-list for method input_type
+	11, // [11:11] is the sub-list for extension type_name
+	11, // [11:11] is the sub-list for extension extendee
+	0,  // [0:11] is the sub-list for field type_name
+}
+
+func init() { file_banyandb_measure_v1_query_proto_init() }
+func file_banyandb_measure_v1_query_proto_init() {
+	if File_banyandb_measure_v1_query_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_banyandb_measure_v1_query_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DataPoint); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_query_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*QueryResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_query_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*QueryRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_query_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DataPoint_Field); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_query_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*QueryRequest_Criteria); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_query_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*QueryRequest_FieldProjection); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_banyandb_measure_v1_query_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   6,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_banyandb_measure_v1_query_proto_goTypes,
+		DependencyIndexes: file_banyandb_measure_v1_query_proto_depIdxs,
+		MessageInfos:      file_banyandb_measure_v1_query_proto_msgTypes,
+	}.Build()
+	File_banyandb_measure_v1_query_proto = out.File
+	file_banyandb_measure_v1_query_proto_rawDesc = nil
+	file_banyandb_measure_v1_query_proto_goTypes = nil
+	file_banyandb_measure_v1_query_proto_depIdxs = nil
+}
diff --git a/api/proto/banyandb/measure/v1/query.proto b/api/proto/banyandb/measure/v1/query.proto
new file mode 100644
index 0000000..1f0063c
--- /dev/null
+++ b/api/proto/banyandb/measure/v1/query.proto
@@ -0,0 +1,69 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+syntax = "proto3";
+
+option java_package = "org.apache.skywalking.banyandb.measure.v1";
+option go_package = "github.com/apache/skywalking-banyandb/api/proto/banyandb/measure/v1";
+
+package banyandb.measure.v1;
+
+import "google/protobuf/timestamp.proto";
+import "banyandb/common/v1/common.proto";
+import "banyandb/model/v1/common.proto";
+import "banyandb/model/v1/query.proto";
+
+// DataPoint is stored in Measures
+message DataPoint {
+  // timestamp is in the timeunit of nanoseconds.
+  google.protobuf.Timestamp timestamp = 1;
+  // tag_families contains tags selected in the projection
+  repeated model.v1.TagFamily tag_families = 2;
+  message Field {
+    string name = 1;
+    model.v1.FieldValue value = 2;
+  }
+  // fields contains fields selected in the projection
+  repeated Field fields = 3;
+}
+
+// QueryResponse is the response for a query to the Query module.
+message QueryResponse {
+  // data_points are the actual data returned
+  repeated DataPoint data_points = 1;
+}
+
+// QueryRequest is the request contract for query.
+message QueryRequest {
+  // metadata is required
+  common.v1.Metadata metadata = 1;
+  // time_range is a range query with begin/end time of entities in the timeunit of nanoseconds.
+  model.v1.TimeRange time_range = 2;
+  message Criteria {
+    string tag_family_name = 1;
+    repeated model.v1.Condition conditions = 2;
+  }
+  // criteria select the data points.
+  repeated Criteria criteria = 4;
+  // tag_projection can be used to select tags of the data points in the response
+  model.v1.TagProjection tag_projection = 5;
+  message FieldProjection {
+    repeated string name = 1;
+  }
+  // field_projection can be used to select fields of the data points in the response
+  FieldProjection field_projection = 6;
+}
diff --git a/api/proto/banyandb/measure/v1/rpc.pb.go b/api/proto/banyandb/measure/v1/rpc.pb.go
new file mode 100644
index 0000000..535c380
--- /dev/null
+++ b/api/proto/banyandb/measure/v1/rpc.pb.go
@@ -0,0 +1,126 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.18.1
+// source: banyandb/measure/v1/rpc.proto
+
+package v1
+
+import (
+	reflect "reflect"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+var File_banyandb_measure_v1_rpc_proto protoreflect.FileDescriptor
+
+var file_banyandb_measure_v1_rpc_proto_rawDesc = []byte{
+	0x0a, 0x1d, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x65, 0x61, 0x73, 0x75,
+	0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+	0x13, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72,
+	0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d,
+	0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f,
+	0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x72, 0x69, 0x74, 0x65,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2f, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x70, 0x6e,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x81, 0x02, 0x0a, 0x0e, 0x4d, 0x65, 0x61, 0x73, 0x75,
+	0x72, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x05, 0x51, 0x75, 0x65,
+	0x72, 0x79, 0x12, 0x21, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65,
+	0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72,
+	0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x05, 0x57, 0x72, 0x69,
+	0x74, 0x65, 0x12, 0x21, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65,
+	0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74,
+	0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x4b, 0x0a,
+	0x04, 0x54, 0x6f, 0x70, 0x4e, 0x12, 0x20, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
+	0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f,
+	0x70, 0x4e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x70, 0x0a, 0x29, 0x6f, 0x72,
+	0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b,
+	0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61,
+	0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61,
+	0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61,
+	0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2f, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x33,
+}
+
+var file_banyandb_measure_v1_rpc_proto_goTypes = []interface{}{
+	(*QueryRequest)(nil),  // 0: banyandb.measure.v1.QueryRequest
+	(*WriteRequest)(nil),  // 1: banyandb.measure.v1.WriteRequest
+	(*TopNRequest)(nil),   // 2: banyandb.measure.v1.TopNRequest
+	(*QueryResponse)(nil), // 3: banyandb.measure.v1.QueryResponse
+	(*WriteResponse)(nil), // 4: banyandb.measure.v1.WriteResponse
+	(*TopNResponse)(nil),  // 5: banyandb.measure.v1.TopNResponse
+}
+var file_banyandb_measure_v1_rpc_proto_depIdxs = []int32{
+	0, // 0: banyandb.measure.v1.MeasureService.Query:input_type -> banyandb.measure.v1.QueryRequest
+	1, // 1: banyandb.measure.v1.MeasureService.Write:input_type -> banyandb.measure.v1.WriteRequest
+	2, // 2: banyandb.measure.v1.MeasureService.TopN:input_type -> banyandb.measure.v1.TopNRequest
+	3, // 3: banyandb.measure.v1.MeasureService.Query:output_type -> banyandb.measure.v1.QueryResponse
+	4, // 4: banyandb.measure.v1.MeasureService.Write:output_type -> banyandb.measure.v1.WriteResponse
+	5, // 5: banyandb.measure.v1.MeasureService.TopN:output_type -> banyandb.measure.v1.TopNResponse
+	3, // [3:6] is the sub-list for method output_type
+	0, // [0:3] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_banyandb_measure_v1_rpc_proto_init() }
+func file_banyandb_measure_v1_rpc_proto_init() {
+	if File_banyandb_measure_v1_rpc_proto != nil {
+		return
+	}
+	file_banyandb_measure_v1_query_proto_init()
+	file_banyandb_measure_v1_write_proto_init()
+	file_banyandb_measure_v1_topn_proto_init()
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_banyandb_measure_v1_rpc_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   0,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_banyandb_measure_v1_rpc_proto_goTypes,
+		DependencyIndexes: file_banyandb_measure_v1_rpc_proto_depIdxs,
+	}.Build()
+	File_banyandb_measure_v1_rpc_proto = out.File
+	file_banyandb_measure_v1_rpc_proto_rawDesc = nil
+	file_banyandb_measure_v1_rpc_proto_goTypes = nil
+	file_banyandb_measure_v1_rpc_proto_depIdxs = nil
+}
diff --git a/api/proto/banyandb/model/v1/common.proto b/api/proto/banyandb/measure/v1/rpc.proto
similarity index 59%
copy from api/proto/banyandb/model/v1/common.proto
copy to api/proto/banyandb/measure/v1/rpc.proto
index 2314215..6fc1ba8 100644
--- a/api/proto/banyandb/model/v1/common.proto
+++ b/api/proto/banyandb/measure/v1/rpc.proto
@@ -17,40 +17,17 @@
 
 syntax = "proto3";
 
-package banyandb.model.v1;
+option java_package = "org.apache.skywalking.banyandb.measure.v1";
+option go_package = "github.com/apache/skywalking-banyandb/api/proto/banyandb/measure/v1";
 
-option java_package = "org.apache.skywalking.banyandb.model.v1";
-option go_package = "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1";
+package banyandb.measure.v1;
 
-import "google/protobuf/struct.proto";
+import "banyandb/measure/v1/query.proto";
+import "banyandb/measure/v1/write.proto";
+import "banyandb/measure/v1/topn.proto";
 
-message Str {
-    string value = 1;
-}
-
-message Int {
-    int64 value = 1;
-}
-
-message StrArray {
-    repeated string value = 1;
-}
-
-message IntArray {
-    repeated int64 value = 1;
-}
-
-message TagValue {
-    oneof value {
-        google.protobuf.NullValue null = 1;
-        Str str = 2;
-        StrArray str_array = 3;
-        Int int = 4;
-        IntArray int_array = 5;
-        bytes binary_data = 6;
-    }
-}
-
-message TagFamilyForWrite {
-    repeated TagValue tags = 1;
-}
+service MeasureService {
+  rpc Query(banyandb.measure.v1.QueryRequest) returns (banyandb.measure.v1.QueryResponse);
+  rpc Write(stream banyandb.measure.v1.WriteRequest) returns (stream banyandb.measure.v1.WriteResponse);
+  rpc TopN(banyandb.measure.v1.TopNRequest) returns (banyandb.measure.v1.TopNResponse);
+}
\ No newline at end of file
diff --git a/api/proto/banyandb/measure/v1/rpc_grpc.pb.go b/api/proto/banyandb/measure/v1/rpc_grpc.pb.go
new file mode 100644
index 0000000..22d61d6
--- /dev/null
+++ b/api/proto/banyandb/measure/v1/rpc_grpc.pb.go
@@ -0,0 +1,207 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package v1
+
+import (
+	context "context"
+
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// MeasureServiceClient is the client API for MeasureService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type MeasureServiceClient interface {
+	Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error)
+	Write(ctx context.Context, opts ...grpc.CallOption) (MeasureService_WriteClient, error)
+	TopN(ctx context.Context, in *TopNRequest, opts ...grpc.CallOption) (*TopNResponse, error)
+}
+
+type measureServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewMeasureServiceClient(cc grpc.ClientConnInterface) MeasureServiceClient {
+	return &measureServiceClient{cc}
+}
+
+func (c *measureServiceClient) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) {
+	out := new(QueryResponse)
+	err := c.cc.Invoke(ctx, "/banyandb.measure.v1.MeasureService/Query", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *measureServiceClient) Write(ctx context.Context, opts ...grpc.CallOption) (MeasureService_WriteClient, error) {
+	stream, err := c.cc.NewStream(ctx, &MeasureService_ServiceDesc.Streams[0], "/banyandb.measure.v1.MeasureService/Write", opts...)
+	if err != nil {
+		return nil, err
+	}
+	x := &measureServiceWriteClient{stream}
+	return x, nil
+}
+
+type MeasureService_WriteClient interface {
+	Send(*WriteRequest) error
+	Recv() (*WriteResponse, error)
+	grpc.ClientStream
+}
+
+type measureServiceWriteClient struct {
+	grpc.ClientStream
+}
+
+func (x *measureServiceWriteClient) Send(m *WriteRequest) error {
+	return x.ClientStream.SendMsg(m)
+}
+
+func (x *measureServiceWriteClient) Recv() (*WriteResponse, error) {
+	m := new(WriteResponse)
+	if err := x.ClientStream.RecvMsg(m); err != nil {
+		return nil, err
+	}
+	return m, nil
+}
+
+func (c *measureServiceClient) TopN(ctx context.Context, in *TopNRequest, opts ...grpc.CallOption) (*TopNResponse, error) {
+	out := new(TopNResponse)
+	err := c.cc.Invoke(ctx, "/banyandb.measure.v1.MeasureService/TopN", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// MeasureServiceServer is the server API for MeasureService service.
+// All implementations must embed UnimplementedMeasureServiceServer
+// for forward compatibility
+type MeasureServiceServer interface {
+	Query(context.Context, *QueryRequest) (*QueryResponse, error)
+	Write(MeasureService_WriteServer) error
+	TopN(context.Context, *TopNRequest) (*TopNResponse, error)
+	mustEmbedUnimplementedMeasureServiceServer()
+}
+
+// UnimplementedMeasureServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedMeasureServiceServer struct {
+}
+
+func (UnimplementedMeasureServiceServer) Query(context.Context, *QueryRequest) (*QueryResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Query not implemented")
+}
+func (UnimplementedMeasureServiceServer) Write(MeasureService_WriteServer) error {
+	return status.Errorf(codes.Unimplemented, "method Write not implemented")
+}
+func (UnimplementedMeasureServiceServer) TopN(context.Context, *TopNRequest) (*TopNResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method TopN not implemented")
+}
+func (UnimplementedMeasureServiceServer) mustEmbedUnimplementedMeasureServiceServer() {}
+
+// UnsafeMeasureServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to MeasureServiceServer will
+// result in compilation errors.
+type UnsafeMeasureServiceServer interface {
+	mustEmbedUnimplementedMeasureServiceServer()
+}
+
+func RegisterMeasureServiceServer(s grpc.ServiceRegistrar, srv MeasureServiceServer) {
+	s.RegisterService(&MeasureService_ServiceDesc, srv)
+}
+
+func _MeasureService_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(QueryRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MeasureServiceServer).Query(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/banyandb.measure.v1.MeasureService/Query",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MeasureServiceServer).Query(ctx, req.(*QueryRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _MeasureService_Write_Handler(srv interface{}, stream grpc.ServerStream) error {
+	return srv.(MeasureServiceServer).Write(&measureServiceWriteServer{stream})
+}
+
+type MeasureService_WriteServer interface {
+	Send(*WriteResponse) error
+	Recv() (*WriteRequest, error)
+	grpc.ServerStream
+}
+
+type measureServiceWriteServer struct {
+	grpc.ServerStream
+}
+
+func (x *measureServiceWriteServer) Send(m *WriteResponse) error {
+	return x.ServerStream.SendMsg(m)
+}
+
+func (x *measureServiceWriteServer) Recv() (*WriteRequest, error) {
+	m := new(WriteRequest)
+	if err := x.ServerStream.RecvMsg(m); err != nil {
+		return nil, err
+	}
+	return m, nil
+}
+
+func _MeasureService_TopN_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(TopNRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MeasureServiceServer).TopN(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/banyandb.measure.v1.MeasureService/TopN",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MeasureServiceServer).TopN(ctx, req.(*TopNRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// MeasureService_ServiceDesc is the grpc.ServiceDesc for MeasureService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var MeasureService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "banyandb.measure.v1.MeasureService",
+	HandlerType: (*MeasureServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Query",
+			Handler:    _MeasureService_Query_Handler,
+		},
+		{
+			MethodName: "TopN",
+			Handler:    _MeasureService_TopN_Handler,
+		},
+	},
+	Streams: []grpc.StreamDesc{
+		{
+			StreamName:    "Write",
+			Handler:       _MeasureService_Write_Handler,
+			ServerStreams: true,
+			ClientStreams: true,
+		},
+	},
+	Metadata: "banyandb/measure/v1/rpc.proto",
+}
diff --git a/api/proto/banyandb/measure/v1/topn.pb.go b/api/proto/banyandb/measure/v1/topn.pb.go
new file mode 100644
index 0000000..b25a116
--- /dev/null
+++ b/api/proto/banyandb/measure/v1/topn.pb.go
@@ -0,0 +1,520 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.18.1
+// source: banyandb/measure/v1/topn.proto
+
+package v1
+
+import (
+	reflect "reflect"
+	sync "sync"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+
+	v1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/common/v1"
+	v11 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type AggregationFunction int32
+
+const (
+	AggregationFunction_AGGREGATION_FUNCTION_UNSPECIFIED AggregationFunction = 0
+	AggregationFunction_AGGREGATION_FUNCTION_MEAN        AggregationFunction = 1
+)
+
+// Enum value maps for AggregationFunction.
+var (
+	AggregationFunction_name = map[int32]string{
+		0: "AGGREGATION_FUNCTION_UNSPECIFIED",
+		1: "AGGREGATION_FUNCTION_MEAN",
+	}
+	AggregationFunction_value = map[string]int32{
+		"AGGREGATION_FUNCTION_UNSPECIFIED": 0,
+		"AGGREGATION_FUNCTION_MEAN":        1,
+	}
+)
+
+func (x AggregationFunction) Enum() *AggregationFunction {
+	p := new(AggregationFunction)
+	*p = x
+	return p
+}
+
+func (x AggregationFunction) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AggregationFunction) Descriptor() protoreflect.EnumDescriptor {
+	return file_banyandb_measure_v1_topn_proto_enumTypes[0].Descriptor()
+}
+
+func (AggregationFunction) Type() protoreflect.EnumType {
+	return &file_banyandb_measure_v1_topn_proto_enumTypes[0]
+}
+
+func (x AggregationFunction) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use AggregationFunction.Descriptor instead.
+func (AggregationFunction) EnumDescriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_topn_proto_rawDescGZIP(), []int{0}
+}
+
+//TopNList contains a series of topN items
+type TopNList struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// timestamp is in the timeunit of nanoseconds.
+	Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	// items contains top-n items in a list
+	Items []*TopNList_Item `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"`
+}
+
+func (x *TopNList) Reset() {
+	*x = TopNList{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_topn_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TopNList) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopNList) ProtoMessage() {}
+
+func (x *TopNList) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_topn_proto_msgTypes[0]
+	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 TopNList.ProtoReflect.Descriptor instead.
+func (*TopNList) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_topn_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TopNList) GetTimestamp() *timestamppb.Timestamp {
+	if x != nil {
+		return x.Timestamp
+	}
+	return nil
+}
+
+func (x *TopNList) GetItems() []*TopNList_Item {
+	if x != nil {
+		return x.Items
+	}
+	return nil
+}
+
+// TopNResponse is the response for a query to the Query module.
+type TopNResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// lists contain a series topN lists ranked by timestamp
+	// if agg_func in query request is specified, lists' size should be one.
+	Lists []*TopNList `protobuf:"bytes,1,rep,name=lists,proto3" json:"lists,omitempty"`
+}
+
+func (x *TopNResponse) Reset() {
+	*x = TopNResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_topn_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TopNResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopNResponse) ProtoMessage() {}
+
+func (x *TopNResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_topn_proto_msgTypes[1]
+	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 TopNResponse.ProtoReflect.Descriptor instead.
+func (*TopNResponse) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_topn_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *TopNResponse) GetLists() []*TopNList {
+	if x != nil {
+		return x.Lists
+	}
+	return nil
+}
+
+// TopNRequest is the request contract for query.
+type TopNRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// metadata is required
+	Metadata *v1.Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+	// time_range is a range query with begin/end time of entities in the timeunit of nanoseconds.
+	TimeRange *v11.TimeRange `protobuf:"bytes,2,opt,name=time_range,json=timeRange,proto3" json:"time_range,omitempty"`
+	// top_n set the how many items should be returned in each list.
+	TopN int32 `protobuf:"varint,3,opt,name=top_n,json=topN,proto3" json:"top_n,omitempty"`
+	// agg aggregates lists grouped by field names in the time_range
+	Agg AggregationFunction `protobuf:"varint,4,opt,name=agg,proto3,enum=banyandb.measure.v1.AggregationFunction" json:"agg,omitempty"`
+	// criteria select counters.
+	Conditions []*v11.Condition `protobuf:"bytes,5,rep,name=conditions,proto3" json:"conditions,omitempty"`
+}
+
+func (x *TopNRequest) Reset() {
+	*x = TopNRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_topn_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TopNRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopNRequest) ProtoMessage() {}
+
+func (x *TopNRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_topn_proto_msgTypes[2]
+	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 TopNRequest.ProtoReflect.Descriptor instead.
+func (*TopNRequest) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_topn_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *TopNRequest) GetMetadata() *v1.Metadata {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+func (x *TopNRequest) GetTimeRange() *v11.TimeRange {
+	if x != nil {
+		return x.TimeRange
+	}
+	return nil
+}
+
+func (x *TopNRequest) GetTopN() int32 {
+	if x != nil {
+		return x.TopN
+	}
+	return 0
+}
+
+func (x *TopNRequest) GetAgg() AggregationFunction {
+	if x != nil {
+		return x.Agg
+	}
+	return AggregationFunction_AGGREGATION_FUNCTION_UNSPECIFIED
+}
+
+func (x *TopNRequest) GetConditions() []*v11.Condition {
+	if x != nil {
+		return x.Conditions
+	}
+	return nil
+}
+
+type TopNList_Item struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name  string          `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Value *v11.FieldValue `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *TopNList_Item) Reset() {
+	*x = TopNList_Item{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_topn_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TopNList_Item) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopNList_Item) ProtoMessage() {}
+
+func (x *TopNList_Item) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_topn_proto_msgTypes[3]
+	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 TopNList_Item.ProtoReflect.Descriptor instead.
+func (*TopNList_Item) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_topn_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *TopNList_Item) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *TopNList_Item) GetValue() *v11.FieldValue {
+	if x != nil {
+		return x.Value
+	}
+	return nil
+}
+
+var File_banyandb_measure_v1_topn_proto protoreflect.FileDescriptor
+
+var file_banyandb_measure_v1_topn_proto_rawDesc = []byte{
+	0x0a, 0x1e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x65, 0x61, 0x73, 0x75,
+	0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x70, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x12, 0x13, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75,
+	0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
+	0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+	0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+	0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcf, 0x01, 0x0a, 0x08, 0x54, 0x6f, 0x70, 0x4e, 0x4c,
+	0x69, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+	0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x38, 0x0a,
+	0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62,
+	0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e,
+	0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4e, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x49, 0x74, 0x65, 0x6d,
+	0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x4f, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12,
+	0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f,
+	0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x43, 0x0a, 0x0c, 0x54, 0x6f, 0x70, 0x4e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x05, 0x6c, 0x69, 0x73, 0x74,
+	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
+	0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f,
+	0x70, 0x4e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x22, 0x93, 0x02,
+	0x0a, 0x0b, 0x54, 0x6f, 0x70, 0x4e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a,
+	0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+	0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d,
+	0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3b, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f,
+	0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61,
+	0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
+	0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x52,
+	0x61, 0x6e, 0x67, 0x65, 0x12, 0x13, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x5f, 0x6e, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x6f, 0x70, 0x4e, 0x12, 0x3a, 0x0a, 0x03, 0x61, 0x67, 0x67,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x67,
+	0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+	0x52, 0x03, 0x61, 0x67, 0x67, 0x12, 0x3c, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79,
+	0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f,
+	0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2a, 0x5a, 0x0a, 0x13, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x20, 0x41, 0x47,
+	0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x55, 0x4e, 0x43, 0x54, 0x49,
+	0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
+	0x12, 0x1d, 0x0a, 0x19, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f,
+	0x46, 0x55, 0x4e, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x4e, 0x10, 0x01, 0x42,
+	0x70, 0x0a, 0x29, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x73, 0x6b,
+	0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x5a, 0x43, 0x67, 0x69,
+	0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f,
+	0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61, 0x6e, 0x79, 0x61,
+	0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x61,
+	0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2f, 0x76,
+	0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_banyandb_measure_v1_topn_proto_rawDescOnce sync.Once
+	file_banyandb_measure_v1_topn_proto_rawDescData = file_banyandb_measure_v1_topn_proto_rawDesc
+)
+
+func file_banyandb_measure_v1_topn_proto_rawDescGZIP() []byte {
+	file_banyandb_measure_v1_topn_proto_rawDescOnce.Do(func() {
+		file_banyandb_measure_v1_topn_proto_rawDescData = protoimpl.X.CompressGZIP(file_banyandb_measure_v1_topn_proto_rawDescData)
+	})
+	return file_banyandb_measure_v1_topn_proto_rawDescData
+}
+
+var file_banyandb_measure_v1_topn_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_banyandb_measure_v1_topn_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_banyandb_measure_v1_topn_proto_goTypes = []interface{}{
+	(AggregationFunction)(0),      // 0: banyandb.measure.v1.AggregationFunction
+	(*TopNList)(nil),              // 1: banyandb.measure.v1.TopNList
+	(*TopNResponse)(nil),          // 2: banyandb.measure.v1.TopNResponse
+	(*TopNRequest)(nil),           // 3: banyandb.measure.v1.TopNRequest
+	(*TopNList_Item)(nil),         // 4: banyandb.measure.v1.TopNList.Item
+	(*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp
+	(*v1.Metadata)(nil),           // 6: banyandb.common.v1.Metadata
+	(*v11.TimeRange)(nil),         // 7: banyandb.model.v1.TimeRange
+	(*v11.Condition)(nil),         // 8: banyandb.model.v1.Condition
+	(*v11.FieldValue)(nil),        // 9: banyandb.model.v1.FieldValue
+}
+var file_banyandb_measure_v1_topn_proto_depIdxs = []int32{
+	5, // 0: banyandb.measure.v1.TopNList.timestamp:type_name -> google.protobuf.Timestamp
+	4, // 1: banyandb.measure.v1.TopNList.items:type_name -> banyandb.measure.v1.TopNList.Item
+	1, // 2: banyandb.measure.v1.TopNResponse.lists:type_name -> banyandb.measure.v1.TopNList
+	6, // 3: banyandb.measure.v1.TopNRequest.metadata:type_name -> banyandb.common.v1.Metadata
+	7, // 4: banyandb.measure.v1.TopNRequest.time_range:type_name -> banyandb.model.v1.TimeRange
+	0, // 5: banyandb.measure.v1.TopNRequest.agg:type_name -> banyandb.measure.v1.AggregationFunction
+	8, // 6: banyandb.measure.v1.TopNRequest.conditions:type_name -> banyandb.model.v1.Condition
+	9, // 7: banyandb.measure.v1.TopNList.Item.value:type_name -> banyandb.model.v1.FieldValue
+	8, // [8:8] is the sub-list for method output_type
+	8, // [8:8] is the sub-list for method input_type
+	8, // [8:8] is the sub-list for extension type_name
+	8, // [8:8] is the sub-list for extension extendee
+	0, // [0:8] is the sub-list for field type_name
+}
+
+func init() { file_banyandb_measure_v1_topn_proto_init() }
+func file_banyandb_measure_v1_topn_proto_init() {
+	if File_banyandb_measure_v1_topn_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_banyandb_measure_v1_topn_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TopNList); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_topn_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TopNResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_topn_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TopNRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_topn_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TopNList_Item); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_banyandb_measure_v1_topn_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   4,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_banyandb_measure_v1_topn_proto_goTypes,
+		DependencyIndexes: file_banyandb_measure_v1_topn_proto_depIdxs,
+		EnumInfos:         file_banyandb_measure_v1_topn_proto_enumTypes,
+		MessageInfos:      file_banyandb_measure_v1_topn_proto_msgTypes,
+	}.Build()
+	File_banyandb_measure_v1_topn_proto = out.File
+	file_banyandb_measure_v1_topn_proto_rawDesc = nil
+	file_banyandb_measure_v1_topn_proto_goTypes = nil
+	file_banyandb_measure_v1_topn_proto_depIdxs = nil
+}
diff --git a/api/proto/banyandb/measure/v1/topn.proto b/api/proto/banyandb/measure/v1/topn.proto
new file mode 100644
index 0000000..bde07b6
--- /dev/null
+++ b/api/proto/banyandb/measure/v1/topn.proto
@@ -0,0 +1,66 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+syntax = "proto3";
+
+option java_package = "org.apache.skywalking.banyandb.measure.v1";
+option go_package = "github.com/apache/skywalking-banyandb/api/proto/banyandb/measure/v1";
+
+package banyandb.measure.v1;
+
+import "google/protobuf/timestamp.proto";
+import "banyandb/common/v1/common.proto";
+import "banyandb/model/v1/common.proto";
+import "banyandb/model/v1/query.proto";
+
+//TopNList contains a series of topN items
+message TopNList {
+    // timestamp is in the timeunit of nanoseconds.
+    google.protobuf.Timestamp timestamp = 1;
+    message Item {
+        string name = 1;
+        model.v1.FieldValue value = 2;
+    }
+    // items contains top-n items in a list
+    repeated Item items = 2;
+}
+
+// TopNResponse is the response for a query to the Query module.
+message TopNResponse {
+    // lists contain a series topN lists ranked by timestamp
+    // if agg_func in query request is specified, lists' size should be one.
+    repeated TopNList lists = 1;
+}
+
+enum AggregationFunction {
+    AGGREGATION_FUNCTION_UNSPECIFIED = 0;
+    AGGREGATION_FUNCTION_MEAN = 1;
+}
+
+// TopNRequest is the request contract for query.
+message TopNRequest {
+    // metadata is required
+    common.v1.Metadata metadata = 1;
+    // time_range is a range query with begin/end time of entities in the timeunit of nanoseconds.
+    model.v1.TimeRange time_range = 2;
+    // top_n set the how many items should be returned in each list.
+    int32 top_n = 3;
+    // agg aggregates lists grouped by field names in the time_range
+    AggregationFunction agg = 4;
+    // criteria select counters.
+    repeated model.v1.Condition conditions = 5;
+}
diff --git a/api/proto/banyandb/measure/v1/write.pb.go b/api/proto/banyandb/measure/v1/write.pb.go
new file mode 100644
index 0000000..bc6f682
--- /dev/null
+++ b/api/proto/banyandb/measure/v1/write.pb.go
@@ -0,0 +1,350 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.18.1
+// source: banyandb/measure/v1/write.proto
+
+package v1
+
+import (
+	reflect "reflect"
+	sync "sync"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+
+	v11 "github.com/apache/skywalking-banyandb/api/proto/banyandb/common/v1"
+	v1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+//DataPointValue is the data point for writing. It only contains values.
+type DataPointValue struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// timestamp is in the timeunit of nanoseconds.
+	Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	// the order of tag_families' items match the measure schema
+	TagFamilies []*v1.TagFamilyForWrite `protobuf:"bytes,2,rep,name=tag_families,json=tagFamilies,proto3" json:"tag_families,omitempty"`
+	// the order of fields match the measure schema
+	Fields []*v1.FieldValue `protobuf:"bytes,3,rep,name=fields,proto3" json:"fields,omitempty"`
+}
+
+func (x *DataPointValue) Reset() {
+	*x = DataPointValue{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_write_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DataPointValue) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DataPointValue) ProtoMessage() {}
+
+func (x *DataPointValue) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_write_proto_msgTypes[0]
+	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 DataPointValue.ProtoReflect.Descriptor instead.
+func (*DataPointValue) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_write_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DataPointValue) GetTimestamp() *timestamppb.Timestamp {
+	if x != nil {
+		return x.Timestamp
+	}
+	return nil
+}
+
+func (x *DataPointValue) GetTagFamilies() []*v1.TagFamilyForWrite {
+	if x != nil {
+		return x.TagFamilies
+	}
+	return nil
+}
+
+func (x *DataPointValue) GetFields() []*v1.FieldValue {
+	if x != nil {
+		return x.Fields
+	}
+	return nil
+}
+
+// WriteRequest is the request contract for write
+type WriteRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// the metadata is required.
+	Metadata *v11.Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
+	// the data_point is required.
+	DataPoint *DataPointValue `protobuf:"bytes,2,opt,name=data_point,json=dataPoint,proto3" json:"data_point,omitempty"`
+}
+
+func (x *WriteRequest) Reset() {
+	*x = WriteRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_write_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *WriteRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WriteRequest) ProtoMessage() {}
+
+func (x *WriteRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_write_proto_msgTypes[1]
+	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 WriteRequest.ProtoReflect.Descriptor instead.
+func (*WriteRequest) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_write_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *WriteRequest) GetMetadata() *v11.Metadata {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+func (x *WriteRequest) GetDataPoint() *DataPointValue {
+	if x != nil {
+		return x.DataPoint
+	}
+	return nil
+}
+
+// WriteResponse is the response contract for write
+type WriteResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *WriteResponse) Reset() {
+	*x = WriteResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_measure_v1_write_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *WriteResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WriteResponse) ProtoMessage() {}
+
+func (x *WriteResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_measure_v1_write_proto_msgTypes[2]
+	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 WriteResponse.ProtoReflect.Descriptor instead.
+func (*WriteResponse) Descriptor() ([]byte, []int) {
+	return file_banyandb_measure_v1_write_proto_rawDescGZIP(), []int{2}
+}
+
+var File_banyandb_measure_v1_write_proto protoreflect.FileDescriptor
+
+var file_banyandb_measure_v1_write_proto_rawDesc = []byte{
+	0x0a, 0x1f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x65, 0x61, 0x73, 0x75,
+	0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x13, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73,
+	0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+	0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64,
+	0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
+	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
+	0x64, 0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
+	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xca, 0x01, 0x0a, 0x0e, 0x44, 0x61, 0x74,
+	0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74,
+	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x47, 0x0a, 0x0c, 0x74, 0x61, 0x67, 0x5f, 0x66, 0x61, 0x6d,
+	0x69, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x62, 0x61,
+	0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
+	0x54, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x46, 0x6f, 0x72, 0x57, 0x72, 0x69, 0x74,
+	0x65, 0x52, 0x0b, 0x74, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x35,
+	0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d,
+	0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e,
+	0x76, 0x31, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x66,
+	0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x0c, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+	0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61,
+	0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65,
+	0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+	0x12, 0x42, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e,
+	0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x50,
+	0x6f, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x50,
+	0x6f, 0x69, 0x6e, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x70, 0x0a, 0x29, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61,
+	0x63, 0x68, 0x65, 0x2e, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62,
+	0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x2e,
+	0x76, 0x31, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61,
+	0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67,
+	0x2d, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x65, 0x61,
+	0x73, 0x75, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_banyandb_measure_v1_write_proto_rawDescOnce sync.Once
+	file_banyandb_measure_v1_write_proto_rawDescData = file_banyandb_measure_v1_write_proto_rawDesc
+)
+
+func file_banyandb_measure_v1_write_proto_rawDescGZIP() []byte {
+	file_banyandb_measure_v1_write_proto_rawDescOnce.Do(func() {
+		file_banyandb_measure_v1_write_proto_rawDescData = protoimpl.X.CompressGZIP(file_banyandb_measure_v1_write_proto_rawDescData)
+	})
+	return file_banyandb_measure_v1_write_proto_rawDescData
+}
+
+var file_banyandb_measure_v1_write_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_banyandb_measure_v1_write_proto_goTypes = []interface{}{
+	(*DataPointValue)(nil),        // 0: banyandb.measure.v1.DataPointValue
+	(*WriteRequest)(nil),          // 1: banyandb.measure.v1.WriteRequest
+	(*WriteResponse)(nil),         // 2: banyandb.measure.v1.WriteResponse
+	(*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp
+	(*v1.TagFamilyForWrite)(nil),  // 4: banyandb.model.v1.TagFamilyForWrite
+	(*v1.FieldValue)(nil),         // 5: banyandb.model.v1.FieldValue
+	(*v11.Metadata)(nil),          // 6: banyandb.common.v1.Metadata
+}
+var file_banyandb_measure_v1_write_proto_depIdxs = []int32{
+	3, // 0: banyandb.measure.v1.DataPointValue.timestamp:type_name -> google.protobuf.Timestamp
+	4, // 1: banyandb.measure.v1.DataPointValue.tag_families:type_name -> banyandb.model.v1.TagFamilyForWrite
+	5, // 2: banyandb.measure.v1.DataPointValue.fields:type_name -> banyandb.model.v1.FieldValue
+	6, // 3: banyandb.measure.v1.WriteRequest.metadata:type_name -> banyandb.common.v1.Metadata
+	0, // 4: banyandb.measure.v1.WriteRequest.data_point:type_name -> banyandb.measure.v1.DataPointValue
+	5, // [5:5] is the sub-list for method output_type
+	5, // [5:5] is the sub-list for method input_type
+	5, // [5:5] is the sub-list for extension type_name
+	5, // [5:5] is the sub-list for extension extendee
+	0, // [0:5] is the sub-list for field type_name
+}
+
+func init() { file_banyandb_measure_v1_write_proto_init() }
+func file_banyandb_measure_v1_write_proto_init() {
+	if File_banyandb_measure_v1_write_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_banyandb_measure_v1_write_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DataPointValue); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_write_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*WriteRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_measure_v1_write_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*WriteResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_banyandb_measure_v1_write_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   3,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_banyandb_measure_v1_write_proto_goTypes,
+		DependencyIndexes: file_banyandb_measure_v1_write_proto_depIdxs,
+		MessageInfos:      file_banyandb_measure_v1_write_proto_msgTypes,
+	}.Build()
+	File_banyandb_measure_v1_write_proto = out.File
+	file_banyandb_measure_v1_write_proto_rawDesc = nil
+	file_banyandb_measure_v1_write_proto_goTypes = nil
+	file_banyandb_measure_v1_write_proto_depIdxs = nil
+}
diff --git a/api/proto/banyandb/measure/v1/write.proto b/api/proto/banyandb/measure/v1/write.proto
new file mode 100644
index 0000000..11ab62a
--- /dev/null
+++ b/api/proto/banyandb/measure/v1/write.proto
@@ -0,0 +1,48 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+syntax = "proto3";
+
+option java_package = "org.apache.skywalking.banyandb.measure.v1";
+option go_package = "github.com/apache/skywalking-banyandb/api/proto/banyandb/measure/v1";
+
+package banyandb.measure.v1;
+
+import "google/protobuf/timestamp.proto";
+import "banyandb/common/v1/common.proto";
+import "banyandb/model/v1/common.proto";
+
+//DataPointValue is the data point for writing. It only contains values.
+message DataPointValue {
+  // timestamp is in the timeunit of nanoseconds.
+  google.protobuf.Timestamp timestamp = 1;
+  // the order of tag_families' items match the measure schema
+  repeated model.v1.TagFamilyForWrite tag_families = 2;
+  // the order of fields match the measure schema
+  repeated model.v1.FieldValue fields = 3;
+}
+
+// WriteRequest is the request contract for write
+message WriteRequest {
+  // the metadata is required.
+  common.v1.Metadata metadata = 1;
+  // the data_point is required.
+  DataPointValue data_point = 2;
+}
+
+// WriteResponse is the response contract for write
+message WriteResponse {}
diff --git a/api/proto/banyandb/model/v1/common.pb.go b/api/proto/banyandb/model/v1/common.pb.go
index 22e60c4..99be7fa 100644
--- a/api/proto/banyandb/model/v1/common.pb.go
+++ b/api/proto/banyandb/model/v1/common.pb.go
@@ -410,6 +410,114 @@ func (x *TagFamilyForWrite) GetTags() []*TagValue {
 	return nil
 }
 
+type FieldValue struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Types that are assignable to Value:
+	//	*FieldValue_Null
+	//	*FieldValue_Str
+	//	*FieldValue_Int
+	//	*FieldValue_BinaryData
+	Value isFieldValue_Value `protobuf_oneof:"value"`
+}
+
+func (x *FieldValue) Reset() {
+	*x = FieldValue{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_model_v1_common_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FieldValue) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FieldValue) ProtoMessage() {}
+
+func (x *FieldValue) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_model_v1_common_proto_msgTypes[6]
+	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 FieldValue.ProtoReflect.Descriptor instead.
+func (*FieldValue) Descriptor() ([]byte, []int) {
+	return file_banyandb_model_v1_common_proto_rawDescGZIP(), []int{6}
+}
+
+func (m *FieldValue) GetValue() isFieldValue_Value {
+	if m != nil {
+		return m.Value
+	}
+	return nil
+}
+
+func (x *FieldValue) GetNull() structpb.NullValue {
+	if x, ok := x.GetValue().(*FieldValue_Null); ok {
+		return x.Null
+	}
+	return structpb.NullValue(0)
+}
+
+func (x *FieldValue) GetStr() *Str {
+	if x, ok := x.GetValue().(*FieldValue_Str); ok {
+		return x.Str
+	}
+	return nil
+}
+
+func (x *FieldValue) GetInt() *Int {
+	if x, ok := x.GetValue().(*FieldValue_Int); ok {
+		return x.Int
+	}
+	return nil
+}
+
+func (x *FieldValue) GetBinaryData() []byte {
+	if x, ok := x.GetValue().(*FieldValue_BinaryData); ok {
+		return x.BinaryData
+	}
+	return nil
+}
+
+type isFieldValue_Value interface {
+	isFieldValue_Value()
+}
+
+type FieldValue_Null struct {
+	Null structpb.NullValue `protobuf:"varint,1,opt,name=null,proto3,enum=google.protobuf.NullValue,oneof"`
+}
+
+type FieldValue_Str struct {
+	Str *Str `protobuf:"bytes,2,opt,name=str,proto3,oneof"`
+}
+
+type FieldValue_Int struct {
+	Int *Int `protobuf:"bytes,3,opt,name=int,proto3,oneof"`
+}
+
+type FieldValue_BinaryData struct {
+	BinaryData []byte `protobuf:"bytes,4,opt,name=binary_data,json=binaryData,proto3,oneof"`
+}
+
+func (*FieldValue_Null) isFieldValue_Value() {}
+
+func (*FieldValue_Str) isFieldValue_Value() {}
+
+func (*FieldValue_Int) isFieldValue_Value() {}
+
+func (*FieldValue_BinaryData) isFieldValue_Value() {}
+
 var File_banyandb_model_v1_common_proto protoreflect.FileDescriptor
 
 var file_banyandb_model_v1_common_proto_rawDesc = []byte{
@@ -450,14 +558,26 @@ var file_banyandb_model_v1_common_proto_rawDesc = []byte{
 	0x2f, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
 	0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76,
 	0x31, 0x2e, 0x54, 0x61, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73,
-	0x42, 0x6c, 0x0a, 0x27, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x73,
-	0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
-	0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x5a, 0x41, 0x67, 0x69, 0x74,
-	0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x73,
-	0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
-	0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x61, 0x6e,
-	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x62, 0x06,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x22, 0xc2, 0x01, 0x0a, 0x0a, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12,
+	0x30, 0x0a, 0x04, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+	0x4e, 0x75, 0x6c, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x75, 0x6c,
+	0x6c, 0x12, 0x2a, 0x0a, 0x03, 0x73, 0x74, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
+	0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e,
+	0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x48, 0x00, 0x52, 0x03, 0x73, 0x74, 0x72, 0x12, 0x2a, 0x0a,
+	0x03, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x61, 0x6e,
+	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x49,
+	0x6e, 0x74, 0x48, 0x00, 0x52, 0x03, 0x69, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0b, 0x62, 0x69, 0x6e,
+	0x61, 0x72, 0x79, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00,
+	0x52, 0x0a, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x42, 0x07, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x6c, 0x0a, 0x27, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61,
+	0x63, 0x68, 0x65, 0x2e, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62,
+	0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31,
+	0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61,
+	0x63, 0x68, 0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62,
+	0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c,
+	0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -472,7 +592,7 @@ func file_banyandb_model_v1_common_proto_rawDescGZIP() []byte {
 	return file_banyandb_model_v1_common_proto_rawDescData
 }
 
-var file_banyandb_model_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
+var file_banyandb_model_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
 var file_banyandb_model_v1_common_proto_goTypes = []interface{}{
 	(*Str)(nil),               // 0: banyandb.model.v1.Str
 	(*Int)(nil),               // 1: banyandb.model.v1.Int
@@ -480,20 +600,24 @@ var file_banyandb_model_v1_common_proto_goTypes = []interface{}{
 	(*IntArray)(nil),          // 3: banyandb.model.v1.IntArray
 	(*TagValue)(nil),          // 4: banyandb.model.v1.TagValue
 	(*TagFamilyForWrite)(nil), // 5: banyandb.model.v1.TagFamilyForWrite
-	(structpb.NullValue)(0),   // 6: google.protobuf.NullValue
+	(*FieldValue)(nil),        // 6: banyandb.model.v1.FieldValue
+	(structpb.NullValue)(0),   // 7: google.protobuf.NullValue
 }
 var file_banyandb_model_v1_common_proto_depIdxs = []int32{
-	6, // 0: banyandb.model.v1.TagValue.null:type_name -> google.protobuf.NullValue
+	7, // 0: banyandb.model.v1.TagValue.null:type_name -> google.protobuf.NullValue
 	0, // 1: banyandb.model.v1.TagValue.str:type_name -> banyandb.model.v1.Str
 	2, // 2: banyandb.model.v1.TagValue.str_array:type_name -> banyandb.model.v1.StrArray
 	1, // 3: banyandb.model.v1.TagValue.int:type_name -> banyandb.model.v1.Int
 	3, // 4: banyandb.model.v1.TagValue.int_array:type_name -> banyandb.model.v1.IntArray
 	4, // 5: banyandb.model.v1.TagFamilyForWrite.tags:type_name -> banyandb.model.v1.TagValue
-	6, // [6:6] is the sub-list for method output_type
-	6, // [6:6] is the sub-list for method input_type
-	6, // [6:6] is the sub-list for extension type_name
-	6, // [6:6] is the sub-list for extension extendee
-	0, // [0:6] is the sub-list for field type_name
+	7, // 6: banyandb.model.v1.FieldValue.null:type_name -> google.protobuf.NullValue
+	0, // 7: banyandb.model.v1.FieldValue.str:type_name -> banyandb.model.v1.Str
+	1, // 8: banyandb.model.v1.FieldValue.int:type_name -> banyandb.model.v1.Int
+	9, // [9:9] is the sub-list for method output_type
+	9, // [9:9] is the sub-list for method input_type
+	9, // [9:9] is the sub-list for extension type_name
+	9, // [9:9] is the sub-list for extension extendee
+	0, // [0:9] is the sub-list for field type_name
 }
 
 func init() { file_banyandb_model_v1_common_proto_init() }
@@ -574,6 +698,18 @@ func file_banyandb_model_v1_common_proto_init() {
 				return nil
 			}
 		}
+		file_banyandb_model_v1_common_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FieldValue); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	file_banyandb_model_v1_common_proto_msgTypes[4].OneofWrappers = []interface{}{
 		(*TagValue_Null)(nil),
@@ -583,13 +719,19 @@ func file_banyandb_model_v1_common_proto_init() {
 		(*TagValue_IntArray)(nil),
 		(*TagValue_BinaryData)(nil),
 	}
+	file_banyandb_model_v1_common_proto_msgTypes[6].OneofWrappers = []interface{}{
+		(*FieldValue_Null)(nil),
+		(*FieldValue_Str)(nil),
+		(*FieldValue_Int)(nil),
+		(*FieldValue_BinaryData)(nil),
+	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_banyandb_model_v1_common_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   6,
+			NumMessages:   7,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/api/proto/banyandb/model/v1/common.proto b/api/proto/banyandb/model/v1/common.proto
index 2314215..e8dc2e2 100644
--- a/api/proto/banyandb/model/v1/common.proto
+++ b/api/proto/banyandb/model/v1/common.proto
@@ -54,3 +54,12 @@ message TagValue {
 message TagFamilyForWrite {
     repeated TagValue tags = 1;
 }
+
+message FieldValue {
+    oneof value {
+        google.protobuf.NullValue null = 1;
+        model.v1.Str str = 2;
+        model.v1.Int int = 3;
+        bytes binary_data = 4;
+    }
+}
diff --git a/api/proto/banyandb/model/v1/query.pb.go b/api/proto/banyandb/model/v1/query.pb.go
index 226845f..a11a211 100644
--- a/api/proto/banyandb/model/v1/query.pb.go
+++ b/api/proto/banyandb/model/v1/query.pb.go
@@ -39,6 +39,55 @@ const (
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
+type Sort int32
+
+const (
+	Sort_SORT_UNSPECIFIED Sort = 0
+	Sort_SORT_DESC        Sort = 1
+	Sort_SORT_ASC         Sort = 2
+)
+
+// Enum value maps for Sort.
+var (
+	Sort_name = map[int32]string{
+		0: "SORT_UNSPECIFIED",
+		1: "SORT_DESC",
+		2: "SORT_ASC",
+	}
+	Sort_value = map[string]int32{
+		"SORT_UNSPECIFIED": 0,
+		"SORT_DESC":        1,
+		"SORT_ASC":         2,
+	}
+)
+
+func (x Sort) Enum() *Sort {
+	p := new(Sort)
+	*p = x
+	return p
+}
+
+func (x Sort) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Sort) Descriptor() protoreflect.EnumDescriptor {
+	return file_banyandb_model_v1_query_proto_enumTypes[0].Descriptor()
+}
+
+func (Sort) Type() protoreflect.EnumType {
+	return &file_banyandb_model_v1_query_proto_enumTypes[0]
+}
+
+func (x Sort) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Sort.Descriptor instead.
+func (Sort) EnumDescriptor() ([]byte, []int) {
+	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{0}
+}
+
 // BinaryOp specifies the operation imposed to the given query condition
 // For EQ, NE, LT, GT, LE and GE, only one operand should be given, i.e. one-to-one relationship.
 // HAVING and NOT_HAVING allow multi-value to be the operand such as array/vector, i.e. one-to-many relationship.
@@ -55,20 +104,24 @@ const (
 	Condition_BINARY_OP_GE          Condition_BinaryOp = 6
 	Condition_BINARY_OP_HAVING      Condition_BinaryOp = 7
 	Condition_BINARY_OP_NOT_HAVING  Condition_BinaryOp = 8
+	Condition_BINARY_OP_IN          Condition_BinaryOp = 9
+	Condition_BINARY_OP_NOT_IN      Condition_BinaryOp = 10
 )
 
 // Enum value maps for Condition_BinaryOp.
 var (
 	Condition_BinaryOp_name = map[int32]string{
-		0: "BINARY_OP_UNSPECIFIED",
-		1: "BINARY_OP_EQ",
-		2: "BINARY_OP_NE",
-		3: "BINARY_OP_LT",
-		4: "BINARY_OP_GT",
-		5: "BINARY_OP_LE",
-		6: "BINARY_OP_GE",
-		7: "BINARY_OP_HAVING",
-		8: "BINARY_OP_NOT_HAVING",
+		0:  "BINARY_OP_UNSPECIFIED",
+		1:  "BINARY_OP_EQ",
+		2:  "BINARY_OP_NE",
+		3:  "BINARY_OP_LT",
+		4:  "BINARY_OP_GT",
+		5:  "BINARY_OP_LE",
+		6:  "BINARY_OP_GE",
+		7:  "BINARY_OP_HAVING",
+		8:  "BINARY_OP_NOT_HAVING",
+		9:  "BINARY_OP_IN",
+		10: "BINARY_OP_NOT_IN",
 	}
 	Condition_BinaryOp_value = map[string]int32{
 		"BINARY_OP_UNSPECIFIED": 0,
@@ -80,6 +133,8 @@ var (
 		"BINARY_OP_GE":          6,
 		"BINARY_OP_HAVING":      7,
 		"BINARY_OP_NOT_HAVING":  8,
+		"BINARY_OP_IN":          9,
+		"BINARY_OP_NOT_IN":      10,
 	}
 )
 
@@ -94,11 +149,11 @@ func (x Condition_BinaryOp) String() string {
 }
 
 func (Condition_BinaryOp) Descriptor() protoreflect.EnumDescriptor {
-	return file_banyandb_model_v1_query_proto_enumTypes[0].Descriptor()
+	return file_banyandb_model_v1_query_proto_enumTypes[1].Descriptor()
 }
 
 func (Condition_BinaryOp) Type() protoreflect.EnumType {
-	return &file_banyandb_model_v1_query_proto_enumTypes[0]
+	return &file_banyandb_model_v1_query_proto_enumTypes[1]
 }
 
 func (x Condition_BinaryOp) Number() protoreflect.EnumNumber {
@@ -110,55 +165,6 @@ func (Condition_BinaryOp) EnumDescriptor() ([]byte, []int) {
 	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{2, 0}
 }
 
-type QueryOrder_Sort int32
-
-const (
-	QueryOrder_SORT_UNSPECIFIED QueryOrder_Sort = 0
-	QueryOrder_SORT_DESC        QueryOrder_Sort = 1
-	QueryOrder_SORT_ASC         QueryOrder_Sort = 2
-)
-
-// Enum value maps for QueryOrder_Sort.
-var (
-	QueryOrder_Sort_name = map[int32]string{
-		0: "SORT_UNSPECIFIED",
-		1: "SORT_DESC",
-		2: "SORT_ASC",
-	}
-	QueryOrder_Sort_value = map[string]int32{
-		"SORT_UNSPECIFIED": 0,
-		"SORT_DESC":        1,
-		"SORT_ASC":         2,
-	}
-)
-
-func (x QueryOrder_Sort) Enum() *QueryOrder_Sort {
-	p := new(QueryOrder_Sort)
-	*p = x
-	return p
-}
-
-func (x QueryOrder_Sort) String() string {
-	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (QueryOrder_Sort) Descriptor() protoreflect.EnumDescriptor {
-	return file_banyandb_model_v1_query_proto_enumTypes[1].Descriptor()
-}
-
-func (QueryOrder_Sort) Type() protoreflect.EnumType {
-	return &file_banyandb_model_v1_query_proto_enumTypes[1]
-}
-
-func (x QueryOrder_Sort) Number() protoreflect.EnumNumber {
-	return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Use QueryOrder_Sort.Descriptor instead.
-func (QueryOrder_Sort) EnumDescriptor() ([]byte, []int) {
-	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{3, 0}
-}
-
 // Pair is the building block of a record which is equivalent to a key-value pair.
 // In the context of Trace, it could be metadata of a trace such as service_name, service_instance, etc.
 // Besides, other tags are organized in key-value pair in the underlying storage layer.
@@ -339,6 +345,62 @@ func (x *Condition) GetValue() *TagValue {
 	return nil
 }
 
+// tag_families are indexed.
+type Criteria struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TagFamilyName string       `protobuf:"bytes,1,opt,name=tag_family_name,json=tagFamilyName,proto3" json:"tag_family_name,omitempty"`
+	Conditions    []*Condition `protobuf:"bytes,2,rep,name=conditions,proto3" json:"conditions,omitempty"`
+}
+
+func (x *Criteria) Reset() {
+	*x = Criteria{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_banyandb_model_v1_query_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Criteria) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Criteria) ProtoMessage() {}
+
+func (x *Criteria) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_model_v1_query_proto_msgTypes[3]
+	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 Criteria.ProtoReflect.Descriptor instead.
+func (*Criteria) Descriptor() ([]byte, []int) {
+	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *Criteria) GetTagFamilyName() string {
+	if x != nil {
+		return x.TagFamilyName
+	}
+	return ""
+}
+
+func (x *Criteria) GetConditions() []*Condition {
+	if x != nil {
+		return x.Conditions
+	}
+	return nil
+}
+
 // QueryOrder means a Sort operation to be done for a given index rule.
 // The index_rule_name refers to the name of a index rule bound to the subject.
 type QueryOrder struct {
@@ -346,14 +408,14 @@ type QueryOrder struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	IndexRuleName string          `protobuf:"bytes,1,opt,name=index_rule_name,json=indexRuleName,proto3" json:"index_rule_name,omitempty"`
-	Sort          QueryOrder_Sort `protobuf:"varint,2,opt,name=sort,proto3,enum=banyandb.model.v1.QueryOrder_Sort" json:"sort,omitempty"`
+	IndexRuleName string `protobuf:"bytes,1,opt,name=index_rule_name,json=indexRuleName,proto3" json:"index_rule_name,omitempty"`
+	Sort          Sort   `protobuf:"varint,2,opt,name=sort,proto3,enum=banyandb.model.v1.Sort" json:"sort,omitempty"`
 }
 
 func (x *QueryOrder) Reset() {
 	*x = QueryOrder{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_model_v1_query_proto_msgTypes[3]
+		mi := &file_banyandb_model_v1_query_proto_msgTypes[4]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -366,7 +428,7 @@ func (x *QueryOrder) String() string {
 func (*QueryOrder) ProtoMessage() {}
 
 func (x *QueryOrder) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_model_v1_query_proto_msgTypes[3]
+	mi := &file_banyandb_model_v1_query_proto_msgTypes[4]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -379,7 +441,7 @@ func (x *QueryOrder) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use QueryOrder.ProtoReflect.Descriptor instead.
 func (*QueryOrder) Descriptor() ([]byte, []int) {
-	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{3}
+	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *QueryOrder) GetIndexRuleName() string {
@@ -389,40 +451,39 @@ func (x *QueryOrder) GetIndexRuleName() string {
 	return ""
 }
 
-func (x *QueryOrder) GetSort() QueryOrder_Sort {
+func (x *QueryOrder) GetSort() Sort {
 	if x != nil {
 		return x.Sort
 	}
-	return QueryOrder_SORT_UNSPECIFIED
+	return Sort_SORT_UNSPECIFIED
 }
 
-// Projection is used to select the names of keys to be returned.
-type Projection struct {
+// TagProjection is used to select the names of keys to be returned.
+type TagProjection struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	// The key_name refers to the key(s) of Pair(s).
-	TagFamilies []*Projection_TagFamily `protobuf:"bytes,1,rep,name=tag_families,json=tagFamilies,proto3" json:"tag_families,omitempty"`
+	TagFamilies []*TagProjection_TagFamily `protobuf:"bytes,1,rep,name=tag_families,json=tagFamilies,proto3" json:"tag_families,omitempty"`
 }
 
-func (x *Projection) Reset() {
-	*x = Projection{}
+func (x *TagProjection) Reset() {
+	*x = TagProjection{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_model_v1_query_proto_msgTypes[4]
+		mi := &file_banyandb_model_v1_query_proto_msgTypes[5]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
 }
 
-func (x *Projection) String() string {
+func (x *TagProjection) String() string {
 	return protoimpl.X.MessageStringOf(x)
 }
 
-func (*Projection) ProtoMessage() {}
+func (*TagProjection) ProtoMessage() {}
 
-func (x *Projection) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_model_v1_query_proto_msgTypes[4]
+func (x *TagProjection) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_model_v1_query_proto_msgTypes[5]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -433,12 +494,12 @@ func (x *Projection) ProtoReflect() protoreflect.Message {
 	return mi.MessageOf(x)
 }
 
-// Deprecated: Use Projection.ProtoReflect.Descriptor instead.
-func (*Projection) Descriptor() ([]byte, []int) {
-	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{4}
+// Deprecated: Use TagProjection.ProtoReflect.Descriptor instead.
+func (*TagProjection) Descriptor() ([]byte, []int) {
+	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{5}
 }
 
-func (x *Projection) GetTagFamilies() []*Projection_TagFamily {
+func (x *TagProjection) GetTagFamilies() []*TagProjection_TagFamily {
 	if x != nil {
 		return x.TagFamilies
 	}
@@ -459,7 +520,7 @@ type TimeRange struct {
 func (x *TimeRange) Reset() {
 	*x = TimeRange{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_model_v1_query_proto_msgTypes[5]
+		mi := &file_banyandb_model_v1_query_proto_msgTypes[6]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -472,7 +533,7 @@ func (x *TimeRange) String() string {
 func (*TimeRange) ProtoMessage() {}
 
 func (x *TimeRange) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_model_v1_query_proto_msgTypes[5]
+	mi := &file_banyandb_model_v1_query_proto_msgTypes[6]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -485,7 +546,7 @@ func (x *TimeRange) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use TimeRange.ProtoReflect.Descriptor instead.
 func (*TimeRange) Descriptor() ([]byte, []int) {
-	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{5}
+	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *TimeRange) GetBegin() *timestamppb.Timestamp {
@@ -502,7 +563,7 @@ func (x *TimeRange) GetEnd() *timestamppb.Timestamp {
 	return nil
 }
 
-type Projection_TagFamily struct {
+type TagProjection_TagFamily struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
@@ -511,23 +572,23 @@ type Projection_TagFamily struct {
 	Tags []string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty"`
 }
 
-func (x *Projection_TagFamily) Reset() {
-	*x = Projection_TagFamily{}
+func (x *TagProjection_TagFamily) Reset() {
+	*x = TagProjection_TagFamily{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_model_v1_query_proto_msgTypes[6]
+		mi := &file_banyandb_model_v1_query_proto_msgTypes[7]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
 }
 
-func (x *Projection_TagFamily) String() string {
+func (x *TagProjection_TagFamily) String() string {
 	return protoimpl.X.MessageStringOf(x)
 }
 
-func (*Projection_TagFamily) ProtoMessage() {}
+func (*TagProjection_TagFamily) ProtoMessage() {}
 
-func (x *Projection_TagFamily) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_model_v1_query_proto_msgTypes[6]
+func (x *TagProjection_TagFamily) ProtoReflect() protoreflect.Message {
+	mi := &file_banyandb_model_v1_query_proto_msgTypes[7]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -538,19 +599,19 @@ func (x *Projection_TagFamily) ProtoReflect() protoreflect.Message {
 	return mi.MessageOf(x)
 }
 
-// Deprecated: Use Projection_TagFamily.ProtoReflect.Descriptor instead.
-func (*Projection_TagFamily) Descriptor() ([]byte, []int) {
-	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{4, 0}
+// Deprecated: Use TagProjection_TagFamily.ProtoReflect.Descriptor instead.
+func (*TagProjection_TagFamily) Descriptor() ([]byte, []int) {
+	return file_banyandb_model_v1_query_proto_rawDescGZIP(), []int{5, 0}
 }
 
-func (x *Projection_TagFamily) GetName() string {
+func (x *TagProjection_TagFamily) GetName() string {
 	if x != nil {
 		return x.Name
 	}
 	return ""
 }
 
-func (x *Projection_TagFamily) GetTags() []string {
+func (x *TagProjection_TagFamily) GetTags() []string {
 	if x != nil {
 		return x.Tags
 	}
@@ -576,7 +637,7 @@ var file_banyandb_model_v1_query_proto_rawDesc = []byte{
 	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
 	0x12, 0x2a, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16,
 	0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e,
-	0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0xcd, 0x02, 0x0a,
+	0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0xf5, 0x02, 0x0a,
 	0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
 	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35,
 	0x0a, 0x02, 0x6f, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x62, 0x61, 0x6e,
@@ -585,7 +646,7 @@ var file_banyandb_model_v1_query_proto_rawDesc = []byte{
 	0x70, 0x52, 0x02, 0x6f, 0x70, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03,
 	0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e,
 	0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x56, 0x61, 0x6c, 0x75,
-	0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc1, 0x01, 0x0a, 0x08, 0x42, 0x69, 0x6e,
+	0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe9, 0x01, 0x0a, 0x08, 0x42, 0x69, 0x6e,
 	0x61, 0x72, 0x79, 0x4f, 0x70, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x5f,
 	0x4f, 0x50, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
 	0x12, 0x10, 0x0a, 0x0c, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x50, 0x5f, 0x45, 0x51,
@@ -597,41 +658,50 @@ var file_banyandb_model_v1_query_proto_rawDesc = []byte{
 	0x4e, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x50, 0x5f, 0x47, 0x45, 0x10, 0x06, 0x12, 0x14, 0x0a, 0x10,
 	0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x50, 0x5f, 0x48, 0x41, 0x56, 0x49, 0x4e, 0x47,
 	0x10, 0x07, 0x12, 0x18, 0x0a, 0x14, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x50, 0x5f,
-	0x4e, 0x4f, 0x54, 0x5f, 0x48, 0x41, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x22, 0xa7, 0x01, 0x0a,
-	0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x69,
-	0x6e, 0x64, 0x65, 0x78, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x4e,
-	0x61, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x0e, 0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64,
-	0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72,
-	0x2e, 0x53, 0x6f, 0x72, 0x74, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x22, 0x39, 0x0a, 0x04, 0x53,
-	0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50,
-	0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x4f, 0x52,
-	0x54, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4f, 0x52, 0x54,
-	0x5f, 0x41, 0x53, 0x43, 0x10, 0x02, 0x22, 0x8d, 0x01, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x6a, 0x65,
-	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4a, 0x0a, 0x0c, 0x74, 0x61, 0x67, 0x5f, 0x66, 0x61, 0x6d,
-	0x69, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x62, 0x61,
-	0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
-	0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x61, 0x67, 0x46, 0x61,
-	0x6d, 0x69, 0x6c, 0x79, 0x52, 0x0b, 0x74, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65,
-	0x73, 0x1a, 0x33, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x12,
-	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
-	0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
-	0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0x6b, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61,
-	0x6e, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05,
-	0x62, 0x65, 0x67, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03,
-	0x65, 0x6e, 0x64, 0x42, 0x6c, 0x0a, 0x27, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68,
-	0x65, 0x2e, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e,
-	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x5a, 0x41,
-	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68,
-	0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61, 0x6e,
-	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
-	0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76,
-	0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x4e, 0x4f, 0x54, 0x5f, 0x48, 0x41, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x12, 0x10, 0x0a, 0x0c,
+	0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x09, 0x12, 0x14,
+	0x0a, 0x10, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x50, 0x5f, 0x4e, 0x4f, 0x54, 0x5f,
+	0x49, 0x4e, 0x10, 0x0a, 0x22, 0x70, 0x0a, 0x08, 0x43, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61,
+	0x12, 0x26, 0x0a, 0x0f, 0x74, 0x61, 0x67, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x5f, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x67, 0x46, 0x61,
+	0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64,
+	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62,
+	0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31,
+	0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64,
+	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x61, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4f,
+	0x72, 0x64, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x72, 0x75,
+	0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69,
+	0x6e, 0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x04,
+	0x73, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x62, 0x61, 0x6e,
+	0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53,
+	0x6f, 0x72, 0x74, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x22, 0x93, 0x01, 0x0a, 0x0d, 0x54, 0x61,
+	0x67, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x74,
+	0x61, 0x67, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x2a, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64,
+	0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+	0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x52, 0x0b, 0x74,
+	0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73, 0x1a, 0x33, 0x0a, 0x09, 0x54, 0x61,
+	0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74,
+	0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22,
+	0x6b, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x05,
+	0x62, 0x65, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x12, 0x2c,
+	0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x2a, 0x39, 0x0a, 0x04,
+	0x53, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x55, 0x4e, 0x53,
+	0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x4f,
+	0x52, 0x54, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4f, 0x52,
+	0x54, 0x5f, 0x41, 0x53, 0x43, 0x10, 0x02, 0x42, 0x6c, 0x0a, 0x27, 0x6f, 0x72, 0x67, 0x2e, 0x61,
+	0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67,
+	0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e,
+	0x76, 0x31, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61,
+	0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67,
+	0x2d, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x6d, 0x6f, 0x64,
+	0x65, 0x6c, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -647,34 +717,36 @@ func file_banyandb_model_v1_query_proto_rawDescGZIP() []byte {
 }
 
 var file_banyandb_model_v1_query_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
-var file_banyandb_model_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
+var file_banyandb_model_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
 var file_banyandb_model_v1_query_proto_goTypes = []interface{}{
-	(Condition_BinaryOp)(0),       // 0: banyandb.model.v1.Condition.BinaryOp
-	(QueryOrder_Sort)(0),          // 1: banyandb.model.v1.QueryOrder.Sort
-	(*Tag)(nil),                   // 2: banyandb.model.v1.Tag
-	(*TagFamily)(nil),             // 3: banyandb.model.v1.TagFamily
-	(*Condition)(nil),             // 4: banyandb.model.v1.Condition
-	(*QueryOrder)(nil),            // 5: banyandb.model.v1.QueryOrder
-	(*Projection)(nil),            // 6: banyandb.model.v1.Projection
-	(*TimeRange)(nil),             // 7: banyandb.model.v1.TimeRange
-	(*Projection_TagFamily)(nil),  // 8: banyandb.model.v1.Projection.TagFamily
-	(*TagValue)(nil),              // 9: banyandb.model.v1.TagValue
-	(*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp
+	(Sort)(0),                       // 0: banyandb.model.v1.Sort
+	(Condition_BinaryOp)(0),         // 1: banyandb.model.v1.Condition.BinaryOp
+	(*Tag)(nil),                     // 2: banyandb.model.v1.Tag
+	(*TagFamily)(nil),               // 3: banyandb.model.v1.TagFamily
+	(*Condition)(nil),               // 4: banyandb.model.v1.Condition
+	(*Criteria)(nil),                // 5: banyandb.model.v1.Criteria
+	(*QueryOrder)(nil),              // 6: banyandb.model.v1.QueryOrder
+	(*TagProjection)(nil),           // 7: banyandb.model.v1.TagProjection
+	(*TimeRange)(nil),               // 8: banyandb.model.v1.TimeRange
+	(*TagProjection_TagFamily)(nil), // 9: banyandb.model.v1.TagProjection.TagFamily
+	(*TagValue)(nil),                // 10: banyandb.model.v1.TagValue
+	(*timestamppb.Timestamp)(nil),   // 11: google.protobuf.Timestamp
 }
 var file_banyandb_model_v1_query_proto_depIdxs = []int32{
-	9,  // 0: banyandb.model.v1.Tag.value:type_name -> banyandb.model.v1.TagValue
+	10, // 0: banyandb.model.v1.Tag.value:type_name -> banyandb.model.v1.TagValue
 	2,  // 1: banyandb.model.v1.TagFamily.tags:type_name -> banyandb.model.v1.Tag
-	0,  // 2: banyandb.model.v1.Condition.op:type_name -> banyandb.model.v1.Condition.BinaryOp
-	9,  // 3: banyandb.model.v1.Condition.value:type_name -> banyandb.model.v1.TagValue
-	1,  // 4: banyandb.model.v1.QueryOrder.sort:type_name -> banyandb.model.v1.QueryOrder.Sort
-	8,  // 5: banyandb.model.v1.Projection.tag_families:type_name -> banyandb.model.v1.Projection.TagFamily
-	10, // 6: banyandb.model.v1.TimeRange.begin:type_name -> google.protobuf.Timestamp
-	10, // 7: banyandb.model.v1.TimeRange.end:type_name -> google.protobuf.Timestamp
-	8,  // [8:8] is the sub-list for method output_type
-	8,  // [8:8] is the sub-list for method input_type
-	8,  // [8:8] is the sub-list for extension type_name
-	8,  // [8:8] is the sub-list for extension extendee
-	0,  // [0:8] is the sub-list for field type_name
+	1,  // 2: banyandb.model.v1.Condition.op:type_name -> banyandb.model.v1.Condition.BinaryOp
+	10, // 3: banyandb.model.v1.Condition.value:type_name -> banyandb.model.v1.TagValue
+	4,  // 4: banyandb.model.v1.Criteria.conditions:type_name -> banyandb.model.v1.Condition
+	0,  // 5: banyandb.model.v1.QueryOrder.sort:type_name -> banyandb.model.v1.Sort
+	9,  // 6: banyandb.model.v1.TagProjection.tag_families:type_name -> banyandb.model.v1.TagProjection.TagFamily
+	11, // 7: banyandb.model.v1.TimeRange.begin:type_name -> google.protobuf.Timestamp
+	11, // 8: banyandb.model.v1.TimeRange.end:type_name -> google.protobuf.Timestamp
+	9,  // [9:9] is the sub-list for method output_type
+	9,  // [9:9] is the sub-list for method input_type
+	9,  // [9:9] is the sub-list for extension type_name
+	9,  // [9:9] is the sub-list for extension extendee
+	0,  // [0:9] is the sub-list for field type_name
 }
 
 func init() { file_banyandb_model_v1_query_proto_init() }
@@ -721,7 +793,7 @@ func file_banyandb_model_v1_query_proto_init() {
 			}
 		}
 		file_banyandb_model_v1_query_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*QueryOrder); i {
+			switch v := v.(*Criteria); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -733,7 +805,7 @@ func file_banyandb_model_v1_query_proto_init() {
 			}
 		}
 		file_banyandb_model_v1_query_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Projection); i {
+			switch v := v.(*QueryOrder); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -745,7 +817,7 @@ func file_banyandb_model_v1_query_proto_init() {
 			}
 		}
 		file_banyandb_model_v1_query_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*TimeRange); i {
+			switch v := v.(*TagProjection); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -757,7 +829,19 @@ func file_banyandb_model_v1_query_proto_init() {
 			}
 		}
 		file_banyandb_model_v1_query_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Projection_TagFamily); i {
+			switch v := v.(*TimeRange); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_banyandb_model_v1_query_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TagProjection_TagFamily); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -775,7 +859,7 @@ func file_banyandb_model_v1_query_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_banyandb_model_v1_query_proto_rawDesc,
 			NumEnums:      2,
-			NumMessages:   7,
+			NumMessages:   8,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/api/proto/banyandb/model/v1/query.proto b/api/proto/banyandb/model/v1/query.proto
index eaacc9f..2966341 100644
--- a/api/proto/banyandb/model/v1/query.proto
+++ b/api/proto/banyandb/model/v1/query.proto
@@ -57,31 +57,39 @@ message Condition {
         BINARY_OP_GE = 6;
         BINARY_OP_HAVING = 7;
         BINARY_OP_NOT_HAVING = 8;
+        BINARY_OP_IN = 9;
+        BINARY_OP_NOT_IN = 10;
     }
     string name = 1;
     BinaryOp op = 2;
     TagValue value = 3;
 }
 
+// tag_families are indexed.
+message Criteria {
+    string tag_family_name = 1;
+    repeated model.v1.Condition conditions = 2;
+}
+
+enum Sort {
+    SORT_UNSPECIFIED = 0;
+    SORT_DESC = 1;
+    SORT_ASC = 2;
+}
+
 // QueryOrder means a Sort operation to be done for a given index rule.
 // The index_rule_name refers to the name of a index rule bound to the subject.
 message QueryOrder {
     string index_rule_name = 1;
-    enum Sort {
-        SORT_UNSPECIFIED = 0;
-        SORT_DESC = 1;
-        SORT_ASC = 2;
-    }
     Sort sort = 2;
 }
 
-// Projection is used to select the names of keys to be returned.
-message Projection {
+// TagProjection is used to select the names of keys to be returned.
+message TagProjection {
     message TagFamily {
         string name = 1;
         repeated string tags = 2;
     }
-    // The key_name refers to the key(s) of Pair(s).
     repeated TagFamily tag_families = 1;
 }
 
diff --git a/api/proto/banyandb/stream/v1/query.pb.go b/api/proto/banyandb/stream/v1/query.pb.go
index 883638a..2804c39 100644
--- a/api/proto/banyandb/stream/v1/query.pb.go
+++ b/api/proto/banyandb/stream/v1/query.pb.go
@@ -185,10 +185,11 @@ type QueryRequest struct {
 	// limit is used to impose a boundary on the number of records being returned
 	Limit uint32 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"`
 	// order_by is given to specify the sort for a field. So far, only fields in the type of Integer are supported
-	OrderBy  *v1.QueryOrder           `protobuf:"bytes,5,opt,name=order_by,json=orderBy,proto3" json:"order_by,omitempty"`
-	Criteria []*QueryRequest_Criteria `protobuf:"bytes,6,rep,name=criteria,proto3" json:"criteria,omitempty"`
+	OrderBy *v1.QueryOrder `protobuf:"bytes,5,opt,name=order_by,json=orderBy,proto3" json:"order_by,omitempty"`
+	// tag_families are indexed.
+	Criteria []*v1.Criteria `protobuf:"bytes,6,rep,name=criteria,proto3" json:"criteria,omitempty"`
 	// projection can be used to select the key names of the element in the response
-	Projection *v1.Projection `protobuf:"bytes,7,opt,name=projection,proto3" json:"projection,omitempty"`
+	Projection *v1.TagProjection `protobuf:"bytes,7,opt,name=projection,proto3" json:"projection,omitempty"`
 }
 
 func (x *QueryRequest) Reset() {
@@ -258,76 +259,20 @@ func (x *QueryRequest) GetOrderBy() *v1.QueryOrder {
 	return nil
 }
 
-func (x *QueryRequest) GetCriteria() []*QueryRequest_Criteria {
+func (x *QueryRequest) GetCriteria() []*v1.Criteria {
 	if x != nil {
 		return x.Criteria
 	}
 	return nil
 }
 
-func (x *QueryRequest) GetProjection() *v1.Projection {
+func (x *QueryRequest) GetProjection() *v1.TagProjection {
 	if x != nil {
 		return x.Projection
 	}
 	return nil
 }
 
-// tag_families are indexed.
-type QueryRequest_Criteria struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	TagFamilyName string          `protobuf:"bytes,1,opt,name=tag_family_name,json=tagFamilyName,proto3" json:"tag_family_name,omitempty"`
-	Conditions    []*v1.Condition `protobuf:"bytes,2,rep,name=conditions,proto3" json:"conditions,omitempty"`
-}
-
-func (x *QueryRequest_Criteria) Reset() {
-	*x = QueryRequest_Criteria{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_banyandb_stream_v1_query_proto_msgTypes[3]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *QueryRequest_Criteria) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*QueryRequest_Criteria) ProtoMessage() {}
-
-func (x *QueryRequest_Criteria) ProtoReflect() protoreflect.Message {
-	mi := &file_banyandb_stream_v1_query_proto_msgTypes[3]
-	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 QueryRequest_Criteria.ProtoReflect.Descriptor instead.
-func (*QueryRequest_Criteria) Descriptor() ([]byte, []int) {
-	return file_banyandb_stream_v1_query_proto_rawDescGZIP(), []int{2, 0}
-}
-
-func (x *QueryRequest_Criteria) GetTagFamilyName() string {
-	if x != nil {
-		return x.TagFamilyName
-	}
-	return ""
-}
-
-func (x *QueryRequest_Criteria) GetConditions() []*v1.Condition {
-	if x != nil {
-		return x.Conditions
-	}
-	return nil
-}
-
 var File_banyandb_stream_v1_query_proto protoreflect.FileDescriptor
 
 var file_banyandb_stream_v1_query_proto_rawDesc = []byte{
@@ -355,7 +300,7 @@ var file_banyandb_stream_v1_query_proto_rawDesc = []byte{
 	0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b,
 	0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
 	0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, 0x65, 0x6c, 0x65,
-	0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xe5, 0x03, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52,
+	0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xe8, 0x02, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52,
 	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
 	0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61,
 	0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65,
@@ -370,30 +315,22 @@ var file_banyandb_stream_v1_query_proto_rawDesc = []byte{
 	0x72, 0x64, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e,
 	0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76,
 	0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x07, 0x6f, 0x72,
-	0x64, 0x65, 0x72, 0x42, 0x79, 0x12, 0x45, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69,
-	0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
-	0x64, 0x62, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65,
-	0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x65, 0x72,
-	0x69, 0x61, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x12, 0x3d, 0x0a, 0x0a,
-	0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x1d, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65,
-	0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52,
-	0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x70, 0x0a, 0x08, 0x43,
-	0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x61, 0x67, 0x5f, 0x66,
-	0x61, 0x6d, 0x69, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0d, 0x74, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12,
-	0x3c, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d,
-	0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f,
-	0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x6e, 0x0a,
-	0x28, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x73, 0x6b, 0x79, 0x77,
-	0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e,
-	0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75,
-	0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x73, 0x6b, 0x79,
-	0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62,
-	0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x61, 0x6e, 0x79, 0x61,
-	0x6e, 0x64, 0x62, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x64, 0x65, 0x72, 0x42, 0x79, 0x12, 0x37, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69,
+	0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
+	0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x69, 0x74,
+	0x65, 0x72, 0x69, 0x61, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x12, 0x40,
+	0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x20, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f,
+	0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+	0x42, 0x6e, 0x0a, 0x28, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x73,
+	0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e,
+	0x64, 0x62, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x5a, 0x42, 0x67, 0x69,
+	0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f,
+	0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61, 0x6e, 0x79, 0x61,
+	0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x61,
+	0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2f, 0x76, 0x31,
+	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -408,35 +345,33 @@ func file_banyandb_stream_v1_query_proto_rawDescGZIP() []byte {
 	return file_banyandb_stream_v1_query_proto_rawDescData
 }
 
-var file_banyandb_stream_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_banyandb_stream_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
 var file_banyandb_stream_v1_query_proto_goTypes = []interface{}{
 	(*Element)(nil),               // 0: banyandb.stream.v1.Element
 	(*QueryResponse)(nil),         // 1: banyandb.stream.v1.QueryResponse
 	(*QueryRequest)(nil),          // 2: banyandb.stream.v1.QueryRequest
-	(*QueryRequest_Criteria)(nil), // 3: banyandb.stream.v1.QueryRequest.Criteria
-	(*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp
-	(*v1.TagFamily)(nil),          // 5: banyandb.model.v1.TagFamily
-	(*v11.Metadata)(nil),          // 6: banyandb.common.v1.Metadata
-	(*v1.TimeRange)(nil),          // 7: banyandb.model.v1.TimeRange
-	(*v1.QueryOrder)(nil),         // 8: banyandb.model.v1.QueryOrder
-	(*v1.Projection)(nil),         // 9: banyandb.model.v1.Projection
-	(*v1.Condition)(nil),          // 10: banyandb.model.v1.Condition
+	(*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp
+	(*v1.TagFamily)(nil),          // 4: banyandb.model.v1.TagFamily
+	(*v11.Metadata)(nil),          // 5: banyandb.common.v1.Metadata
+	(*v1.TimeRange)(nil),          // 6: banyandb.model.v1.TimeRange
+	(*v1.QueryOrder)(nil),         // 7: banyandb.model.v1.QueryOrder
+	(*v1.Criteria)(nil),           // 8: banyandb.model.v1.Criteria
+	(*v1.TagProjection)(nil),      // 9: banyandb.model.v1.TagProjection
 }
 var file_banyandb_stream_v1_query_proto_depIdxs = []int32{
-	4,  // 0: banyandb.stream.v1.Element.timestamp:type_name -> google.protobuf.Timestamp
-	5,  // 1: banyandb.stream.v1.Element.tag_families:type_name -> banyandb.model.v1.TagFamily
-	0,  // 2: banyandb.stream.v1.QueryResponse.elements:type_name -> banyandb.stream.v1.Element
-	6,  // 3: banyandb.stream.v1.QueryRequest.metadata:type_name -> banyandb.common.v1.Metadata
-	7,  // 4: banyandb.stream.v1.QueryRequest.time_range:type_name -> banyandb.model.v1.TimeRange
-	8,  // 5: banyandb.stream.v1.QueryRequest.order_by:type_name -> banyandb.model.v1.QueryOrder
-	3,  // 6: banyandb.stream.v1.QueryRequest.criteria:type_name -> banyandb.stream.v1.QueryRequest.Criteria
-	9,  // 7: banyandb.stream.v1.QueryRequest.projection:type_name -> banyandb.model.v1.Projection
-	10, // 8: banyandb.stream.v1.QueryRequest.Criteria.conditions:type_name -> banyandb.model.v1.Condition
-	9,  // [9:9] is the sub-list for method output_type
-	9,  // [9:9] is the sub-list for method input_type
-	9,  // [9:9] is the sub-list for extension type_name
-	9,  // [9:9] is the sub-list for extension extendee
-	0,  // [0:9] is the sub-list for field type_name
+	3, // 0: banyandb.stream.v1.Element.timestamp:type_name -> google.protobuf.Timestamp
+	4, // 1: banyandb.stream.v1.Element.tag_families:type_name -> banyandb.model.v1.TagFamily
+	0, // 2: banyandb.stream.v1.QueryResponse.elements:type_name -> banyandb.stream.v1.Element
+	5, // 3: banyandb.stream.v1.QueryRequest.metadata:type_name -> banyandb.common.v1.Metadata
+	6, // 4: banyandb.stream.v1.QueryRequest.time_range:type_name -> banyandb.model.v1.TimeRange
+	7, // 5: banyandb.stream.v1.QueryRequest.order_by:type_name -> banyandb.model.v1.QueryOrder
+	8, // 6: banyandb.stream.v1.QueryRequest.criteria:type_name -> banyandb.model.v1.Criteria
+	9, // 7: banyandb.stream.v1.QueryRequest.projection:type_name -> banyandb.model.v1.TagProjection
+	8, // [8:8] is the sub-list for method output_type
+	8, // [8:8] is the sub-list for method input_type
+	8, // [8:8] is the sub-list for extension type_name
+	8, // [8:8] is the sub-list for extension extendee
+	0, // [0:8] is the sub-list for field type_name
 }
 
 func init() { file_banyandb_stream_v1_query_proto_init() }
@@ -481,18 +416,6 @@ func file_banyandb_stream_v1_query_proto_init() {
 				return nil
 			}
 		}
-		file_banyandb_stream_v1_query_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*QueryRequest_Criteria); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -500,7 +423,7 @@ func file_banyandb_stream_v1_query_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_banyandb_stream_v1_query_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   4,
+			NumMessages:   3,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/api/proto/banyandb/stream/v1/query.proto b/api/proto/banyandb/stream/v1/query.proto
index 2dccd89..ae11f8c 100644
--- a/api/proto/banyandb/stream/v1/query.proto
+++ b/api/proto/banyandb/stream/v1/query.proto
@@ -67,11 +67,7 @@ message QueryRequest {
   // order_by is given to specify the sort for a field. So far, only fields in the type of Integer are supported
   model.v1.QueryOrder order_by = 5;
   // tag_families are indexed.
-  message Criteria {
-    string tag_family_name = 1;
-    repeated model.v1.Condition conditions = 2;
-  }
-  repeated Criteria criteria = 6;
+  repeated model.v1.Criteria criteria = 6;
   // projection can be used to select the key names of the element in the response
-  model.v1.Projection projection = 7;
+  model.v1.TagProjection projection = 7;
 }
diff --git a/banyand/metadata/schema/etcd_test.go b/banyand/metadata/schema/etcd_test.go
index a079155..cacb5d2 100644
--- a/banyand/metadata/schema/etcd_test.go
+++ b/banyand/metadata/schema/etcd_test.go
@@ -45,7 +45,7 @@ var (
 	streamJSON string
 )
 
-func PreloadSchema(e Registry) error {
+func preloadSchema(e Registry) error {
 	if err := e.CreateGroup(context.TODO(), "default"); err != nil {
 		return err
 	}
@@ -118,7 +118,7 @@ func Test_Etcd_Entity_Get(t *testing.T) {
 	tester.NotNil(registry)
 	defer registry.Close()
 
-	err = PreloadSchema(registry)
+	err = preloadSchema(registry)
 	tester.NoError(err)
 
 	tests := []struct {
@@ -197,7 +197,7 @@ func Test_Etcd_Entity_List(t *testing.T) {
 	tester.NotNil(registry)
 	defer registry.Close()
 
-	err = PreloadSchema(registry)
+	err = preloadSchema(registry)
 	tester.NoError(err)
 
 	tests := []struct {
@@ -312,7 +312,7 @@ func Test_Etcd_Delete(t *testing.T) {
 	tester.NotNil(registry)
 	defer registry.Close()
 
-	err = PreloadSchema(registry)
+	err = preloadSchema(registry)
 	tester.NoError(err)
 
 	tests := []struct {
diff --git a/banyand/metadata/schema/testdata/stream.json b/banyand/metadata/schema/testdata/stream.json
index 41b3b52..d4f9df9 100644
--- a/banyand/metadata/schema/testdata/stream.json
+++ b/banyand/metadata/schema/testdata/stream.json
@@ -82,10 +82,12 @@
       "state"
     ]
   },
-  "shard_num": 2,
-  "duration": {
-    "val": 7,
-    "unit": "DURATION_UNIT_DAY"
+  "opts": {
+    "shard_num": 2,
+    "ttl": {
+      "val": 7,
+      "unit": "DURATION_UNIT_DAY"
+    }
   },
-  "updated_at": "2021-04-15T01:30:15.01Z"
+  "updated_at_nanoseconds": "2021-04-15T01:30:15.01Z"
 }
\ No newline at end of file
diff --git a/banyand/query/processor_test.go b/banyand/query/processor_test.go
index 9319f83..2320317 100644
--- a/banyand/query/processor_test.go
+++ b/banyand/query/processor_test.go
@@ -228,13 +228,13 @@ func TestQueryProcessor(t *testing.T) {
 					Offset(0).
 					Metadata("default", "sw").
 					TimeRange(sT, eT).
-					OrderBy("duration", modelv1.QueryOrder_SORT_DESC).
+					OrderBy("duration", modelv1.Sort_SORT_DESC).
 					Projection("searchable", "trace_id", "duration").
 					Build()
 			},
 			wantLen: 5,
 			checker: func(elements []*streamv1.Element) bool {
-				return logical.SortedByIndex(elements, 0, 1, modelv1.QueryOrder_SORT_DESC)
+				return logical.SortedByIndex(elements, 0, 1, modelv1.Sort_SORT_DESC)
 			},
 		},
 		{
diff --git a/banyand/stream/index.go b/banyand/stream/index.go
index 63445c1..c1b5e7b 100644
--- a/banyand/stream/index.go
+++ b/banyand/stream/index.go
@@ -72,7 +72,7 @@ func (s *stream) writeGlobalIndex(ruleIndex indexRule, ref tsdb.GlobalItemID, va
 	if err != nil {
 		return err
 	}
-	indexShardID, err := partition.ShardID(val, s.schema.ShardNum)
+	indexShardID, err := partition.ShardID(val, s.schema.GetOpts().GetShardNum())
 	if err != nil {
 		return err
 	}
diff --git a/banyand/stream/service.go b/banyand/stream/service.go
index fef3f6a..6af8634 100644
--- a/banyand/stream/service.go
+++ b/banyand/stream/service.go
@@ -140,11 +140,11 @@ func (s *service) Serve() error {
 		if err != nil {
 			return err
 		}
-		for i := 0; i < int(sMeta.schema.GetShardNum()); i++ {
+		for i := 0; i < int(sMeta.schema.GetOpts().GetShardNum()); i++ {
 			_, errShard := s.repo.Publish(event.TopicShardEvent, bus.NewMessage(bus.MessageID(now), &databasev1.ShardEvent{
 				Shard: &databasev1.Shard{
 					Id:    uint64(i),
-					Total: sMeta.schema.GetShardNum(),
+					Total: sMeta.schema.GetOpts().GetShardNum(),
 					Metadata: &commonv1.Metadata{
 						Name:  sMeta.name,
 						Group: sMeta.group,
diff --git a/banyand/stream/stream.go b/banyand/stream/stream.go
index ece7795..35ae2a5 100644
--- a/banyand/stream/stream.go
+++ b/banyand/stream/stream.go
@@ -100,7 +100,7 @@ func openStream(root string, spec streamSpec, l *logger.Logger) (*stream, error)
 		context.WithValue(context.Background(), logger.ContextKey, l),
 		tsdb.DatabaseOpts{
 			Location:   root,
-			ShardNum:   sm.schema.GetShardNum(),
+			ShardNum:   sm.schema.GetOpts().GetShardNum(),
 			IndexRules: spec.indexRules,
 		})
 	if err != nil {
diff --git a/banyand/stream/stream_query.go b/banyand/stream/stream_query.go
index 250b5d5..0c75b14 100644
--- a/banyand/stream/stream_query.go
+++ b/banyand/stream/stream_query.go
@@ -60,7 +60,7 @@ func (s *stream) Shards(entity tsdb.Entity) ([]tsdb.Shard, error) {
 			return s.db.Shards(), nil
 		}
 	}
-	shardID, err := partition.ShardID(entity.Marshal(), s.schema.GetShardNum())
+	shardID, err := partition.ShardID(entity.Marshal(), s.schema.GetOpts().GetShardNum())
 	if err != nil {
 		return nil, err
 	}
diff --git a/banyand/stream/stream_query_test.go b/banyand/stream/stream_query_test.go
index 07e614c..f77cfd6 100644
--- a/banyand/stream/stream_query_test.go
+++ b/banyand/stream/stream_query_test.go
@@ -254,7 +254,7 @@ func Test_Stream_Series(t *testing.T) {
 						Tags:     []string{"duration"},
 						Type:     databasev1.IndexRule_TYPE_TREE,
 						Location: databasev1.IndexRule_LOCATION_SERIES,
-					}, modelv1.QueryOrder_SORT_ASC)
+					}, modelv1.Sort_SORT_ASC)
 				},
 			},
 			want: shardsForTest{
@@ -351,7 +351,7 @@ func Test_Stream_Series(t *testing.T) {
 							},
 						},
 					})
-					builder.OrderByIndex(rule, modelv1.QueryOrder_SORT_ASC)
+					builder.OrderByIndex(rule, modelv1.Sort_SORT_ASC)
 				},
 			},
 			want: shardsForTest{
@@ -462,7 +462,7 @@ func Test_Stream_Series(t *testing.T) {
 							},
 						},
 					})
-					builder.OrderByIndex(rule, modelv1.QueryOrder_SORT_ASC)
+					builder.OrderByIndex(rule, modelv1.Sort_SORT_ASC)
 					builder.Filter(&databasev1.IndexRule{
 						Metadata: &commonv1.Metadata{
 							Name:  "endpoint_id",
diff --git a/banyand/stream/stream_write.go b/banyand/stream/stream_write.go
index fac0f3e..8afed59 100644
--- a/banyand/stream/stream_write.go
+++ b/banyand/stream/stream_write.go
@@ -35,7 +35,7 @@ var (
 )
 
 func (s *stream) Write(value *streamv1.ElementValue) error {
-	entity, shardID, err := s.entityLocator.Locate(value.GetTagFamilies(), s.schema.GetShardNum())
+	entity, shardID, err := s.entityLocator.Locate(value.GetTagFamilies(), s.schema.GetOpts().GetShardNum())
 	if err != nil {
 		return err
 	}
diff --git a/banyand/tsdb/series_seek.go b/banyand/tsdb/series_seek.go
index 579ebad..eec6104 100644
--- a/banyand/tsdb/series_seek.go
+++ b/banyand/tsdb/series_seek.go
@@ -41,8 +41,8 @@ type Item interface {
 
 type SeekerBuilder interface {
 	Filter(indexRule *databasev1.IndexRule, condition Condition) SeekerBuilder
-	OrderByIndex(indexRule *databasev1.IndexRule, order modelv1.QueryOrder_Sort) SeekerBuilder
-	OrderByTime(order modelv1.QueryOrder_Sort) SeekerBuilder
+	OrderByIndex(indexRule *databasev1.IndexRule, order modelv1.Sort) SeekerBuilder
+	OrderByTime(order modelv1.Sort) SeekerBuilder
 	Build() (Seeker, error)
 }
 
@@ -60,14 +60,14 @@ type seekerBuilder struct {
 		indexRuleID   uint32
 		condition     Condition
 	}
-	order               modelv1.QueryOrder_Sort
+	order               modelv1.Sort
 	indexRuleForSorting *databasev1.IndexRule
 	rangeOptsForSorting index.RangeOpts
 }
 
 func (s *seekerBuilder) Build() (Seeker, error) {
-	if s.order == modelv1.QueryOrder_SORT_UNSPECIFIED {
-		s.order = modelv1.QueryOrder_SORT_ASC
+	if s.order == modelv1.Sort_SORT_UNSPECIFIED {
+		s.order = modelv1.Sort_SORT_ASC
 	}
 	conditions, err := s.buildConditions()
 	if err != nil {
diff --git a/banyand/tsdb/series_seek_sort.go b/banyand/tsdb/series_seek_sort.go
index a96607c..6182d96 100644
--- a/banyand/tsdb/series_seek_sort.go
+++ b/banyand/tsdb/series_seek_sort.go
@@ -35,13 +35,13 @@ import (
 
 var emptyFilters = make([]filterFn, 0)
 
-func (s *seekerBuilder) OrderByIndex(indexRule *databasev1.IndexRule, order modelv1.QueryOrder_Sort) SeekerBuilder {
+func (s *seekerBuilder) OrderByIndex(indexRule *databasev1.IndexRule, order modelv1.Sort) SeekerBuilder {
 	s.indexRuleForSorting = indexRule
 	s.order = order
 	return s
 }
 
-func (s *seekerBuilder) OrderByTime(order modelv1.QueryOrder_Sort) SeekerBuilder {
+func (s *seekerBuilder) OrderByTime(order modelv1.Sort) SeekerBuilder {
 	s.order = order
 	s.indexRuleForSorting = nil
 	return s
@@ -97,12 +97,12 @@ func (s *seekerBuilder) buildSeriesByIndex(conditions []condWithIRT) (series []I
 func (s *seekerBuilder) buildSeriesByTime(conditions []condWithIRT) ([]Iterator, error) {
 	bb := s.seriesSpan.blocks
 	switch s.order {
-	case modelv1.QueryOrder_SORT_ASC, modelv1.QueryOrder_SORT_UNSPECIFIED:
+	case modelv1.Sort_SORT_ASC, modelv1.Sort_SORT_UNSPECIFIED:
 		sort.SliceStable(bb, func(i, j int) bool {
 			return bb[i].startTime().Before(bb[j].startTime())
 		})
 
-	case modelv1.QueryOrder_SORT_DESC:
+	case modelv1.Sort_SORT_DESC:
 		sort.SliceStable(bb, func(i, j int) bool {
 			return bb[i].startTime().After(bb[j].startTime())
 		})
@@ -141,7 +141,7 @@ func (s *seekerBuilder) buildSeriesByTime(conditions []condWithIRT) ([]Iterator,
 		}
 	}
 	s.seriesSpan.l.Debug().
-		Str("order", modelv1.QueryOrder_Sort_name[int32(s.order)]).
+		Str("order", modelv1.Sort_name[int32(s.order)]).
 		Times("blocks", bTimes).
 		Uint64("series_id", uint64(s.seriesSpan.seriesID)).
 		Int("shard_id", int(s.seriesSpan.shardID)).
diff --git a/pkg/index/index.go b/pkg/index/index.go
index f3274f0..39bd478 100644
--- a/pkg/index/index.go
+++ b/pkg/index/index.go
@@ -161,7 +161,7 @@ type Writer interface {
 }
 
 type FieldIterable interface {
-	Iterator(fieldKey FieldKey, termRange RangeOpts, order modelv1.QueryOrder_Sort) (iter FieldIterator, err error)
+	Iterator(fieldKey FieldKey, termRange RangeOpts, order modelv1.Sort) (iter FieldIterator, err error)
 }
 
 type Searcher interface {
diff --git a/pkg/index/inverted/inverted.go b/pkg/index/inverted/inverted.go
index 5680eed..cd56d18 100644
--- a/pkg/index/inverted/inverted.go
+++ b/pkg/index/inverted/inverted.go
@@ -132,7 +132,7 @@ func (s *store) MatchTerms(field index.Field) (posting.List, error) {
 }
 
 func (s *store) Range(fieldKey index.FieldKey, opts index.RangeOpts) (list posting.List, err error) {
-	iter, err := s.Iterator(fieldKey, opts, modelv1.QueryOrder_SORT_ASC)
+	iter, err := s.Iterator(fieldKey, opts, modelv1.Sort_SORT_ASC)
 	if err != nil {
 		return roaring.EmptyPostingList, err
 	}
@@ -148,7 +148,7 @@ func (s *store) Range(fieldKey index.FieldKey, opts index.RangeOpts) (list posti
 }
 
 func (s *store) Iterator(fieldKey index.FieldKey, termRange index.RangeOpts,
-	order modelv1.QueryOrder_Sort) (index.FieldIterator, error) {
+	order modelv1.Sort) (index.FieldIterator, error) {
 	s.rwMutex.RLock()
 	defer s.rwMutex.RUnlock()
 	tt := []*memTable{s.memTable, s.immutableMemTable}
@@ -211,11 +211,11 @@ func (s *store) Iterator(fieldKey index.FieldKey, termRange index.RangeOpts,
 	}
 	var fn index.SwitchFn
 	switch order {
-	case modelv1.QueryOrder_SORT_ASC, modelv1.QueryOrder_SORT_UNSPECIFIED:
+	case modelv1.Sort_SORT_ASC, modelv1.Sort_SORT_UNSPECIFIED:
 		fn = func(a, b []byte) bool {
 			return bytes.Compare(a, b) > 0
 		}
-	case modelv1.QueryOrder_SORT_DESC:
+	case modelv1.Sort_SORT_DESC:
 		fn = func(a, b []byte) bool {
 			return bytes.Compare(a, b) < 0
 		}
diff --git a/pkg/index/inverted/mem.go b/pkg/index/inverted/mem.go
index 731df48..aed68fe 100644
--- a/pkg/index/inverted/mem.go
+++ b/pkg/index/inverted/mem.go
@@ -94,7 +94,7 @@ func newFieldIterator(keys [][]byte, fValue *termMap) index.FieldIterator {
 }
 
 func (m *memTable) Iterator(fieldKey index.FieldKey, rangeOpts index.RangeOpts,
-	order modelv1.QueryOrder_Sort) (iter index.FieldIterator, err error) {
+	order modelv1.Sort) (iter index.FieldIterator, err error) {
 	fieldsValues, ok := m.fields.get(fieldKey)
 	if !ok {
 		return nil, nil
@@ -114,11 +114,11 @@ func (m *memTable) Iterator(fieldKey index.FieldKey, rangeOpts index.RangeOpts,
 		return nil, nil
 	}
 	switch order {
-	case modelv1.QueryOrder_SORT_ASC, modelv1.QueryOrder_SORT_UNSPECIFIED:
+	case modelv1.Sort_SORT_ASC, modelv1.Sort_SORT_UNSPECIFIED:
 		sort.SliceStable(terms, func(i, j int) bool {
 			return bytes.Compare(terms[i], terms[j]) < 0
 		})
-	case modelv1.QueryOrder_SORT_DESC:
+	case modelv1.Sort_SORT_DESC:
 		sort.SliceStable(terms, func(i, j int) bool {
 			return bytes.Compare(terms[i], terms[j]) > 0
 		})
diff --git a/pkg/index/iterator.go b/pkg/index/iterator.go
index be34065..a933c0d 100644
--- a/pkg/index/iterator.go
+++ b/pkg/index/iterator.go
@@ -95,7 +95,7 @@ func (f *FieldIteratorTemplate) Close() error {
 	return multierr.Append(f.err, f.delegated.Close())
 }
 
-func NewFieldIteratorTemplate(fieldKey FieldKey, termRange RangeOpts, order modelv1.QueryOrder_Sort, iterable kv.Iterable,
+func NewFieldIteratorTemplate(fieldKey FieldKey, termRange RangeOpts, order modelv1.Sort, iterable kv.Iterable,
 	metadata metadata.Term, fn CompositePostingValueFn) (*FieldIteratorTemplate, error) {
 	if termRange.Upper == nil {
 		termRange.Upper = DefaultUpper
@@ -106,14 +106,14 @@ func NewFieldIteratorTemplate(fieldKey FieldKey, termRange RangeOpts, order mode
 	var reverse bool
 	var term []byte
 	switch order {
-	case modelv1.QueryOrder_SORT_ASC, modelv1.QueryOrder_SORT_UNSPECIFIED:
+	case modelv1.Sort_SORT_ASC, modelv1.Sort_SORT_UNSPECIFIED:
 		term = termRange.Lower
 		reverse = false
-	case modelv1.QueryOrder_SORT_DESC:
+	case modelv1.Sort_SORT_DESC:
 		term = termRange.Upper
 		reverse = true
 	}
-	if order == modelv1.QueryOrder_SORT_DESC {
+	if order == modelv1.Sort_SORT_DESC {
 		reverse = true
 	}
 	iter := iterable.NewIterator(kv.ScanOpts{
diff --git a/pkg/index/lsm/search.go b/pkg/index/lsm/search.go
index c71ae1b..69a84d9 100644
--- a/pkg/index/lsm/search.go
+++ b/pkg/index/lsm/search.go
@@ -53,7 +53,7 @@ func (s *store) MatchTerms(field index.Field) (list posting.List, err error) {
 }
 
 func (s *store) Range(fieldKey index.FieldKey, opts index.RangeOpts) (list posting.List, err error) {
-	iter, err := s.Iterator(fieldKey, opts, modelv1.QueryOrder_SORT_ASC)
+	iter, err := s.Iterator(fieldKey, opts, modelv1.Sort_SORT_ASC)
 	if err != nil {
 		return roaring.EmptyPostingList, err
 	}
@@ -65,7 +65,7 @@ func (s *store) Range(fieldKey index.FieldKey, opts index.RangeOpts) (list posti
 	return
 }
 
-func (s *store) Iterator(fieldKey index.FieldKey, termRange index.RangeOpts, order modelv1.QueryOrder_Sort) (index.FieldIterator, error) {
+func (s *store) Iterator(fieldKey index.FieldKey, termRange index.RangeOpts, order modelv1.Sort) (index.FieldIterator, error) {
 	return index.NewFieldIteratorTemplate(fieldKey, termRange, order, s.lsm, s.termMetadata, func(term, value []byte, delegated kv.Iterator) (*index.PostingValue, error) {
 		pv := &index.PostingValue{
 			Term:  term,
diff --git a/pkg/index/testcases/duration.go b/pkg/index/testcases/duration.go
index 9dae9eb..8748598 100644
--- a/pkg/index/testcases/duration.go
+++ b/pkg/index/testcases/duration.go
@@ -48,7 +48,7 @@ type SimpleStore interface {
 type args struct {
 	fieldKey  index.FieldKey
 	termRange index.RangeOpts
-	orderType modelv1.QueryOrder_Sort
+	orderType modelv1.Sort
 }
 
 type result struct {
@@ -68,7 +68,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "sort in asc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_ASC,
+				orderType: modelv1.Sort_SORT_ASC,
 			},
 			want: []int{50, 200, 500, 1000, 2000},
 		},
@@ -76,7 +76,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "sort in desc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_DESC,
+				orderType: modelv1.Sort_SORT_DESC,
 			},
 			want: []int{2000, 1000, 500, 200, 50},
 		},
@@ -84,7 +84,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan in (lower, upper) and sort in asc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_ASC,
+				orderType: modelv1.Sort_SORT_ASC,
 				termRange: index.RangeOpts{
 					Lower: convert.Int64ToBytes(50),
 					Upper: convert.Int64ToBytes(2000),
@@ -96,7 +96,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan in (lower, upper) and sort in desc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_DESC,
+				orderType: modelv1.Sort_SORT_DESC,
 				termRange: index.RangeOpts{
 					Lower: convert.Int64ToBytes(50),
 					Upper: convert.Int64ToBytes(2000),
@@ -108,7 +108,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan in [lower, upper] and sort in asc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_ASC,
+				orderType: modelv1.Sort_SORT_ASC,
 				termRange: index.RangeOpts{
 					Lower:         convert.Int64ToBytes(200),
 					IncludesLower: true,
@@ -122,7 +122,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan in [lower, upper] and sort in desc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_DESC,
+				orderType: modelv1.Sort_SORT_DESC,
 				termRange: index.RangeOpts{
 					Lower:         convert.Int64ToBytes(200),
 					IncludesLower: true,
@@ -136,7 +136,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan in [lower, undefined)  and sort in asc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_ASC,
+				orderType: modelv1.Sort_SORT_ASC,
 				termRange: index.RangeOpts{
 					Lower:         convert.Int64ToBytes(200),
 					IncludesLower: true,
@@ -148,7 +148,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan in [lower, undefined) and sort in desc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_DESC,
+				orderType: modelv1.Sort_SORT_DESC,
 				termRange: index.RangeOpts{
 					Lower:         convert.Int64ToBytes(200),
 					IncludesLower: true,
@@ -160,7 +160,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan in (undefined, upper] and sort in asc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_ASC,
+				orderType: modelv1.Sort_SORT_ASC,
 				termRange: index.RangeOpts{
 					Upper:         convert.Int64ToBytes(1000),
 					IncludesUpper: true,
@@ -172,7 +172,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan in (undefined, upper] and sort in desc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_DESC,
+				orderType: modelv1.Sort_SORT_DESC,
 				termRange: index.RangeOpts{
 					Upper:         convert.Int64ToBytes(1000),
 					IncludesUpper: true,
@@ -184,7 +184,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan splice in (lower, upper) and sort in asc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_ASC,
+				orderType: modelv1.Sort_SORT_ASC,
 				termRange: index.RangeOpts{
 					Lower: convert.Int64ToBytes(50 + 100),
 					Upper: convert.Int64ToBytes(2000 - 100),
@@ -196,7 +196,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan splice in (lower, upper) and sort in desc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_DESC,
+				orderType: modelv1.Sort_SORT_DESC,
 				termRange: index.RangeOpts{
 					Lower: convert.Int64ToBytes(50 + 100),
 					Upper: convert.Int64ToBytes(2000 - 100),
@@ -208,7 +208,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan splice in [lower, upper] and sort in asc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_ASC,
+				orderType: modelv1.Sort_SORT_ASC,
 				termRange: index.RangeOpts{
 					Lower:         convert.Int64ToBytes(50 + 100),
 					IncludesLower: true,
@@ -222,7 +222,7 @@ func RunDuration(t *testing.T, data map[int]posting.List, store SimpleStore) {
 			name: "scan splice in [lower, upper] and sort in desc order",
 			args: args{
 				fieldKey:  duration,
-				orderType: modelv1.QueryOrder_SORT_DESC,
+				orderType: modelv1.Sort_SORT_DESC,
 				termRange: index.RangeOpts{
 					Lower:         convert.Int64ToBytes(50 + 100),
 					IncludesLower: true,
diff --git a/pkg/pb/v1/query.go b/pkg/pb/v1/query.go
index e8b8c9a..d66e0f3 100644
--- a/pkg/pb/v1/query.go
+++ b/pkg/pb/v1/query.go
@@ -48,7 +48,7 @@ type QueryRequestBuilder struct {
 func NewQueryRequestBuilder() *QueryRequestBuilder {
 	return &QueryRequestBuilder{
 		ec: &streamv1.QueryRequest{
-			Projection: &modelv1.Projection{},
+			Projection: &modelv1.TagProjection{},
 		},
 	}
 }
@@ -86,7 +86,7 @@ func (b *QueryRequestBuilder) FieldsInTagFamily(tagFamilyName string, items ...i
 		}
 	}
 
-	b.ec.Criteria = append(b.ec.Criteria, &streamv1.QueryRequest_Criteria{
+	b.ec.Criteria = append(b.ec.Criteria, &modelv1.Criteria{
 		TagFamilyName: tagFamilyName,
 		Conditions:    criteriaConditions,
 	})
@@ -149,14 +149,14 @@ func buildTagValue(value interface{}) *modelv1.TagValue {
 }
 
 func (b *QueryRequestBuilder) Projection(tagFamily string, projections ...string) *QueryRequestBuilder {
-	b.ec.Projection.TagFamilies = append(b.ec.Projection.GetTagFamilies(), &modelv1.Projection_TagFamily{
+	b.ec.Projection.TagFamilies = append(b.ec.Projection.GetTagFamilies(), &modelv1.TagProjection_TagFamily{
 		Name: tagFamily,
 		Tags: projections,
 	})
 	return b
 }
 
-func (b *QueryRequestBuilder) OrderBy(indexRuleName string, sort modelv1.QueryOrder_Sort) *QueryRequestBuilder {
+func (b *QueryRequestBuilder) OrderBy(indexRuleName string, sort modelv1.Sort) *QueryRequestBuilder {
 	b.ec.OrderBy = &modelv1.QueryOrder{
 		IndexRuleName: indexRuleName,
 		Sort:          sort,
diff --git a/pkg/query/logical/analyzer_test.go b/pkg/query/logical/analyzer_test.go
index e6616af..58cdb8c 100644
--- a/pkg/query/logical/analyzer_test.go
+++ b/pkg/query/logical/analyzer_test.go
@@ -123,7 +123,7 @@ func TestAnalyzer_ComplexQuery(t *testing.T) {
 	criteria := pb.NewQueryRequestBuilder().
 		Limit(5).
 		Offset(10).
-		OrderBy("duration", modelv1.QueryOrder_SORT_DESC).
+		OrderBy("duration", modelv1.Sort_SORT_DESC).
 		Metadata("default", "sw").
 		Projection("searchable", "http.method", "service_id", "duration").
 		FieldsInTagFamily("searchable", "service_id", "=", "my_app", "http.method", "=", "GET", "mq.topic", "=", "event_topic").
@@ -146,7 +146,7 @@ func TestAnalyzer_ComplexQuery(t *testing.T) {
 					logical.Eq(logical.NewSearchableFieldRef("mq.topic"), logical.Str("event_topic")),
 					logical.Eq(logical.NewSearchableFieldRef("http.method"), logical.Str("GET")),
 				}, tsdb.Entity{tsdb.Entry("my_app"), tsdb.AnyEntry, tsdb.AnyEntry},
-				logical.OrderBy("duration", modelv1.QueryOrder_SORT_DESC),
+				logical.OrderBy("duration", modelv1.Sort_SORT_DESC),
 				logical.NewTags("searchable", "http.method", "service_id", "duration")),
 			10),
 		5).
@@ -201,7 +201,7 @@ func TestAnalyzer_OrderBy_IndexNotDefined(t *testing.T) {
 	criteria := pb.NewQueryRequestBuilder().
 		Limit(5).
 		Offset(10).
-		OrderBy("service_instance_id", modelv1.QueryOrder_SORT_DESC).
+		OrderBy("service_instance_id", modelv1.Sort_SORT_DESC).
 		Metadata("default", "sw").
 		Projection("searchable", "trace_id", "service_id").
 		FieldsInTagFamily("searchable", "duration", ">", 500).
@@ -228,7 +228,7 @@ func TestAnalyzer_OrderBy_FieldNotDefined(t *testing.T) {
 	criteria := pb.NewQueryRequestBuilder().
 		Limit(5).
 		Offset(10).
-		OrderBy("duration2", modelv1.QueryOrder_SORT_DESC).
+		OrderBy("duration2", modelv1.Sort_SORT_DESC).
 		Metadata("default", "sw").
 		Projection("searchable", "trace_id", "service_id").
 		TimeRange(time.Now().Add(-3*time.Hour), time.Now()).
@@ -254,7 +254,7 @@ func TestAnalyzer_Projection_FieldNotDefined(t *testing.T) {
 	criteria := pb.NewQueryRequestBuilder().
 		Limit(5).
 		Offset(10).
-		OrderBy("duration", modelv1.QueryOrder_SORT_DESC).
+		OrderBy("duration", modelv1.Sort_SORT_DESC).
 		Metadata("default", "sw").
 		Projection("searchable", "duration", "service_id", "unknown").
 		TimeRange(time.Now().Add(-3*time.Hour), time.Now()).
diff --git a/pkg/query/logical/common.go b/pkg/query/logical/common.go
index fee6638..bacb9a1 100644
--- a/pkg/query/logical/common.go
+++ b/pkg/query/logical/common.go
@@ -30,10 +30,10 @@ type (
 	comparator    func(a, b tsdb.Item) bool
 )
 
-func createComparator(sortDirection modelv1.QueryOrder_Sort) comparator {
+func createComparator(sortDirection modelv1.Sort) comparator {
 	return func(a, b tsdb.Item) bool {
 		comp := bytes.Compare(a.SortedField(), b.SortedField())
-		if sortDirection == modelv1.QueryOrder_SORT_DESC {
+		if sortDirection == modelv1.Sort_SORT_DESC {
 			return comp == 1
 		}
 		return comp == -1
diff --git a/pkg/query/logical/plan_execution_test.go b/pkg/query/logical/plan_execution_test.go
index 71450e5..debd715 100644
--- a/pkg/query/logical/plan_execution_test.go
+++ b/pkg/query/logical/plan_execution_test.go
@@ -82,7 +82,7 @@ func TestPlanExecution_TableScan_Limit(t *testing.T) {
 			entities, err := plan.Execute(streamSvc)
 			tester.NoError(err)
 			tester.Len(entities, tt.wantLength)
-			tester.True(logical.SortedByTimestamp(entities, modelv1.QueryOrder_SORT_ASC))
+			tester.True(logical.SortedByTimestamp(entities, modelv1.Sort_SORT_ASC))
 		})
 	}
 }
@@ -316,7 +316,7 @@ func TestPlanExecution_OrderBy(t *testing.T) {
 	tests := []struct {
 		name            string
 		targetIndexRule string
-		sortDirection   modelv1.QueryOrder_Sort
+		sortDirection   modelv1.Sort
 		// TODO: avoid hardcoded index?
 		targetFamilyIdx int
 		targetTagIdx    int
@@ -324,26 +324,26 @@ func TestPlanExecution_OrderBy(t *testing.T) {
 		{
 			name:            "Sort By duration ASC",
 			targetIndexRule: "duration",
-			sortDirection:   modelv1.QueryOrder_SORT_ASC,
+			sortDirection:   modelv1.Sort_SORT_ASC,
 			targetFamilyIdx: 0,
 			targetTagIdx:    0,
 		},
 		{
 			name:            "Sort By duration DESC",
 			targetIndexRule: "duration",
-			sortDirection:   modelv1.QueryOrder_SORT_DESC,
+			sortDirection:   modelv1.Sort_SORT_DESC,
 			targetFamilyIdx: 0,
 			targetTagIdx:    0,
 		},
 		{
 			name:            "Sort By start_time DESC",
 			targetIndexRule: "",
-			sortDirection:   modelv1.QueryOrder_SORT_DESC,
+			sortDirection:   modelv1.Sort_SORT_DESC,
 		},
 		{
 			name:            "Sort By start_time ASC",
 			targetIndexRule: "",
-			sortDirection:   modelv1.QueryOrder_SORT_ASC,
+			sortDirection:   modelv1.Sort_SORT_ASC,
 		},
 	}
 
diff --git a/pkg/query/logical/plan_orderby.go b/pkg/query/logical/plan_orderby.go
index 42597fe..9cfec41 100644
--- a/pkg/query/logical/plan_orderby.go
+++ b/pkg/query/logical/plan_orderby.go
@@ -31,7 +31,7 @@ import (
 )
 
 type UnresolvedOrderBy struct {
-	sort                modelv1.QueryOrder_Sort
+	sort                modelv1.Sort
 	targetIndexRuleName string
 }
 
@@ -39,7 +39,7 @@ func (u *UnresolvedOrderBy) analyze(s Schema) (*orderBy, error) {
 	if u == nil {
 		// return a default orderBy sub-plan
 		return &orderBy{
-			sort: modelv1.QueryOrder_SORT_UNSPECIFIED,
+			sort: modelv1.Sort_SORT_UNSPECIFIED,
 		}, nil
 	}
 
@@ -72,7 +72,7 @@ type orderBy struct {
 	// It can be null since by default we may sort by created-time.
 	index *databasev1.IndexRule
 	// while orderBySort describes the sort direction
-	sort modelv1.QueryOrder_Sort
+	sort modelv1.Sort
 	// TODO: support multiple tags. Currently only the first member will be used for sorting.
 	fieldRefs []*FieldRef
 }
@@ -96,7 +96,7 @@ func (o *orderBy) String() string {
 	return fmt.Sprintf("OrderBy: %v, sort=%s", o.index.GetTags(), o.sort.String())
 }
 
-func OrderBy(indexRuleName string, sort modelv1.QueryOrder_Sort) *UnresolvedOrderBy {
+func OrderBy(indexRuleName string, sort modelv1.Sort) *UnresolvedOrderBy {
 	return &UnresolvedOrderBy{
 		sort:                sort,
 		targetIndexRuleName: indexRuleName,
@@ -116,9 +116,9 @@ func getRawTagValue(typedPair *modelv1.Tag) ([]byte, error) {
 
 // SortedByIndex is used to test whether the given entities are sorted by the sortDirection
 // The given entities MUST satisfy both the positive check and the negative check for the reversed direction
-func SortedByIndex(elements []*streamv1.Element, tagFamilyIdx, tagIdx int, sortDirection modelv1.QueryOrder_Sort) bool {
-	if modelv1.QueryOrder_SORT_UNSPECIFIED == sortDirection {
-		sortDirection = modelv1.QueryOrder_SORT_ASC
+func SortedByIndex(elements []*streamv1.Element, tagFamilyIdx, tagIdx int, sortDirection modelv1.Sort) bool {
+	if modelv1.Sort_SORT_UNSPECIFIED == sortDirection {
+		sortDirection = modelv1.Sort_SORT_ASC
 	}
 	if len(elements) == 1 {
 		return true
@@ -127,9 +127,9 @@ func SortedByIndex(elements []*streamv1.Element, tagFamilyIdx, tagIdx int, sortD
 		!sort.SliceIsSorted(elements, sortByIndex(elements, tagFamilyIdx, tagIdx, reverseSortDirection(sortDirection)))
 }
 
-func SortedByTimestamp(elements []*streamv1.Element, sortDirection modelv1.QueryOrder_Sort) bool {
-	if modelv1.QueryOrder_SORT_UNSPECIFIED == sortDirection {
-		sortDirection = modelv1.QueryOrder_SORT_ASC
+func SortedByTimestamp(elements []*streamv1.Element, sortDirection modelv1.Sort) bool {
+	if modelv1.Sort_SORT_UNSPECIFIED == sortDirection {
+		sortDirection = modelv1.Sort_SORT_ASC
 	}
 	if len(elements) == 1 {
 		return true
@@ -138,32 +138,32 @@ func SortedByTimestamp(elements []*streamv1.Element, sortDirection modelv1.Query
 		!sort.SliceIsSorted(elements, sortByTimestamp(elements, reverseSortDirection(sortDirection)))
 }
 
-func reverseSortDirection(sort modelv1.QueryOrder_Sort) modelv1.QueryOrder_Sort {
-	if sort == modelv1.QueryOrder_SORT_DESC {
-		return modelv1.QueryOrder_SORT_ASC
+func reverseSortDirection(sort modelv1.Sort) modelv1.Sort {
+	if sort == modelv1.Sort_SORT_DESC {
+		return modelv1.Sort_SORT_ASC
 	}
-	return modelv1.QueryOrder_SORT_DESC
+	return modelv1.Sort_SORT_DESC
 }
 
-func sortByIndex(entities []*streamv1.Element, tagFamilyIdx, tagIdx int, sortDirection modelv1.QueryOrder_Sort) func(i, j int) bool {
+func sortByIndex(entities []*streamv1.Element, tagFamilyIdx, tagIdx int, sortDirection modelv1.Sort) func(i, j int) bool {
 	return func(i, j int) bool {
 		iPair := entities[i].GetTagFamilies()[tagFamilyIdx].GetTags()[tagIdx]
 		jPair := entities[j].GetTagFamilies()[tagFamilyIdx].GetTags()[tagIdx]
 		lField, _ := getRawTagValue(iPair)
 		rField, _ := getRawTagValue(jPair)
 		comp := bytes.Compare(lField, rField)
-		if sortDirection == modelv1.QueryOrder_SORT_ASC {
+		if sortDirection == modelv1.Sort_SORT_ASC {
 			return comp == -1
 		}
 		return comp == 1
 	}
 }
 
-func sortByTimestamp(entities []*streamv1.Element, sortDirection modelv1.QueryOrder_Sort) func(i, j int) bool {
+func sortByTimestamp(entities []*streamv1.Element, sortDirection modelv1.Sort) func(i, j int) bool {
 	return func(i, j int) bool {
 		iPair := entities[i].GetTimestamp().AsTime().UnixNano()
 		jPair := entities[j].GetTimestamp().AsTime().UnixNano()
-		if sortDirection == modelv1.QueryOrder_SORT_DESC {
+		if sortDirection == modelv1.Sort_SORT_DESC {
 			return iPair > jPair
 		}
 		return iPair < jPair
diff --git a/pkg/query/logical/schema.go b/pkg/query/logical/schema.go
index bd50a15..597beb4 100644
--- a/pkg/query/logical/schema.go
+++ b/pkg/query/logical/schema.go
@@ -172,5 +172,5 @@ func (s *schema) Proj(refs ...[]*FieldRef) Schema {
 }
 
 func (s *schema) ShardNumber() uint32 {
-	return s.stream.ShardNum
+	return s.stream.GetOpts().GetShardNum()
 }
diff --git a/pkg/test/testdata/stream.json b/pkg/test/testdata/stream.json
index 41b3b52..d4f9df9 100644
--- a/pkg/test/testdata/stream.json
+++ b/pkg/test/testdata/stream.json
@@ -82,10 +82,12 @@
       "state"
     ]
   },
-  "shard_num": 2,
-  "duration": {
-    "val": 7,
-    "unit": "DURATION_UNIT_DAY"
+  "opts": {
+    "shard_num": 2,
+    "ttl": {
+      "val": 7,
+      "unit": "DURATION_UNIT_DAY"
+    }
   },
-  "updated_at": "2021-04-15T01:30:15.01Z"
+  "updated_at_nanoseconds": "2021-04-15T01:30:15.01Z"
 }
\ No newline at end of file