Skip to content

[#17939] Implement FFT table function for table model#18006

Open
DaZuiZui wants to merge 8 commits into
apache:masterfrom
DaZuiZui:feat/fft-table-v1-17939
Open

[#17939] Implement FFT table function for table model#18006
DaZuiZui wants to merge 8 commits into
apache:masterfrom
DaZuiZui:feat/fft-table-v1-17939

Conversation

@DaZuiZui

@DaZuiZui DaZuiZui commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Description

FFT table-valued function

This PR implements the v1 built-in FFT / fft table-valued function for the table model.

The function accepts a required DATA table argument with set semantics and ORDER BY <TIMECOL> (TIMECOL defaults to time), plus optional SAMPLE_INTERVAL, N, NORM, and TIMECOL arguments. It emits the full complex spectrum for each eligible numeric transform column and returns frequency_index, frequency, and <column>_real / <column>_imag columns. When partition columns exist, they are kept at the front of the output schema.

The FFT implementation uses JTransforms DoubleFFT_1D / FloatFFT_1D. N supports default partition length, truncation, and zero padding. NORM supports backward, forward, and ortho. SAMPLE_INTERVAL can be supplied as a duration literal; otherwise the interval is inferred from the partition time range as (last_time - first_time) / (row_count - 1). Input gaps are not validated against either the inferred interval or an explicitly supplied SAMPLE_INTERVAL.

Analyzer, planner, and validation

The function is registered as a built-in table function and gets analyzer/planner handling similar to M4 where needed so the output column order matches the table-function contract.

Validation covers:

  • DATA must have ORDER BY <TIMECOL> in ascending order (TIMECOL defaults to time).
  • SAMPLE_INTERVAL, if provided, must be positive.
  • N, if provided, must be positive.
  • NORM must be one of backward, forward, or ortho.
  • After excluding the selected time column (TIMECOL, default time) and partition columns, at least one numeric transform column is required.
  • Runtime data must be strictly increasing by time and numeric transform values must not be null.
  • If SAMPLE_INTERVAL is omitted, at least two rows are required to infer it.

Tests

This PR adds focused unit coverage for the FFT processor, analyzer/planner coverage for built-in table-function recognition and schema handling, and a table-model IT covering normal execution and failure cases.

Tested locally with:

./mvnw spotless:apply -pl iotdb-core/node-commons,integration-test -P with-integration-tests
./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -DskipITs
./mvnw verify -DskipUTs -Dit.test=IoTDBFFTTableFunctionIT -DfailIfNoTests=false -Dfailsafe.failIfNoSpecifiedTests=false -pl integration-test -am -PTableSimpleIT -P with-integration-tests

This PR has:

  • been self-reviewed.
  • added Javadocs for most classes and all non-trivial methods.
  • added comments explaining the "why" and the intent of the code wherever would not be obvious for an unfamiliar reader.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold for code coverage.
  • added integration tests.
  • been tested in a test IoTDB cluster.

Key changed/added classes (or packages if there are too many classes) in this PR
  • org.apache.iotdb.commons.udf.builtin.relational.tvf.FFTTableFunction
  • org.apache.iotdb.commons.queryengine.plan.relational.function.TableBuiltinTableFunction
  • org.apache.iotdb.db.queryengine.plan.relational.analyzer.StatementAnalyzer
  • org.apache.iotdb.db.queryengine.plan.relational.planner.RelationPlanner
  • org.apache.iotdb.commons.udf.builtin.relational.tvf.FFTTableFunctionTest
  • org.apache.iotdb.db.queryengine.plan.relational.analyzer.TableFunctionTest
  • org.apache.iotdb.relational.it.db.it.IoTDBFFTTableFunctionIT

Related to #17939.

@DaZuiZui DaZuiZui force-pushed the feat/fft-table-v1-17939 branch from dc535ca to 2faa54b Compare June 23, 2026 06:28
@DaZuiZui

Copy link
Copy Markdown
Contributor Author

Updated this PR for the latest review comments:

  • Capped FFT transform length at 65,536 and added a spectrum buffer-size guard for multi-column input.
  • Validate evenly spaced timestamps when SAMPLE_INTERVAL is omitted, and validate input gaps against SAMPLE_INTERVAL when it is provided.
  • Added UT/IT coverage for oversized N, irregular timestamps, and explicit interval mismatch.

Tests run locally with JDK 21:

  • JAVA_HOME=$( /usr/libexec/java_home -v 21 ) ./mvnw spotless:apply -pl iotdb-core/node-commons,iotdb-core/datanode,integration-test -P with-integration-tests
  • JAVA_HOME=$( /usr/libexec/java_home -v 21 ) ./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false
  • JAVA_HOME=$( /usr/libexec/java_home -v 21 ) ./mvnw test -pl iotdb-core/datanode -am -Dtest=TableFunctionTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false
  • JAVA_HOME=$( /usr/libexec/java_home -v 21 ) ./mvnw verify -DskipUTs -Dit.test=IoTDBFFTTableFunctionIT -DfailIfNoTests=false -Dfailsafe.failIfNoSpecifiedTests=false -pl integration-test -am -PTableSimpleIT -P with-integration-tests

@DaZuiZui

Copy link
Copy Markdown
Contributor Author

Follow-up update:

  • Added node-commons unit coverage for actual FFT spectrum output, zero padding, N truncation, and the explicit failure behavior for invalid rows even when they are beyond the truncated N range.
  • Added a release-note level entry documenting SAMPLE_INTERVAL, default/capped N, null rejection, and timestamp spacing behavior.

Pushed as a normal follow-up commit (no force push).

Tests run locally with JDK 21:

  • JAVA_HOME=$( /usr/libexec/java_home -v 21 ) ./mvnw spotless:apply -pl iotdb-core/node-commons
  • JAVA_HOME=$( /usr/libexec/java_home -v 21 ) ./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false

@DaZuiZui

DaZuiZui commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

English

The PR branch has been updated with the following main changes:

The Maven dependency of iotdb-core/node-commons on JTransforms has been removed to avoid adding third-party dependencies to the core module.

A new in-package implementation of DoubleFft1d has been added, and FFTTableFunction now directly uses this built-in implementation.

DoubleFft1d retains the double complex forward FFT capability required by DoubleFFT_1D#complexForward(double[]): lengths raised to powers of 2 follow radix-2, and lengths not raised to powers of 2 follow Bluestein, thus not narrowing the behavior of N.

The JTransforms/BSD-2-Clause source description has been added to the LICENSE.

Unit test coverage for non-powers of 2 when N = 3 has been added.

Verification:

./mvnw spotless:apply -pl iotdb-core/node-commons

./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -Dsurefire.failIfNoSpecifiedTests=false -DfailIfNoTests=false -DskipITs

Additionally, I used a local JTransforms 3.1 jar to verify the length of multiple sets of outputs, and the results were consistent.

Chinese

已更新 PR 分支,主要改动如下:

  • 移除了 iotdb-core/node-commonsJTransforms 的 Maven 依赖,避免在核心模块新增第三方依赖。
  • 新增包内 DoubleFft1d 实现,FFTTableFunction 改为直接使用该内置实现。
  • DoubleFft1d 保留了 DoubleFFT_1D#complexForward(double[]) 这次表函数需要的 double complex forward FFT 能力:2 的幂长度走 radix-2,非 2 的幂长度走 Bluestein,因此不收窄 N 的行为。
  • LICENSE 中补充了 JTransforms/BSD-2-Clause 来源说明。
  • 补充了 N = 3 的非 2 的幂单测覆盖。

验证:

  • ./mvnw spotless:apply -pl iotdb-core/node-commons
  • ./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -Dsurefire.failIfNoSpecifiedTests=false -DfailIfNoTests=false -DskipITs
  • 额外用本地 JTransforms 3.1 jar 对多组长度输出做了对照校验,结果一致。

@DaZuiZui

DaZuiZui commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Added commit 039c240 to replace the vendored FFT implementation with JTransforms, route FLOAT inputs through FloatFFT_1D and other numeric inputs through DoubleFFT_1D, and add focused coverage plus binary license entries.

@DaZuiZui

DaZuiZui commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

已更新 PR 分支,主要改动如下:

  • 根据评审意见,将 FFT 计算路径按输入类型拆分:FLOAT 输入使用 FloatFFT_1DDOUBLE 及其他数值输入使用 DoubleFFT_1D,避免 FLOAT 输入先转换为 double 后统一处理。
  • 移除了包内 DoubleFft1d 实现,FFTTableFunction 改为直接调用 JTransforms 的 DoubleFFT_1D / FloatFFT_1D
  • iotdb-core/node-commons 补充 JTransforms Maven 依赖,并同步更新 LICENSE / LICENSE-binary 中相关许可证说明。
  • 补充并收紧 FLOAT 输入单测:mock RecordFLOAT 只能通过 getFloat() 读取,确保测试可以覆盖 FloatFFT_1D 路径。
  • 将相关集成测试中的 FFT 结果断言调整为带 delta 的数值比较,适配 float FFT 计算精度差异。

验证:

  • ./mvnw spotless:apply -pl iotdb-core/node-commons
  • ./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -DskipITs
  • ./mvnw dependency:analyze-only -pl iotdb-core/node-commons -DskipTests -DskipITs
  • ./mvnw -N apache-rat:check
  • ./mvnw verify -DskipUTs -Dit.test=IoTDBFFTTableFunctionIT -DfailIfNoTests=false -Dfailsafe.failIfNoSpecifiedTests=false -pl integration-test -am -PTableSimpleIT -P with-integration-tests

@DaZuiZui

DaZuiZui commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Correction on the time column contract for FFT V1: we should support TIMECOL instead of requiring the input time column to be literally named time.

Reason: the table model supports custom TIME column names, for example CREATE TABLE t(event_time TIMESTAMP TIME, value DOUBLE FIELD). If FFT hard-codes time, valid table-model tables with a custom TIME column cannot use the built-in FFT directly, and this is also inconsistent with existing table/window TVFs that accept TIMECOL.

The intended contract should be:

  • TIMECOL is optional and defaults to time, preserving the simple/default syntax.
  • DATA must include a TIMESTAMP/TIME column matching TIMECOL.
  • ORDER BY must contain exactly that selected time column in ascending order.
  • Numeric FFT value columns should exclude the selected time column and partition columns.

So the previous wording in the PR description that says ORDER BY time should be corrected to ORDER BY <TIMECOL> / default time.

@DaZuiZui

DaZuiZui commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up update for custom FFT time columns:

  • Added optional TIMECOL support for FFT, defaulting to time, so tables with custom TIME column names such as event_time TIMESTAMP TIME can use FFT directly.

  • Validation now requires DATA ... ORDER BY to reference the column selected by TIMECOL, and FFT excludes that selected time column from value columns.

  • Moved TIMECOL to the end of the FFT argument specification (DATA, SAMPLE_INTERVAL, N, NORM, TIMECOL) to preserve existing positional-argument semantics. Named usage such as TIMECOL => 'event_time' is supported as expected.

  • Added unit/planner/IT coverage for custom time column usage, plus planner coverage that positional arguments like FFT(TABLE(table1) ORDER BY time, 1s, 4, 'ortho') still bind 1s to SAMPLE_INTERVAL.

  • ./mvnw spotless:apply -pl iotdb-core/node-commons,iotdb-core/datanode

  • ./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -DskipITs

  • ./mvnw test -pl iotdb-core/datanode -am -Dtest=TableFunctionTest#testFFTWithSpecifiedTimeColumn+testFFTPositionalArgumentsKeepExistingOrder -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -DskipITs

@DaZuiZui

DaZuiZui commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

自定义 FFT 时间列的后续更新:

为 FFT 添加了可选的 TIMECOL 支持,默认值为 time,因此具有自定义 TIME 列名(例如 event_time TIMESTAMP TIME)的表可以直接使用 FFT。

验证现在要求 DATA ... ORDER BY 引用 TIMECOL 选择的列,并且 FFT 会将该选定的时间列从值列中排除。

将 TIMECOL 移至 FFT 参数规范(DATA、SAMPLE_INTERVAL、N、NORM、TIMECOL)的末尾,以保留现有的位置参数语义。按预期支持命名用法,例如 TIMECOL => 'event_time'。

添加了自定义时间列用法的单元/规划器/IT 覆盖率,以及规划器覆盖率,其中位置参数(例如 FFT(TABLE(table1) ORDER BY time, 1s, 4, 'ortho'))仍然将 1s 绑定到 SAMPLE_INTERVAL。

./mvnw spotless:apply -pl iotdb-core/node-commons,iotdb-core/datanode

./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -DskipITs

./mvnw test -pl iotdb-core/datanode -am -Dtest=TableFunctionTest#testFFTWithSpecifiedTimeColumn+testFFTPositionalArgumentsKeepExistingOrder -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -DskipITs

@DaZuiZui

DaZuiZui commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up update after the sampling-interval clarification:

  • Removed the runtime validation that required evenly spaced timestamps when SAMPLE_INTERVAL is omitted.
  • Removed the runtime validation that required input gaps to match an explicitly supplied SAMPLE_INTERVAL.
  • When SAMPLE_INTERVAL is omitted, FFT now infers the interval from the partition time range as (last_time - first_time) / (row_count - 1).
  • When SAMPLE_INTERVAL is supplied, FFT uses that value directly. Input gaps are not validated against it.
  • Timestamps are still required to be strictly ascending, and numeric transform values still cannot be null.

Verification:

./mvnw spotless:apply -pl iotdb-core/node-commons,integration-test -P with-integration-tests
./mvnw test -pl iotdb-core/node-commons -am -Dtest=FFTTableFunctionTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -DskipITs
./mvnw verify -DskipUTs -Dit.test=IoTDBFFTTableFunctionIT -DfailIfNoTests=false -Dfailsafe.failIfNoSpecifiedTests=false -pl integration-test -am -PTableSimpleIT -P with-integration-tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant