When rows are deleted from a window, some queries may need to be re-evaluated.
If you have a query that calculates the sum of the prices in a window, then when a row expires, the price in that row should be subtracted from the sum of the prices in the window. Thus if you have a query on a window, each row that arrives in that window may generate two output messages: one for the arriving row and one for the expiring row.
Let's look at an example. Here, two windows are created and a set of queries is created when the output of one window is fed to another window:
CREATE WINDOW StockTradeHistory SCHEMA ... KEEP 8 HOURS; -- Query #1: Insert source data into "history" window. INSERT INTO StockTradeHistory SELECT * FROM NYSEStockTrades; -- Query #2: Process data from "history" window and -- generate output. INSERT INTO OutputStream... SELECT StockSymbol, AVG(Price) FROM StockTradeHistory KEEP LAST PER StockSymbol GROUP BY StockSymbol;
As you can see, the output of the last query depends upon the contents of the StockTradesHistory window. When a new row arrives in the NYSEStockTrades stream and is put into the StockTradeHistory window, we should calculate a new average price, and when a stock trade's information expires from the StockTradeHistory window, the window will calculate a new average price based on the remaining rows in the window.
If this window directly feeds another window, then when a row from this window expires, the window sends a "delete" message to the second (downstream) window, telling that window to delete its copy of the row.
When one window sends another window a "delete this row" notice, we refer to the notice as a "negative tuple" (because it cancels out the original "positive tuple").
When a User-Defined Function is called from a CCL statement, the function may be passed either a positive tuple or a negative tuple. If you write your own output adapter to subscribe to a stream, your adapter may receive negative tuples and will need to handle them properly. In many cases, all you need to do is determine that the tuple is a negative tuple and then discard it, but in some cases your adapter, like a query, may want to pass on or act upon that negative tuple. To learn how your adapter can recognize that a tuple is negative, see User-Defined Aggregate Functions in the C/C++ SDK chapter.