[SERVER-39567] Query with min/max modifier uses hashed index Created: 13/Feb/19 Updated: 29/Oct/23 Resolved: 12/Apr/19 |
|
| Status: | Closed |
| Project: | Core Server |
| Component/s: | Querying |
| Affects Version/s: | 4.0.4 |
| Fix Version/s: | 4.1.11 |
| Type: | Bug | Priority: | Critical - P2 |
| Reporter: | Artem | Assignee: | Ian Boros |
| Resolution: | Fixed | Votes: | 2 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Issue Links: |
|
|||||||||||||||||||||||||||||||||||
| Backwards Compatibility: | Minor Change | |||||||||||||||||||||||||||||||||||
| Operating System: | ALL | |||||||||||||||||||||||||||||||||||
| Steps To Reproduce: |
|
|||||||||||||||||||||||||||||||||||
| Sprint: | Query 2019-04-22 | |||||||||||||||||||||||||||||||||||
| Participants: | ||||||||||||||||||||||||||||||||||||
| Description |
| Comments |
| Comment by Githook User [ 11/Apr/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Author: {'name': 'Ian Boros', 'username': 'puppyofkosh', 'email': 'puppyofkosh@gmail.com'}Message: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Artem [ 07/Mar/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Interesting trick, but it don't solve pagination issue:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Asya Kamsky [ 07/Mar/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Continuing on capabilities of $expr and aggregation semantics, regarding your use case 2 > sort after tuple need really complex expression
You can achieve that with $expr as this (if sorting on a, b, c):
This is if the last values on the last page are 1, 1, "20". Full example:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Asya Kamsky [ 07/Mar/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
bozaro please note that in aggregation expressions, there is no type bracketing and therefore if you use aggregation
As of 3.6 you can achieve aggregation semantics in find via $expr syntax. I understand the current workaround providing a hint is working for you, but I'm mentioning the aggregation semantics for completeness. I believe it should work the way you describe your use case, but let us know if it would not. I do want to mention that since indexes serve queries with type bracketing semantics, using $expr for $gt/$lt expressions will not use the index in order to get correct complete results. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Artem [ 07/Mar/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Actually we use `min()`/`max()` as very ugly workaround. Originally we need simple pagination feature, but we can't use `$gt`/`$gte`/`$lt`/`$lte` for this purpose:
Pagination workaround with `min()`/`max()` the only solution found, but:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Юрий Соколов [ 07/Mar/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
My friend demonstrated me that "range of partition hashes" works currently. I apologize. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Юрий Соколов [ 07/Mar/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sorry, I will be rude. Does min max currently work as "range of partition hashes" ? If not then why the hell you want it to work this way? Why you want to add almost meaningless excess semantic to simple thing and make it more complex for no reason? If some one really needs "range of partition hashes", then lets add it as a separate construction instead of everloading "min/max". | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by David Storch [ 06/Mar/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
asya and I spoke in person. We discussed two high-level alternatives for how to address this ticket:
We believe that option #2 is both easier to implement, and superior in that it doesn't remove any pre-existing functionality. With Asya's final approval, the future assignee of this ticket should implement fix #2 and request corresponding documentation changes. This should be part of the 4.2 compatibility notes, since users of min()/max() without hint() will have to add the hint() before upgrading to 4.2. I'm putting this ticket back into "Needs Scheduling" so that it can be triaged by the Query Team. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by David Storch [ 22/Feb/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
funny_falcon, thanks for the excellent issue report! Your workaround of using a hint() seems appropriate until this problem can be resolved on our end. Here is an even simpler demonstration of the issue:
The result set associated with the min() and max() operators currently depends on the type of index selected to answer the query. The easiest solution to this problem, as funny_falcon hinted at above, would be to make indices which store a function of the data ("hashed", "2d", "2dsphere", etc.) ineligible for servicing a min()/max() query. The one potential problem I see with this fix is that it would prevent users from issuing queries which specify ranges of hashes. Suppose, for example, that you wish to write application code which partitions your data into n roughly equal-size partitions (where the size is given by the number of documents in the partition). Also suppose that you want to partition your data by the field f. This could be achieved by building the index {f: "hashed"}, and then evenly dividing the space of hashes into n ranges. Where [imin, imax) denotes the range of hash values for the ith partition, the data in this partition would be returned by the query below:
Similarly, users would no longer be able to query by a range of geohashes for geospatial indices, but the use case for this seems much less compelling. Finally, min()/max() queries which specify hash or geohash ranges are useful for running queries that return the contents of particular chunks on a sharded system. Without min()/max() the query which would return only the contents of a chunk is not always expressible. asya, I'd like to discuss with you whether it would be acceptable to pursue the simple solution in which we prevent min()/max() from using a hashed or geospatial index. If we build this solution, would we have to give users a new way to express ranges of index keys directly? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Kelsey Schubert [ 13/Feb/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Thanks for the report and clear reproduction, bozaro, and for the initial investigation of the issue, funny_falcon. I can reproduce this behavior and we're looking into it. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Юрий Соколов [ 13/Feb/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
And second reason, CollectionBulkLoaderImpl::init initiates _id index after secondaries. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Юрий Соколов [ 13/Feb/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
4.0 and master branches looks to be both affected. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Юрий Соколов [ 13/Feb/19 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Looks like one of the bug's reasons is that indexCompatibleMaxMin doesn't skip INDEX_HASHED indexes. Probably it should skip all index types except INDEX_BTREE, not only INDEX_WILDCARD as in master. |