[{"data":1,"prerenderedAt":4394},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fbuilding\u002Fwindowing":314,"\u002Fdocs\u002Fbuilding\u002Fwindowing-surround":4389},[4,38,86,149,176,219,257,273],{"title":5,"path":6,"stem":7,"children":8,"icon":37},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,17,22,27,32],{"title":10,"path":6,"stem":7,"icon":11},"Getting started","i-lucide-flag",{"title":13,"path":14,"stem":15,"icon":16},"Modules overview","\u002Fdocs\u002Fgetting-started\u002Fmodules-overview","1.docs\u002F1.getting-started\u002F2.modules-overview","i-lucide-boxes",{"title":18,"path":19,"stem":20,"icon":21},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F3.installation","i-lucide-download",{"title":23,"path":24,"stem":25,"icon":26},"License configuration","\u002Fdocs\u002Fgetting-started\u002Flicense-configuration","1.docs\u002F1.getting-started\u002F4.license-configuration","i-lucide-key-round",{"title":28,"path":29,"stem":30,"icon":31},"Your first app","\u002Fdocs\u002Fgetting-started\u002Ffirst-app","1.docs\u002F1.getting-started\u002F5.first-app","i-lucide-square-play",{"title":33,"path":34,"stem":35,"icon":36},"Project setup","\u002Fdocs\u002Fgetting-started\u002Fproject-setup","1.docs\u002F1.getting-started\u002F6.project-setup","i-lucide-package",false,{"title":39,"path":40,"stem":41,"children":42,"icon":45},"Core Concepts","\u002Fdocs\u002Fconcepts","1.docs\u002F2.concepts\u002F1.index",[43,46,51,56,61,66,71,76,81],{"title":44,"path":40,"stem":41,"icon":45},"Core concepts","i-lucide-book-open",{"title":47,"path":48,"stem":49,"icon":50},"Architecture","\u002Fdocs\u002Fconcepts\u002Farchitecture","1.docs\u002F2.concepts\u002F2.architecture","i-lucide-layers",{"title":52,"path":53,"stem":54,"icon":55},"Exactly-once semantics","\u002Fdocs\u002Fconcepts\u002Fexactly-once","1.docs\u002F2.concepts\u002F3.exactly-once","i-lucide-shield-check",{"title":57,"path":58,"stem":59,"icon":60},"Lanes and parallelism","\u002Fdocs\u002Fconcepts\u002Flanes-and-parallelism","1.docs\u002F2.concepts\u002F4.lanes-and-parallelism","i-lucide-split",{"title":62,"path":63,"stem":64,"icon":65},"State and thread-safety","\u002Fdocs\u002Fconcepts\u002Fstate-and-thread-safety","1.docs\u002F2.concepts\u002F5.state-and-thread-safety","i-lucide-lock",{"title":67,"path":68,"stem":69,"icon":70},"Event time and watermarks","\u002Fdocs\u002Fconcepts\u002Fevent-time-and-watermarks","1.docs\u002F2.concepts\u002F6.event-time-and-watermarks","i-lucide-clock",{"title":72,"path":73,"stem":74,"icon":75},"The configuration model","\u002Fdocs\u002Fconcepts\u002Fconfiguration-model","1.docs\u002F2.concepts\u002F7.configuration-model","i-lucide-sliders-horizontal",{"title":77,"path":78,"stem":79,"icon":80},"The error-handling model","\u002Fdocs\u002Fconcepts\u002Ferror-handling-model","1.docs\u002F2.concepts\u002F8.error-handling-model","i-lucide-triangle-alert",{"title":82,"path":83,"stem":84,"icon":85},"How StoatFlow differs from Kafka Streams","\u002Fdocs\u002Fconcepts\u002Fhow-stoatflow-differs-from-ks","1.docs\u002F2.concepts\u002F9.how-stoatflow-differs-from-ks","i-lucide-arrow-left-right",{"title":87,"path":88,"stem":89,"children":90,"icon":93},"Building Topologies","\u002Fdocs\u002Fbuilding","1.docs\u002F3.building\u002F1.index",[91,94,99,104,109,114,119,124,129,134,139,144],{"title":92,"path":88,"stem":89,"icon":93},"Building topologies","i-lucide-blocks",{"title":95,"path":96,"stem":97,"icon":98},"Error handling and DLQ","\u002Fdocs\u002Fbuilding\u002Ferror-handling-dlq","1.docs\u002F3.building\u002F10.error-handling-dlq","i-lucide-circle-x",{"title":100,"path":101,"stem":102,"icon":103},"State stores","\u002Fdocs\u002Fbuilding\u002Fstate-stores","1.docs\u002F3.building\u002F11.state-stores","i-lucide-database",{"title":105,"path":106,"stem":107,"icon":108},"Testing topologies","\u002Fdocs\u002Fbuilding\u002Ftesting","1.docs\u002F3.building\u002F12.testing","i-lucide-flask-conical",{"title":110,"path":111,"stem":112,"icon":113},"Sources and sinks","\u002Fdocs\u002Fbuilding\u002Fstreams-builder","1.docs\u002F3.building\u002F2.streams-builder","i-lucide-import",{"title":115,"path":116,"stem":117,"icon":118},"KStream and KTable operations","\u002Fdocs\u002Fbuilding\u002Fkstream-ktable","1.docs\u002F3.building\u002F3.kstream-ktable","i-lucide-waypoints",{"title":120,"path":121,"stem":122,"icon":123},"Aggregations","\u002Fdocs\u002Fbuilding\u002Faggregations","1.docs\u002F3.building\u002F4.aggregations","i-lucide-sigma",{"title":125,"path":126,"stem":127,"icon":128},"Windowing","\u002Fdocs\u002Fbuilding\u002Fwindowing","1.docs\u002F3.building\u002F5.windowing","i-lucide-calendar-clock",{"title":130,"path":131,"stem":132,"icon":133},"Joins","\u002Fdocs\u002Fbuilding\u002Fjoins","1.docs\u002F3.building\u002F6.joins","i-lucide-git-merge",{"title":135,"path":136,"stem":137,"icon":138},"The Processor API","\u002Fdocs\u002Fbuilding\u002Fprocessor-api","1.docs\u002F3.building\u002F7.processor-api","i-lucide-cpu",{"title":140,"path":141,"stem":142,"icon":143},"Scheduled sources","\u002Fdocs\u002Fbuilding\u002Fscheduled-sources","1.docs\u002F3.building\u002F8.scheduled-sources","i-lucide-timer",{"title":145,"path":146,"stem":147,"icon":148},"Serdes and Avro","\u002Fdocs\u002Fbuilding\u002Fserdes","1.docs\u002F3.building\u002F9.serdes","i-lucide-binary",{"title":150,"path":151,"stem":152,"children":153,"icon":75},"Configuration","\u002Fdocs\u002Fconfiguration","1.docs\u002F4.configuration\u002F1.index",[154,156,161,166,171],{"title":155,"path":151,"stem":152,"icon":75},"How configuration works",{"title":157,"path":158,"stem":159,"icon":160},"Engine configuration (:core)","\u002Fdocs\u002Fconfiguration\u002Fcore-config","1.docs\u002F4.configuration\u002F2.core-config","i-lucide-settings-2",{"title":162,"path":163,"stem":164,"icon":165},"Runtime configuration (:runtime)","\u002Fdocs\u002Fconfiguration\u002Fruntime-config","1.docs\u002F4.configuration\u002F3.runtime-config","i-lucide-server-cog",{"title":167,"path":168,"stem":169,"icon":170},"Defaults, adaptivity, and presets","\u002Fdocs\u002Fconfiguration\u002Fdefaults-and-presets","1.docs\u002F4.configuration\u002F4.defaults-and-presets","i-lucide-gauge",{"title":172,"path":173,"stem":174,"icon":175},"Kafka client configuration","\u002Fdocs\u002Fconfiguration\u002Fkafka-client-config","1.docs\u002F4.configuration\u002F5.kafka-client-config","i-lucide-plug",{"title":177,"path":178,"stem":179,"children":180,"icon":183},"Running in Production","\u002Fdocs\u002Fruntime","1.docs\u002F5.runtime\u002F1.index",[181,184,189,194,199,204,209,214],{"title":182,"path":178,"stem":179,"icon":183},"The runtime","i-lucide-server",{"title":185,"path":186,"stem":187,"icon":188},"The REST API","\u002Fdocs\u002Fruntime\u002Frest-api","1.docs\u002F5.runtime\u002F2.rest-api","i-lucide-globe",{"title":190,"path":191,"stem":192,"icon":193},"Health checks","\u002Fdocs\u002Fruntime\u002Fhealth-checks","1.docs\u002F5.runtime\u002F3.health-checks","i-lucide-heart-pulse",{"title":195,"path":196,"stem":197,"icon":198},"Metrics","\u002Fdocs\u002Fruntime\u002Fmetrics","1.docs\u002F5.runtime\u002F4.metrics","i-lucide-activity",{"title":200,"path":201,"stem":202,"icon":203},"Pause and resume","\u002Fdocs\u002Fruntime\u002Fpause-unpause","1.docs\u002F5.runtime\u002F5.pause-unpause","i-lucide-pause",{"title":205,"path":206,"stem":207,"icon":208},"Plugins and lifecycle hooks","\u002Fdocs\u002Fruntime\u002Fplugins","1.docs\u002F5.runtime\u002F6.plugins","i-lucide-puzzle",{"title":210,"path":211,"stem":212,"icon":213},"Docker images","\u002Fdocs\u002Fruntime\u002Fdocker","1.docs\u002F5.runtime\u002F7.docker","i-lucide-container",{"title":215,"path":216,"stem":217,"icon":218},"GraalVM native image","\u002Fdocs\u002Fruntime\u002Fnative-image","1.docs\u002F5.runtime\u002F8.native-image","i-lucide-zap",{"title":220,"path":221,"stem":222,"children":223,"icon":226},"Deploying & Operating","\u002Fdocs\u002Foperating","1.docs\u002F6.operating\u002F1.index",[224,227,232,237,242,247,252],{"title":225,"path":221,"stem":222,"icon":226},"Deploying and operating","i-lucide-life-buoy",{"title":228,"path":229,"stem":230,"icon":231},"Running on Kubernetes","\u002Fdocs\u002Foperating\u002Fkubernetes","1.docs\u002F6.operating\u002F2.kubernetes","i-lucide-ship",{"title":233,"path":234,"stem":235,"icon":236},"High availability","\u002Fdocs\u002Foperating\u002Fhigh-availability","1.docs\u002F6.operating\u002F3.high-availability","i-lucide-copy",{"title":238,"path":239,"stem":240,"icon":241},"Liveness and readiness probes","\u002Fdocs\u002Foperating\u002Fprobes","1.docs\u002F6.operating\u002F4.probes","i-lucide-stethoscope",{"title":243,"path":244,"stem":245,"icon":246},"Observability","\u002Fdocs\u002Foperating\u002Fobservability","1.docs\u002F6.operating\u002F5.observability","i-lucide-telescope",{"title":248,"path":249,"stem":250,"icon":251},"Tuning under load","\u002Fdocs\u002Foperating\u002Ftuning","1.docs\u002F6.operating\u002F6.tuning","i-lucide-sliders",{"title":253,"path":254,"stem":255,"icon":256},"Production checklist","\u002Fdocs\u002Foperating\u002Fproduction-checklist","1.docs\u002F6.operating\u002F7.production-checklist","i-lucide-clipboard-check",{"title":258,"path":259,"stem":260,"children":261,"icon":85},"Migrating from Kafka Streams","\u002Fdocs\u002Fmigration","1.docs\u002F7.migration\u002F1.index",[262,263,268],{"title":258,"path":259,"stem":260,"icon":85},{"title":264,"path":265,"stem":266,"icon":267},"Migration without carrying state","\u002Fdocs\u002Fmigration\u002Fwithout-data-migration","1.docs\u002F7.migration\u002F2.without-data-migration","i-lucide-sparkles",{"title":269,"path":270,"stem":271,"icon":272},"Migration carrying state","\u002Fdocs\u002Fmigration\u002Fwith-data-migration","1.docs\u002F7.migration\u002F3.with-data-migration","i-lucide-database-backup",{"title":274,"path":275,"stem":276,"children":277,"icon":279},"Reference","\u002Fdocs\u002Freference","1.docs\u002F8.reference\u002F1.index",[278,280,285,290,295,300,305,309],{"title":274,"path":275,"stem":276,"icon":279},"i-lucide-list",{"title":281,"path":282,"stem":283,"icon":284},"Configuration reference","\u002Fdocs\u002Freference\u002Fconfiguration-reference","1.docs\u002F8.reference\u002F2.configuration-reference","i-lucide-table",{"title":286,"path":287,"stem":288,"icon":289},"REST API reference","\u002Fdocs\u002Freference\u002Frest-api-reference","1.docs\u002F8.reference\u002F3.rest-api-reference","i-lucide-network",{"title":291,"path":292,"stem":293,"icon":294},"Gradle plugin reference","\u002Fdocs\u002Freference\u002Fgradle-plugin-reference","1.docs\u002F8.reference\u002F4.gradle-plugin-reference","i-lucide-box",{"title":296,"path":297,"stem":298,"icon":299},"Maven reference","\u002Fdocs\u002Freference\u002Fmaven-reference","1.docs\u002F8.reference\u002F5.maven-reference","i-simple-icons-apachemaven",{"title":301,"path":302,"stem":303,"icon":304},"Kafka Streams compatibility matrix","\u002Fdocs\u002Freference\u002Fks-compatibility-matrix","1.docs\u002F8.reference\u002F6.ks-compatibility-matrix","i-lucide-table-2",{"title":306,"path":307,"stem":308,"icon":170},"Metrics reference","\u002Fdocs\u002Freference\u002Fmetrics-reference","1.docs\u002F8.reference\u002F7.metrics-reference",{"title":310,"path":311,"stem":312,"icon":313},"Glossary","\u002Fdocs\u002Freference\u002Fglossary","1.docs\u002F8.reference\u002F8.glossary","i-lucide-book-a",{"id":315,"title":125,"body":316,"description":4382,"extension":4383,"meta":4384,"navigation":4385,"pageType":4386,"path":126,"seo":4387,"stem":127,"__hash__":4388},"docs\u002F1.docs\u002F3.building\u002F5.windowing.md",{"type":317,"value":318,"toc":4368},"minimark",[319,356,366,450,455,566,577,581,598,1229,1241,1272,1276,1283,1527,1547,1551,1558,1576,2238,2244,2248,2275,2518,2551,2571,2575,2590,2914,2933,2937,2945,2956,3327,3334,3339,3353,3425,3449,3466,3470,3479,3935,3953,3957,3960,4313,4325,4329,4364],[320,321,322,323,327,328,332,333,336,337,347,348,351,352,355],"p",{},"Windowing groups records by key ",[324,325,326],"strong",{},"and"," by time, so an aggregation produces one result per key per window instead of a single running total. You reach a windowed aggregation by calling ",[329,330,331],"code",{},".windowedBy(...)"," on a ",[329,334,335],{},"KGroupedStream"," — the same grouped type you get from ",[338,339,340,343,344],"a",{"href":121},[329,341,342],{},"groupByKey()"," \u002F ",[329,345,346],{},"groupBy()",". The result is a ",[329,349,350],{},"KTable"," whose key is a ",[329,353,354],{},"Windowed\u003CK>",": the original key plus the window bounds.",[320,357,358,359,362,363,365],{},"Windows are reasoned about in ",[324,360,361],{},"event time",", not wall-clock time — when a window closes is driven by the watermark, not by the clock on the machine. Read ",[338,364,67],{"href":68}," for the model that underpins everything on this page.",[367,368,369],"tldr-panel",{},[370,371,372,392,414,433],"ul",{},[373,374,375,378,379,382,383,382,386,332,389,391],"li",{},[324,376,377],{},"Entry points:"," ",[329,380,381],{},".windowedBy(TimeWindows…)",", ",[329,384,385],{},".windowedBy(SlidingWindows…)",[329,387,388],{},".windowedBy(SessionWindows…)",[329,390,335],{},".",[373,393,394,397,398,401,402,405,406,409,410,413],{},[324,395,396],{},"Window kinds:"," tumbling (",[329,399,400],{},"ofSizeWithNoGrace","), hopping (",[329,403,404],{},".advanceBy(...)","), sliding (",[329,407,408],{},"ofTimeDifference…","), session (",[329,411,412],{},"ofInactivityGap…",").",[373,415,416,378,419,422,423,343,426,429,430,391],{},[324,417,418],{},"Result:",[329,420,421],{},"KTable\u003CWindowed\u003CK>, V>"," — key carries ",[329,424,425],{},"windowStart()",[329,427,428],{},"windowEnd()",". Serialize it for a sink with ",[329,431,432],{},"WindowedSerdes",[373,434,435,378,438,441,442,445,446,449],{},[324,436,437],{},"When to emit:",[329,439,440],{},"EmitStrategy.onWindowUpdate()"," (default, every update) vs ",[329,443,444],{},"EmitStrategy.onWindowClose()"," (one final result). Or ",[329,447,448],{},"KTable.suppress(...)"," for buffering control.",[451,452,454],"h2",{"id":453},"window-kinds-at-a-glance","Window kinds at a glance",[456,457,458,477],"table",{},[459,460,461],"thead",{},[462,463,464,468,471,474],"tr",{},[465,466,467],"th",{},"Kind",[465,469,470],{},"Factory",[465,472,473],{},"Overlap",[465,475,476],{},"Result key window",[478,479,480,501,524,546],"tbody",{},[462,481,482,488,493,496],{},[483,484,485],"td",{},[324,486,487],{},"Tumbling",[483,489,490],{},[329,491,492],{},"TimeWindows.ofSizeWithNoGrace(size)",[483,494,495],{},"None — each record in exactly one window",[483,497,498],{},[329,499,500],{},"TimeWindow",[462,502,503,508,513,520],{},[483,504,505],{},[324,506,507],{},"Hopping",[483,509,510],{},[329,511,512],{},"TimeWindows.ofSizeWithNoGrace(size).advanceBy(advance)",[483,514,515,516,519],{},"Yes — ",[329,517,518],{},"advance \u003C size"," means a record lands in multiple windows",[483,521,522],{},[329,523,500],{},[462,525,526,531,536,542],{},[483,527,528],{},[324,529,530],{},"Sliding",[483,532,533],{},[329,534,535],{},"SlidingWindows.ofTimeDifferenceWithNoGrace(diff)",[483,537,538,539],{},"Event-driven; two events share a window if ",[329,540,541],{},"|t1 - t2| \u003C= diff",[483,543,544],{},[329,545,500],{},[462,547,548,553,558,561],{},[483,549,550],{},[324,551,552],{},"Session",[483,554,555],{},[329,556,557],{},"SessionWindows.ofInactivityGapWithNoGrace(gap)",[483,559,560],{},"Dynamic — sessions grow and merge across activity",[483,562,563],{},[329,564,565],{},"SessionWindow",[320,567,568,569,572,573,576],{},"Every factory has a ",[329,570,571],{},"…AndGrace(…, grace)"," variant that accepts late records for ",[329,574,575],{},"grace"," after the window's end before the window closes. The factories are static methods, so they call identically from Kotlin and Java.",[451,578,580],{"id":579},"tumbling-and-hopping-windows","Tumbling and hopping windows",[320,582,583,586,587,590,591,593,594,597],{},[329,584,585],{},"TimeWindows"," covers both fixed-size cases. A ",[324,588,589],{},"tumbling"," window has no overlap — its advance equals its size. Calling ",[329,592,404],{}," with an interval smaller than the size turns it into a ",[324,595,596],{},"hopping"," window, where each record falls into several overlapping windows.",[599,600,602,893],"code-tabs",{"group":601},"lang",[603,604,610],"pre",{"className":605,"code":606,"filename":607,"language":608,"meta":609,"style":609},"language-kotlin shiki shiki-themes vitesse-light","import io.stoatflow.core.topology.Grouped\nimport io.stoatflow.core.topology.TimeWindows\nimport io.stoatflow.core.topology.Windowed\nimport java.time.Duration\n\n\u002F\u002F Tumbling: count page views per user in fixed 5-minute windows\nval tumbling: KTable\u003CWindowed\u003CString>, Long> =\n    pageViews\n        .groupByKey(Grouped.with(Serdes.String(), pageViewSerde))\n        .windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5)))\n        .count()\n\n\u002F\u002F Hopping: 5-minute windows that advance every 1 minute (each view lands in 5 windows)\nval hopping: KTable\u003CWindowed\u003CString>, Long> =\n    pageViews\n        .groupByKey(Grouped.with(Serdes.String(), pageViewSerde))\n        .windowedBy(\n            TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5))\n                .advanceBy(Duration.ofMinutes(1)),\n        )\n        .count()\n","Kotlin","kotlin","",[329,611,612,625,633,641,649,656,663,700,706,729,758,769,774,780,806,811,828,838,857,878,884],{"__ignoreMap":609},[613,614,617,621],"span",{"class":615,"line":616},"line",1,[613,618,620],{"class":619},"sbBg2","import",[613,622,624],{"class":623},"sySUi"," io.stoatflow.core.topology.Grouped\n",[613,626,628,630],{"class":615,"line":627},2,[613,629,620],{"class":619},[613,631,632],{"class":623}," io.stoatflow.core.topology.TimeWindows\n",[613,634,636,638],{"class":615,"line":635},3,[613,637,620],{"class":619},[613,639,640],{"class":623}," io.stoatflow.core.topology.Windowed\n",[613,642,644,646],{"class":615,"line":643},4,[613,645,620],{"class":619},[613,647,648],{"class":623}," java.time.Duration\n",[613,650,652],{"class":615,"line":651},5,[613,653,655],{"emptyLinePlaceholder":654},true,"\n",[613,657,659],{"class":615,"line":658},6,[613,660,662],{"class":661},"s8zF2","\u002F\u002F Tumbling: count page views per user in fixed 5-minute windows\n",[613,664,666,669,673,676,679,682,684,687,690,693,696],{"class":615,"line":665},7,[613,667,668],{"class":619},"val",[613,670,672],{"class":671},"suHK_"," tumbling: ",[613,674,350],{"class":675},"sUxyF",[613,677,678],{"class":671},"\u003C",[613,680,681],{"class":675},"Windowed",[613,683,678],{"class":671},[613,685,686],{"class":675},"String",[613,688,689],{"class":671},">, ",[613,691,692],{"class":675},"Long",[613,694,695],{"class":671},"> ",[613,697,699],{"class":698},"sYZai","=\n",[613,701,703],{"class":615,"line":702},8,[613,704,705],{"class":671},"    pageViews\n",[613,707,709,712,715,718,721,724,726],{"class":615,"line":708},9,[613,710,711],{"class":671},"        .",[613,713,714],{"class":623},"groupByKey",[613,716,717],{"class":671},"(Grouped.",[613,719,720],{"class":623},"with",[613,722,723],{"class":671},"(Serdes.",[613,725,686],{"class":623},[613,727,728],{"class":671},"(), pageViewSerde))\n",[613,730,732,734,737,740,742,745,748,751,755],{"class":615,"line":731},10,[613,733,711],{"class":671},[613,735,736],{"class":623},"windowedBy",[613,738,739],{"class":671},"(TimeWindows.",[613,741,400],{"class":623},[613,743,744],{"class":671},"(Duration.",[613,746,747],{"class":623},"ofMinutes",[613,749,750],{"class":671},"(",[613,752,754],{"class":753},"s-TwI","5",[613,756,757],{"class":671},")))\n",[613,759,761,763,766],{"class":615,"line":760},11,[613,762,711],{"class":671},[613,764,765],{"class":623},"count",[613,767,768],{"class":671},"()\n",[613,770,772],{"class":615,"line":771},12,[613,773,655],{"emptyLinePlaceholder":654},[613,775,777],{"class":615,"line":776},13,[613,778,779],{"class":661},"\u002F\u002F Hopping: 5-minute windows that advance every 1 minute (each view lands in 5 windows)\n",[613,781,783,785,788,790,792,794,796,798,800,802,804],{"class":615,"line":782},14,[613,784,668],{"class":619},[613,786,787],{"class":671}," hopping: ",[613,789,350],{"class":675},[613,791,678],{"class":671},[613,793,681],{"class":675},[613,795,678],{"class":671},[613,797,686],{"class":675},[613,799,689],{"class":671},[613,801,692],{"class":675},[613,803,695],{"class":671},[613,805,699],{"class":698},[613,807,809],{"class":615,"line":808},15,[613,810,705],{"class":671},[613,812,814,816,818,820,822,824,826],{"class":615,"line":813},16,[613,815,711],{"class":671},[613,817,714],{"class":623},[613,819,717],{"class":671},[613,821,720],{"class":623},[613,823,723],{"class":671},[613,825,686],{"class":623},[613,827,728],{"class":671},[613,829,831,833,835],{"class":615,"line":830},17,[613,832,711],{"class":671},[613,834,736],{"class":623},[613,836,837],{"class":671},"(\n",[613,839,841,844,846,848,850,852,854],{"class":615,"line":840},18,[613,842,843],{"class":671},"            TimeWindows.",[613,845,400],{"class":623},[613,847,744],{"class":671},[613,849,747],{"class":623},[613,851,750],{"class":671},[613,853,754],{"class":753},[613,855,856],{"class":671},"))\n",[613,858,860,863,866,868,870,872,875],{"class":615,"line":859},19,[613,861,862],{"class":671},"                .",[613,864,865],{"class":623},"advanceBy",[613,867,744],{"class":671},[613,869,747],{"class":623},[613,871,750],{"class":671},[613,873,874],{"class":753},"1",[613,876,877],{"class":671},")),\n",[613,879,881],{"class":615,"line":880},20,[613,882,883],{"class":671},"        )\n",[613,885,887,889,891],{"class":615,"line":886},21,[613,888,711],{"class":671},[613,890,765],{"class":623},[613,892,768],{"class":671},[603,894,899],{"className":895,"code":896,"filename":897,"language":898,"meta":609,"style":609},"language-java shiki shiki-themes vitesse-light","import io.stoatflow.core.topology.Grouped;\nimport io.stoatflow.core.topology.TimeWindows;\nimport io.stoatflow.core.topology.Windowed;\nimport java.time.Duration;\n\n\u002F\u002F Tumbling: count page views per user in fixed 5-minute windows\nKTable\u003CWindowed\u003CString>, Long> tumbling =\n    pageViews\n        .groupByKey(Grouped.with(Serdes.String(), pageViewSerde))\n        .windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5)))\n        .count();\n\n\u002F\u002F Hopping: 5-minute windows that advance every 1 minute (each view lands in 5 windows)\nKTable\u003CWindowed\u003CString>, Long> hopping =\n    pageViews\n        .groupByKey(Grouped.with(Serdes.String(), pageViewSerde))\n        .windowedBy(\n            TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5))\n                .advanceBy(Duration.ofMinutes(1)))\n        .count();\n","Java","java",[329,900,901,931,955,979,998,1002,1006,1035,1039,1070,1098,1107,1111,1115,1138,1142,1170,1178,1201,1221],{"__ignoreMap":609},[613,902,903,905,908,910,913,915,918,920,923,925,928],{"class":615,"line":616},[613,904,620],{"class":619},[613,906,907],{"class":671}," io",[613,909,391],{"class":698},[613,911,912],{"class":671},"stoatflow",[613,914,391],{"class":698},[613,916,917],{"class":671},"core",[613,919,391],{"class":698},[613,921,922],{"class":671},"topology",[613,924,391],{"class":698},[613,926,927],{"class":671},"Grouped",[613,929,930],{"class":698},";\n",[613,932,933,935,937,939,941,943,945,947,949,951,953],{"class":615,"line":627},[613,934,620],{"class":619},[613,936,907],{"class":671},[613,938,391],{"class":698},[613,940,912],{"class":671},[613,942,391],{"class":698},[613,944,917],{"class":671},[613,946,391],{"class":698},[613,948,922],{"class":671},[613,950,391],{"class":698},[613,952,585],{"class":671},[613,954,930],{"class":698},[613,956,957,959,961,963,965,967,969,971,973,975,977],{"class":615,"line":635},[613,958,620],{"class":619},[613,960,907],{"class":671},[613,962,391],{"class":698},[613,964,912],{"class":671},[613,966,391],{"class":698},[613,968,917],{"class":671},[613,970,391],{"class":698},[613,972,922],{"class":671},[613,974,391],{"class":698},[613,976,681],{"class":671},[613,978,930],{"class":698},[613,980,981,983,986,988,991,993,996],{"class":615,"line":643},[613,982,620],{"class":619},[613,984,985],{"class":671}," java",[613,987,391],{"class":698},[613,989,990],{"class":671},"time",[613,992,391],{"class":698},[613,994,995],{"class":671},"Duration",[613,997,930],{"class":698},[613,999,1000],{"class":615,"line":651},[613,1001,655],{"emptyLinePlaceholder":654},[613,1003,1004],{"class":615,"line":658},[613,1005,662],{"class":661},[613,1007,1008,1010,1012,1014,1016,1019,1022,1025,1028,1032],{"class":615,"line":665},[613,1009,350],{"class":671},[613,1011,678],{"class":698},[613,1013,681],{"class":671},[613,1015,678],{"class":698},[613,1017,686],{"class":1018},"si04Y",[613,1020,1021],{"class":698},">,",[613,1023,1024],{"class":1018}," Long",[613,1026,1027],{"class":698},">",[613,1029,1031],{"class":1030},"svycV"," tumbling",[613,1033,1034],{"class":698}," =\n",[613,1036,1037],{"class":615,"line":702},[613,1038,705],{"class":671},[613,1040,1041,1043,1045,1047,1049,1051,1053,1055,1058,1060,1062,1065,1068],{"class":615,"line":708},[613,1042,711],{"class":698},[613,1044,714],{"class":623},[613,1046,750],{"class":698},[613,1048,927],{"class":1030},[613,1050,391],{"class":698},[613,1052,720],{"class":623},[613,1054,750],{"class":698},[613,1056,1057],{"class":1030},"Serdes",[613,1059,391],{"class":698},[613,1061,686],{"class":623},[613,1063,1064],{"class":698},"(),",[613,1066,1067],{"class":671}," pageViewSerde",[613,1069,856],{"class":698},[613,1071,1072,1074,1076,1078,1080,1082,1084,1086,1088,1090,1092,1094,1096],{"class":615,"line":731},[613,1073,711],{"class":698},[613,1075,736],{"class":623},[613,1077,750],{"class":698},[613,1079,585],{"class":1030},[613,1081,391],{"class":698},[613,1083,400],{"class":623},[613,1085,750],{"class":698},[613,1087,995],{"class":1030},[613,1089,391],{"class":698},[613,1091,747],{"class":623},[613,1093,750],{"class":698},[613,1095,754],{"class":753},[613,1097,757],{"class":698},[613,1099,1100,1102,1104],{"class":615,"line":760},[613,1101,711],{"class":698},[613,1103,765],{"class":623},[613,1105,1106],{"class":698},"();\n",[613,1108,1109],{"class":615,"line":771},[613,1110,655],{"emptyLinePlaceholder":654},[613,1112,1113],{"class":615,"line":776},[613,1114,779],{"class":661},[613,1116,1117,1119,1121,1123,1125,1127,1129,1131,1133,1136],{"class":615,"line":782},[613,1118,350],{"class":671},[613,1120,678],{"class":698},[613,1122,681],{"class":671},[613,1124,678],{"class":698},[613,1126,686],{"class":1018},[613,1128,1021],{"class":698},[613,1130,1024],{"class":1018},[613,1132,1027],{"class":698},[613,1134,1135],{"class":1030}," hopping",[613,1137,1034],{"class":698},[613,1139,1140],{"class":615,"line":808},[613,1141,705],{"class":671},[613,1143,1144,1146,1148,1150,1152,1154,1156,1158,1160,1162,1164,1166,1168],{"class":615,"line":813},[613,1145,711],{"class":698},[613,1147,714],{"class":623},[613,1149,750],{"class":698},[613,1151,927],{"class":1030},[613,1153,391],{"class":698},[613,1155,720],{"class":623},[613,1157,750],{"class":698},[613,1159,1057],{"class":1030},[613,1161,391],{"class":698},[613,1163,686],{"class":623},[613,1165,1064],{"class":698},[613,1167,1067],{"class":671},[613,1169,856],{"class":698},[613,1171,1172,1174,1176],{"class":615,"line":830},[613,1173,711],{"class":698},[613,1175,736],{"class":623},[613,1177,837],{"class":698},[613,1179,1180,1183,1185,1187,1189,1191,1193,1195,1197,1199],{"class":615,"line":840},[613,1181,1182],{"class":1030},"            TimeWindows",[613,1184,391],{"class":698},[613,1186,400],{"class":623},[613,1188,750],{"class":698},[613,1190,995],{"class":1030},[613,1192,391],{"class":698},[613,1194,747],{"class":623},[613,1196,750],{"class":698},[613,1198,754],{"class":753},[613,1200,856],{"class":698},[613,1202,1203,1205,1207,1209,1211,1213,1215,1217,1219],{"class":615,"line":859},[613,1204,862],{"class":698},[613,1206,865],{"class":623},[613,1208,750],{"class":698},[613,1210,995],{"class":1030},[613,1212,391],{"class":698},[613,1214,747],{"class":623},[613,1216,750],{"class":698},[613,1218,874],{"class":753},[613,1220,757],{"class":698},[613,1222,1223,1225,1227],{"class":615,"line":880},[613,1224,711],{"class":698},[613,1226,765],{"class":623},[613,1228,1106],{"class":698},[320,1230,1231,1233,1234,1237,1238,1240],{},[329,1232,404],{}," must be positive and no larger than the window size; an advance equal to the size is just a tumbling window again. To accept late records, swap the factory for ",[329,1235,1236],{},"TimeWindows.ofSizeAndGrace(size, grace)"," — the window then stays open for ",[329,1239,575],{}," past its end before closing.",[320,1242,1243,382,1246,1249,1250,1253,1254,1256,1257,1259,1260,1263,1264,1267,1268,1271],{},[329,1244,1245],{},"count()",[329,1247,1248],{},"reduce(...)",", and ",[329,1251,1252],{},"aggregate(...)"," are all available on the windowed stream, with the same Kotlin-lambda \u002F Java-functional-interface overloads as the non-windowed aggregations (see ",[338,1255,120],{"href":121},"). ",[329,1258,1245],{}," returns ",[329,1261,1262],{},"KTable\u003CWindowed\u003CK>, Long>","; ",[329,1265,1266],{},"reduce"," and ",[329,1269,1270],{},"aggregate"," return your value type.",[451,1273,1275],{"id":1274},"sliding-windows","Sliding windows",[320,1277,1278,1279,1282],{},"A sliding window is defined by a ",[324,1280,1281],{},"time difference"," rather than a fixed grid position. Two events belong to the same window when their event-time difference is within the configured difference; windows are positioned relative to each event. This is the KIP-450 event-driven model — roughly two to three windows per event, not one window per millisecond of advance.",[599,1284,1285,1385],{"group":601},[603,1286,1288],{"className":605,"code":1287,"filename":607,"language":608,"meta":609,"style":609},"import io.stoatflow.core.topology.SlidingWindows\nimport java.time.Duration\n\nval slidingCounts: KTable\u003CWindowed\u003CString>, Long> =\n    events\n        .groupByKey(Grouped.with(Serdes.String(), eventSerde))\n        .windowedBy(SlidingWindows.ofTimeDifferenceWithNoGrace(Duration.ofMinutes(10)))\n        .count()\n",[329,1289,1290,1297,1303,1307,1332,1337,1354,1377],{"__ignoreMap":609},[613,1291,1292,1294],{"class":615,"line":616},[613,1293,620],{"class":619},[613,1295,1296],{"class":623}," io.stoatflow.core.topology.SlidingWindows\n",[613,1298,1299,1301],{"class":615,"line":627},[613,1300,620],{"class":619},[613,1302,648],{"class":623},[613,1304,1305],{"class":615,"line":635},[613,1306,655],{"emptyLinePlaceholder":654},[613,1308,1309,1311,1314,1316,1318,1320,1322,1324,1326,1328,1330],{"class":615,"line":643},[613,1310,668],{"class":619},[613,1312,1313],{"class":671}," slidingCounts: ",[613,1315,350],{"class":675},[613,1317,678],{"class":671},[613,1319,681],{"class":675},[613,1321,678],{"class":671},[613,1323,686],{"class":675},[613,1325,689],{"class":671},[613,1327,692],{"class":675},[613,1329,695],{"class":671},[613,1331,699],{"class":698},[613,1333,1334],{"class":615,"line":651},[613,1335,1336],{"class":671},"    events\n",[613,1338,1339,1341,1343,1345,1347,1349,1351],{"class":615,"line":658},[613,1340,711],{"class":671},[613,1342,714],{"class":623},[613,1344,717],{"class":671},[613,1346,720],{"class":623},[613,1348,723],{"class":671},[613,1350,686],{"class":623},[613,1352,1353],{"class":671},"(), eventSerde))\n",[613,1355,1356,1358,1360,1363,1366,1368,1370,1372,1375],{"class":615,"line":665},[613,1357,711],{"class":671},[613,1359,736],{"class":623},[613,1361,1362],{"class":671},"(SlidingWindows.",[613,1364,1365],{"class":623},"ofTimeDifferenceWithNoGrace",[613,1367,744],{"class":671},[613,1369,747],{"class":623},[613,1371,750],{"class":671},[613,1373,1374],{"class":753},"10",[613,1376,757],{"class":671},[613,1378,1379,1381,1383],{"class":615,"line":702},[613,1380,711],{"class":671},[613,1382,765],{"class":623},[613,1384,768],{"class":671},[603,1386,1388],{"className":895,"code":1387,"filename":897,"language":898,"meta":609,"style":609},"import io.stoatflow.core.topology.SlidingWindows;\nimport java.time.Duration;\n\nKTable\u003CWindowed\u003CString>, Long> slidingCounts =\n    events\n        .groupByKey(Grouped.with(Serdes.String(), eventSerde))\n        .windowedBy(SlidingWindows.ofTimeDifferenceWithNoGrace(Duration.ofMinutes(10)))\n        .count();\n",[329,1389,1390,1415,1431,1435,1458,1462,1491,1519],{"__ignoreMap":609},[613,1391,1392,1394,1396,1398,1400,1402,1404,1406,1408,1410,1413],{"class":615,"line":616},[613,1393,620],{"class":619},[613,1395,907],{"class":671},[613,1397,391],{"class":698},[613,1399,912],{"class":671},[613,1401,391],{"class":698},[613,1403,917],{"class":671},[613,1405,391],{"class":698},[613,1407,922],{"class":671},[613,1409,391],{"class":698},[613,1411,1412],{"class":671},"SlidingWindows",[613,1414,930],{"class":698},[613,1416,1417,1419,1421,1423,1425,1427,1429],{"class":615,"line":627},[613,1418,620],{"class":619},[613,1420,985],{"class":671},[613,1422,391],{"class":698},[613,1424,990],{"class":671},[613,1426,391],{"class":698},[613,1428,995],{"class":671},[613,1430,930],{"class":698},[613,1432,1433],{"class":615,"line":635},[613,1434,655],{"emptyLinePlaceholder":654},[613,1436,1437,1439,1441,1443,1445,1447,1449,1451,1453,1456],{"class":615,"line":643},[613,1438,350],{"class":671},[613,1440,678],{"class":698},[613,1442,681],{"class":671},[613,1444,678],{"class":698},[613,1446,686],{"class":1018},[613,1448,1021],{"class":698},[613,1450,1024],{"class":1018},[613,1452,1027],{"class":698},[613,1454,1455],{"class":1030}," slidingCounts",[613,1457,1034],{"class":698},[613,1459,1460],{"class":615,"line":651},[613,1461,1336],{"class":671},[613,1463,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1484,1486,1489],{"class":615,"line":658},[613,1465,711],{"class":698},[613,1467,714],{"class":623},[613,1469,750],{"class":698},[613,1471,927],{"class":1030},[613,1473,391],{"class":698},[613,1475,720],{"class":623},[613,1477,750],{"class":698},[613,1479,1057],{"class":1030},[613,1481,391],{"class":698},[613,1483,686],{"class":623},[613,1485,1064],{"class":698},[613,1487,1488],{"class":671}," eventSerde",[613,1490,856],{"class":698},[613,1492,1493,1495,1497,1499,1501,1503,1505,1507,1509,1511,1513,1515,1517],{"class":615,"line":665},[613,1494,711],{"class":698},[613,1496,736],{"class":623},[613,1498,750],{"class":698},[613,1500,1412],{"class":1030},[613,1502,391],{"class":698},[613,1504,1365],{"class":623},[613,1506,750],{"class":698},[613,1508,995],{"class":1030},[613,1510,391],{"class":698},[613,1512,747],{"class":623},[613,1514,750],{"class":698},[613,1516,1374],{"class":753},[613,1518,757],{"class":698},[613,1520,1521,1523,1525],{"class":615,"line":702},[613,1522,711],{"class":698},[613,1524,765],{"class":623},[613,1526,1106],{"class":698},[320,1528,1529,1530,1267,1533,1536,1537,1267,1539,1542,1543,1546],{},"For a 10-minute difference, events at ",[329,1531,1532],{},"t=0",[329,1534,1535],{},"t=5min"," share a window (5 ≤ 10), while events at ",[329,1538,1532],{},[329,1540,1541],{},"t=15min"," do not (15 > 10). Use ",[329,1544,1545],{},"SlidingWindows.ofTimeDifferenceAndGrace(diff, grace)"," to admit late records.",[451,1548,1550],{"id":1549},"session-windows","Session windows",[320,1552,1553,1554,1557],{},"Session windows are dynamic. A session grows as long as records keep arriving within the ",[324,1555,1556],{},"inactivity gap","; once activity pauses longer than the gap, the session closes and the next record starts a fresh one. When a record bridges two existing sessions, they merge.",[320,1559,1560,1561,1563,1564,1567,1568,1267,1570,1572,1573,1575],{},"Because sessions merge, ",[329,1562,1252],{}," on a session window ",[324,1565,1566],{},"requires a session merger"," — a function that combines the aggregates of two sessions being joined. ",[329,1569,1245],{},[329,1571,1248],{}," supply this implicitly (counts sum; the reducer doubles as the merger), but ",[329,1574,1270],{}," makes you pass it explicitly.",[599,1577,1578,1837],{"group":601},[603,1579,1581],{"className":605,"code":1580,"filename":607,"language":608,"meta":609,"style":609},"import io.stoatflow.core.topology.SessionWindows\nimport java.time.Duration\n\n\u002F\u002F Count user actions per session (30-minute inactivity gap)\nval sessionCounts: KTable\u003CWindowed\u003CString>, Long> =\n    userActions\n        .groupByKey(Grouped.with(Serdes.String(), actionSerde))\n        .windowedBy(SessionWindows.ofInactivityGapWithNoGrace(Duration.ofMinutes(30)))\n        .count()\n\n\u002F\u002F Aggregate with an explicit session merger\nval sessionActions: KTable\u003CWindowed\u003CString>, List\u003CAction>> =\n    userActions\n        .groupByKey(Grouped.with(Serdes.String(), actionSerde))\n        .windowedBy(SessionWindows.ofInactivityGapWithNoGrace(Duration.ofMinutes(30)))\n        .aggregate(\n            { emptyList() },                                   \u002F\u002F initializer\n            { _, value, agg -> agg + value },                 \u002F\u002F aggregator\n            { _, agg1, agg2 -> agg1 + agg2 },                 \u002F\u002F session merger (required)\n        )\n",[329,1582,1583,1590,1596,1600,1605,1630,1635,1652,1675,1683,1687,1692,1724,1728,1744,1764,1772,1786,1815,1833],{"__ignoreMap":609},[613,1584,1585,1587],{"class":615,"line":616},[613,1586,620],{"class":619},[613,1588,1589],{"class":623}," io.stoatflow.core.topology.SessionWindows\n",[613,1591,1592,1594],{"class":615,"line":627},[613,1593,620],{"class":619},[613,1595,648],{"class":623},[613,1597,1598],{"class":615,"line":635},[613,1599,655],{"emptyLinePlaceholder":654},[613,1601,1602],{"class":615,"line":643},[613,1603,1604],{"class":661},"\u002F\u002F Count user actions per session (30-minute inactivity gap)\n",[613,1606,1607,1609,1612,1614,1616,1618,1620,1622,1624,1626,1628],{"class":615,"line":651},[613,1608,668],{"class":619},[613,1610,1611],{"class":671}," sessionCounts: ",[613,1613,350],{"class":675},[613,1615,678],{"class":671},[613,1617,681],{"class":675},[613,1619,678],{"class":671},[613,1621,686],{"class":675},[613,1623,689],{"class":671},[613,1625,692],{"class":675},[613,1627,695],{"class":671},[613,1629,699],{"class":698},[613,1631,1632],{"class":615,"line":658},[613,1633,1634],{"class":671},"    userActions\n",[613,1636,1637,1639,1641,1643,1645,1647,1649],{"class":615,"line":665},[613,1638,711],{"class":671},[613,1640,714],{"class":623},[613,1642,717],{"class":671},[613,1644,720],{"class":623},[613,1646,723],{"class":671},[613,1648,686],{"class":623},[613,1650,1651],{"class":671},"(), actionSerde))\n",[613,1653,1654,1656,1658,1661,1664,1666,1668,1670,1673],{"class":615,"line":702},[613,1655,711],{"class":671},[613,1657,736],{"class":623},[613,1659,1660],{"class":671},"(SessionWindows.",[613,1662,1663],{"class":623},"ofInactivityGapWithNoGrace",[613,1665,744],{"class":671},[613,1667,747],{"class":623},[613,1669,750],{"class":671},[613,1671,1672],{"class":753},"30",[613,1674,757],{"class":671},[613,1676,1677,1679,1681],{"class":615,"line":708},[613,1678,711],{"class":671},[613,1680,765],{"class":623},[613,1682,768],{"class":671},[613,1684,1685],{"class":615,"line":731},[613,1686,655],{"emptyLinePlaceholder":654},[613,1688,1689],{"class":615,"line":760},[613,1690,1691],{"class":661},"\u002F\u002F Aggregate with an explicit session merger\n",[613,1693,1694,1696,1699,1701,1703,1705,1707,1709,1711,1714,1716,1719,1722],{"class":615,"line":771},[613,1695,668],{"class":619},[613,1697,1698],{"class":671}," sessionActions: ",[613,1700,350],{"class":675},[613,1702,678],{"class":671},[613,1704,681],{"class":675},[613,1706,678],{"class":671},[613,1708,686],{"class":675},[613,1710,689],{"class":671},[613,1712,1713],{"class":675},"List",[613,1715,678],{"class":671},[613,1717,1718],{"class":675},"Action",[613,1720,1721],{"class":671},">> ",[613,1723,699],{"class":698},[613,1725,1726],{"class":615,"line":776},[613,1727,1634],{"class":671},[613,1729,1730,1732,1734,1736,1738,1740,1742],{"class":615,"line":782},[613,1731,711],{"class":671},[613,1733,714],{"class":623},[613,1735,717],{"class":671},[613,1737,720],{"class":623},[613,1739,723],{"class":671},[613,1741,686],{"class":623},[613,1743,1651],{"class":671},[613,1745,1746,1748,1750,1752,1754,1756,1758,1760,1762],{"class":615,"line":808},[613,1747,711],{"class":671},[613,1749,736],{"class":623},[613,1751,1660],{"class":671},[613,1753,1663],{"class":623},[613,1755,744],{"class":671},[613,1757,747],{"class":623},[613,1759,750],{"class":671},[613,1761,1672],{"class":753},[613,1763,757],{"class":671},[613,1765,1766,1768,1770],{"class":615,"line":813},[613,1767,711],{"class":671},[613,1769,1270],{"class":623},[613,1771,837],{"class":671},[613,1773,1774,1777,1780,1783],{"class":615,"line":830},[613,1775,1776],{"class":671},"            { ",[613,1778,1779],{"class":623},"emptyList",[613,1781,1782],{"class":671},"() },                                   ",[613,1784,1785],{"class":661},"\u002F\u002F initializer\n",[613,1787,1788,1791,1794,1797,1800,1803,1806,1809,1812],{"class":615,"line":840},[613,1789,1790],{"class":671},"            { _, ",[613,1792,1793],{"class":1018},"value",[613,1795,1796],{"class":671},", agg ",[613,1798,1799],{"class":698},"->",[613,1801,1802],{"class":671}," agg ",[613,1804,1805],{"class":1018},"+",[613,1807,1808],{"class":1018}," value",[613,1810,1811],{"class":671}," },                 ",[613,1813,1814],{"class":661},"\u002F\u002F aggregator\n",[613,1816,1817,1820,1822,1825,1827,1830],{"class":615,"line":859},[613,1818,1819],{"class":671},"            { _, agg1, agg2 ",[613,1821,1799],{"class":698},[613,1823,1824],{"class":671}," agg1 ",[613,1826,1805],{"class":1018},[613,1828,1829],{"class":671}," agg2 },                 ",[613,1831,1832],{"class":661},"\u002F\u002F session merger (required)\n",[613,1834,1835],{"class":615,"line":880},[613,1836,883],{"class":671},[603,1838,1840],{"className":895,"code":1839,"filename":897,"language":898,"meta":609,"style":609},"import io.stoatflow.core.topology.SessionWindows;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.time.Duration;\n\n\u002F\u002F Count user actions per session (30-minute inactivity gap)\nKTable\u003CWindowed\u003CString>, Long> sessionCounts =\n    userActions\n        .groupByKey(Grouped.with(Serdes.String(), actionSerde))\n        .windowedBy(SessionWindows.ofInactivityGapWithNoGrace(Duration.ofMinutes(30)))\n        .count();\n\n\u002F\u002F Aggregate with an explicit session merger\nKTable\u003CWindowed\u003CString>, List\u003CAction>> sessionActions =\n    userActions\n        .groupByKey(Grouped.with(Serdes.String(), actionSerde))\n        .windowedBy(SessionWindows.ofInactivityGapWithNoGrace(Duration.ofMinutes(30)))\n        .aggregate(\n            ArrayList::new,                                   \u002F\u002F initializer\n            (key, value, agg) -> { agg.add(value); return agg; },  \u002F\u002F aggregator\n            (key, agg1, agg2) -> { agg1.addAll(agg2); return agg1; });  \u002F\u002F session merger (required)\n",[329,1841,1842,1867,1885,1901,1917,1921,1925,1948,1952,1981,2009,2017,2021,2025,2054,2058,2086,2114,2122,2136,2190],{"__ignoreMap":609},[613,1843,1844,1846,1848,1850,1852,1854,1856,1858,1860,1862,1865],{"class":615,"line":616},[613,1845,620],{"class":619},[613,1847,907],{"class":671},[613,1849,391],{"class":698},[613,1851,912],{"class":671},[613,1853,391],{"class":698},[613,1855,917],{"class":671},[613,1857,391],{"class":698},[613,1859,922],{"class":671},[613,1861,391],{"class":698},[613,1863,1864],{"class":671},"SessionWindows",[613,1866,930],{"class":698},[613,1868,1869,1871,1873,1875,1878,1880,1883],{"class":615,"line":627},[613,1870,620],{"class":619},[613,1872,985],{"class":671},[613,1874,391],{"class":698},[613,1876,1877],{"class":671},"util",[613,1879,391],{"class":698},[613,1881,1882],{"class":671},"ArrayList",[613,1884,930],{"class":698},[613,1886,1887,1889,1891,1893,1895,1897,1899],{"class":615,"line":635},[613,1888,620],{"class":619},[613,1890,985],{"class":671},[613,1892,391],{"class":698},[613,1894,1877],{"class":671},[613,1896,391],{"class":698},[613,1898,1713],{"class":671},[613,1900,930],{"class":698},[613,1902,1903,1905,1907,1909,1911,1913,1915],{"class":615,"line":643},[613,1904,620],{"class":619},[613,1906,985],{"class":671},[613,1908,391],{"class":698},[613,1910,990],{"class":671},[613,1912,391],{"class":698},[613,1914,995],{"class":671},[613,1916,930],{"class":698},[613,1918,1919],{"class":615,"line":651},[613,1920,655],{"emptyLinePlaceholder":654},[613,1922,1923],{"class":615,"line":658},[613,1924,1604],{"class":661},[613,1926,1927,1929,1931,1933,1935,1937,1939,1941,1943,1946],{"class":615,"line":665},[613,1928,350],{"class":671},[613,1930,678],{"class":698},[613,1932,681],{"class":671},[613,1934,678],{"class":698},[613,1936,686],{"class":1018},[613,1938,1021],{"class":698},[613,1940,1024],{"class":1018},[613,1942,1027],{"class":698},[613,1944,1945],{"class":1030}," sessionCounts",[613,1947,1034],{"class":698},[613,1949,1950],{"class":615,"line":702},[613,1951,1634],{"class":671},[613,1953,1954,1956,1958,1960,1962,1964,1966,1968,1970,1972,1974,1976,1979],{"class":615,"line":708},[613,1955,711],{"class":698},[613,1957,714],{"class":623},[613,1959,750],{"class":698},[613,1961,927],{"class":1030},[613,1963,391],{"class":698},[613,1965,720],{"class":623},[613,1967,750],{"class":698},[613,1969,1057],{"class":1030},[613,1971,391],{"class":698},[613,1973,686],{"class":623},[613,1975,1064],{"class":698},[613,1977,1978],{"class":671}," actionSerde",[613,1980,856],{"class":698},[613,1982,1983,1985,1987,1989,1991,1993,1995,1997,1999,2001,2003,2005,2007],{"class":615,"line":731},[613,1984,711],{"class":698},[613,1986,736],{"class":623},[613,1988,750],{"class":698},[613,1990,1864],{"class":1030},[613,1992,391],{"class":698},[613,1994,1663],{"class":623},[613,1996,750],{"class":698},[613,1998,995],{"class":1030},[613,2000,391],{"class":698},[613,2002,747],{"class":623},[613,2004,750],{"class":698},[613,2006,1672],{"class":753},[613,2008,757],{"class":698},[613,2010,2011,2013,2015],{"class":615,"line":760},[613,2012,711],{"class":698},[613,2014,765],{"class":623},[613,2016,1106],{"class":698},[613,2018,2019],{"class":615,"line":771},[613,2020,655],{"emptyLinePlaceholder":654},[613,2022,2023],{"class":615,"line":776},[613,2024,1691],{"class":661},[613,2026,2027,2029,2031,2033,2035,2037,2039,2042,2044,2046,2049,2052],{"class":615,"line":782},[613,2028,350],{"class":671},[613,2030,678],{"class":698},[613,2032,681],{"class":671},[613,2034,678],{"class":698},[613,2036,686],{"class":1018},[613,2038,1021],{"class":698},[613,2040,2041],{"class":671}," List",[613,2043,678],{"class":698},[613,2045,1718],{"class":1018},[613,2047,2048],{"class":698},">>",[613,2050,2051],{"class":1030}," sessionActions",[613,2053,1034],{"class":698},[613,2055,2056],{"class":615,"line":808},[613,2057,1634],{"class":671},[613,2059,2060,2062,2064,2066,2068,2070,2072,2074,2076,2078,2080,2082,2084],{"class":615,"line":813},[613,2061,711],{"class":698},[613,2063,714],{"class":623},[613,2065,750],{"class":698},[613,2067,927],{"class":1030},[613,2069,391],{"class":698},[613,2071,720],{"class":623},[613,2073,750],{"class":698},[613,2075,1057],{"class":1030},[613,2077,391],{"class":698},[613,2079,686],{"class":623},[613,2081,1064],{"class":698},[613,2083,1978],{"class":671},[613,2085,856],{"class":698},[613,2087,2088,2090,2092,2094,2096,2098,2100,2102,2104,2106,2108,2110,2112],{"class":615,"line":830},[613,2089,711],{"class":698},[613,2091,736],{"class":623},[613,2093,750],{"class":698},[613,2095,1864],{"class":1030},[613,2097,391],{"class":698},[613,2099,1663],{"class":623},[613,2101,750],{"class":698},[613,2103,995],{"class":1030},[613,2105,391],{"class":698},[613,2107,747],{"class":623},[613,2109,750],{"class":698},[613,2111,1672],{"class":753},[613,2113,757],{"class":698},[613,2115,2116,2118,2120],{"class":615,"line":840},[613,2117,711],{"class":698},[613,2119,1270],{"class":623},[613,2121,837],{"class":698},[613,2123,2124,2127,2130,2133],{"class":615,"line":859},[613,2125,2126],{"class":671},"            ArrayList",[613,2128,2129],{"class":619},"::new",[613,2131,2132],{"class":698},",",[613,2134,2135],{"class":661},"                                   \u002F\u002F initializer\n",[613,2137,2138,2141,2144,2146,2148,2150,2153,2156,2159,2162,2164,2166,2169,2171,2173,2176,2179,2181,2184,2187],{"class":615,"line":880},[613,2139,2140],{"class":698},"            (",[613,2142,2143],{"class":671},"key",[613,2145,2132],{"class":698},[613,2147,1808],{"class":671},[613,2149,2132],{"class":698},[613,2151,2152],{"class":671}," agg",[613,2154,2155],{"class":698},")",[613,2157,2158],{"class":698}," ->",[613,2160,2161],{"class":698}," {",[613,2163,2152],{"class":1030},[613,2165,391],{"class":698},[613,2167,2168],{"class":623},"add",[613,2170,750],{"class":698},[613,2172,1793],{"class":671},[613,2174,2175],{"class":698},");",[613,2177,2178],{"class":619}," return",[613,2180,2152],{"class":671},[613,2182,2183],{"class":698},";",[613,2185,2186],{"class":698}," },",[613,2188,2189],{"class":661},"  \u002F\u002F aggregator\n",[613,2191,2192,2194,2196,2198,2201,2203,2206,2208,2210,2212,2214,2216,2219,2221,2224,2226,2228,2230,2232,2235],{"class":615,"line":886},[613,2193,2140],{"class":698},[613,2195,2143],{"class":671},[613,2197,2132],{"class":698},[613,2199,2200],{"class":671}," agg1",[613,2202,2132],{"class":698},[613,2204,2205],{"class":671}," agg2",[613,2207,2155],{"class":698},[613,2209,2158],{"class":698},[613,2211,2161],{"class":698},[613,2213,2200],{"class":1030},[613,2215,391],{"class":698},[613,2217,2218],{"class":623},"addAll",[613,2220,750],{"class":698},[613,2222,2223],{"class":671},"agg2",[613,2225,2175],{"class":698},[613,2227,2178],{"class":619},[613,2229,2200],{"class":671},[613,2231,2183],{"class":698},[613,2233,2234],{"class":698}," });",[613,2236,2237],{"class":661},"  \u002F\u002F session merger (required)\n",[320,2239,2240,2243],{},[329,2241,2242],{},"SessionWindows.ofInactivityGapAndGrace(gap, grace)"," adds a grace period on top of the inactivity gap before a session is considered closed.",[451,2245,2247],{"id":2246},"windowed-keys","Windowed keys",[320,2249,2250,2251,2253,2254,2257,2258,2260,2261,2263,2264,2267,2268,2271,2272,391],{},"Every windowed aggregation keys its output by ",[329,2252,354],{}," — the original key plus a ",[329,2255,2256],{},"Window"," (a ",[329,2259,500],{}," for time\u002Fsliding aggregations, a ",[329,2262,565],{}," for sessions). The window is a half-open interval ",[329,2265,2266],{},"[start, end)",": it includes ",[329,2269,2270],{},"start"," and excludes ",[329,2273,2274],{},"end",[599,2276,2277,2384],{"group":601},[603,2278,2280],{"className":605,"code":2279,"filename":607,"language":608,"meta":609,"style":609},"windowedCounts.toStream().forEach { windowedKey, count ->\n    println(\n        \"key=${windowedKey.key} \" +\n            \"window=${windowedKey.windowStartTime()}..${windowedKey.windowEndTime()} \" +\n            \"count=$count\",\n    )\n}\n",[329,2281,2282,2302,2309,2330,2366,2374,2379],{"__ignoreMap":609},[613,2283,2284,2287,2290,2293,2296,2299],{"class":615,"line":616},[613,2285,2286],{"class":671},"windowedCounts.",[613,2288,2289],{"class":623},"toStream",[613,2291,2292],{"class":671},"().",[613,2294,2295],{"class":623},"forEach",[613,2297,2298],{"class":671}," { windowedKey, count ",[613,2300,2301],{"class":698},"->\n",[613,2303,2304,2307],{"class":615,"line":627},[613,2305,2306],{"class":623},"    println",[613,2308,837],{"class":671},[613,2310,2311,2315,2318,2321,2324,2327],{"class":615,"line":635},[613,2312,2314],{"class":2313},"spphp","        \"key=",[613,2316,2317],{"class":619},"${",[613,2319,2320],{"class":2313},"windowedKey.key",[613,2322,2323],{"class":619},"}",[613,2325,2326],{"class":2313}," \"",[613,2328,2329],{"class":1018}," +\n",[613,2331,2332,2335,2337,2340,2343,2346,2348,2351,2353,2355,2358,2360,2362,2364],{"class":615,"line":643},[613,2333,2334],{"class":2313},"            \"window=",[613,2336,2317],{"class":619},[613,2338,2339],{"class":2313},"windowedKey.",[613,2341,2342],{"class":623},"windowStartTime",[613,2344,2345],{"class":2313},"()",[613,2347,2323],{"class":619},[613,2349,2350],{"class":2313},"..",[613,2352,2317],{"class":619},[613,2354,2339],{"class":2313},[613,2356,2357],{"class":623},"windowEndTime",[613,2359,2345],{"class":2313},[613,2361,2323],{"class":619},[613,2363,2326],{"class":2313},[613,2365,2329],{"class":1018},[613,2367,2368,2371],{"class":615,"line":651},[613,2369,2370],{"class":2313},"            \"count=$count\"",[613,2372,2373],{"class":671},",\n",[613,2375,2376],{"class":615,"line":658},[613,2377,2378],{"class":671},"    )\n",[613,2380,2381],{"class":615,"line":665},[613,2382,2383],{"class":671},"}\n",[603,2385,2387],{"className":895,"code":2386,"filename":897,"language":898,"meta":609,"style":609},"windowedCounts.toStream().forEach((windowedKey, count) ->\n    System.out.println(\n        \"key=\" + windowedKey.getKey()\n            + \" window=\" + windowedKey.windowStartTime() + \"..\" + windowedKey.windowEndTime()\n            + \" count=\" + count));\n",[329,2388,2389,2418,2435,2460,2500],{"__ignoreMap":609},[613,2390,2391,2394,2396,2398,2400,2402,2405,2408,2410,2413,2415],{"class":615,"line":616},[613,2392,2393],{"class":1030},"windowedCounts",[613,2395,391],{"class":698},[613,2397,2289],{"class":623},[613,2399,2292],{"class":698},[613,2401,2295],{"class":623},[613,2403,2404],{"class":698},"((",[613,2406,2407],{"class":671},"windowedKey",[613,2409,2132],{"class":698},[613,2411,2412],{"class":671}," count",[613,2414,2155],{"class":698},[613,2416,2417],{"class":698}," ->\n",[613,2419,2420,2423,2425,2428,2430,2433],{"class":615,"line":627},[613,2421,2422],{"class":1030},"    System",[613,2424,391],{"class":698},[613,2426,2427],{"class":1030},"out",[613,2429,391],{"class":698},[613,2431,2432],{"class":623},"println",[613,2434,837],{"class":698},[613,2436,2437,2441,2444,2447,2450,2453,2455,2458],{"class":615,"line":635},[613,2438,2440],{"class":2439},"sSP4y","        \"",[613,2442,2443],{"class":2313},"key=",[613,2445,2446],{"class":2439},"\"",[613,2448,2449],{"class":1018}," +",[613,2451,2452],{"class":1030}," windowedKey",[613,2454,391],{"class":698},[613,2456,2457],{"class":623},"getKey",[613,2459,768],{"class":698},[613,2461,2462,2465,2467,2470,2472,2474,2476,2478,2480,2482,2484,2486,2488,2490,2492,2494,2496,2498],{"class":615,"line":643},[613,2463,2464],{"class":1018},"            +",[613,2466,2326],{"class":2439},[613,2468,2469],{"class":2313}," window=",[613,2471,2446],{"class":2439},[613,2473,2449],{"class":1018},[613,2475,2452],{"class":1030},[613,2477,391],{"class":698},[613,2479,2342],{"class":623},[613,2481,2345],{"class":698},[613,2483,2449],{"class":1018},[613,2485,2326],{"class":2439},[613,2487,2350],{"class":2313},[613,2489,2446],{"class":2439},[613,2491,2449],{"class":1018},[613,2493,2452],{"class":1030},[613,2495,391],{"class":698},[613,2497,2357],{"class":623},[613,2499,768],{"class":698},[613,2501,2502,2504,2506,2509,2511,2513,2515],{"class":615,"line":651},[613,2503,2464],{"class":1018},[613,2505,2326],{"class":2439},[613,2507,2508],{"class":2313}," count=",[613,2510,2446],{"class":2439},[613,2512,2449],{"class":1018},[613,2514,2412],{"class":671},[613,2516,2517],{"class":698},"));\n",[320,2519,2520,2522,2523,343,2525,2527,2528,343,2531,2534,2535,2538,2539,382,2541,2544,2545,1267,2548,391],{},[329,2521,354],{}," exposes ",[329,2524,425],{},[329,2526,428],{}," (epoch millis) and ",[329,2529,2530],{},"windowStartTime()",[329,2532,2533],{},"windowEndTime()"," (",[329,2536,2537],{},"Instant","). In Kotlin the underlying key and window are properties (",[329,2540,2320],{},[329,2542,2543],{},"windowedKey.window","); from Java they are the generated accessors ",[329,2546,2547],{},"getKey()",[329,2549,2550],{},"getWindow()",[2552,2553,2556],"callout",{"color":2554,"icon":2555},"info","i-lucide-info",[320,2557,2558,2559,2562,2563,2566,2567,2570],{},"A common pattern is to fold the window bounds into the value before re-keying back to the plain key. The e-commerce example does exactly this — its ",[329,2560,2561],{},"mapValues"," reads ",[329,2564,2565],{},"wk.getWindow().startTime()"," to stamp the aggregate with its date, then ",[329,2568,2569],{},"toStream((wk, v) -> wk.getKey(), …)"," re-keys by the original customer id.",[451,2572,2574],{"id":2573},"when-results-are-emitted","When results are emitted",[320,2576,2577,2578,2581,2582,2585,2586,2589],{},"By default a windowed aggregation emits a result on ",[324,2579,2580],{},"every update"," — each record that changes a window's aggregate produces a new downstream record (continuous refinement). For high-volume windows that is a lot of intermediate output. ",[329,2583,2584],{},"EmitStrategy"," lets you switch to emitting only the ",[324,2587,2588],{},"final"," result when the window closes.",[599,2591,2592,2720],{"group":601},[603,2593,2595],{"className":605,"code":2594,"filename":607,"language":608,"meta":609,"style":609},"import io.stoatflow.core.topology.EmitStrategy\nimport io.stoatflow.core.topology.TimeWindows\nimport java.time.Duration\n\nval finalCounts: KTable\u003CWindowed\u003CString>, Long> =\n    pageViews\n        .groupByKey(Grouped.with(Serdes.String(), pageViewSerde))\n        .windowedBy(TimeWindows.ofSizeAndGrace(Duration.ofMinutes(5), Duration.ofSeconds(30)))\n        .emitStrategy(EmitStrategy.onWindowClose())\n        .count()\n",[329,2596,2597,2604,2610,2616,2620,2645,2649,2665,2696,2712],{"__ignoreMap":609},[613,2598,2599,2601],{"class":615,"line":616},[613,2600,620],{"class":619},[613,2602,2603],{"class":623}," io.stoatflow.core.topology.EmitStrategy\n",[613,2605,2606,2608],{"class":615,"line":627},[613,2607,620],{"class":619},[613,2609,632],{"class":623},[613,2611,2612,2614],{"class":615,"line":635},[613,2613,620],{"class":619},[613,2615,648],{"class":623},[613,2617,2618],{"class":615,"line":643},[613,2619,655],{"emptyLinePlaceholder":654},[613,2621,2622,2624,2627,2629,2631,2633,2635,2637,2639,2641,2643],{"class":615,"line":651},[613,2623,668],{"class":619},[613,2625,2626],{"class":671}," finalCounts: ",[613,2628,350],{"class":675},[613,2630,678],{"class":671},[613,2632,681],{"class":675},[613,2634,678],{"class":671},[613,2636,686],{"class":675},[613,2638,689],{"class":671},[613,2640,692],{"class":675},[613,2642,695],{"class":671},[613,2644,699],{"class":698},[613,2646,2647],{"class":615,"line":658},[613,2648,705],{"class":671},[613,2650,2651,2653,2655,2657,2659,2661,2663],{"class":615,"line":665},[613,2652,711],{"class":671},[613,2654,714],{"class":623},[613,2656,717],{"class":671},[613,2658,720],{"class":623},[613,2660,723],{"class":671},[613,2662,686],{"class":623},[613,2664,728],{"class":671},[613,2666,2667,2669,2671,2673,2676,2678,2680,2682,2684,2687,2690,2692,2694],{"class":615,"line":702},[613,2668,711],{"class":671},[613,2670,736],{"class":623},[613,2672,739],{"class":671},[613,2674,2675],{"class":623},"ofSizeAndGrace",[613,2677,744],{"class":671},[613,2679,747],{"class":623},[613,2681,750],{"class":671},[613,2683,754],{"class":753},[613,2685,2686],{"class":671},"), Duration.",[613,2688,2689],{"class":623},"ofSeconds",[613,2691,750],{"class":671},[613,2693,1672],{"class":753},[613,2695,757],{"class":671},[613,2697,2698,2700,2703,2706,2709],{"class":615,"line":708},[613,2699,711],{"class":671},[613,2701,2702],{"class":623},"emitStrategy",[613,2704,2705],{"class":671},"(EmitStrategy.",[613,2707,2708],{"class":623},"onWindowClose",[613,2710,2711],{"class":671},"())\n",[613,2713,2714,2716,2718],{"class":615,"line":731},[613,2715,711],{"class":671},[613,2717,765],{"class":623},[613,2719,768],{"class":671},[603,2721,2723],{"className":895,"code":2722,"filename":897,"language":898,"meta":609,"style":609},"import io.stoatflow.core.topology.EmitStrategy;\nimport io.stoatflow.core.topology.TimeWindows;\nimport java.time.Duration;\n\nKTable\u003CWindowed\u003CString>, Long> finalCounts =\n    pageViews\n        .groupByKey(Grouped.with(Serdes.String(), pageViewSerde))\n        .windowedBy(TimeWindows.ofSizeAndGrace(Duration.ofMinutes(5), Duration.ofSeconds(30)))\n        .emitStrategy(EmitStrategy.onWindowClose())\n        .count();\n",[329,2724,2725,2749,2773,2789,2793,2816,2820,2848,2890,2906],{"__ignoreMap":609},[613,2726,2727,2729,2731,2733,2735,2737,2739,2741,2743,2745,2747],{"class":615,"line":616},[613,2728,620],{"class":619},[613,2730,907],{"class":671},[613,2732,391],{"class":698},[613,2734,912],{"class":671},[613,2736,391],{"class":698},[613,2738,917],{"class":671},[613,2740,391],{"class":698},[613,2742,922],{"class":671},[613,2744,391],{"class":698},[613,2746,2584],{"class":671},[613,2748,930],{"class":698},[613,2750,2751,2753,2755,2757,2759,2761,2763,2765,2767,2769,2771],{"class":615,"line":627},[613,2752,620],{"class":619},[613,2754,907],{"class":671},[613,2756,391],{"class":698},[613,2758,912],{"class":671},[613,2760,391],{"class":698},[613,2762,917],{"class":671},[613,2764,391],{"class":698},[613,2766,922],{"class":671},[613,2768,391],{"class":698},[613,2770,585],{"class":671},[613,2772,930],{"class":698},[613,2774,2775,2777,2779,2781,2783,2785,2787],{"class":615,"line":635},[613,2776,620],{"class":619},[613,2778,985],{"class":671},[613,2780,391],{"class":698},[613,2782,990],{"class":671},[613,2784,391],{"class":698},[613,2786,995],{"class":671},[613,2788,930],{"class":698},[613,2790,2791],{"class":615,"line":643},[613,2792,655],{"emptyLinePlaceholder":654},[613,2794,2795,2797,2799,2801,2803,2805,2807,2809,2811,2814],{"class":615,"line":651},[613,2796,350],{"class":671},[613,2798,678],{"class":698},[613,2800,681],{"class":671},[613,2802,678],{"class":698},[613,2804,686],{"class":1018},[613,2806,1021],{"class":698},[613,2808,1024],{"class":1018},[613,2810,1027],{"class":698},[613,2812,2813],{"class":1030}," finalCounts",[613,2815,1034],{"class":698},[613,2817,2818],{"class":615,"line":658},[613,2819,705],{"class":671},[613,2821,2822,2824,2826,2828,2830,2832,2834,2836,2838,2840,2842,2844,2846],{"class":615,"line":665},[613,2823,711],{"class":698},[613,2825,714],{"class":623},[613,2827,750],{"class":698},[613,2829,927],{"class":1030},[613,2831,391],{"class":698},[613,2833,720],{"class":623},[613,2835,750],{"class":698},[613,2837,1057],{"class":1030},[613,2839,391],{"class":698},[613,2841,686],{"class":623},[613,2843,1064],{"class":698},[613,2845,1067],{"class":671},[613,2847,856],{"class":698},[613,2849,2850,2852,2854,2856,2858,2860,2862,2864,2866,2868,2870,2872,2874,2877,2880,2882,2884,2886,2888],{"class":615,"line":702},[613,2851,711],{"class":698},[613,2853,736],{"class":623},[613,2855,750],{"class":698},[613,2857,585],{"class":1030},[613,2859,391],{"class":698},[613,2861,2675],{"class":623},[613,2863,750],{"class":698},[613,2865,995],{"class":1030},[613,2867,391],{"class":698},[613,2869,747],{"class":623},[613,2871,750],{"class":698},[613,2873,754],{"class":753},[613,2875,2876],{"class":698},"),",[613,2878,2879],{"class":1030}," Duration",[613,2881,391],{"class":698},[613,2883,2689],{"class":623},[613,2885,750],{"class":698},[613,2887,1672],{"class":753},[613,2889,757],{"class":698},[613,2891,2892,2894,2896,2898,2900,2902,2904],{"class":615,"line":708},[613,2893,711],{"class":698},[613,2895,2702],{"class":623},[613,2897,750],{"class":698},[613,2899,2584],{"class":1030},[613,2901,391],{"class":698},[613,2903,2708],{"class":623},[613,2905,2711],{"class":698},[613,2907,2908,2910,2912],{"class":615,"line":731},[613,2909,711],{"class":698},[613,2911,765],{"class":623},[613,2913,1106],{"class":698},[320,2915,2916,2918,2919,2922,2923,2926,2927,2930,2931,391],{},[329,2917,444],{}," produces exactly one output per window per key, at the cost of latency equal to the grace period — the window can't close until the watermark passes ",[329,2920,2921],{},"windowEnd + grace",". It is available on the windowed stream types (",[329,2924,2925],{},"TimeWindowedKStream"," — which covers both fixed-size and sliding windows — and ",[329,2928,2929],{},"SessionWindowedKStream",") and requires watermark propagation to detect closure. The default is ",[329,2932,440],{},[451,2934,2936],{"id":2935},"suppression","Suppression",[320,2938,2939,2941,2942,2944],{},[329,2940,2584],{}," is the declarative way to ask for final-only output. ",[329,2943,448],{}," is the lower-level control: it holds updates in a buffer and you choose both the release condition and how the buffer behaves when it fills.",[320,2946,2947,2948,2951,2952,2955],{},"For windowed tables, ",[329,2949,2950],{},"Suppressed.untilWindowCloses(bufferConfig)"," buffers every update until the window closes — equivalent in effect to ",[329,2953,2954],{},"onWindowClose()",", but with explicit buffer-overflow control:",[599,2957,2958,3096],{"group":601},[603,2959,2961],{"className":605,"code":2960,"filename":607,"language":608,"meta":609,"style":609},"import io.stoatflow.core.topology.Suppressed\nimport io.stoatflow.core.topology.Suppressed.BufferConfig\nimport io.stoatflow.core.topology.TimeWindows\nimport java.time.Duration\n\nval suppressed: KTable\u003CWindowed\u003CString>, Long> =\n    pageViews\n        .groupByKey(Grouped.with(Serdes.String(), pageViewSerde))\n        .windowedBy(TimeWindows.ofSizeAndGrace(Duration.ofMinutes(5), Duration.ofSeconds(30)))\n        .count()\n        .suppress(Suppressed.untilWindowCloses(BufferConfig.unbounded()))\n",[329,2962,2963,2970,2977,2983,2989,2993,3018,3022,3038,3066,3074],{"__ignoreMap":609},[613,2964,2965,2967],{"class":615,"line":616},[613,2966,620],{"class":619},[613,2968,2969],{"class":623}," io.stoatflow.core.topology.Suppressed\n",[613,2971,2972,2974],{"class":615,"line":627},[613,2973,620],{"class":619},[613,2975,2976],{"class":623}," io.stoatflow.core.topology.Suppressed.BufferConfig\n",[613,2978,2979,2981],{"class":615,"line":635},[613,2980,620],{"class":619},[613,2982,632],{"class":623},[613,2984,2985,2987],{"class":615,"line":643},[613,2986,620],{"class":619},[613,2988,648],{"class":623},[613,2990,2991],{"class":615,"line":651},[613,2992,655],{"emptyLinePlaceholder":654},[613,2994,2995,2997,3000,3002,3004,3006,3008,3010,3012,3014,3016],{"class":615,"line":658},[613,2996,668],{"class":619},[613,2998,2999],{"class":671}," suppressed: ",[613,3001,350],{"class":675},[613,3003,678],{"class":671},[613,3005,681],{"class":675},[613,3007,678],{"class":671},[613,3009,686],{"class":675},[613,3011,689],{"class":671},[613,3013,692],{"class":675},[613,3015,695],{"class":671},[613,3017,699],{"class":698},[613,3019,3020],{"class":615,"line":665},[613,3021,705],{"class":671},[613,3023,3024,3026,3028,3030,3032,3034,3036],{"class":615,"line":702},[613,3025,711],{"class":671},[613,3027,714],{"class":623},[613,3029,717],{"class":671},[613,3031,720],{"class":623},[613,3033,723],{"class":671},[613,3035,686],{"class":623},[613,3037,728],{"class":671},[613,3039,3040,3042,3044,3046,3048,3050,3052,3054,3056,3058,3060,3062,3064],{"class":615,"line":708},[613,3041,711],{"class":671},[613,3043,736],{"class":623},[613,3045,739],{"class":671},[613,3047,2675],{"class":623},[613,3049,744],{"class":671},[613,3051,747],{"class":623},[613,3053,750],{"class":671},[613,3055,754],{"class":753},[613,3057,2686],{"class":671},[613,3059,2689],{"class":623},[613,3061,750],{"class":671},[613,3063,1672],{"class":753},[613,3065,757],{"class":671},[613,3067,3068,3070,3072],{"class":615,"line":731},[613,3069,711],{"class":671},[613,3071,765],{"class":623},[613,3073,768],{"class":671},[613,3075,3076,3078,3081,3084,3087,3090,3093],{"class":615,"line":760},[613,3077,711],{"class":671},[613,3079,3080],{"class":623},"suppress",[613,3082,3083],{"class":671},"(Suppressed.",[613,3085,3086],{"class":623},"untilWindowCloses",[613,3088,3089],{"class":671},"(BufferConfig.",[613,3091,3092],{"class":623},"unbounded",[613,3094,3095],{"class":671},"()))\n",[603,3097,3099],{"className":895,"code":3098,"filename":897,"language":898,"meta":609,"style":609},"import io.stoatflow.core.topology.Suppressed;\nimport io.stoatflow.core.topology.Suppressed.BufferConfig;\nimport io.stoatflow.core.topology.TimeWindows;\nimport java.time.Duration;\n\nKTable\u003CWindowed\u003CString>, Long> suppressed =\n    pageViews\n        .groupByKey(Grouped.with(Serdes.String(), pageViewSerde))\n        .windowedBy(TimeWindows.ofSizeAndGrace(Duration.ofMinutes(5), Duration.ofSeconds(30)))\n        .count()\n        .suppress(Suppressed.untilWindowCloses(BufferConfig.unbounded()));\n",[329,3100,3101,3126,3155,3179,3195,3199,3222,3226,3254,3294,3302],{"__ignoreMap":609},[613,3102,3103,3105,3107,3109,3111,3113,3115,3117,3119,3121,3124],{"class":615,"line":616},[613,3104,620],{"class":619},[613,3106,907],{"class":671},[613,3108,391],{"class":698},[613,3110,912],{"class":671},[613,3112,391],{"class":698},[613,3114,917],{"class":671},[613,3116,391],{"class":698},[613,3118,922],{"class":671},[613,3120,391],{"class":698},[613,3122,3123],{"class":671},"Suppressed",[613,3125,930],{"class":698},[613,3127,3128,3130,3132,3134,3136,3138,3140,3142,3144,3146,3148,3150,3153],{"class":615,"line":627},[613,3129,620],{"class":619},[613,3131,907],{"class":671},[613,3133,391],{"class":698},[613,3135,912],{"class":671},[613,3137,391],{"class":698},[613,3139,917],{"class":671},[613,3141,391],{"class":698},[613,3143,922],{"class":671},[613,3145,391],{"class":698},[613,3147,3123],{"class":671},[613,3149,391],{"class":698},[613,3151,3152],{"class":671},"BufferConfig",[613,3154,930],{"class":698},[613,3156,3157,3159,3161,3163,3165,3167,3169,3171,3173,3175,3177],{"class":615,"line":635},[613,3158,620],{"class":619},[613,3160,907],{"class":671},[613,3162,391],{"class":698},[613,3164,912],{"class":671},[613,3166,391],{"class":698},[613,3168,917],{"class":671},[613,3170,391],{"class":698},[613,3172,922],{"class":671},[613,3174,391],{"class":698},[613,3176,585],{"class":671},[613,3178,930],{"class":698},[613,3180,3181,3183,3185,3187,3189,3191,3193],{"class":615,"line":643},[613,3182,620],{"class":619},[613,3184,985],{"class":671},[613,3186,391],{"class":698},[613,3188,990],{"class":671},[613,3190,391],{"class":698},[613,3192,995],{"class":671},[613,3194,930],{"class":698},[613,3196,3197],{"class":615,"line":651},[613,3198,655],{"emptyLinePlaceholder":654},[613,3200,3201,3203,3205,3207,3209,3211,3213,3215,3217,3220],{"class":615,"line":658},[613,3202,350],{"class":671},[613,3204,678],{"class":698},[613,3206,681],{"class":671},[613,3208,678],{"class":698},[613,3210,686],{"class":1018},[613,3212,1021],{"class":698},[613,3214,1024],{"class":1018},[613,3216,1027],{"class":698},[613,3218,3219],{"class":1030}," suppressed",[613,3221,1034],{"class":698},[613,3223,3224],{"class":615,"line":665},[613,3225,705],{"class":671},[613,3227,3228,3230,3232,3234,3236,3238,3240,3242,3244,3246,3248,3250,3252],{"class":615,"line":702},[613,3229,711],{"class":698},[613,3231,714],{"class":623},[613,3233,750],{"class":698},[613,3235,927],{"class":1030},[613,3237,391],{"class":698},[613,3239,720],{"class":623},[613,3241,750],{"class":698},[613,3243,1057],{"class":1030},[613,3245,391],{"class":698},[613,3247,686],{"class":623},[613,3249,1064],{"class":698},[613,3251,1067],{"class":671},[613,3253,856],{"class":698},[613,3255,3256,3258,3260,3262,3264,3266,3268,3270,3272,3274,3276,3278,3280,3282,3284,3286,3288,3290,3292],{"class":615,"line":708},[613,3257,711],{"class":698},[613,3259,736],{"class":623},[613,3261,750],{"class":698},[613,3263,585],{"class":1030},[613,3265,391],{"class":698},[613,3267,2675],{"class":623},[613,3269,750],{"class":698},[613,3271,995],{"class":1030},[613,3273,391],{"class":698},[613,3275,747],{"class":623},[613,3277,750],{"class":698},[613,3279,754],{"class":753},[613,3281,2876],{"class":698},[613,3283,2879],{"class":1030},[613,3285,391],{"class":698},[613,3287,2689],{"class":623},[613,3289,750],{"class":698},[613,3291,1672],{"class":753},[613,3293,757],{"class":698},[613,3295,3296,3298,3300],{"class":615,"line":731},[613,3297,711],{"class":698},[613,3299,765],{"class":623},[613,3301,768],{"class":698},[613,3303,3304,3306,3308,3310,3312,3314,3316,3318,3320,3322,3324],{"class":615,"line":760},[613,3305,711],{"class":698},[613,3307,3080],{"class":623},[613,3309,750],{"class":698},[613,3311,3123],{"class":1030},[613,3313,391],{"class":698},[613,3315,3086],{"class":623},[613,3317,750],{"class":698},[613,3319,3152],{"class":1030},[613,3321,391],{"class":698},[613,3323,3092],{"class":623},[613,3325,3326],{"class":698},"()));\n",[320,3328,3329,3330,3333],{},"For non-windowed tables, ",[329,3331,3332],{},"Suppressed.untilTimeLimit(duration, bufferConfig)"," rate-limits per key: at most one update per key per interval, keeping only the most recent value within each interval.",[3335,3336,3338],"h3",{"id":3337},"buffer-configuration","Buffer configuration",[320,3340,3341,3343,3344,3346,3347,2534,3349,3352],{},[329,3342,3080],{}," needs a ",[329,3345,3152],{}," — a type nested inside ",[329,3348,3123],{},[329,3350,3351],{},"Suppressed.BufferConfig",", matching Kafka Streams) — describing how much to hold and what to do on overflow:",[456,3354,3355,3365],{},[459,3356,3357],{},[462,3358,3359,3362],{},[465,3360,3361],{},"Builder",[465,3363,3364],{},"Behaviour",[478,3366,3367,3381,3395,3405,3415],{},[462,3368,3369,3374],{},[483,3370,3371],{},[329,3372,3373],{},"BufferConfig.unbounded()",[483,3375,3376,3377,3380],{},"No size limit (a ",[329,3378,3379],{},"StrictBufferConfig","). Use with care — memory grows with buffered records.",[462,3382,3383,3388],{},[483,3384,3385],{},[329,3386,3387],{},"BufferConfig.maxRecords(n)",[483,3389,3390,3391,3394],{},"Bound the buffer to ",[329,3392,3393],{},"n"," records.",[462,3396,3397,3402],{},[483,3398,3399],{},[329,3400,3401],{},".emitEarlyWhenFull()",[483,3403,3404],{},"On overflow, emit the oldest records to make room (no data loss, but non-final values may be emitted).",[462,3406,3407,3412],{},[483,3408,3409],{},[329,3410,3411],{},".shutDownWhenFull()",[483,3413,3414],{},"On overflow, shut the application down rather than emit early or lose data.",[462,3416,3417,3422],{},[483,3418,3419],{},[329,3420,3421],{},".withLoggingDisabled()",[483,3423,3424],{},"Don't back the buffer with a changelog. Faster, but suppressed records are lost on restart.",[2552,3426,3428],{"color":3427,"icon":80},"warning",[320,3429,3430,3433,3434,3437,3438,3441,3442,3445,3446,391],{},[329,3431,3432],{},"BufferConfig.maxBytes(...)"," from Kafka Streams is ",[324,3435,3436],{},"not supported"," — StoatFlow buffers in-memory objects, not serialized bytes, so a byte limit can't be enforced accurately. Use ",[329,3439,3440],{},"maxRecords(...)"," instead; calling ",[329,3443,3444],{},"maxBytes(...)"," throws ",[329,3447,3448],{},"UnsupportedOperationException",[320,3450,3451,3452,3455,3456,3458,3459,3462,3463,413],{},"By default suppress buffers are changelog-backed for fault tolerance. ",[329,3453,3454],{},"suppress(...)"," with logging enabled requires the upstream ",[329,3457,350],{}," to carry serdes (provide them via ",[329,3460,3461],{},"Materialized"," on the aggregation, or disable logging with ",[329,3464,3465],{},"BufferConfig.withLoggingDisabled()",[451,3467,3469],{"id":3468},"serializing-windowed-keys-to-a-sink","Serializing windowed keys to a sink",[320,3471,3472,3473,3475,3476,3478],{},"To write a windowed table to a topic, the ",[329,3474,354],{}," key needs a serde. ",[329,3477,432],{}," wraps the inner key serde with the window bounds:",[599,3480,3481,3648],{"group":601},[603,3482,3484],{"className":605,"code":3483,"filename":607,"language":608,"meta":609,"style":609},"import io.stoatflow.core.topology.Named\nimport io.stoatflow.core.topology.Produced\nimport io.stoatflow.core.topology.Windowed\nimport io.stoatflow.core.topology.WindowedSerdes\nimport org.apache.kafka.common.serialization.Serdes\n\nval windowedKeySerde = WindowedSerdes.timeWindowedSerdeFrom(Serdes.String())\n\nwindowedCounts\n    .toStream(Named.`as`(\"to-stream\"))\n    .to(\n        \"windowed-counts\",\n        Produced.`as`\u003CWindowed\u003CString>, Long>(\"sink\")\n            .withKeySerde(windowedKeySerde)\n            .withValueSerde(Serdes.Long()),\n    )\n",[329,3485,3486,3493,3500,3506,3513,3520,3524,3546,3550,3555,3575,3584,3591,3619,3630,3644],{"__ignoreMap":609},[613,3487,3488,3490],{"class":615,"line":616},[613,3489,620],{"class":619},[613,3491,3492],{"class":623}," io.stoatflow.core.topology.Named\n",[613,3494,3495,3497],{"class":615,"line":627},[613,3496,620],{"class":619},[613,3498,3499],{"class":623}," io.stoatflow.core.topology.Produced\n",[613,3501,3502,3504],{"class":615,"line":635},[613,3503,620],{"class":619},[613,3505,640],{"class":623},[613,3507,3508,3510],{"class":615,"line":643},[613,3509,620],{"class":619},[613,3511,3512],{"class":623}," io.stoatflow.core.topology.WindowedSerdes\n",[613,3514,3515,3517],{"class":615,"line":651},[613,3516,620],{"class":619},[613,3518,3519],{"class":623}," org.apache.kafka.common.serialization.Serdes\n",[613,3521,3522],{"class":615,"line":658},[613,3523,655],{"emptyLinePlaceholder":654},[613,3525,3526,3528,3531,3534,3537,3540,3542,3544],{"class":615,"line":665},[613,3527,668],{"class":619},[613,3529,3530],{"class":671}," windowedKeySerde ",[613,3532,3533],{"class":698},"=",[613,3535,3536],{"class":671}," WindowedSerdes.",[613,3538,3539],{"class":623},"timeWindowedSerdeFrom",[613,3541,723],{"class":671},[613,3543,686],{"class":623},[613,3545,2711],{"class":671},[613,3547,3548],{"class":615,"line":702},[613,3549,655],{"emptyLinePlaceholder":654},[613,3551,3552],{"class":615,"line":708},[613,3553,3554],{"class":671},"windowedCounts\n",[613,3556,3557,3560,3562,3565,3568,3570,3573],{"class":615,"line":731},[613,3558,3559],{"class":671},"    .",[613,3561,2289],{"class":623},[613,3563,3564],{"class":671},"(Named.",[613,3566,3567],{"class":623},"`as`",[613,3569,750],{"class":671},[613,3571,3572],{"class":2313},"\"to-stream\"",[613,3574,856],{"class":671},[613,3576,3577,3579,3582],{"class":615,"line":760},[613,3578,3559],{"class":671},[613,3580,3581],{"class":623},"to",[613,3583,837],{"class":671},[613,3585,3586,3589],{"class":615,"line":771},[613,3587,3588],{"class":2313},"        \"windowed-counts\"",[613,3590,2373],{"class":671},[613,3592,3593,3596,3598,3600,3602,3604,3606,3608,3610,3613,3616],{"class":615,"line":776},[613,3594,3595],{"class":671},"        Produced.",[613,3597,3567],{"class":623},[613,3599,678],{"class":671},[613,3601,681],{"class":675},[613,3603,678],{"class":671},[613,3605,686],{"class":675},[613,3607,689],{"class":671},[613,3609,692],{"class":675},[613,3611,3612],{"class":671},">(",[613,3614,3615],{"class":2313},"\"sink\"",[613,3617,3618],{"class":671},")\n",[613,3620,3621,3624,3627],{"class":615,"line":782},[613,3622,3623],{"class":671},"            .",[613,3625,3626],{"class":623},"withKeySerde",[613,3628,3629],{"class":671},"(windowedKeySerde)\n",[613,3631,3632,3634,3637,3639,3641],{"class":615,"line":808},[613,3633,3623],{"class":671},[613,3635,3636],{"class":623},"withValueSerde",[613,3638,723],{"class":671},[613,3640,692],{"class":623},[613,3642,3643],{"class":671},"()),\n",[613,3645,3646],{"class":615,"line":813},[613,3647,2378],{"class":671},[603,3649,3651],{"className":895,"code":3650,"filename":897,"language":898,"meta":609,"style":609},"import io.stoatflow.core.topology.Named;\nimport io.stoatflow.core.topology.Produced;\nimport io.stoatflow.core.topology.Windowed;\nimport io.stoatflow.core.topology.WindowedSerdes;\nimport org.apache.kafka.common.serialization.Serdes;\n\nvar windowedKeySerde = WindowedSerdes.timeWindowedSerdeFrom(Serdes.String());\n\nwindowedCounts\n    .toStream(Named.as(\"to-stream\"))\n    .to(\n        \"windowed-counts\",\n        Produced.\u003CWindowed\u003CString>, Long>as(\"sink\")\n            .withKeySerde(windowedKeySerde)\n            .withValueSerde(Serdes.Long()));\n",[329,3652,3653,3678,3703,3727,3751,3784,3788,3817,3821,3825,3851,3859,3870,3906,3919],{"__ignoreMap":609},[613,3654,3655,3657,3659,3661,3663,3665,3667,3669,3671,3673,3676],{"class":615,"line":616},[613,3656,620],{"class":619},[613,3658,907],{"class":671},[613,3660,391],{"class":698},[613,3662,912],{"class":671},[613,3664,391],{"class":698},[613,3666,917],{"class":671},[613,3668,391],{"class":698},[613,3670,922],{"class":671},[613,3672,391],{"class":698},[613,3674,3675],{"class":671},"Named",[613,3677,930],{"class":698},[613,3679,3680,3682,3684,3686,3688,3690,3692,3694,3696,3698,3701],{"class":615,"line":627},[613,3681,620],{"class":619},[613,3683,907],{"class":671},[613,3685,391],{"class":698},[613,3687,912],{"class":671},[613,3689,391],{"class":698},[613,3691,917],{"class":671},[613,3693,391],{"class":698},[613,3695,922],{"class":671},[613,3697,391],{"class":698},[613,3699,3700],{"class":671},"Produced",[613,3702,930],{"class":698},[613,3704,3705,3707,3709,3711,3713,3715,3717,3719,3721,3723,3725],{"class":615,"line":635},[613,3706,620],{"class":619},[613,3708,907],{"class":671},[613,3710,391],{"class":698},[613,3712,912],{"class":671},[613,3714,391],{"class":698},[613,3716,917],{"class":671},[613,3718,391],{"class":698},[613,3720,922],{"class":671},[613,3722,391],{"class":698},[613,3724,681],{"class":671},[613,3726,930],{"class":698},[613,3728,3729,3731,3733,3735,3737,3739,3741,3743,3745,3747,3749],{"class":615,"line":643},[613,3730,620],{"class":619},[613,3732,907],{"class":671},[613,3734,391],{"class":698},[613,3736,912],{"class":671},[613,3738,391],{"class":698},[613,3740,917],{"class":671},[613,3742,391],{"class":698},[613,3744,922],{"class":671},[613,3746,391],{"class":698},[613,3748,432],{"class":671},[613,3750,930],{"class":698},[613,3752,3753,3755,3758,3760,3763,3765,3768,3770,3773,3775,3778,3780,3782],{"class":615,"line":651},[613,3754,620],{"class":619},[613,3756,3757],{"class":671}," org",[613,3759,391],{"class":698},[613,3761,3762],{"class":671},"apache",[613,3764,391],{"class":698},[613,3766,3767],{"class":671},"kafka",[613,3769,391],{"class":698},[613,3771,3772],{"class":671},"common",[613,3774,391],{"class":698},[613,3776,3777],{"class":671},"serialization",[613,3779,391],{"class":698},[613,3781,1057],{"class":671},[613,3783,930],{"class":698},[613,3785,3786],{"class":615,"line":658},[613,3787,655],{"emptyLinePlaceholder":654},[613,3789,3790,3793,3796,3799,3802,3804,3806,3808,3810,3812,3814],{"class":615,"line":665},[613,3791,3792],{"class":1018},"var",[613,3794,3795],{"class":1030}," windowedKeySerde",[613,3797,3798],{"class":698}," =",[613,3800,3801],{"class":1030}," WindowedSerdes",[613,3803,391],{"class":698},[613,3805,3539],{"class":623},[613,3807,750],{"class":698},[613,3809,1057],{"class":1030},[613,3811,391],{"class":698},[613,3813,686],{"class":623},[613,3815,3816],{"class":698},"());\n",[613,3818,3819],{"class":615,"line":702},[613,3820,655],{"emptyLinePlaceholder":654},[613,3822,3823],{"class":615,"line":708},[613,3824,3554],{"class":671},[613,3826,3827,3829,3831,3833,3835,3837,3840,3842,3844,3847,3849],{"class":615,"line":731},[613,3828,3559],{"class":698},[613,3830,2289],{"class":623},[613,3832,750],{"class":698},[613,3834,3675],{"class":1030},[613,3836,391],{"class":698},[613,3838,3839],{"class":623},"as",[613,3841,750],{"class":698},[613,3843,2446],{"class":2439},[613,3845,3846],{"class":2313},"to-stream",[613,3848,2446],{"class":2439},[613,3850,856],{"class":698},[613,3852,3853,3855,3857],{"class":615,"line":760},[613,3854,3559],{"class":698},[613,3856,3581],{"class":623},[613,3858,837],{"class":698},[613,3860,3861,3863,3866,3868],{"class":615,"line":771},[613,3862,2440],{"class":2439},[613,3864,3865],{"class":2313},"windowed-counts",[613,3867,2446],{"class":2439},[613,3869,2373],{"class":698},[613,3871,3872,3875,3877,3879,3881,3883,3885,3887,3889,3891,3893,3895,3897,3899,3902,3904],{"class":615,"line":776},[613,3873,3874],{"class":671},"        Produced",[613,3876,391],{"class":698},[613,3878,678],{"class":1018},[613,3880,681],{"class":671},[613,3882,678],{"class":1018},[613,3884,686],{"class":671},[613,3886,1027],{"class":1018},[613,3888,2132],{"class":698},[613,3890,1024],{"class":671},[613,3892,1027],{"class":1018},[613,3894,3839],{"class":623},[613,3896,750],{"class":698},[613,3898,2446],{"class":2439},[613,3900,3901],{"class":2313},"sink",[613,3903,2446],{"class":2439},[613,3905,3618],{"class":698},[613,3907,3908,3910,3912,3914,3917],{"class":615,"line":782},[613,3909,3623],{"class":698},[613,3911,3626],{"class":623},[613,3913,750],{"class":698},[613,3915,3916],{"class":671},"windowedKeySerde",[613,3918,3618],{"class":698},[613,3920,3921,3923,3925,3927,3929,3931,3933],{"class":615,"line":808},[613,3922,3623],{"class":698},[613,3924,3636],{"class":623},[613,3926,750],{"class":698},[613,3928,1057],{"class":1030},[613,3930,391],{"class":698},[613,3932,692],{"class":623},[613,3934,3326],{"class":698},[320,3936,3937,3938,3941,3942,3944,3945,3948,3949,3952],{},"Use ",[329,3939,3940],{},"WindowedSerdes.sessionWindowedSerdeFrom(inner)"," for session-windowed keys so deserialization reconstructs ",[329,3943,565],{}," instances. Both factories take a ",[329,3946,3947],{},"Serde\u003CT>"," for the inner key (a StoatFlow deviation from Kafka Streams, which takes a ",[329,3950,3951],{},"Class\u003CT>","); the window size is omitted because the bounds are encoded in the serialized bytes.",[451,3954,3956],{"id":3955},"a-complete-windowed-aggregation","A complete windowed aggregation",[320,3958,3959],{},"The e-commerce example aggregates per-customer activity into a daily window, then re-keys back to the customer id and joins a profile table. Its core is a tumbling daily window with a 15-minute grace period:",[603,3961,3963],{"className":895,"code":3962,"language":898,"meta":609,"style":609},"\u002F\u002F Daily tumbling windows, 15-minute grace for late events\nTimeWindows dailyWindows =\n    TimeWindows.ofSizeAndGrace(Duration.ofDays(1), Duration.ofMinutes(15));\n\nTimeWindowedKStream\u003CString, WebActivityOrPurchase> windowedStream = mergedStreams\n    .groupBy(\n        (k, v) -> v.purchase() != null ? v.purchase().customerId() : v.webActivity().customerId(),\n        Grouped.with(\"grouped-by-customer-id\", stringSerde, webActivityOrPurchaseSerde))\n    .windowedBy(dailyWindows);\n\nKTable\u003CWindowed\u003CString>, DailyAggregates> dailyAggregation = windowedStream\n    .aggregate(\n        () -> new DailyAggregates(\u002F* empty *\u002F),\n        (key, value, agg) -> \u002F* fold value into agg *\u002F agg,\n        Named.as(\"daily-aggregation\"),\n        Materialized.\u003CString, DailyAggregates, StateStore>as(\"daily-aggregation-store\")\n            .withValueSerde(dailyAggregatesSerde));\n",[329,3964,3965,3970,3979,4016,4020,4043,4052,4117,4147,4161,4165,4192,4200,4220,4245,4265,4300],{"__ignoreMap":609},[613,3966,3967],{"class":615,"line":616},[613,3968,3969],{"class":661},"\u002F\u002F Daily tumbling windows, 15-minute grace for late events\n",[613,3971,3972,3974,3977],{"class":615,"line":627},[613,3973,585],{"class":671},[613,3975,3976],{"class":1030}," dailyWindows",[613,3978,1034],{"class":698},[613,3980,3981,3984,3986,3988,3990,3992,3994,3997,3999,4001,4003,4005,4007,4009,4011,4014],{"class":615,"line":635},[613,3982,3983],{"class":1030},"    TimeWindows",[613,3985,391],{"class":698},[613,3987,2675],{"class":623},[613,3989,750],{"class":698},[613,3991,995],{"class":1030},[613,3993,391],{"class":698},[613,3995,3996],{"class":623},"ofDays",[613,3998,750],{"class":698},[613,4000,874],{"class":753},[613,4002,2876],{"class":698},[613,4004,2879],{"class":1030},[613,4006,391],{"class":698},[613,4008,747],{"class":623},[613,4010,750],{"class":698},[613,4012,4013],{"class":753},"15",[613,4015,2517],{"class":698},[613,4017,4018],{"class":615,"line":643},[613,4019,655],{"emptyLinePlaceholder":654},[613,4021,4022,4024,4026,4028,4030,4033,4035,4038,4040],{"class":615,"line":651},[613,4023,2925],{"class":671},[613,4025,678],{"class":698},[613,4027,686],{"class":1018},[613,4029,2132],{"class":698},[613,4031,4032],{"class":1018}," WebActivityOrPurchase",[613,4034,1027],{"class":698},[613,4036,4037],{"class":1030}," windowedStream",[613,4039,3798],{"class":698},[613,4041,4042],{"class":671}," mergedStreams\n",[613,4044,4045,4047,4050],{"class":615,"line":658},[613,4046,3559],{"class":698},[613,4048,4049],{"class":623},"groupBy",[613,4051,837],{"class":698},[613,4053,4054,4057,4060,4062,4065,4067,4069,4071,4073,4076,4078,4081,4084,4087,4089,4091,4093,4095,4098,4100,4103,4105,4107,4110,4112,4114],{"class":615,"line":665},[613,4055,4056],{"class":698},"        (",[613,4058,4059],{"class":671},"k",[613,4061,2132],{"class":698},[613,4063,4064],{"class":671}," v",[613,4066,2155],{"class":698},[613,4068,2158],{"class":698},[613,4070,4064],{"class":1030},[613,4072,391],{"class":698},[613,4074,4075],{"class":623},"purchase",[613,4077,2345],{"class":698},[613,4079,4080],{"class":1018}," !=",[613,4082,4083],{"class":619}," null",[613,4085,4086],{"class":619}," ?",[613,4088,4064],{"class":1030},[613,4090,391],{"class":698},[613,4092,4075],{"class":623},[613,4094,2292],{"class":698},[613,4096,4097],{"class":623},"customerId",[613,4099,2345],{"class":698},[613,4101,4102],{"class":619}," :",[613,4104,4064],{"class":1030},[613,4106,391],{"class":698},[613,4108,4109],{"class":623},"webActivity",[613,4111,2292],{"class":698},[613,4113,4097],{"class":623},[613,4115,4116],{"class":698},"(),\n",[613,4118,4119,4122,4124,4126,4128,4130,4133,4135,4137,4140,4142,4145],{"class":615,"line":702},[613,4120,4121],{"class":1030},"        Grouped",[613,4123,391],{"class":698},[613,4125,720],{"class":623},[613,4127,750],{"class":698},[613,4129,2446],{"class":2439},[613,4131,4132],{"class":2313},"grouped-by-customer-id",[613,4134,2446],{"class":2439},[613,4136,2132],{"class":698},[613,4138,4139],{"class":671}," stringSerde",[613,4141,2132],{"class":698},[613,4143,4144],{"class":671}," webActivityOrPurchaseSerde",[613,4146,856],{"class":698},[613,4148,4149,4151,4153,4155,4158],{"class":615,"line":708},[613,4150,3559],{"class":698},[613,4152,736],{"class":623},[613,4154,750],{"class":698},[613,4156,4157],{"class":671},"dailyWindows",[613,4159,4160],{"class":698},");\n",[613,4162,4163],{"class":615,"line":731},[613,4164,655],{"emptyLinePlaceholder":654},[613,4166,4167,4169,4171,4173,4175,4177,4179,4182,4184,4187,4189],{"class":615,"line":760},[613,4168,350],{"class":671},[613,4170,678],{"class":698},[613,4172,681],{"class":671},[613,4174,678],{"class":698},[613,4176,686],{"class":1018},[613,4178,1021],{"class":698},[613,4180,4181],{"class":1018}," DailyAggregates",[613,4183,1027],{"class":698},[613,4185,4186],{"class":1030}," dailyAggregation",[613,4188,3798],{"class":698},[613,4190,4191],{"class":671}," windowedStream\n",[613,4193,4194,4196,4198],{"class":615,"line":771},[613,4195,3559],{"class":698},[613,4197,1270],{"class":623},[613,4199,837],{"class":698},[613,4201,4202,4205,4207,4210,4212,4214,4217],{"class":615,"line":776},[613,4203,4204],{"class":698},"        ()",[613,4206,2158],{"class":698},[613,4208,4209],{"class":619}," new",[613,4211,4181],{"class":623},[613,4213,750],{"class":698},[613,4215,4216],{"class":661},"\u002F* empty *\u002F",[613,4218,4219],{"class":698},"),\n",[613,4221,4222,4224,4226,4228,4230,4232,4234,4236,4238,4241,4243],{"class":615,"line":782},[613,4223,4056],{"class":698},[613,4225,2143],{"class":671},[613,4227,2132],{"class":698},[613,4229,1808],{"class":671},[613,4231,2132],{"class":698},[613,4233,2152],{"class":671},[613,4235,2155],{"class":698},[613,4237,2158],{"class":698},[613,4239,4240],{"class":661}," \u002F* fold value into agg *\u002F",[613,4242,2152],{"class":671},[613,4244,2373],{"class":698},[613,4246,4247,4250,4252,4254,4256,4258,4261,4263],{"class":615,"line":808},[613,4248,4249],{"class":1030},"        Named",[613,4251,391],{"class":698},[613,4253,3839],{"class":623},[613,4255,750],{"class":698},[613,4257,2446],{"class":2439},[613,4259,4260],{"class":2313},"daily-aggregation",[613,4262,2446],{"class":2439},[613,4264,4219],{"class":698},[613,4266,4267,4270,4272,4274,4276,4278,4280,4282,4285,4287,4289,4291,4293,4296,4298],{"class":615,"line":813},[613,4268,4269],{"class":671},"        Materialized",[613,4271,391],{"class":698},[613,4273,678],{"class":1018},[613,4275,686],{"class":671},[613,4277,2132],{"class":698},[613,4279,4181],{"class":671},[613,4281,2132],{"class":698},[613,4283,4284],{"class":671}," StateStore",[613,4286,1027],{"class":1018},[613,4288,3839],{"class":623},[613,4290,750],{"class":698},[613,4292,2446],{"class":2439},[613,4294,4295],{"class":2313},"daily-aggregation-store",[613,4297,2446],{"class":2439},[613,4299,3618],{"class":698},[613,4301,4302,4304,4306,4308,4311],{"class":615,"line":830},[613,4303,3623],{"class":698},[613,4305,3636],{"class":623},[613,4307,750],{"class":698},[613,4309,4310],{"class":671},"dailyAggregatesSerde",[613,4312,2517],{"class":698},[320,4314,4315,4316,4318,4319,4321,4322,391],{},"The full source — including how it reads ",[329,4317,2565],{}," to stamp each aggregate with its date and ",[329,4320,2569],{}," to re-key — is in ",[329,4323,4324],{},"examples\u002Fecommerce-daily-customer-behaviour",[451,4326,4328],{"id":4327},"where-to-go-next","Where to go next",[370,4330,4331,4343,4348,4353,4358],{},[373,4332,4333,4335,4336,382,4338,382,4340,4342],{},[338,4334,120],{"href":121}," — ",[329,4337,765],{},[329,4339,1266],{},[329,4341,1270],{}," and the grouped types that windowing builds on",[373,4344,4345,4347],{},[338,4346,67],{"href":68}," — how StoatFlow decides when a window closes",[373,4349,4350,4352],{},[338,4351,1057],{"href":146}," — serializers for keys and values, including custom value types",[373,4354,4355,4357],{},[338,4356,100],{"href":101}," — the window\u002Fsession stores backing these aggregations",[373,4359,4360,4363],{},[338,4361,4362],{"href":106},"Testing"," — advancing the watermark to drive window closes in tests",[4365,4366,4367],"style",{},"html pre.shiki code .sbBg2, html code.shiki .sbBg2{--shiki-default:#1E754F}html pre.shiki code .sySUi, html code.shiki .sySUi{--shiki-default:#59873A}html pre.shiki code .s8zF2, html code.shiki .s8zF2{--shiki-default:#A0ADA0}html pre.shiki code .suHK_, html code.shiki .suHK_{--shiki-default:#393A34}html pre.shiki code .sUxyF, html code.shiki .sUxyF{--shiki-default:#2E8F82}html pre.shiki code .sYZai, html code.shiki .sYZai{--shiki-default:#999999}html pre.shiki code .s-TwI, html code.shiki .s-TwI{--shiki-default:#2F798A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .si04Y, html code.shiki .si04Y{--shiki-default:#AB5959}html pre.shiki code .svycV, html code.shiki .svycV{--shiki-default:#B07D48}html pre.shiki code .spphp, html code.shiki .spphp{--shiki-default:#B56959}html pre.shiki code .sSP4y, html code.shiki .sSP4y{--shiki-default:#B5695977}",{"title":609,"searchDepth":627,"depth":627,"links":4369},[4370,4371,4372,4373,4374,4375,4376,4379,4380,4381],{"id":453,"depth":627,"text":454},{"id":579,"depth":627,"text":580},{"id":1274,"depth":627,"text":1275},{"id":1549,"depth":627,"text":1550},{"id":2246,"depth":627,"text":2247},{"id":2573,"depth":627,"text":2574},{"id":2935,"depth":627,"text":2936,"children":4377},[4378],{"id":3337,"depth":635,"text":3338},{"id":3468,"depth":627,"text":3469},{"id":3955,"depth":627,"text":3956},{"id":4327,"depth":627,"text":4328},"Windowed aggregations in StoatFlow — tumbling, hopping, sliding, and session windows; emit strategies, suppression, Windowed keys, and WindowedSerdes.","md",{},{"icon":128},"how-to",{"title":125,"description":4382},"7lX7Rddb_wGm4TLD6LA74ur655LUusnf_GXWixr94LQ",[4390,4392],{"title":120,"path":121,"stem":122,"description":4391,"icon":123,"children":-1},"Group records by key and fold them into running totals — count, reduce, aggregate on grouped streams and grouped tables, with the result backed by a state store.",{"title":130,"path":131,"stem":132,"description":4393,"icon":133,"children":-1},"Combine two streams or tables on a shared key — stream-stream windowed joins, stream-table enrichment lookups, table-table joins, foreign-key joins, and co-grouping.",1783713358961]