-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Secondary index reader #829
Conversation
6b78318
to
5d5a089
Compare
} | ||
} | ||
|
||
// TODO: I think this might need to be changed, we should only support search on the search endpoint | ||
if options.filter.None() || !options.filter.IsIndexed() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still support search as a reader option or should it only be part of the search API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reader option is internal to us but to answer your question, yes we need to support it till we backfill the secondary indexes and point the read queries to start using secondary indexes. Then it will only be Search.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created issue #869 for this
5d5a089
to
7a925db
Compare
7a925db
to
d7051f1
Compare
server/config/options.go
Outdated
@@ -226,8 +226,8 @@ var DefaultConfig = Config{ | |||
WriteEnabled: true, | |||
}, | |||
SecondaryIndex: SecondaryIndexConfig{ | |||
ReadEnabled: false, | |||
WriteEnabled: false, | |||
ReadEnabled: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's not enable it in the config yet.
} | ||
} | ||
|
||
// TODO: I think this might need to be changed, we should only support search on the search endpoint | ||
if options.filter.None() || !options.filter.IsIndexed() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reader option is internal to us but to answer your question, yes we need to support it till we backfill the secondary indexes and point the read queries to start using secondary indexes. Then it will only be Search.
eqPlan, err := eqKeyBuilder.Build(queryFilters, coll.QueryableFields) | ||
if err == nil { | ||
for _, plan := range eqPlan { | ||
if indexedDataType(plan) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it is equality and the plan is not index type what is the behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can happen if the field is a []byte
. Then the plan is ignored and we look for another eq
plan or move to range plans
@@ -121,56 +226,176 @@ func (s *StrictEqKeyComposer) Compose(selectors []*Selector, userDefinedKeys []* | |||
} | |||
|
|||
if len(repeatedFields) == 0 { | |||
// nothing found or a gap | |||
return nil, errors.InvalidArgument("filters doesn't contains primary key fields") | |||
if s.matchAll { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this will go away once we move to secondary indexes because then it doesn't matter if we are able to build the primary key from the filter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that will be awesome. I've created #870 to remember to do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great
} | ||
|
||
// Prefer a RANGE scan which should read back less keys than a FULLRANGE | ||
// for _, queryType := range []filter.QueryPlanType{filter.RANGE, filter.FULLRANGE} { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove it if not needed.
// Range Key Composer will generate a range key set on the user defined keys | ||
// It will set the KeyQuery to `FullRange` if the start or end key is not defined in the query | ||
// if there is a defined start and end key for a range then `Range` is set. | ||
type RangeKeyComposer[F fieldable] struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this diff, the structure is good. But if we think about it, we just need two high level abstractions here,
NewQueryableKeyBuilder(composer, primaryKey)
[will be used by insert/replace only]NewQueryableKeyBuilder()
: This will internally use eq/range composer to build plans i.e. equality as well as range. The reason being once we don't rely on the search store then either the plan is formed or we need to fall back to full table scan, there will be no other option. ThenRead/Update/Delete
can rely directly on it. This means we need to add something to the QueryPlan so that caller knows whether the keys are for primary or secondary indexes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I like it. We can definitely move to that direction once search and secondary are ready.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sg
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback. I've made the changes.
} | ||
|
||
// NewPrimaryKeyEQBuild returns a KeyBuilder for use with schema.Field to build a primary key query plan. | ||
func NewPrimaryKeyEqBuilder(keyEncodingFunc KeyEncodingFunc) *KeyBuilder[*schema.Field] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could do that a little later once secondary indexes are deployed. At the moment we have to pass some extra params if it is a PrimaryKey versus secondary.
@@ -121,56 +226,176 @@ func (s *StrictEqKeyComposer) Compose(selectors []*Selector, userDefinedKeys []* | |||
} | |||
|
|||
if len(repeatedFields) == 0 { | |||
// nothing found or a gap | |||
return nil, errors.InvalidArgument("filters doesn't contains primary key fields") | |||
if s.matchAll { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that will be awesome. I've created #870 to remember to do this.
// Range Key Composer will generate a range key set on the user defined keys | ||
// It will set the KeyQuery to `FullRange` if the start or end key is not defined in the query | ||
// if there is a defined start and end key for a range then `Range` is set. | ||
type RangeKeyComposer[F fieldable] struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I like it. We can definitely move to that direction once search and secondary are ready.
eqPlan, err := eqKeyBuilder.Build(queryFilters, coll.QueryableFields) | ||
if err == nil { | ||
for _, plan := range eqPlan { | ||
if indexedDataType(plan) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can happen if the field is a []byte
. Then the plan is ignored and we look for another eq
plan or move to range plans
0eb65ee
to
2726177
Compare
@@ -303,6 +316,12 @@ func buildValueMatcher(input jsoniter.RawMessage, field *schema.QueryableField) | |||
return nil, nil, err | |||
} | |||
collation = value.NewCollationFrom(apiCollation) | |||
|
|||
if buildForSecondaryIndex && collation.IsCaseInsensitive() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we won't be supporting case-insensitive queries on secondary indexes fields?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can support it in the in-memory filter part but not part of what we use to build the range keys. Or at least I can't think of a way of making that work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, we can figure it out iteratively.
0896d17
to
74869e7
Compare
Supports $eq, $lt, $lte, $gt and $gte queries from the secondary index. The secondary index can be used for reads, updates and deletes.
74869e7
to
76374a1
Compare
🎉 This PR is included in version 1.0.0-beta.46 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Describe your changes
Secondary Index reader that queries from the secondary index.
How best to test these changes
Issue ticket number and link