DaZuiZui commented on issue #18532:
URL: https://github.com/apache/iotdb/issues/18532#issuecomment-5437228680

   ## Proposed functional definition
   
   I suggest defining LTTB as a built-in Table Model table function, with 
parameter conventions aligned with the existing M4 table function.
   
   ### 1. SQL syntax
   
   ~~~sql
   SELECT *
   FROM LTTB(
     DATA    => TABLE(<query>),
     TIMECOL => DESCRIPTOR(<time_column>),
     N       => <target_count>
   );
   ~~~
   
   or:
   
   ~~~sql
   SELECT *
   FROM LTTB(
     DATA    => TABLE(<query>),
     TIMECOL => DESCRIPTOR(<time_column>),
     SIZE    => <window_size>,
     SLIDE   => <window_step>,
     ORIGIN  => <time_origin>
   );
   ~~~
   
   DATA and TIMECOL are required. Exactly one execution mode must be selected:
   
   * Target-count mode: specify N; N is mutually exclusive with SIZE, SLIDE, 
and ORIGIN.
   * Window/bucket mode: specify SIZE; SLIDE defaults to SIZE, and ORIGIN is 
valid only for time-based windows.
   
   ### 2. Parameter semantics
   
   * DATA: the input table, using the same table-argument semantics as M4.
   * TIMECOL: a descriptor identifying exactly one input time column. The 
column must have type TIMESTAMP. Input rows must be ordered by this column in 
ascending order within each partition; the function should enforce or establish 
this ordering before sampling.
   * N: a positive integer target number of points for each partition and each 
participant column. The minimum valid value is 3, because LTTB keeps the first 
point, the last point, and at least one intermediate point.
   * SIZE: the bucket/window size. A duration value selects time-window mode; 
an integer value selects count-window mode.
   * SLIDE: the window step, defaulting to SIZE. It is valid only with SIZE.
   * ORIGIN: the origin of a time window. It is valid only with duration-based 
SIZE, not with count windows.
   
   No explicit COL parameter is needed. As with M4, participant columns should 
be inferred from the input table: every supported numeric column other than the 
time column and partition columns is processed independently. Partition columns 
are preserved and define independent series.
   
   ### 3. Supported data types
   
   For the first implementation, participant columns should support INT32, 
INT64, FLOAT, and DOUBLE. The time column must be TIMESTAMP. Partition columns 
may retain the data types already supported by Table Model grouping.
   
   BOOLEAN, TEXT/STRING, binary types, and complex types should be rejected as 
participant columns in the first version, because triangle-area calculation 
requires an ordered numeric value. They can be added later if a well-defined 
conversion policy is agreed.
   
   ### 4. Target-count mode
   
   For each partition and participant column:
   
   1. Build the ordered sequence of eligible (timestamp, value) points.
   2. Ignore rows where that participant value is NULL; NULL rows must not be 
converted to zero and must not affect averages or triangle areas.
   3. If the number of eligible points is less than or equal to N, return all 
eligible points without interpolation.
   4. Otherwise apply the standard LTTB algorithm and return exactly N points.
   5. Always preserve the first and last eligible points and return the 
selected points in ascending timestamp order.
   
   LTTB is applied independently to every participant column. Consequently, 
different columns may select different timestamps. The target-count output 
should follow the count-window shape used by M4:
   
   ~~~text
   window_index, <partition_columns>,
   <column_1>_time, <column_1>,
   <column_2>_time, <column_2>, ...
   ~~~
   
   For target-count mode, window_index is fixed to 0. Selected values are 
aligned by output position; if columns have different numbers of eligible 
points, shorter sequences are padded with NULL. Therefore each partition 
produces at most N rows (and exactly N rows when every participant column has 
more than N eligible points).
   
   ### 5. Window/bucket mode
   
   Window construction must follow the same boundary, inclusiveness, 
timestamp-origin, and count-window rules as M4.
   
   For each bucket and participant column, select one representative point 
using the LTTB triangle:
   
   * A: the previously selected point (the anchor);
   * B: each non-NULL candidate point in the current bucket;
   * C: the average point of the next bucket (average timestamp and average 
numeric value over eligible points).
   
   Select the candidate with the largest triangle area. Ties should be resolved 
