2010YOUY01 commented on PR #23407:
URL: https://github.com/apache/datafusion/pull/23407#issuecomment-4964509896

   > @2010YOUY01 @Rachelint you might want to consider using the generator to 
simplify the aggregate rewrite
   
   Yes this makes sense, I'll give it a try later.
   
   > I also agree with @rluvaton that the SortPreservingMerge code is about as 
complicated as it can get and still be undersrtandable without some refactoring 
-- so to make progress we will have to refactor it (basically what @Rachelint 
@2010YOUY01 and I are doing to the aggregate code in #22710)
   > 
   > One thing I think helps is separting the stream control flow (aka the 
poll_next implementations) from the actual logic (aka messing around with data).
   > 
   > A major win of this PR for simplicity I think is that it moves the logic 
of updating the Loser tree implementation out of the control logic. Rather than 
using a new crate / control flow pattern, we could instead try moving the loser 
tree implementation into its own struct (encapsulate the logic and make the 
boundaries of the different responsibilities clearer, and make the control flow 
easier to read)
   
   I have similar opinions to @alamb on how to reduce complexity in many 
existing operators, I’ll try to explain them a little differently.
   
   To make an operator implementation easy to read, its entry point should look 
like pseudocode:
   
   ```text
   # Ideal shape of aggregation
   # aggregate_hash_table stores: group_keys -> group_states (with all internal 
details encapsulated)
   for batch in input_stream:
       aggregate_hash_table.push(batch)
   
   output_stream = aggregate_hash_table.finish()
   
   for batch in output_stream:
       yield batch
   ```
   
   There are two major gaps between this ideal and the current implementation:
   
   1. The yield-based pattern is difficult to express using the existing 
streaming interface. (this PR is trying to improve)
   2. Most implementations directly manipulate low-level primitives—such as 
vectors, batches, and flags—in their main control flow. 
   
   Point 2 causes an issue: in order to read the code, at the same time, we 
have to deal with the complexity for both control flow and logic details around 
low-level primitives. This causes huge cognitive load.
   
   A better approach would be to encapsulate these details in a deeper module, 
and implement the core logic around that deep module. The goal is to make the 
entry-point code look as much like pseudocode as possible—e.g.  the 
`aggregate_hash_table` abstraction above. This gives readers a clear 
abstraction boundary: they can understand the overall control flow first, then 
examine the implementation details only when needed.
   
   I think the second issue is the larger source of complexity, but it's often 
overlooked.
   
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to