- 
                Notifications
    You must be signed in to change notification settings 
- Fork 25.6k
ESQL: Fill in topn values if competitive #135734
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
Changes from 5 commits
fb951eb
              83f9ed1
              16cdf9c
              025e7ab
              37a9229
              04ac9dd
              1c1fb18
              215ff81
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| pr: 135734 | ||
| summary: Fill in topn values if competitive | ||
| area: ES|QL | ||
| type: enhancement | ||
| issues: [] | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -199,15 +199,7 @@ static final class RowFiller { | |
| } | ||
| } | ||
|  | ||
| /** | ||
| * Fill a {@link Row} for {@code position}. | ||
| */ | ||
| void row(int position, Row destination) { | ||
| writeKey(position, destination); | ||
| writeValues(position, destination); | ||
| } | ||
|  | ||
| private void writeKey(int position, Row row) { | ||
| void writeKey(int position, Row row) { | ||
| int orderByCompositeKeyCurrentPosition = 0; | ||
| for (int i = 0; i < keyFactories.length; i++) { | ||
| int valueAsBytesSize = keyFactories[i].extractor.writeKey(row.keys, position); | ||
|  | @@ -217,7 +209,7 @@ private void writeKey(int position, Row row) { | |
| } | ||
| } | ||
|  | ||
| private void writeValues(int position, Row destination) { | ||
| void writeValues(int position, Row destination) { | ||
| for (ValueExtractor e : valueExtractors) { | ||
| var refCounted = e.getRefCountedForShard(position); | ||
| if (refCounted != null) { | ||
|  | @@ -416,15 +408,27 @@ public void addInput(Page page) { | |
| spare.values.clear(); | ||
| spare.clearRefCounters(); | ||
| } | ||
| rowFiller.row(i, spare); | ||
| rowFiller.writeKey(i, spare); | ||
|  | ||
| // When rows are very long, appending the values one by one can lead to lots of allocations. | ||
| // To avoid this, pre-allocate at least as much size as in the last seen row. | ||
| // Let the pre-allocation size decay in case we only have 1 huge row and smaller rows otherwise. | ||
| spareKeysPreAllocSize = Math.max(spare.keys.length(), spareKeysPreAllocSize / 2); | ||
| spareValuesPreAllocSize = Math.max(spare.values.length(), spareValuesPreAllocSize / 2); | ||
|  | ||
| spare = inputQueue.insertWithOverflow(spare); | ||
| if (inputQueue.size() < inputQueue.topCount) { | ||
| // Heap not yet full, just add elements | ||
| rowFiller.writeValues(i, spare); | ||
| spareValuesPreAllocSize = Math.max(spare.values.length(), spareValuesPreAllocSize / 2); | ||
| inputQueue.add(spare); | ||
| spare = null; | ||
| } else if (inputQueue.lessThan(inputQueue.top(), spare)) { | ||
| // Heap full AND this node fit in it. | ||
| Row nextSpare = inputQueue.top(); | ||
| rowFiller.writeValues(i, spare); | ||
| spareValuesPreAllocSize = Math.max(spare.values.length(), spareValuesPreAllocSize / 2); | ||
| inputQueue.updateTop(spare); | ||
| spare = nextSpare; | ||
| } | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could have used the slightly shorter: but this feels less magic. And this is the hot path so I prefer seeing the guts a little bit. Also, it cries out for a further optimization where we bail from the loop as soon as  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the shorter one has the definite of making the common parts (the code inside the if) more obvious. Perhaps just extract  | ||
| } | ||
| } finally { | ||
| page.releaseBlocks(); | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -92,7 +92,6 @@ | |
| import static org.hamcrest.Matchers.equalTo; | ||
| import static org.hamcrest.Matchers.greaterThan; | ||
| import static org.hamcrest.Matchers.hasSize; | ||
| import static org.hamcrest.Matchers.is; | ||
| import static org.hamcrest.Matchers.lessThan; | ||
| import static org.hamcrest.Matchers.lessThanOrEqualTo; | ||
|  | ||
|  | @@ -470,7 +469,8 @@ private TopNOperator.Row row( | |
| page | ||
| ); | ||
| TopNOperator.Row row = new TopNOperator.Row(nonBreakingBigArrays().breakerService().getBreaker("request"), sortOrders, 0, 0); | ||
| rf.row(position, row); | ||
| rf.writeKey(position, row); | ||
| rf.writeValues(position, row); | ||
| return row; | ||
| } | ||
|  | ||
|  | @@ -1491,7 +1491,8 @@ public void testRowResizes() { | |
|  | ||
| // 105 are from the objects | ||
| // 1 is for the min-heap itself | ||
| assertThat(breaker.getMemoryRequestCount(), is(106L)); | ||
| // could be less than because we don't always insert | ||
| assertThat(breaker.getMemoryRequestCount(), lessThanOrEqualTo(106L)); | ||
|          | ||
| } | ||
| } | ||
|  | ||
|  | ||
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.
Nit: Maybe worth commenting here that this is a
insertWithOverflow()that skips some work if the value is not competitiveThere 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.
👍