deterministically, for example by the earliest timestamp. Empty buckets produce 
no participant point. The implementation should define how the first bucket is 
anchored (the first eligible point in the partition is the initial anchor) and 
how the final bucket is handled when no next bucket exists (the last eligible 
point should be retained).
   
   The output schema follows M4:
   
   * Time-window mode:
     ~~~text
     window_start, window_end, <partition_columns>,
     <column_1>_time, <column_1>,
     <column_2>_time, <column_2>, ...
     ~~~
   * Count-window mode:
     ~~~text
     window_index, <partition_columns>,
     <column_1>_time, <column_1>,
     <column_2>_time, <column_2>, ...
     ~~~
   
   With SLIDE < SIZE, overlapping windows are expected to follow M4's set 
semantics. LTTB state must be computed per partition/window; results must not 
depend on fragment-local input boundaries.
   
   ### 6. NULL and edge-case behavior
   
   * NULL participant values are ignored independently per column.
   * A partition with no eligible points for a participant column returns NULL 
for that column.
   * A partition with one eligible point returns that point; a partition with 
two eligible points returns both points. This short-series behavior applies 
even though N >= 3 is required for downsampling.
   * Duplicate timestamps should be handled consistently with the rest of the 
Table Model (prefer stable input order after sorting); implementations should 
document this behavior.
   * Numeric overflow in average/area calculations must be avoided by using a 
sufficiently wide intermediate type, for example DOUBLE.
   
   ### 7. Validation errors
   
   The function should reject at least:
   
   * neither N nor SIZE is specified;
   * both N and SIZE are specified;
   * N < 3 or a non-positive/non-integer N;
   * N combined with SLIDE or ORIGIN;
   * SLIDE or ORIGIN without SIZE;
   * ORIGIN with count-window mode;
   * invalid or non-TIMESTAMP TIMECOL;
   * zero/negative/invalid SIZE or SLIDE;
   * unsupported participant data types.
   
   Example:
   
   ~~~sql
   SELECT *
   FROM LTTB(
     DATA => TABLE(sensor_data),
     TIMECOL => DESCRIPTOR(time),
     N => 500,
     SIZE => 1m
   );
   ~~~
   
   This must fail because N and SIZE select mutually exclusive modes.
   
   ### 8. Execution and distributed semantics
   
   The function should have set semantics, consistent with M4. In target-count 
mode, bucket boundaries depend on the total number of eligible points, so the 
implementation may need to buffer each partition, with memory accounting and 
spill support where required. Window mode can use bounded state by retaining 
the previous selected point plus current and next buckets.
   
   LTTB is not generally mergeable. In distributed execution, all rows for a 
partition must be gathered and ordered before sampling; fragment-local LTTB 
results cannot simply be concatenated or merged into a globally correct result.
   
   ### 9. Examples
   
   Target-count mode:
   
   ~~~sql
   SELECT *
   FROM LTTB(
     DATA => TABLE(
       SELECT time, temperature, pressure
       FROM sensor_data
       WHERE device_id = 'd1'
     ),
     TIMECOL => DESCRIPTOR(time),
     N => 500
   );
   ~~~
   
   Count-window mode:
   
   ~~~sql
   SELECT *
   FROM LTTB(
     DATA => TABLE(SELECT time, temperature, pressure FROM sensor_data),
     TIMECOL => DESCRIPTOR(time),
     SIZE => 100,
     SLIDE => 100
   );
   ~~~
   
   Time-window mode:
   
   ~~~sql
   SELECT *
   FROM LTTB(
     DATA => TABLE(SELECT time, temperature, pressure FROM sensor_data),
     TIMECOL => DESCRIPTOR(time),
     SIZE => 1m,
     SLIDE => 1m,
     ORIGIN => TIMESTAMP '2026-01-01 00:00:00'
   );
   ~~~
   
   ### 10. Suggested tests
   
   Tests should cover:
   
   * deterministic output for a known LTTB data set;
   * preservation of first/last points;
   * exactly N points when input has more than N eligible points;
   * returning all points when input has no more than N points;
   * fixed window_index = 0 in target-count mode;
   * multiple participant columns selecting different timestamps;
   * different NULL distributions and empty participant series;
   * partitioned input;
   * count-based and time-based SIZE;
   * default and explicit SLIDE;
   * ORIGIN alignment;
   * overlapping windows;
   * invalid parameter combinations and unsupported types;
   * consistent standalone and distributed results.
   
   ### 11. Scope for the first version
   
   The first version should keep the behavior deterministic and aligned with 
M4, while explicitly documenting the final-bucket/short-series rules and the 
treatment of overlapping windows. Follow-up work can add more participant types 
or alternative output layouts if there is a concrete use case.


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

To unsubscribe, e-mail: [email protected]

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

Reply via email to