Blog post about TopK per partition (`PartitionedTopKExec` / `enable_window_topn`)
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 72/100
- Tipo de issue
- Documentación
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Área
- documentation
Línea de trabajo
Start with the draft in this issue and the linked DataFusion site pull request #203; use the referenced TopK per partition issues and pull requests to check behavior, implementation details, and whether the optimization is enabled by default for the target release. Write a self-contained post for the DataFusion blog using the suggested outline, examples, and related posts for style. Done means a site PR explains the use case, how the operator works and is used, implementation highlights, and remaining work.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Is your feature request related to a problem or challenge?
There is a lot of great work from @SubhamSinghal, @jayzhan211 and others on the "TopK per partition" optimization for window queries like
SELECT * FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY category ORDER BY revenue DESC) AS rn, *
FROM sales
) WHERE rn <= 5;
The original request is from 2023:
The optimization landed in DataFusion 55 behind datafusion.optimizer.enable_window_topn, and the EPIC to turn it on by default is
As always, telling the community about it will be good
- To advertise the feature for others who have the same use case,
- To document in an easier to understand way how the feature works
- The authors to raise their visibility.
I had drafted a section about it for the DataFusion 55 release post (see below) but a release post isn't great as it has limited space to explain how the operator works
- https://github.com/apache/datafusion/issues/24216
- https://github.com/apache/datafusion-site/pull/203
Describe the solution you'd like
Thus I suggest a complete self contained blog post on https://datafusion.apache.org/blog/ (make a PR to https://github.com/apache/datafusion-site) about TopK per partition.
I suggest the standard structure of "informative post with low key DataFusion pitch"
For example, the pattern of
- Dynamic Filters (TopK and hash join, 25x faster): https://datafusion.apache.org/blog/2025/09/10/dynamic-filters/
- Fast high cardinality grouping: https://datafusion.apache.org/blog/2023/08/05/datafusion_fast_grouping/
Here are some ideas for an outline:
- An understandable representative usecase: "top N per group" (e.g latest N events per device) so readers can tell if it applies to them. Mention this is db-benchmark / h2o query 8 shape.
- Background / technical intuition: the naive plan sorts the entire input to compute the window function and then throws almost all of it away. The TopK per partition operator keeps a bounded heap per partition instead. Explain how
ROW_NUMBER,RANKandDENSE_RANKdiffer in what has to be retained. - How to use it in DataFusion: What version is it introduced in (57 I hope, show
EXPLAINbefore/after withPartitionedTopKExec), and how to turn it off) - A bit about how it is implemented: the
WindowTopNphysical optimizer rule,PartitionedTopKExec, and then some of the highlights of making it work for high cardinality:- the 100K+ partition cliff, https://github.com/apache/datafusion/pull/21479#issuecomment-4221809099
- Memory optimizations, etc
- Emitting the rank column directly from the operator so the window node can be removed (#26133)
- Call for help 🎣: Any remaining work that needs to happen
I think the best time to publish is around 57 release (when #27197 is merged and released, so the post can say the optimization is on by default.
Describe alternatives you've considered
Here is the original text I had drafted for the 55 release post (from https://github.com/apache/datafusion/issues/24608), which could be a starting point:
Details
Per-Partition TopK for Window Functions
A common analytics pattern selects the top N rows per group using a window
function:
SELECT * FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY category ORDER BY revenue DESC) AS rn, *
FROM sales
) WHERE rn <= 5;
DataFusion previously sorted the entire input to evaluate the window
function, even though only a handful of rows per partition survive the filter.
DataFusion 55 recognizes this pattern and uses a new PartitionedTopKExec
operator that keeps only the top N rows per partition, dramatically reducing
sorting and memory for high-cardinality inputs. The optimization applies to
ROW_NUMBER and RANK, resolving a feature request first filed in 2023
(#6899).
Thanks to @SubhamSinghal for implementing this feature, with reviews from
@2010YOUY01 and @kosiew. Related PRs: #21479, #22885, #23096
Additional context
Tracking issues:
- https://github.com/apache/datafusion/issues/6899 (original 2023 request)
- https://github.com/apache/datafusion/issues/24608 (enable by default EPIC)
- https://github.com/apache/datafusion/issues/24060 (follow on optimizations)
- https://github.com/apache/datafusion/issues/23197 (window function performance EPIC)
Core operator and optimizer rule:
- https://github.com/apache/datafusion/pull/21479 (
ROW_NUMBER, @SubhamSinghal) - https://github.com/apache/datafusion/pull/22885 (
RANK, @SubhamSinghal) - https://github.com/apache/datafusion/pull/23869 (
DENSE_RANK, @SubhamSinghal) - https://github.com/apache/datafusion/pull/24191 (run
WindowTopNbeforeEnforceRequirements, @saadtajwar) - https://github.com/apache/datafusion/pull/23355 (range partitioned inputs, @stuhood)
- https://github.com/apache/datafusion/pull/26133 (emit the rank column from the operator, @SubhamSinghal)
- https://github.com/apache/datafusion/pull/27197 (enable by default, @SubhamSinghal)
Closing the high cardinality gap:
- https://github.com/apache/datafusion/pull/23096 (share encoder and reservation across partitions)
- https://github.com/apache/datafusion/pull/24591 (
RANKmemory from O(input) to O(K + ties), @jayzhan211) - https://github.com/apache/datafusion/pull/25468 (interleave retained rows at emit)
- https://github.com/apache/datafusion/pull/25730 (shared
RecordBatchStoreforROW_NUMBER) - https://github.com/apache/datafusion/pull/25968 (
RANKon the shared store with decide-then-gather)
Correctness fixes and metrics:
- https://github.com/apache/datafusion/pull/24405 (@viirya)
- https://github.com/apache/datafusion/pull/23599 (@zhuqi-lucas)
- https://github.com/apache/datafusion/pull/24495 (metrics, @shinzoxD)
- https://github.com/apache/datafusion/pull/26417 (filter column through projections)
- https://github.com/apache/datafusion/pull/25535 (@jayzhan211)
Benchmarks:
- https://github.com/apache/datafusion/pull/24050 (
dense_rankbenchmark) - https://github.com/apache/datafusion/pull/24732 (h2o
window_sortedsweep)
Open follow on work:
- https://github.com/apache/datafusion/issues/26381 (
Utf8Viewbuffers kept alive) - https://github.com/apache/datafusion/issues/26876 / https://github.com/apache/datafusion/pull/27136 (
DENSE_RANKon the shared store) - https://github.com/apache/datafusion/issues/21596 (filters with embedded projections)
- https://github.com/apache/datafusion/pull/26160 (
rn = 1) - https://github.com/apache/datafusion/issues/23600 (
ROW_NUMBER() = 1/DISTINCT ONdedup) - https://github.com/apache/datafusion/pull/24629 (streaming path for pre-sorted input, closed but a good idea)
Related prior posts for style / context:
- Lenguaje dominante
- Rust
- Estrellas
- 9.6k
- Forks
- 2.6k
- Merge medio
- 3 d 4 h
- PR fusionados (30 d)
- 345
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de apache/datafusion
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
apache/datafusion#27315 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
apache/datafusion#27094 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Substrait consumer doesn't recognise `shift_left` / `shift_right` from functions_arithmetic.yamlPosiblemente ocupada @jonasHanhan la tomó hace 9 días. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
apache/datafusion#27059 ·
Los mantenedores suelen responder en 1 día
-
`ProjectionExprs::project_statistics` computes approximate `Statistics::total_byte_size` ignoring column statsPosiblemente ocupada @joseph-isaacs la tomó hace 9 días. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
apache/datafusion#27050 ·
Los mantenedores suelen responder en 1 día
-
physical-plan: decoding an Unnest or Explain node with an unset field panicsPosiblemente ocupada @geoHeil la tomó hace 8 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
apache/datafusion#26999 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de apache/datafusion
Issues similares
-
area:schema documentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
ElectronicWave/Elemental#252 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
dekobon/big-code-analysis#1887 ·
Los mantenedores suelen responder en 1 día
-
Shell中文符号输入异常Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día