Skip to content
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

Skip DisiPriorityQueue on single filter agg #99215

Merged
merged 25 commits into from Sep 6, 2023
Merged

Conversation

kkrik-es
Copy link
Contributor

@kkrik-es kkrik-es commented Sep 6, 2023

When FiltersAggregator has a single filter, there is no benefit in using
a DisiPriorityQueue as the heap will only contain values from a single
iterator. In such a case, it's preferable to use the filtering
approximation iterator directly as competitive iterator.

Fixes #99202

kkrik-es and others added 22 commits August 10, 2023 19:04
The iterator is used to combine filtering with querying in leaf
collection. Its benefit is that rangers with docs that are filtered out
by all filters are skipped from doc collection.

The competitive iterator is restricted to FiltersAggregator, not used in
FilterByFilterAggregator that's already optimized. It only applies to
top-level filter aggregations with no "other" bucket defined; the latter
leads to collecting all docs so there's no point in skipping doc ranges.

Fixes elastic#97544
# Conflicts:
#	server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FiltersAggregator.java
When FiltersAggregator has a single filter, there is no benefit in using
a DisiPriorityQueue as the heap will only contain values from a single
iterator. In such a case, it's preferable to use the filtering
approximation iterator directly as competitive iterator.

Fixes elastic#99202
# Conflicts:
#	server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FiltersAggregator.java
@kkrik-es kkrik-es added >enhancement :Analytics/Aggregations Aggregations Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) v8.11.0 labels Sep 6, 2023
@elasticsearchmachine
Copy link
Collaborator

Hi @kkrik-es, I've created a changelog YAML for you.

@kkrik-es
Copy link
Contributor Author

kkrik-es commented Sep 6, 2023

Rally results on track [noaa], challenge [filter-aggs] look promising:

