Heavy Hitters And Collection Aggregates
Generic Description
Use this family when you need to preserve or summarize the values themselves rather than only collapse everything to one scalar number. Documenting it separately matters because aggregate placement changes row grain, grouping behavior, and whether state/merge forms are valid.
Simple example:
MATCH (u:User)-[:HAS_APP_SESSION]->(s:AppSession)
RETURN top_k(s.mode, 3) AS hottest_modes,
collect(DISTINCT s.mode) AS distinct_modes,
group_concat(s.mode, '|') AS mode_path
Consumer-Level Explanation
This family is about two related but different jobs:
- heavy hitters: which values dominate a grouped population?
- collection-preserving summaries: which values did I actually see, and in what retained order or concatenated form?
The current implemented surface includes:
top_kheavy_hitterscollectgroup_concatlistaggfirstlastsample
These are useful when plain scalar summaries are too lossy. In social, content, or operational data, you often care about the leading categories, an ordered sample, or a retained list of labels or modes.
More Detailed Explanation
top_k and heavy_hitters are about exact frequency ranking on the current engine path. They are not just a convenience alias for sorting rows outside the query. They preserve the idea that “most common values” is part of the aggregate layer itself.
collect, group_concat, first, last, and sample matter for a different reason: they keep value identity around. That makes them useful in:
- rollups that still need examples
- ordered session-mode or state summaries
- collection-oriented post-processing in later Cypher steps
The current implementation also pushes a large part of this family into:
- aggregate state / merge forms
- spill-backed grouped execution for the supported exact subset
- exact incremental materialized-view maintenance on the safe subset
That is a meaningful architectural improvement because ordered and collection-oriented aggregates are usually where systems fall back to “refresh everything.”
Advanced Example
MATCH (u:User)-[:HAS_APP_SESSION]->(s:AppSession)
WITH u.profile.location.country AS country,
s
RETURN country,
top_k(s.mode, 2) AS hottest_modes,
collect(DISTINCT s.entry_point) AS distinct_entry_points,
group_concat(DISTINCT s.entry_point, '|') AS entry_points_joined,
first(s.mode) AS first_mode,
last(s.mode) AS last_mode,
sample(s.mode) AS sample_mode
ORDER BY country
Real Use Cases
- social analytics where the top interaction types or session modes matter more than only raw counts
- content analytics where category lists or joined labels are used for reporting and exports
- operational timelines where an ordered first/last state is needed alongside scalar metrics
Real Limitations And Tradeoffs
- collection-preserving aggregates can grow result size quickly when groups are large
- order-sensitive aggregates are inherently harder to maintain incrementally than pure scalar aggregates
- heavy-hitter results are only as useful as the grouped slice; broad noisy groups produce broad noisy leaders