-
Notifications
You must be signed in to change notification settings - Fork 37
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
Implement searchv2 #3058
Comments
Caveat: creating a cursor from merged values can be non-trivial if attribute is not included into the requested list. It can be degraded to a simple OID then (complicating continuation somewhat) and in general most of use cases do need attribute values, but still. |
Caveat 2: numeric values might require an additional prefix anyway since we can have |
note: |
Yes, we need to limit changes to this specific feature (expose API as early as possible) and deal with associated meta code (GC and alike) in future. Search is still possible with multiple DBs since results can be merged similar to the way results from different nodes are merged. |
choice is obvious for system fields. For example, owner ID is a string while payload size is an integer for user-defined attributes it is not so obvious. Like here #3058 (comment). In current protocol, there is no way to determine whether user attribute is numeric or not. So, I rly doubt storing them in various formats is legit. But we can resolve this on search query processing. In original search, any non-integer attribute mismatches any numeric query. Do we wanna change this behaviour for SearchV2 somehow? @roman-khimov u also mentioned some special prefix, could u pls elaborate on this thought? |
You can only do this content-based, just like you do this now for old search. The only difference is that the choice is made when processing the object instead of when processing the search request. Special prefix means splitting PREFIXB into B1 and B2 for numeric and string data. |
shouldnt cursor be OID + values of requested attributes to sort/continue in PREFIXC in this case? UPD: seems like no, missed this requirement https://github.com/nspcc-dev/neofs-api/blob/9f1f12866a4742adb7778c51bd632cd240f81262/object/service.proto#L554-L555 |
i'd like to clarify primary seek in proposed algo. Consider objects:
where request: first resp: on 2nd request, we position to this example shows that primary one more nuance if last resp was |
Correct. We have two options here:
Our primary use cases for now:
Secondary attribute order does have some advantages for the REST/S3 cases. But to be fair both would benefit a bit more from the reverse order, since when we're talking about time stamps we usually need the latest and it's going to be the last. Implementing reverse result order is certainly not something we want now. We still need this to be simple and to be fast. Both REST and S3 cases are not very likely to produce a lot of results at the same time (very likely to fit into 1000 limit). So I'd opt for relaxing ordering requirements to be "primary attribute only". Easier to implement, will work good enough for current users. If we're to find other use cases we can think of (even more advanced) ordering again. |
full agree, lets start with this |
There is a need to serve `ObjectService.SearchV2` RPC by the SN. In order not to expand the structure and configuration of the node, the best place to store metadata is metabase. Metabases are extended with per-container object metadata buckets. For each object, following indexes are created: - OID; - attribute->OID; - OID->attribute. Integers are stored specifically to reach lexicographic comparisons without decoding. New `Search` method is provided: it allows to filter out container's objects and receive specified attributes. Count is also limited, op is paged via cursor. In other words, the method follows SearchV2 behavior within single metabase. Refs #3058.
There is a need to serve `ObjectService.SearchV2` RPC by the SN. In order not to expand the structure and configuration of the node, the best place to store metadata is metabase. Metabases are extended with per-container object metadata buckets. For each object, following indexes are created: - OID; - attribute->OID; - OID->attribute. Integers are stored specifically to reach lexicographic comparisons without decoding. New `Search` method is provided: it allows to filter out container's objects and receive specified attributes. Count is also limited, op is paged via cursor. In other words, the method follows SearchV2 behavior within single metabase. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Future use-cases: - merge results from several shard's metabases; - merge results from several SNs. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Future use-cases: - merge results from several shard's metabases; - merge results from several SNs. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
There is a need to serve `ObjectService.SearchV2` RPC by the SN. In order not to expand the structure and configuration of the node, the best place to store metadata is metabase. Metabases are extended with per-container object metadata buckets. For each object, following indexes are created: - OID; - attribute->OID; - OID->attribute. Integers are stored specifically to reach lexicographic comparisons without decoding. New `Search` method is provided: it allows to filter out container's objects and receive specified attributes. Count is also limited, op is paged via cursor. In other words, the method follows SearchV2 behavior within single metabase. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Future use-cases: - merge results from several shard's metabases; - merge results from several SNs. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
WIP Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
There is a need to serve `ObjectService.SearchV2` RPC by the SN. In order not to expand the structure and configuration of the node, the best place to store metadata is metabase. Metabases are extended with per-container object metadata buckets. For each object, following indexes are created: - OID; - attribute->OID; - OID->attribute. Integers are stored specifically to reach lexicographic comparisons without decoding. New `Search` method is provided: it allows to filter out container's objects and receive specified attributes. Count is also limited, op is paged via cursor. In other words, the method follows SearchV2 behavior within single metabase. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
There is a need to serve `ObjectService.SearchV2` RPC by the SN. In order not to expand the structure and configuration of the node, the best place to store metadata is metabase. Metabases are extended with per-container object metadata buckets. For each object, following indexes are created: - OID; - attribute->OID; - OID->attribute. Integers are stored specifically to reach lexicographic comparisons without decoding. New `Search` method is provided: it allows to filter out container's objects and receive specified attributes. Count is also limited, op is paged via cursor. In other words, the method follows SearchV2 behavior within single metabase. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
There is a need to serve `ObjectService.SearchV2` RPC by the SN. In order not to expand the structure and configuration of the node, the best place to store metadata is metabase. Metabases are extended with per-container object metadata buckets. For each object, following indexes are created: - OID; - attribute->OID; - OID->attribute. Integers are stored specifically to reach lexicographic comparisons without decoding. New `Search` method is provided: it allows to filter out container's objects and receive specified attributes. Count is also limited, op is paged via cursor. In other words, the method follows SearchV2 behavior within single metabase. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
There is a need to serve `ObjectService.SearchV2` RPC by the SN. In order not to expand the structure and configuration of the node, the best place to store metadata is metabase. Metabases are extended with per-container object metadata buckets. For each object, following indexes are created: - OID; - attribute->OID; - OID->attribute. Integers are stored specifically to reach lexicographic comparisons without decoding. New `Search` method is provided: it allows to filter out container's objects and receive specified attributes. Count is also limited, op is paged via cursor. In other words, the method follows SearchV2 behavior within single metabase. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
There is a need to serve `ObjectService.SearchV2` RPC by the SN. In order not to expand the structure and configuration of the node, the best place to store metadata is metabase. Metabases are extended with per-container object metadata buckets. For each object, following indexes are created: - OID; - attribute->OID; - OID->attribute. Integers are stored specifically to reach lexicographic comparisons without decoding. New `Search` method is provided: it allows to filter out container's objects and receive specified attributes. Count is also limited, op is paged via cursor. In other words, the method follows SearchV2 behavior within single metabase. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Single field of the returned struct is used, so this refactors the method and cursor re-calculation func to return this field only. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
With this, it'll be easier to tune the behavior according to the primary attribute. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Binary and string representation of some attributes differ. When sorting a search result, the metabase compares the binary format. When merging responses from multiple nodes, string sorting is used. For all user attributes, this is essentially the same. However, for some system ones, this is not the case. For example, object IDs and owners are base58btc strings which do not preserve byte order. Now sorting at metabase and merging server levels are synchronized, and disorder is fixed. Fixes #3160. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Previously, since attributes were stored in PREFIX_KEY_DELIM_VAL_OID format, the lexicographic order of values could be violated. For example, if two objects had the same attribute with values '1' and '1a', and the 1st one had OID starting from byte > 'a', they were stored in the meta bucket in reverse order. Keeping natural order is essential for the DB iterator's effectiveness for sorted SearchV2. This extends storage scheme with zero byte delimiter b/w VAL and OID. It can be a delimiter since none VAL can include it. At the same time, it preserves the order and resolves mentioned problem. The original separator was 0xFF as an invalid UTF-8 the 0xFF byte was banned. In order not to have two different separators, KEY and VAL are now also separated by 0x00. Any attempt to write metadata with a zero byte in the attributes will now fail. Although with 6f9647e such an object cannot come from the upper-level object service, relying only on it is risky: migration already works without it, and the metadata limits are critical to the SearchV2 provision. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Previously, since attributes were stored in PREFIX_KEY_DELIM_VAL_OID format, the lexicographic order of values could be violated. For example, if two objects had the same attribute with values '1' and '1a', and the 1st one had OID starting from byte > 'a', they were stored in the meta bucket in reverse order. Keeping natural order is essential for the DB iterator's effectiveness for sorted SearchV2. This extends storage scheme with zero byte delimiter b/w VAL and OID. It can be a delimiter since none VAL can include it. At the same time, it preserves the order and resolves mentioned problem. The original separator was 0xFF as an invalid UTF-8 the 0xFF byte was banned. In order not to have two different separators, KEY and VAL are now also separated by 0x00. Any attempt to write metadata with a zero byte in the attributes will now fail. Although with 6f9647e such an object cannot come from the upper-level object service, relying only on it is risky: migration already works without it, and the metadata limits are critical to the SearchV2 provision. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Previously, `SearchV2` RPC server responded with the deepest Go error message in the status message. To achieve this, the server made `errors .Unwrap` to the lowest level. This approach was reused from other API calls, so it brought up the same shortcomings to new search. For example, CLI user could face following error: ``` rpc error: status: code = 1024 message = illegal base64 data at input byte 4 ``` and only imagine which part of the request processing is an invalid Base64. This cancels error unwrapping for `SearchV2`, making it to respond with: ``` rpc error: status: code = 1024 message = invalid cursor: decode cursor from Base64: illegal base64 data at input byte 0 ``` instead. Note that previously existed RPCs are untouched to avoid system destabilization. They will be considered separately. Refs #2744. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Single field of the returned struct is used, so this refactors the method and cursor re-calculation func to return this field only. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Starting from 8f593f9, any iterator over meta bucket elements is done in ascending order. Since cursor requests start traversing _after_ the last element, comparing subsequent matching elements against it or each other is no longer needed. One more bonus is that we no longer need to cache matching keys in slice. Closes #3153. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
When attributes are not requested, simple OID traverse should be performed. Previously the behavior was determined according to the primary filter only. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Single field of the returned struct is used, so this refactors the method and cursor re-calculation func to return this field only. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Starting from 8f593f9, any iterator over meta bucket elements is done in ascending order. Since cursor requests start traversing _after_ the last element, comparing subsequent matching elements against it or each other is no longer needed. One more bonus is that we no longer need to cache matching keys in slice. Closes #3153. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Primary filters are applied to sorted meta bucket's elements. This allows us to speed up execution when we reached mismatch at some point: - for EQ/PREFIX/LT/LE/GE matchers, any next item will definitely fail; - for GT matcher, any next item will definitely fail if some previous element matched. Now the meta bucket iterator breaks when the mentioned conditions are reached. This speeds up the processing of most search queries, especially as the number of objects increases. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Starting from 8f593f9, any iterator over meta bucket elements is done in ascending order. Since cursor requests start traversing _after_ the last element, comparing subsequent matching elements against it or each other is no longer needed. One more bonus is that we no longer need to cache matching keys in slice. Closes #3153. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Primary filters are applied to sorted meta bucket's elements. This allows us to speed up execution when we reached mismatch at some point: - for EQ/PREFIX/LT/LE/GE matchers, any next item will definitely fail; - for GT matcher, any next item will definitely fail if some previous element matched. Now the meta bucket iterator breaks when the mentioned conditions are reached. This speeds up the processing of most search queries, especially as the number of objects increases. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Primary filters are applied to sorted meta bucket's elements. This allows us to speed up execution when we reached mismatch at some point: - for EQ/PREFIX/LT/LE/GE matchers, any next item will definitely fail; - for GT matcher, any next item will definitely fail if some previous element matched. Now the meta bucket iterator breaks when the mentioned conditions are reached. This speeds up the processing of most search queries, especially as the number of objects increases. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
When attributes are not requested, simple OID traverse should be performed. Previously the behavior was determined according to the primary filter only. This also extends unit test coverage. Cursors are tested deeper. Many tests failed revealing implementation bugs fixed here, mainly ordering. A lot of code has been deduplicated also. Refs #3160. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Single field of the returned struct is used, so this refactors the method and cursor re-calculation func to return this field only. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Starting from 8f593f9, any iterator over meta bucket elements is done in ascending order. Since cursor requests start traversing _after_ the last element, comparing subsequent matching elements against it or each other is no longer needed. One more bonus is that we no longer need to cache matching keys in slice. Closes #3153. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Primary filters are applied to sorted meta bucket's elements. This allows us to speed up execution when we reached mismatch at some point: - for EQ/PREFIX/LT/LE/GE matchers, any next item will definitely fail; - for GT matcher, any next item will definitely fail if some previous element matched. Now the meta bucket iterator breaks when the mentioned conditions are reached. This speeds up the processing of most search queries, especially as the number of objects increases. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
When attributes are not requested, simple OID traverse should be performed. Previously the behavior was determined according to the primary filter only. This also extends unit test coverage. Cursors are tested deeper. Many tests failed revealing implementation bugs fixed here, mainly ordering. A lot of code has been deduplicated also. Refs #3160. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Single field of the returned struct is used, so this refactors the method and cursor re-calculation func to return this field only. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Starting from 8f593f9, any iterator over meta bucket elements is done in ascending order. Since cursor requests start traversing _after_ the last element, comparing subsequent matching elements against it or each other is no longer needed. One more bonus is that we no longer need to cache matching keys in slice. Closes #3153. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Primary filters are applied to sorted meta bucket's elements. This allows us to speed up execution when we reached mismatch at some point: - for EQ/PREFIX/LT/LE/GE matchers, any next item will definitely fail; - for GT matcher, any next item will definitely fail if some previous element matched. Now the meta bucket iterator breaks when the mentioned conditions are reached. This speeds up the processing of most search queries, especially as the number of objects increases. Refs #3058. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Is your feature request related to a problem? Please describe.
I'm always frustrated when we don't have an implementation for nspcc-dev/neofs-api#314.
Describe the solution you'd like
The per-container DB should be structured like:
The mechanics is:
Each node does the following:
key>N && key <M
), this can shortcut the search more quickly for numericsDescribe alternatives you've considered
SQL, various other types of DBs. But the scheme above should be sufficient for our primary cases now.
Additional context
#2990, #2757, #2989, nspcc-dev/neofs-api#306
The text was updated successfully, but these errors were encountered: