-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
perf: Initially trim leading and trailing filtered rows #19850
perf: Initially trim leading and trailing filtered rows #19850
Conversation
This adds a small step before doing a `filter` and trims away the leading and trailing filtered rows. This cost us practically nothing in the cases where there are no items to trim and saves massively where it can trim items. This is for example in cases where we are filtering by at least one sorted column. Here is a code snippet to show the effectiveness. Before, it had to copy the memory and go into the filter loop. Now, it can just take the fast path. This also holds for sorted columns which is where I think most of the performance will come from. ```python import numpy as np import polars as pl import os from timeit import timeit SIZE = 10_000_000 os.environ['POLARS_MAX_THREADS'] = '1' df = pl.DataFrame([ pl.Series('f', sum(([i] * (SIZE // 10) for i in range(10)), []), pl.Int32), ] + [ pl.Series(f'data{i}', np.random.randint(0, 500, SIZE), pl.Int64) for i in range(100) ]) t = timeit(lambda: df.filter(pl.col.f == 5), number=10) print(f"{t}s") ``` ```console Before: 1.1825743649969809s After: 0.07909882599778939s ```
Wow! Great idea. And basically free indeed. |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #19850 +/- ##
==========================================
+ Coverage 79.37% 79.40% +0.02%
==========================================
Files 1550 1550
Lines 214743 214826 +83
Branches 2460 2447 -13
==========================================
+ Hits 170457 170575 +118
+ Misses 43727 43694 -33
+ Partials 559 557 -2 ☔ View full report in Codecov by Sentry. 🚨 Try these New Features:
|
// is very minimal: only a clone of the mask and the array. | ||
// | ||
// This also allows dispatching to the fast paths way, way, way more often. | ||
let mut mask = mask.clone(); |
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.
Maybe we should do this one line 51? After the full and empty check.
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.
No the effectiveness stems exactly from doing it before. If we trim to an exact full or empty block, we can take the fast path.
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.
Ah, right. 👍
This adds a small step before doing a
filter
and trims away the leading and trailing filtered rows. This cost us practically nothing in the cases where there are no items to trim and saves massively where it can trim items. This is for example in cases where we are filtering by at least one sorted column.Here is a code snippet to show the effectiveness. Before, it had to copy the memory and go into the filter loop. Now, it can just take the fast path. This also holds for sorted columns which is where I think most of the performance will come from.