|                                                        Metric |                                      Task |         Baseline |        Contender |       Diff |   Unit |   Diff % |
|--------------------------------------------------------------:|------------------------------------------:|-----------------:|-----------------:|-----------:|-------:|---------:|
|                    Cumulative indexing time of primary shards |                                           |     15.778       |     15.6891      |   -0.08883 |    min |   -0.56% |
|             Min cumulative indexing time across primary shard |                                           |     15.778       |     15.6891      |   -0.08883 |    min |   -0.56% |
|          Median cumulative indexing time across primary shard |                                           |     15.778       |     15.6891      |   -0.08883 |    min |   -0.56% |
|             Max cumulative indexing time across primary shard |                                           |     15.778       |     15.6891      |   -0.08883 |    min |   -0.56% |
|           Cumulative indexing throttle time of primary shards |                                           |      0           |      0           |    0       |    min |    0.00% |
|    Min cumulative indexing throttle time across primary shard |                                           |      0           |      0           |    0       |    min |    0.00% |
| Median cumulative indexing throttle time across primary shard |                                           |      0           |      0           |    0       |    min |    0.00% |
|    Max cumulative indexing throttle time across primary shard |                                           |      0           |      0           |    0       |    min |    0.00% |
|                       Cumulative merge time of primary shards |                                           |      5.52327     |      5.71243     |    0.18917 |    min |   +3.42% |
|                      Cumulative merge count of primary shards |                                           |     42           |     42           |    0       |        |    0.00% |
|                Min cumulative merge time across primary shard |                                           |      5.52327     |      5.71243     |    0.18917 |    min |   +3.42% |
|             Median cumulative merge time across primary shard |                                           |      5.52327     |      5.71243     |    0.18917 |    min |   +3.42% |
|                Max cumulative merge time across primary shard |                                           |      5.52327     |      5.71243     |    0.18917 |    min |   +3.42% |
|              Cumulative merge throttle time of primary shards |                                           |      0.539583    |      0.6766      |    0.13702 |    min |  +25.39% |
|       Min cumulative merge throttle time across primary shard |                                           |      0.539583    |      0.6766      |    0.13702 |    min |  +25.39% |
|    Median cumulative merge throttle time across primary shard |                                           |      0.539583    |      0.6766      |    0.13702 |    min |  +25.39% |
|       Max cumulative merge throttle time across primary shard |                                           |      0.539583    |      0.6766      |    0.13702 |    min |  +25.39% |
|                     Cumulative refresh time of primary shards |                                           |      0.135583    |      0.146767    |    0.01118 |    min |   +8.25% |
|                    Cumulative refresh count of primary shards |                                           |     23           |     24           |    1       |        |   +4.35% |
|              Min cumulative refresh time across primary shard |                                           |      0.135583    |      0.146767    |    0.01118 |    min |   +8.25% |
|           Median cumulative refresh time across primary shard |                                           |      0.135583    |      0.146767    |    0.01118 |    min |   +8.25% |
|              Max cumulative refresh time across primary shard |                                           |      0.135583    |      0.146767    |    0.01118 |    min |   +8.25% |
|                       Cumulative flush time of primary shards |                                           |      0.138817    |      0.141633    |    0.00282 |    min |   +2.03% |
|                      Cumulative flush count of primary shards |                                           |      4           |      4           |    0       |        |    0.00% |
|                Min cumulative flush time across primary shard |                                           |      0.138817    |      0.141633    |    0.00282 |    min |   +2.03% |
|             Median cumulative flush time across primary shard |                                           |      0.138817    |      0.141633    |    0.00282 |    min |   +2.03% |
|                Max cumulative flush time across primary shard |                                           |      0.138817    |      0.141633    |    0.00282 |    min |   +2.03% |
|                                       Total Young Gen GC time |                                           |      6.861       |      6.913       |    0.052   |      s |   +0.76% |
|                                      Total Young Gen GC count |                                           |   2283           |   2317           |   34       |        |   +1.49% |
|                                         Total Old Gen GC time |                                           |      0           |      0           |    0       |      s |    0.00% |
|                                        Total Old Gen GC count |                                           |      0           |      0           |    0       |        |    0.00% |
|                                                    Store size |                                           |      8.08249     |      8.13524     |    0.05275 |     GB |   +0.65% |
|                                                 Translog size |                                           |      5.12227e-08 |      5.12227e-08 |    0       |     GB |    0.00% |
|                                        Heap used for segments |                                           |      0           |      0           |    0       |     MB |    0.00% |
|                                      Heap used for doc values |                                           |      0           |      0           |    0       |     MB |    0.00% |
|                                           Heap used for terms |                                           |      0           |      0           |    0       |     MB |    0.00% |
|                                           Heap used for norms |                                           |      0           |      0           |    0       |     MB |    0.00% |
|                                          Heap used for points |                                           |      0           |      0           |    0       |     MB |    0.00% |
|                                   Heap used for stored fields |                                           |      0           |      0           |    0       |     MB |    0.00% |
|                                                 Segment count |                                           |     28           |     26           |   -2       |        |   -7.14% |
|                                   Total Ingest Pipeline count |                                           |      0           |      0           |    0       |        |    0.00% |
|                                    Total Ingest Pipeline time |                                           |      0           |      0           |    0       |     ms |    0.00% |
|                                  Total Ingest Pipeline failed |                                           |      0           |      0           |    0       |        |    0.00% |
|                                                Min Throughput |                                     index | 102589           | 109468           | 6878.57    | docs/s |   +6.70% |
|                                               Mean Throughput |                                     index | 209532           | 210451           |  919.038   | docs/s |   +0.44% |
|                                             Median Throughput |                                     index | 218468           | 219513           | 1044.98    | docs/s |   +0.48% |
|                                                Max Throughput |                                     index | 223519           | 224742           | 1223.3     | docs/s |   +0.55% |
|                                       50th percentile latency |                                     index |    134.831       |    134.727       |   -0.10425 |     ms |   -0.08% |
|                                       90th percentile latency |                                     index |    175.833       |    173.495       |   -2.33823 |     ms |   -1.33% |
|                                       99th percentile latency |                                     index |    853.073       |    846.901       |   -6.17276 |     ms |   -0.72% |
|                                     99.9th percentile latency |                                     index |   1037.66        |   1021.17        |  -16.4914  |     ms |   -1.59% |
|                                      100th percentile latency |                                     index |   1372.16        |   1151.6         | -220.566   |     ms |  -16.07% |
|                                  50th percentile service time |                                     index |    134.831       |    134.727       |   -0.10425 |     ms |   -0.08% |
|                                  90th percentile service time |                                     index |    175.833       |    173.495       |   -2.33823 |     ms |   -1.33% |
|                                  99th percentile service time |                                     index |    853.073       |    846.901       |   -6.17276 |     ms |   -0.72% |
|                                99.9th percentile service time |                                     index |   1037.66        |   1021.17        |  -16.4914  |     ms |   -1.59% |
|                                 100th percentile service time |                                     index |   1372.16        |   1151.6         | -220.566   |     ms |  -16.07% |
|                                                    error rate |                                     index |      0           |      0           |    0       |      % |    0.00% |
|                                                Min Throughput |  filters-agg-with-low-cardinality-filters |    197.929       |    202.627       |    4.69842 |  ops/s |   +2.37% |
|                                               Mean Throughput |  filters-agg-with-low-cardinality-filters |    197.929       |    202.627       |    4.69842 |  ops/s |   +2.37% |
|                                             Median Throughput |  filters-agg-with-low-cardinality-filters |    197.929       |    202.627       |    4.69842 |  ops/s |   +2.37% |
|                                                Max Throughput |  filters-agg-with-low-cardinality-filters |    197.929       |    202.627       |    4.69842 |  ops/s |   +2.37% |
|                                       50th percentile latency |  filters-agg-with-low-cardinality-filters |      1.43013     |      1.57185     |    0.14173 |     ms |   +9.91% |
|                                       90th percentile latency |  filters-agg-with-low-cardinality-filters |      1.86797     |      2.02157     |    0.1536  |     ms |   +8.22% |
|                                      100th percentile latency |  filters-agg-with-low-cardinality-filters |      6.32829     |      6.41912     |    0.09083 |     ms |   +1.44% |
|                                  50th percentile service time |  filters-agg-with-low-cardinality-filters |      1.43013     |      1.57185     |    0.14173 |     ms |   +9.91% |
|                                  90th percentile service time |  filters-agg-with-low-cardinality-filters |      1.86797     |      2.02157     |    0.1536  |     ms |   +8.22% |
|                                 100th percentile service time |  filters-agg-with-low-cardinality-filters |      6.32829     |      6.41912     |    0.09083 |     ms |   +1.44% |
|                                                    error rate |  filters-agg-with-low-cardinality-filters |      0           |      0           |    0       |      % |    0.00% |
|                                                Min Throughput | filters-agg-with-high-cardinality-filters |    444.442       |    609.835       |  165.393   |  ops/s |  +37.21% |
|                                               Mean Throughput | filters-agg-with-high-cardinality-filters |    444.442       |    609.835       |  165.393   |  ops/s |  +37.21% |
|                                             Median Throughput | filters-agg-with-high-cardinality-filters |    444.442       |    609.835       |  165.393   |  ops/s |  +37.21% |
|                                                Max Throughput | filters-agg-with-high-cardinality-filters |    444.442       |    609.835       |  165.393   |  ops/s |  +37.21% |
|                                       50th percentile latency | filters-agg-with-high-cardinality-filters |      1.23425     |      1.10798     |   -0.12627 |     ms |  -10.23% |
|                                       90th percentile latency | filters-agg-with-high-cardinality-filters |      1.58128     |      1.47082     |   -0.11046 |     ms |   -6.99% |
|                                      100th percentile latency | filters-agg-with-high-cardinality-filters |      1.91908     |      1.72404     |   -0.19504 |     ms |  -10.16% |
|                                  50th percentile service time | filters-agg-with-high-cardinality-filters |      1.23425     |      1.10798     |   -0.12627 |     ms |  -10.23% |
|                                  90th percentile service time | filters-agg-with-high-cardinality-filters |      1.58128     |      1.47082     |   -0.11046 |     ms |   -6.99% |
|                                 100th percentile service time | filters-agg-with-high-cardinality-filters |      1.91908     |      1.72404     |   -0.19504 |     ms |  -10.16% |
|                                                    error rate | filters-agg-with-high-cardinality-filters |      0           |      0           |    0       |      % |    0.00% |
|                                                Min Throughput |           filters-per-10-degrees-interval |      2.45909     |      2.62468     |    0.16559 |  ops/s |   +6.73% |
|                                               Mean Throughput |           filters-per-10-degrees-interval |      2.5729      |      2.73527     |    0.16238 |  ops/s |   +6.31% |
|                                             Median Throughput |           filters-per-10-degrees-interval |      2.58864     |      2.75004     |    0.1614  |  ops/s |   +6.23% |
|                                                Max Throughput |           filters-per-10-degrees-interval |      2.61957     |      2.77378     |    0.15421 |  ops/s |   +5.89% |
|                                       50th percentile latency |           filters-per-10-degrees-interval |    374.136       |    354.663       |  -19.4729  |     ms |   -5.20% |
|                                       90th percentile latency |           filters-per-10-degrees-interval |    375.531       |    359.061       |  -16.47    |     ms |   -4.39% |
|                                      100th percentile latency |           filters-per-10-degrees-interval |    380.262       |    361.456       |  -18.8057  |     ms |   -4.95% |
|                                  50th percentile service time |           filters-per-10-degrees-interval |    374.136       |    354.663       |  -19.4729  |     ms |   -5.20% |
|                                  90th percentile service time |           filters-per-10-degrees-interval |    375.531       |    359.061       |  -16.47    |     ms |   -4.39% |
|                                 100th percentile service time |           filters-per-10-degrees-interval |    380.262       |    361.456       |  -18.8057  |     ms |   -4.95% |
|                                                    error rate |           filters-per-10-degrees-interval |      0           |      0           |    0       |      % |    0.00% |
|                                                Min Throughput |  filters-agg-with-high-cardinality-filter |    623.426       |    959.594       |  336.168   |  ops/s |  +53.92% |
|                                               Mean Throughput |  filters-agg-with-high-cardinality-filter |    623.426       |    959.594       |  336.168   |  ops/s |  +53.92% |
|                                             Median Throughput |  filters-agg-with-high-cardinality-filter |    623.426       |    959.594       |  336.168   |  ops/s |  +53.92% |
|                                                Max Throughput |  filters-agg-with-high-cardinality-filter |    623.426       |    959.594       |  336.168   |  ops/s |  +53.92% |
|                                       50th percentile latency |  filters-agg-with-high-cardinality-filter |      0.843938    |      0.722688    |   -0.12125 |     ms |  -14.37% |
|                                       90th percentile latency |  filters-agg-with-high-cardinality-filter |      1.24545     |      0.980634    |   -0.26482 |     ms |  -21.26% |
|                                      100th percentile latency |  filters-agg-with-high-cardinality-filter |      1.48012     |      1.16762     |   -0.3125  |     ms |  -21.11% |
|                                  50th percentile service time |  filters-agg-with-high-cardinality-filter |      0.843938    |      0.722688    |   -0.12125 |     ms |  -14.37% |
|                                  90th percentile service time |  filters-agg-with-high-cardinality-filter |      1.24545     |      0.980634    |   -0.26482 |     ms |  -21.26% |
|                                 100th percentile service time |  filters-agg-with-high-cardinality-filter |      1.48012     |      1.16762     |   -0.3125  |     ms |  -21.11% |
|                                                    error rate |  filters-agg-with-high-cardinality-filter |      0           |      0           |    0       |      % |    0.00% |
|                                                Min Throughput |   filter-agg-with-high-cardinality-filter |    638.174       |    728.106       |   89.932   |  ops/s |  +14.09% |
|                                               Mean Throughput |   filter-agg-with-high-cardinality-filter |    638.174       |    728.106       |   89.932   |  ops/s |  +14.09% |
|                                             Median Throughput |   filter-agg-with-high-cardinality-filter |    638.174       |    728.106       |   89.932   |  ops/s |  +14.09% |
|                                                Max Throughput |   filter-agg-with-high-cardinality-filter |    638.174       |    728.106       |   89.932   |  ops/s |  +14.09% |
|                                       50th percentile latency |   filter-agg-with-high-cardinality-filter |      0.785521    |      0.762979    |   -0.02254 |     ms |   -2.87% |
|                                       90th percentile latency |   filter-agg-with-high-cardinality-filter |      1.12986     |      1.21422     |    0.08436 |     ms |   +7.47% |
|                                      100th percentile latency |   filter-agg-with-high-cardinality-filter |      1.42379     |      1.684       |    0.26021 |     ms |  +18.28% |
|                                  50th percentile service time |   filter-agg-with-high-cardinality-filter |      0.785521    |      0.762979    |   -0.02254 |     ms |   -2.87% |
|                                  90th percentile service time |   filter-agg-with-high-cardinality-filter |      1.12986     |      1.21422     |    0.08436 |     ms |   +7.47% |
|                                 100th percentile service time |   filter-agg-with-high-cardinality-filter |      1.42379     |      1.684       |    0.26021 |     ms |  +18.28% |
|                                                    error rate |   filter-agg-with-high-cardinality-filter |      0           |      0           |    0       |      % |    0.00% |
|                                                Min Throughput |            filter-per-10-degrees-interval |      2.62934     |      2.7898      |    0.16046 |  ops/s |   +6.10% |
|                                               Mean Throughput |            filter-per-10-degrees-interval |      2.67376     |      2.8091      |    0.13534 |  ops/s |   +5.06% |
|                                             Median Throughput |            filter-per-10-degrees-interval |      2.67896     |      2.80913     |    0.13017 |  ops/s |   +4.86% |
|                                                Max Throughput |            filter-per-10-degrees-interval |      2.6911      |      2.82841     |    0.13731 |  ops/s |   +5.10% |
|                                       50th percentile latency |            filter-per-10-degrees-interval |    369.144       |    349.099       |  -20.0442  |     ms |   -5.43% |
|                                       90th percentile latency |            filter-per-10-degrees-interval |    371.119       |    356.204       |  -14.9149  |     ms |   -4.02% |
|                                      100th percentile latency |            filter-per-10-degrees-interval |    374.535       |    399.108       |   24.5732  |     ms |   +6.56% |
|                                  50th percentile service time |            filter-per-10-degrees-interval |    369.144       |    349.099       |  -20.0442  |     ms |   -5.43% |
|                                  90th percentile service time |            filter-per-10-degrees-interval |    371.119       |    356.204       |  -14.9149  |     ms |   -4.02% |
|                                 100th percentile service time |            filter-per-10-degrees-interval |    374.535       |    399.108       |   24.5732  |     ms |   +6.56% |
|                                                    error rate |            filter-per-10-degrees-interval |      0           |      0           |    0       |      % |    0.00% |

@kkrik-es
Copy link
Contributor Author

kkrik-es commented Sep 6, 2023

@elasticsearchmachine run elasticsearch-ci/part-1

@kkrik-es
Copy link
Contributor Author

kkrik-es commented Sep 6, 2023

@elasticsearchmachine run elasticsearch-ci/part-2

@kkrik-es kkrik-es marked this pull request as ready for review September 6, 2023 07:04
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-analytics-geo (Team:Analytics)

Copy link
Contributor

@jpountz jpountz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woohoo, the speedup is greater than I expected, nice! It looks good, I just left two minor suggestions.

}
return (lastMatchingDoc == doc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud, we could change this logic to have a single comparison in the (not uncommon) case when twoPhaseView is null:

boolean checkDocForMatch(int doc) throws IOException {
  if (twoPhaseView == null) {
    return true;
  }
  if (lastCheckedTwoPhaseDoc < doc) {
    lastCheckedTwoPhaseDoc = doc;
    if (twoPhaseView.matches()) {
      lastMatchingTwoPhaseDoc = doc;
    }
  }
  return lastMatchingTwoPhaseDoc == doc;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I missed this. I created separate subclasses to avoid the branch - Martijn suggested this is hot code.

SingleFilterLeafCollector(
LeafBucketCollector sub,
LeafReaderContext leafReaderContext,
QueryToFilterAdapter filter,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should convert QueryToFilterAdapter objects to Scorers up-front. This way we could also use the Single* implementation if there are multiple filters but only one of them has matches on the segment, and we could use the Multi* implementation when no filters have matches on the segments, which would in-turn help remove the filterIterator != null check in SingleFilterLeafCollector#collect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this indeed can improve performance in more cases, while the code is cleaner since more logic is moved outside the subclasses.

@kkrik-es kkrik-es merged commit 92c5271 into elastic:main Sep 6, 2023
12 checks passed
alex-spies pushed a commit to dreamquster/elasticsearch that referenced this pull request Sep 8, 2023
* Use a competitive iterator in FiltersAggregator.

The iterator is used to combine filtering with querying in leaf
collection. Its benefit is that rangers with docs that are filtered out
by all filters are skipped from doc collection.

The competitive iterator is restricted to FiltersAggregator, not used in
FilterByFilterAggregator that's already optimized. It only applies to
top-level filter aggregations with no "other" bucket defined; the latter
leads to collecting all docs so there's no point in skipping doc ranges.

Fixes elastic#97544

* Fix function name.

* Advance iterator on two-phase mismatch.

* Restore docid tracking.

* Fix failing tests.

* Fix failing test.

* Fix more tests.

* Update docs/changelog/98360.yaml

* More test fixes.

* Update docs/changelog/98360.yaml

* Skip checking useCompetitiveIterator in collect

* Find approximate matches in CompetitiveIterator

* Use DisiPriorityQueue to simplify FiltersAggregator

* Skip competitive iterator when all docs match.

* Check for empty priority queue.

* Skip DisiPriorityQueue on single filter agg.

When FiltersAggregator has a single filter, there is no benefit in using
a DisiPriorityQueue as the heap will only contain values from a single
iterator. In such a case, it's preferable to use the filtering
approximation iterator directly as competitive iterator.

Fixes elastic#99202

* Update docs/changelog/99215.yaml

* Use FilterMatchingDisiWrapper in leaf collectors.
@kkrik-es kkrik-es deleted the fix/97544 branch September 14, 2023 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Analytics/Aggregations Aggregations >enhancement Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) v8.11.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Optimize filters aggregation with a single filter
3 participants