You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ro...@apache.org on 2022/12/12 08:33:49 UTC
[iotdb] 01/01: python udf api package
This is an automated email from the ASF dual-hosted git repository.
rong pushed a commit to branch python-udf
in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit d86f3f9a037c5e0ef9afb56bd6988ad25092ec44
Author: Steve Yurong Su <ro...@apache.org>
AuthorDate: Mon Dec 12 16:32:43 2022 +0800
python udf api package
---
udf-py/.flake8 | 32 ++++
udf-py/.gitignore | 3 +
udf-py/LICENSE | 201 +++++++++++++++++++++
udf-py/README.md | 45 +++++
udf-py/pyproject.toml | 45 +++++
udf-py/release.sh | 37 ++++
udf-py/requirements.txt | 17 ++
udf-py/requirements_dev.txt | 26 +++
udf-py/setup.py | 51 ++++++
udf-py/tests/__init__.py | 17 ++
udf-py/udf_api/__init__.py | 16 ++
udf-py/udf_api/access/__init__.py | 16 ++
udf-py/udf_api/access/row.py | 138 ++++++++++++++
udf-py/udf_api/access/row_iterator.py | 41 +++++
udf-py/udf_api/access/row_window.py | 95 ++++++++++
udf-py/udf_api/collector/__init__.py | 16 ++
udf-py/udf_api/collector/point_collector.py | 98 ++++++++++
udf-py/udf_api/customizer/__init__.py | 16 ++
udf-py/udf_api/customizer/config/__init__.py | 16 ++
.../customizer/config/udf_configurations.py | 32 ++++
.../customizer/config/udtf_configurations.py | 64 +++++++
udf-py/udf_api/customizer/parameter/__init__.py | 16 ++
.../parameter/udf_parameter_validator.py | 136 ++++++++++++++
.../udf_api/customizer/parameter/udf_parameters.py | 71 ++++++++
udf-py/udf_api/customizer/strategy/__init__.py | 16 ++
.../udf_api/customizer/strategy/access_strategy.py | 45 +++++
.../customizer/strategy/access_strategy_type.py | 38 ++++
.../mappable_row_by_row_access_strategy.py | 40 ++++
.../strategy/row_by_row_access_strategy.py | 40 ++++
.../session_time_window_access_strategy.py | 77 ++++++++
.../sliding_size_window_access_strategy.py | 98 ++++++++++
.../sliding_time_window_access_strategy.py | 127 +++++++++++++
.../strategy/state_window_access_strategy.py | 77 ++++++++
udf-py/udf_api/exception/__init__.py | 16 ++
.../udf_attribute_not_provided_exception.py | 27 +++
udf-py/udf_api/exception/udf_exception.py | 36 ++++
...f_input_series_data_type_not_valid_exception.py | 32 ++++
.../udf_input_series_index_not_valid_exception.py | 29 +++
.../udf_input_series_number_not_valid_exception.py | 35 ++++
.../udf_api/exception/udf_management_exception.py | 23 +++
..._output_series_data_type_not_valid_exception.py | 29 +++
.../exception/udf_parameter_not_valid_exception.py | 23 +++
udf-py/udf_api/type/__init__.py | 16 ++
udf-py/udf_api/type/binary.py | 77 ++++++++
udf-py/udf_api/type/type.py | 27 +++
udf-py/udf_api/udf.py | 37 ++++
udf-py/udf_api/udtf.py | 104 +++++++++++
47 files changed, 2314 insertions(+)
diff --git a/udf-py/.flake8 b/udf-py/.flake8
new file mode 100644
index 0000000000..8c86f0d1d6
--- /dev/null
+++ b/udf-py/.flake8
@@ -0,0 +1,32 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+[flake8]
+ignore =
+ E203,
+ W503
+max-line-length=200
+exclude =
+ .git,
+ test/*,
+extend-exclude =
+ dist,
+ build,
+ venv
+show-source = True
+statistics = True
+format = %(path)s:%(row)d,%(col)d:%(code)s:%(text)s:https://lintlyci.github.io/Flake8Rules/rules/%(code)s.html
diff --git a/udf-py/.gitignore b/udf-py/.gitignore
new file mode 100644
index 0000000000..237854a3c0
--- /dev/null
+++ b/udf-py/.gitignore
@@ -0,0 +1,3 @@
+# generated by Pypi
+/build/
+/dist/
diff --git a/udf-py/LICENSE b/udf-py/LICENSE
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/udf-py/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/udf-py/README.md b/udf-py/README.md
new file mode 100644
index 0000000000..c45bbb3748
--- /dev/null
+++ b/udf-py/README.md
@@ -0,0 +1,45 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+# Apache IoTDB Python UDF
+
+## Releasing
+
+To do a release just ensure that you have the right set of dev dependencies.
+Then run linting and auto-formatting.
+Then, ensure that all tests work (via `pytest .`).
+Then you are good to go to do a release!
+
+### Preparing your environment
+
+First, install all necessary dev dependencies via `pip install -r requirements_dev.txt`.
+
+### Doing the Release
+
+There is a convenient script `release.sh` to do all steps for a release.
+Namely, these are
+
+* Remove all transient directories from last release (if exists)
+* Run Autoformatting (`black .`)
+* Run Linting (`flake8 .`)
+* Run Tests via pytest
+* Build
+* Release to pypi
diff --git a/udf-py/pyproject.toml b/udf-py/pyproject.toml
new file mode 100644
index 0000000000..0a72182bb7
--- /dev/null
+++ b/udf-py/pyproject.toml
@@ -0,0 +1,45 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+[tool.black]
+line-length = 88
+target-version = ['py37']
+include = '\.pyi?$'
+exclude = '''
+
+(
+ /(
+ \.eggs # exclude a few common directories in the
+ | \.git # root of the project
+ | \.hg
+ | \.mypy_cache
+ | \.tox
+ | \.venv
+ | venv
+ | _build
+ | buck-out
+ | build
+ | dist
+ | migrations
+ | test
+ | iotdb/thrift
+ )/
+ | foo.py # also separately exclude a file named foo.py in
+ # the root of the project
+)
+'''
diff --git a/udf-py/release.sh b/udf-py/release.sh
new file mode 100755
index 0000000000..1c64990cfb
--- /dev/null
+++ b/udf-py/release.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# the python version must be python3.
+python --version
+
+rm -Rf build
+rm -Rf dist
+
+# Run Autoformatting & Linting
+black .
+flake8 .
+
+# Run unit tests
+pytest .
+
+# See https://packaging.python.org/tutorials/packaging-projects/
+python setup.py sdist bdist_wheel
+twine upload --repository pypi dist/*
diff --git a/udf-py/requirements.txt b/udf-py/requirements.txt
new file mode 100644
index 0000000000..2a1e720805
--- /dev/null
+++ b/udf-py/requirements.txt
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
diff --git a/udf-py/requirements_dev.txt b/udf-py/requirements_dev.txt
new file mode 100644
index 0000000000..276fed3ef4
--- /dev/null
+++ b/udf-py/requirements_dev.txt
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+-r requirements.txt
+# Pytest to run tests
+pytest==7.2.0
+flake8==3.9.0
+black==20.8b1
+# For releases
+twine==3.4.1
+wheel==0.36.2
diff --git a/udf-py/setup.py b/udf-py/setup.py
new file mode 100644
index 0000000000..79404284c3
--- /dev/null
+++ b/udf-py/setup.py
@@ -0,0 +1,51 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import setuptools
+import io
+
+try:
+ with io.open("README.md", encoding="utf-8") as f:
+ long_description = f.read()
+except FileNotFoundError:
+ long_description = ""
+
+print(long_description)
+
+setuptools.setup(
+ name="apache-iotdb-udf",
+ version="1.0.0",
+ author=" Apache Software Foundation",
+ author_email="dev@iotdb.apache.org",
+ description="Apache IoTDB client API",
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ url="https://github.com/apache/iotdb",
+ packages=setuptools.find_packages(),
+ install_requires=[],
+ classifiers=[
+ "Programming Language :: Python :: 3",
+ "License :: OSI Approved :: Apache Software License",
+ "Operating System :: OS Independent",
+ "Topic :: Software Development :: Libraries",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ ],
+ python_requires=">=3.7",
+ license="Apache License, Version 2.0",
+ website="https://iotdb.apache.org",
+)
diff --git a/udf-py/tests/__init__.py b/udf-py/tests/__init__.py
new file mode 100644
index 0000000000..2a1e720805
--- /dev/null
+++ b/udf-py/tests/__init__.py
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
diff --git a/udf-py/udf_api/__init__.py b/udf-py/udf_api/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/access/__init__.py b/udf-py/udf_api/access/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/access/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/access/row.py b/udf-py/udf_api/access/row.py
new file mode 100644
index 0000000000..ae9e8b87a4
--- /dev/null
+++ b/udf-py/udf_api/access/row.py
@@ -0,0 +1,138 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from abc import ABCMeta, abstractmethod
+
+from udf_api.type.binary import Binary
+from udf_api.type.type import Type
+
+
+class Row(metaclass=ABCMeta):
+ @abstractmethod
+ def get_time(self) -> int:
+ """
+ Returns the timestamp of this row.
+
+ :return: timestamp
+ """
+ pass
+
+ @abstractmethod
+ def get_int(self, column_index: int) -> int:
+ """
+ Returns the int value at the specified column in this row.
+
+ Users need to ensure that the data type of the specified column is Type.INT32.
+
+ :return: the int value at the specified column in this row
+ """
+ pass
+
+ @abstractmethod
+ def get_long(self, column_index: int) -> int:
+ """
+ Returns the long value at the specified column in this row.
+
+ Users need to ensure that the data type of the specified column is Type.INT64.
+
+ :return: the long value at the specified column in this row
+ """
+ pass
+
+ @abstractmethod
+ def get_float(self, column_index: int) -> float:
+ """
+ Returns the float value at the specified column in this row.
+
+ Users need to ensure that the data type of the specified column is Type.FLOAT.
+
+ :return: the float value at the specified column in this row
+ """
+ pass
+
+ @abstractmethod
+ def get_double(self, column_index: int) -> float:
+ """
+ Returns the double value at the specified column in this row.
+
+ Users need to ensure that the data type of the specified column is Type.DOUBLE.
+
+ :return: the double value at the specified column in this row
+ """
+ pass
+
+ @abstractmethod
+ def get_boolean(self, column_index: int) -> bool:
+ """
+ Returns the bool value at the specified column in this row.
+
+ Users need to ensure that the data type of the specified column is Type.BOOLEAN.
+
+ :return: the bool value at the specified column in this row
+ """
+ pass
+
+ @abstractmethod
+ def get_binary(self, column_index: int) -> Binary:
+ """
+ Returns the Binary value at the specified column in this row.
+
+ Users need to ensure that the data type of the specified column is Type.TEXT.
+
+ :return: the Binary value at the specified column in this row
+ """
+ pass
+
+ @abstractmethod
+ def get_string(self, column_index: int) -> str:
+ """
+ Returns the str value at the specified column in this row.
+
+ Users need to ensure that the data type of the specified column is Type.TEXT.
+
+ :return: the str value at the specified column in this row
+ """
+ pass
+
+ @abstractmethod
+ def get_data_type(self, column_index: int) -> Type:
+ """
+ Returns the actual data type of the value at the specified column in this row.
+
+ Users need to ensure that the data type of the specified column is Type.TEXT.
+
+ :return: the actual data type of the value at the specified column in this row
+ """
+ pass
+
+ @abstractmethod
+ def is_null(self, column_index: int) -> bool:
+ """
+ Returns true if the value of the specified column is null.
+
+ :return: true if the value of the specified column is null
+ """
+ pass
+
+ @abstractmethod
+ def __len__(self):
+ """
+ Returns the number of columns
+
+ :return: the number of columns
+ """
+ pass
diff --git a/udf-py/udf_api/access/row_iterator.py b/udf-py/udf_api/access/row_iterator.py
new file mode 100644
index 0000000000..697d44f44a
--- /dev/null
+++ b/udf-py/udf_api/access/row_iterator.py
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from abc import ABCMeta, abstractmethod
+
+
+class RowIterator(metaclass=ABCMeta):
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ if self._has_next_row():
+ return self._next_row()
+ else:
+ raise StopIteration()
+
+ @abstractmethod
+ def _has_next_row(self):
+ pass
+
+ @abstractmethod
+ def _next_row(self):
+ pass
+
+ @abstractmethod
+ def reset(self):
+ pass
diff --git a/udf-py/udf_api/access/row_window.py b/udf-py/udf_api/access/row_window.py
new file mode 100644
index 0000000000..783c2bb2bd
--- /dev/null
+++ b/udf-py/udf_api/access/row_window.py
@@ -0,0 +1,95 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+from abc import ABCMeta, abstractmethod
+
+from udf_api.access.row import Row
+from udf_api.access.row_iterator import RowIterator
+from udf_api.type.type import Type
+
+
+class RowWindow(metaclass=ABCMeta):
+ @abstractmethod
+ def window_size(self):
+ """
+ Returns the number of rows in this window.
+
+ :return: the number of rows in this window
+ """
+ pass
+
+ @abstractmethod
+ def get_row(self, row_index: int) -> Row:
+ """
+ Returns the row at the specified position in this window.
+
+ Note that the Row instance returned by this method each time is the same instance. In other words, calling this
+ method will only change the member variables inside the Row instance, but will not generate a new Row instance.
+
+ :return: the row at the specified position in this window.
+ """
+ pass
+
+ @abstractmethod
+ def get_data_type(self, column_index: int) -> Type:
+ """
+ Returns the actual data type of the values at the specified column in this window.
+
+ :return: the actual data type of the values at the specified column in this window
+ """
+ pass
+
+ @abstractmethod
+ def get_row_iterator(self) -> RowIterator:
+ """
+ Returns an iterator used to access this window.
+
+ :return: an iterator used to access this window
+ """
+ pass
+
+ @abstractmethod
+ def window_start_time(self) -> int:
+ """
+ For different types of windows, the definition of the window start time is different.
+ For sliding size window: the window start time is equal to the timestamp of the first row.
+ For sliding time window: The window start time is determined by display_window_begin
+ SlidingTimeWindowAccessStrategy#get_display_window_begin() and
+ slidingStep SlidingTimeWindowAccessStrategy#get_sliding_step().
+ The window start time for the i-th window (i starts at 0) can be calculated as
+ display_window_begin + i * sliding_step.
+
+ :return: the start time of the window
+ """
+ pass
+
+ @abstractmethod
+ def window_start_end(self) -> int:
+ """
+ For different types of windows, the definition of the window end time is different.
+ For sliding size window: the window end time is equal to the timestamp of the last row.
+ For sliding time window: The window end time is determined by display_window_begin
+ SlidingTimeWindowAccessStrategy#get_display_window_begin(), time_interval
+ SlidingTimeWindowAccessStrategy#get_time_interval() and sliding_step
+ SlidingTimeWindowAccessStrategy#get_sliding_step(). The window end time for the i-th window (i starts at 0) can
+ be calculated as display_window_begin + i * sliding_step + time_interval - 1 or
+ window_start_time(i) + time_interval - 1.
+
+ :return: the end time of the window
+ """
+ pass
diff --git a/udf-py/udf_api/collector/__init__.py b/udf-py/udf_api/collector/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/collector/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/collector/point_collector.py b/udf-py/udf_api/collector/point_collector.py
new file mode 100644
index 0000000000..2c35439222
--- /dev/null
+++ b/udf-py/udf_api/collector/point_collector.py
@@ -0,0 +1,98 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from abc import ABCMeta, abstractmethod
+
+from udf_api.type.binary import Binary
+
+
+class PointCollector(metaclass=ABCMeta):
+ """
+ Used to collect time series data points generated by UDTF.transform(Row, PointCollector), UDTF.transform(RowWindow,
+ PointCollector) or UDTF.terminate(PointCollector). Notice that one timestamp can not be put in the PointCollector
+ more than once, or it may stop the calculation.
+ """
+
+ @abstractmethod
+ def put_int(self, timestamp: int, value: int):
+ """
+ Collects an int data point with timestamp.
+
+ Before calling this method, you need to ensure that the UDF output data type is set to Type.INT32 by calling
+ UDTFConfigurations.setOutputDataType(Type) in UDTF.beforeStart(UDFParameters, UDTFConfigurations).
+ """
+ pass
+
+ @abstractmethod
+ def put_long(self, timestamp: int, value: int):
+ """
+ Collects a long data point with timestamp.
+
+ Before calling this method, you need to ensure that the UDF output data type is set to Type.INT64 by calling
+ UDTFConfigurations.setOutputDataType(Type) in UDTF.beforeStart(UDFParameters, UDTFConfigurations).
+ """
+ pass
+
+ @abstractmethod
+ def put_float(self, timestamp: int, value: float):
+ """
+ Collects a float data point with timestamp.
+
+ Before calling this method, you need to ensure that the UDF output data type is set to Type.FLOAT by
+ calling UDTFConfigurations.setOutputDataType(Type) in UDTF.beforeStart(UDFParameters, UDTFConfigurations).
+ """
+ pass
+
+ @abstractmethod
+ def put_double(self, timestamp: int, value: float):
+ """
+ Collects a double data point with timestamp.
+
+ Before calling this method, you need to ensure that the UDF output data type is set to Type.DOUBLE by
+ calling UDTFConfigurations.setOutputDataType(Type) in UDTF.beforeStart(UDFParameters, UDTFConfigurations).
+ """
+ pass
+
+ @abstractmethod
+ def put_boolean(self, timestamp: int, value: bool):
+ """
+ Collects a boolean data point with timestamp.
+
+ Before calling this method, you need to ensure that the UDF output data type is set to Type.BOOLEAN by calling
+ UDTFConfigurations.setOutputDataType(Type) in UDTF.beforeStart(UDFParameters, UDTFConfigurations).
+ """
+ pass
+
+ @abstractmethod
+ def put_binary(self, timestamp: int, value: Binary):
+ """
+ Collects a Binary data point with timestamp.
+
+ Before calling this method, you need to ensure that the UDF output data type is set to Type.TEXT by calling
+ UDTFConfigurations.setOutputDataType(Type) in UDTF.beforeStart(UDFParameters, UDTFConfigurations).
+ """
+ pass
+
+ @abstractmethod
+ def put_string(self, timestamp: int, value: str):
+ """
+ Collects a String data point with timestamp.
+
+ Before calling this method, you need to ensure that the UDF output data type is set to Type.TEXT by calling
+ UDTFConfigurations.setOutputDataType(Type) in UDTF.beforeStart(UDFParameters, UDTFConfigurations).
+ """
+ pass
diff --git a/udf-py/udf_api/customizer/__init__.py b/udf-py/udf_api/customizer/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/customizer/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/customizer/config/__init__.py b/udf-py/udf_api/customizer/config/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/customizer/config/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/customizer/config/udf_configurations.py b/udf-py/udf_api/customizer/config/udf_configurations.py
new file mode 100644
index 0000000000..14f9a45d2a
--- /dev/null
+++ b/udf-py/udf_api/customizer/config/udf_configurations.py
@@ -0,0 +1,32 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from abc import ABCMeta
+
+from udf_api.exception.udf_exception import UDFException
+from udf_api.type.type import Type
+
+
+class UDFConfigurations(metaclass=ABCMeta):
+ _output_data_type: Type
+
+ def get_output_data_type(self):
+ return self._output_data_type
+
+ def check(self):
+ if self._output_data_type is None:
+ raise UDFException("UDF output_data_type is not set.")
diff --git a/udf-py/udf_api/customizer/config/udtf_configurations.py b/udf-py/udf_api/customizer/config/udtf_configurations.py
new file mode 100644
index 0000000000..99881bc26b
--- /dev/null
+++ b/udf-py/udf_api/customizer/config/udtf_configurations.py
@@ -0,0 +1,64 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.customizer.config.udf_configurations import UDFConfigurations
+from udf_api.customizer.strategy.access_strategy import AccessStrategy
+from udf_api.exception.udf_exception import UDFException
+from udf_api.type.type import Type
+
+
+class UDTFConfigurations(UDFConfigurations):
+ """
+ Used in UDTF#beforeStart(UDFParameters, UDTFConfigurations).
+ Supports calling methods in a chain.
+ """
+
+ __access_strategy: AccessStrategy
+
+ def set_access_strategy(self, access_strategy: AccessStrategy):
+ """
+ Used to specify the strategy for accessing raw query data in UDTF.
+
+ :param access_strategy: the specified access strategy. it should be an instance of AccessStrategy.
+ :return: self
+ """
+ self.__access_strategy = access_strategy
+ return self
+
+ def get_access_strategy(self) -> AccessStrategy:
+ return self.__access_strategy
+
+ def set_output_data_type(self, output_data_type: Type):
+ """
+ Used to specify the output data type of the UDTF.
+
+ In other words, the data type you set here determines the type of data that the PointCollector in
+ UDTF#transform(Row, PointCollector), UDTF#transform(RowWindow, PointCollector) or UDTF#terminate(PointCollector)
+ can receive.
+
+ :param output_data_type: the output data type of the UDTF
+ :return: self
+ """
+ self._output_data_type = output_data_type
+ return self
+
+ def check(self):
+ super().check()
+
+ if self.__access_strategy is None:
+ raise UDFException("Access strategy is not set.")
+ self.__access_strategy.check()
diff --git a/udf-py/udf_api/customizer/parameter/__init__.py b/udf-py/udf_api/customizer/parameter/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/customizer/parameter/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/customizer/parameter/udf_parameter_validator.py b/udf-py/udf_api/customizer/parameter/udf_parameter_validator.py
new file mode 100644
index 0000000000..0194b60765
--- /dev/null
+++ b/udf-py/udf_api/customizer/parameter/udf_parameter_validator.py
@@ -0,0 +1,136 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from typing import List
+
+from udf_api.customizer.parameter.udf_parameters import UDFParameters
+from udf_api.exception.udf_attribute_not_provided_exception import (
+ UDFAttributeNotProvidedException,
+)
+from udf_api.exception.udf_input_series_data_type_not_valid_exception import (
+ UDFInputSeriesDataTypeNotValidException,
+)
+from udf_api.exception.udf_input_series_index_not_valid_exception import (
+ UDFInputSeriesIndexNotValidException,
+)
+from udf_api.exception.udf_input_series_number_not_valid_exception import (
+ UDFInputSeriesNumberNotValidException,
+)
+from udf_api.exception.udf_parameter_not_valid_exception import (
+ UDFParameterNotValidException,
+)
+from udf_api.type.type import Type
+
+
+class UDFParameterValidator:
+ __parameters: UDFParameters
+
+ def __init__(self, parameters: UDFParameters):
+ self.__parameters = parameters
+
+ def get_parameters(self) -> UDFParameters:
+ return self.__parameters
+
+ def validate_required_attribute(self, attribute_key: str):
+ """
+ Validates whether the attributes entered by the user contain an attribute whose key is
+ attributeKey.
+
+ :param attribute_key: key of the attribute
+ :raise UDFAttributeNotProvidedException: if the attribute is not provided
+ """
+ if not self.__parameters.has_attribute(attribute_key):
+ raise UDFAttributeNotProvidedException(attribute_key)
+
+ return self
+
+ def validate_input_series_data_type(
+ self, index: int, expected_data_types: List[Type]
+ ):
+ """
+ Validates whether the data type of the input series at the specified column is as expected.
+
+ :param index: index of the specified column
+ :param expected_data_types: the expected data types
+ :raise UDFInputSeriesIndexNotValidException: if the index of the specified column is out of bound
+ :raise UDFInputSeriesDataTypeNotValidException: if the data type of the input series at the specified column is
+ not as expected
+ """
+ self.validate_input_series_index(index)
+
+ actual_data_type = self.__parameters.get_child_expression_data_types()[index]
+
+ for expected_data_type in expected_data_types:
+ if expected_data_type == actual_data_type:
+ return self
+
+ raise UDFInputSeriesDataTypeNotValidException(
+ index, actual_data_type, expected_data_types
+ )
+
+ def validate_input_series_number(
+ self,
+ expected_series_number_lower_bound: int,
+ expected_series_number_upper_bound,
+ ):
+ """
+ Validates whether the number of the input series is as expected.
+
+ :param expected_series_number_lower_bound: the number of the input series must be greater than or equal to the
+ expected_series_number_lower_bound
+ :param expected_series_number_upper_bound: the number of the input series must be less than or equal to the
+ expected_series_number_upper_bound
+ :raise UDFInputSeriesNumberNotValidException: if the number of the input series is not as expected
+ """
+ actual_series_number = self.__parameters.get_child_expressions_count()
+ if (
+ actual_series_number < expected_series_number_lower_bound
+ or expected_series_number_upper_bound < actual_series_number
+ ):
+ raise UDFInputSeriesNumberNotValidException(
+ actual_series_number,
+ expected_series_number_lower_bound,
+ expected_series_number_upper_bound,
+ )
+
+ return self
+
+ def validate(self, message_to_raise: str, validation_rule, **kwargs):
+ """
+ Validates the input parameters according to the validation rule given by the user.
+
+ :param message_to_raise: the message to throw when the given arguments are not valid
+ :param validation_rule: the validation rule, which can be a lambda expression
+ :param kwargs: the given arguments
+ :raise UDFParameterNotValidException: if the given arguments are not valid
+ """
+ if not validation_rule(kwargs):
+ raise UDFParameterNotValidException(message_to_raise)
+
+ return self
+
+ def validate_input_series_index(self, index: int):
+ """
+ Validates whether the index of the specified column is out of bound. bound: [0,
+ self.__parameters.get_child_expressions_count())
+
+ :param index: the index of the specified column
+ :raise UDFInputSeriesIndexNotValidException: if the index of the specified column is out of bound
+ """
+ actual_series_number = self.__parameters.get_child_expressions_count()
+ if index < 0 or actual_series_number <= index:
+ raise UDFInputSeriesIndexNotValidException(index, actual_series_number)
diff --git a/udf-py/udf_api/customizer/parameter/udf_parameters.py b/udf-py/udf_api/customizer/parameter/udf_parameters.py
new file mode 100644
index 0000000000..90fc64c05b
--- /dev/null
+++ b/udf-py/udf_api/customizer/parameter/udf_parameters.py
@@ -0,0 +1,71 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from typing import Dict, List
+
+from udf_api.type.type import Type
+
+
+# Used in UDTF#beforeStart(UDFParameters, UDTFConfigurations).
+# This class is used to parse the parameters in the UDF entered by the user.
+# The input parameters of UDF have two parts. The first part is the paths (measurements) of the time series that the UDF
+# needs to process, and the second part is the key-value pair attributes for customization. Only the second part can be
+# empty.
+# Note that the user must enter the paths (measurements) part before entering the attributes part.
+class UDFParameters:
+ __child_expressions: List[str]
+ __child_expression_data_types: List[Type]
+ __child_expressions_count: int
+ __attributes: Dict[str, str]
+
+ def __init__(
+ self,
+ child_expressions: List[str],
+ child_expression_data_types: List[Type],
+ attributes: Dict[str, str],
+ ):
+ self.__child_expressions = child_expressions
+ self.__child_expression_data_types = child_expression_data_types
+ self.__child_expressions_count = len(child_expressions)
+ self.__attributes = attributes
+
+ def get_child_expressions(self) -> List[str]:
+ return self.__child_expressions
+
+ def get_child_expression_data_types(self) -> List[Type]:
+ return self.__child_expression_data_types
+
+ def get_attributes(self) -> Dict[str, str]:
+ return self.__attributes
+
+ def get_child_expressions_count(self) -> int:
+ return self.__child_expressions_count
+
+ def has_attribute(self, key: str) -> bool:
+ return key in self.__attributes
+
+ def get_string(self, key: str, default: str = None) -> str:
+ string_value = self.__attributes[key]
+ return default if string_value is None else string_value
+
+ def get_int(self, key: str, default: int = None) -> int:
+ string_value = self.get_string(key)
+ return default if string_value is None else int(string_value)
+
+ def get_float(self, key: str, default: float = None) -> float:
+ string_value = self.get_string(key)
+ return default if string_value is None else float(string_value)
diff --git a/udf-py/udf_api/customizer/strategy/__init__.py b/udf-py/udf_api/customizer/strategy/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/customizer/strategy/access_strategy.py b/udf-py/udf_api/customizer/strategy/access_strategy.py
new file mode 100644
index 0000000000..007aba9ce8
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/access_strategy.py
@@ -0,0 +1,45 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from abc import ABCMeta, abstractmethod
+
+from udf_api.customizer.strategy.access_strategy_type import AccessStrategyType
+
+
+class AccessStrategy(metaclass=ABCMeta):
+ """
+ Used to customize the strategy for accessing raw data in UDTF#beforeStart(UDFParameters,
+ UDTFConfigurations)}.
+ """
+
+ @abstractmethod
+ def check(self):
+ """
+ Used by the system to check the access strategy.
+
+ :raise UDFException: if invalid strategy is set
+ """
+ pass
+
+ @abstractmethod
+ def get_access_strategy_type(self) -> AccessStrategyType:
+ """
+ Returns the actual access strategy type.
+
+ :return AccessStrategyType: the actual access strategy type
+ """
+ pass
diff --git a/udf-py/udf_api/customizer/strategy/access_strategy_type.py b/udf-py/udf_api/customizer/strategy/access_strategy_type.py
new file mode 100644
index 0000000000..23dbfdad7c
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/access_strategy_type.py
@@ -0,0 +1,38 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from enum import Enum
+
+
+class AccessStrategyType(Enum):
+ # MappableRowByRowAccessStrategy
+ MAPPABLE_ROW_BY_ROW = 0
+
+ # RowByRowAccessStrategy
+ ROW_BY_ROW = 1
+
+ # SlidingTimeWindowAccessStrategy
+ SLIDING_TIME_WINDOW = 2
+
+ # SlidingSizeWindowAccessStrategy
+ SLIDING_SIZE_WINDOW = 3
+
+ # SessionTimeWindowAccessStrategy
+ SESSION_TIME_WINDOW = 4
+
+ # StateWindowAccessStrategy
+ STATE_WINDOW = 5
diff --git a/udf-py/udf_api/customizer/strategy/mappable_row_by_row_access_strategy.py b/udf-py/udf_api/customizer/strategy/mappable_row_by_row_access_strategy.py
new file mode 100644
index 0000000000..eb2e92fc90
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/mappable_row_by_row_access_strategy.py
@@ -0,0 +1,40 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.customizer.strategy.access_strategy import AccessStrategy
+from udf_api.customizer.strategy.access_strategy_type import AccessStrategyType
+
+
+class MappableRowByRowAccessStrategy(AccessStrategy):
+ """
+ Used in UDTF#beforeStart(UDFParameters, UDTFConfigurations).
+
+ When the access strategy of a UDTF is set to an instance of this class, the method UDTF#transform(Row) of the UDTF
+ will be called to transform the original data. You need to override the method in your own UDTF class.
+
+ Each call of the method UDTF#transform(Row) processes only one row (aligned by time) of the original data and can
+ generate any number of data points.
+ """
+
+ def check(self):
+ """
+ nothing needs to check
+ """
+ pass
+
+ def get_access_strategy_type(self) -> AccessStrategyType:
+ return AccessStrategyType.MAPPABLE_ROW_BY_ROW
diff --git a/udf-py/udf_api/customizer/strategy/row_by_row_access_strategy.py b/udf-py/udf_api/customizer/strategy/row_by_row_access_strategy.py
new file mode 100644
index 0000000000..39a272a276
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/row_by_row_access_strategy.py
@@ -0,0 +1,40 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.customizer.strategy.access_strategy import AccessStrategy
+from udf_api.customizer.strategy.access_strategy_type import AccessStrategyType
+
+
+class RowByRowAccessStrategy(AccessStrategy):
+ """
+ Used in UDTF#beforeStart(UDFParameters, UDTFConfigurations).
+
+ When the access strategy of a UDTF is set to an instance of this class, the method UDTF#transform(Row) of the UDTF
+ will be called to transform the original data. You need to override the method in your own UDTF class.
+
+ Each call of the method UDTF#transform(Row) processes only one row (aligned by time) of the original data and can
+ generate any number of data points.
+ """
+
+ def check(self):
+ """
+ nothing needs to check
+ """
+ pass
+
+ def get_access_strategy_type(self) -> AccessStrategyType:
+ return AccessStrategyType.ROW_BY_ROW
diff --git a/udf-py/udf_api/customizer/strategy/session_time_window_access_strategy.py b/udf-py/udf_api/customizer/strategy/session_time_window_access_strategy.py
new file mode 100644
index 0000000000..b9d2bb72b1
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/session_time_window_access_strategy.py
@@ -0,0 +1,77 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.customizer.strategy.access_strategy import AccessStrategy
+from udf_api.customizer.strategy.access_strategy_type import AccessStrategyType
+from udf_api.exception.udf_exception import UDFException
+
+
+class SessionTimeWindowAccessStrategy(AccessStrategy):
+ __session_time_gap: int
+ __display_window_begin: int
+ __display_window_end: int
+
+ def __init__(
+ self,
+ session_time_gap: int,
+ display_window_begin: int = -9223372036854775808,
+ display_window_end: int = 9223372036854775807,
+ ):
+ self.__session_time_gap = session_time_gap
+ self.__display_window_begin = display_window_begin
+ self.__display_window_end = display_window_end
+
+ def check(self):
+ if self.__session_time_gap < 0:
+ raise UDFException(
+ "Parameter session_time_gap({}) should be equal to or greater than zero.".format(
+ self.__session_time_gap
+ )
+ )
+
+ if self.__display_window_begin < -9223372036854775808:
+ raise UDFException(
+ "Parameter display_window_begin({}) should be equal to or greater than -9223372036854775808.".format(
+ self.__display_window_begin
+ )
+ )
+
+ if 9223372036854775807 < self.__display_window_end:
+ raise UDFException(
+ "Parameter display_window_end({}) should be equal to or less than 9223372036854775807.".format(
+ self.__display_window_end
+ )
+ )
+
+ if self.__display_window_end < self.__display_window_begin:
+ raise UDFException(
+ "display_window_end({}) < display_window_begin({})".format(
+ self.__display_window_end, self.__display_window_begin
+ )
+ )
+
+ def get_access_strategy_type(self) -> AccessStrategyType:
+ return AccessStrategyType.SESSION_TIME_WINDOW
+
+ def get_session_time_gap(self) -> int:
+ return self.__session_time_gap
+
+ def get_display_window_begin(self) -> int:
+ return self.__display_window_begin
+
+ def get_display_window_end(self) -> int:
+ return self.__display_window_end
diff --git a/udf-py/udf_api/customizer/strategy/sliding_size_window_access_strategy.py b/udf-py/udf_api/customizer/strategy/sliding_size_window_access_strategy.py
new file mode 100644
index 0000000000..4f992847e9
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/sliding_size_window_access_strategy.py
@@ -0,0 +1,98 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.customizer.strategy.access_strategy import AccessStrategy
+from udf_api.customizer.strategy.access_strategy_type import AccessStrategyType
+from udf_api.exception.udf_exception import UDFException
+
+
+class SlidingSizeWindowAccessStrategy(AccessStrategy):
+ """
+ Used in UDTF#beforeStart(UDFParameters, UDTFConfigurations).
+
+ When the access strategy of a UDTF is set to an instance of this class, the method UDTF#transform(RowWindow,
+ PointCollector) of the UDTF will be called to transform the original data. You need to override the method in your
+ own UDTF class.
+
+ Sliding size window is a kind of size-based window. Except for the last call, each call of the method
+ UDTF#transform(RowWindow, PointCollector) processes a window with windowSize rows (aligned by time) of the original
+ data and can generate any number of data points.
+ """
+
+ __window_size: int
+ __sliding_step: int
+
+ def __init__(self, window_size: int, sliding_step: int):
+ """
+ Constructor. You need to specify the number of rows in each sliding size window (except for the last window) and
+ the sliding step to the next window.
+
+ Example
+ Original data points (time, s1, s2):
+ (1, 100, null )
+ (2, 100, null )
+ (3, 100, null )
+ (4, 100, 'error')
+ (5, 100, null )
+ (6, 101, 'error')
+ (7, 102, 'error')
+
+ Set windowSize to 2 and set slidingStep to 3, windows will be generated as below: Window 0: [(1, 100, null ),
+ (2, 100, null)] Window 1: [(4, 100, 'error'), (5, 100, null)] Window 2: [(7, 102, 'error')]
+
+ :param window_size: the number of rows in each sliding size window (0 < window_size)
+ :param sliding_step: the number of rows between the first point of the next window and the first point of the
+ current window (0 < sliding_step)
+ """
+ self.__window_size = window_size
+ self.__sliding_step = sliding_step
+
+ def check(self):
+ if self.__window_size <= 0:
+ raise UDFException(
+ "Parameter window_size({}) should be positive.".format(
+ self.__window_size
+ )
+ )
+ if 2147483647 < self.__window_size:
+ raise UDFException(
+ "Parameter window_size({}) should be less than or equals to 2147483647.".format(
+ self.__window_size
+ )
+ )
+
+ if self.__sliding_step <= 0:
+ raise UDFException(
+ "Parameter sliding_step({}) should be positive.".format(
+ self.__sliding_step
+ )
+ )
+ if 2147483647 < self.__sliding_step:
+ raise UDFException(
+ "Parameter sliding_step({}) should be less than or equals to 2147483647.".format(
+ self.__sliding_step
+ )
+ )
+
+ def get_access_strategy_type(self) -> AccessStrategyType:
+ return AccessStrategyType.SLIDING_SIZE_WINDOW
+
+ def get_window_size(self) -> int:
+ return self.__window_size
+
+ def get_sliding_step(self) -> int:
+ return self.__sliding_step
diff --git a/udf-py/udf_api/customizer/strategy/sliding_time_window_access_strategy.py b/udf-py/udf_api/customizer/strategy/sliding_time_window_access_strategy.py
new file mode 100644
index 0000000000..3aaaecc4b6
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/sliding_time_window_access_strategy.py
@@ -0,0 +1,127 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.customizer.strategy.access_strategy import AccessStrategy
+from udf_api.customizer.strategy.access_strategy_type import AccessStrategyType
+from udf_api.exception.udf_exception import UDFException
+
+
+class SlidingTimeWindowAccessStrategy(AccessStrategy):
+ """
+ Used in UDTF#beforeStart(UDFParameters, UDTFConfigurations).
+
+ When the access strategy of a UDTF is set to an instance of this class, the method UDTF#transform(RowWindow,
+ PointCollector) of the UDTF will be called to transform the original data. You need to override the method in your
+ own UDTF class.
+
+ Sliding time window is a kind of time-based window. To partition the raw query data set into sliding time windows,
+ you need to give the following 4 parameters:
+
+ * display window begin: determines the start time of the first window
+ * display window end: if the start time of current window + sliding step > display window end, then current window
+ is the last window that your UDTF can process
+ * time interval: determines the time range of a window
+ * sliding step: the start time of the next window = the start time of current window + sliding step
+
+ Each call of the method UDTF.transform(RowWindow, PointCollector) processes one time window and can generate any
+ number of data points. Note that the transform method will still be called when there is no data point in a window.
+ Note that the time range of the last few windows may be less than the specified time interval.
+ """
+
+ __time_interval: int
+ __sliding_step: int
+ __display_window_begin: int
+ __display_window_end: int
+
+ def __init__(
+ self,
+ time_interval: int,
+ sliding_step: int,
+ display_window_begin: int,
+ display_window_end: int,
+ ):
+ """
+ :param time_interval: 0 < time_interval
+ :param sliding_step: 0 < sliding_step
+ :param display_window_begin: display_window_begin < display_window_end
+ :param display_window_end: display_window_begin < display_window_end
+ """
+ self.__time_interval = time_interval
+ self.__sliding_step = sliding_step
+ self.__display_window_begin = display_window_begin
+ self.__display_window_end = display_window_end
+
+ def check(self):
+ if self.__time_interval <= 0:
+ raise UDFException(
+ "Parameter time_interval({}) should be positive.".format(
+ self.__time_interval
+ )
+ )
+ if 9223372036854775807 < self.__time_interval:
+ raise UDFException(
+ "Parameter window_size({}) should be less than or equals to 9223372036854775807.".format(
+ self.__time_interval
+ )
+ )
+
+ if self.__sliding_step <= 0:
+ raise UDFException(
+ "Parameter sliding_step({}) should be positive.".format(
+ self.__sliding_step
+ )
+ )
+ if 9223372036854775807 < self.__sliding_step:
+ raise UDFException(
+ "Parameter sliding_step({}) should be less than or equals to 9223372036854775807.".format(
+ self.__sliding_step
+ )
+ )
+
+ if self.__display_window_begin < -9223372036854775808:
+ raise UDFException(
+ "Parameter display_window_begin({}) should be equal to or greater than -9223372036854775808.".format(
+ self.__display_window_begin
+ )
+ )
+ if 9223372036854775807 < self.__display_window_end:
+ raise UDFException(
+ "Parameter display_window_end({}) should be less than or equals to 9223372036854775807.".format(
+ self.__display_window_end
+ )
+ )
+ if self.__display_window_end < self.__display_window_begin:
+ raise UDFException(
+ "Parameter display_window_end({}) < display_window_begin({})".format(
+ self.__display_window_end, self.__display_window_begin
+ )
+ )
+
+ def get_access_strategy_type(self) -> AccessStrategyType:
+ return AccessStrategyType.SLIDING_TIME_WINDOW
+
+ def get_time_interval(self) -> int:
+ return self.__time_interval
+
+ def get_sliding_step(self) -> int:
+ return self.__sliding_step
+
+ def get_display_window_begin(self) -> int:
+ return self.__display_window_begin
+
+ def get_display_window_end(self) -> int:
+ return self.__display_window_end
diff --git a/udf-py/udf_api/customizer/strategy/state_window_access_strategy.py b/udf-py/udf_api/customizer/strategy/state_window_access_strategy.py
new file mode 100644
index 0000000000..fb6d35b142
--- /dev/null
+++ b/udf-py/udf_api/customizer/strategy/state_window_access_strategy.py
@@ -0,0 +1,77 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.customizer.strategy.access_strategy import AccessStrategy
+from udf_api.customizer.strategy.access_strategy_type import AccessStrategyType
+from udf_api.exception.udf_exception import UDFException
+
+
+class StateWindowAccessStrategy(AccessStrategy):
+ __delta: float = 0
+ __display_window_begin: int = -9223372036854775808
+ __display_window_end: int = 9223372036854775807
+
+ def __init__(
+ self,
+ delta: float = 0,
+ display_window_begin: int = -9223372036854775808,
+ display_window_end: int = 9223372036854775807,
+ ):
+ self.__delta = delta
+ self.__display_window_begin = display_window_begin
+ self.__display_window_end = display_window_end
+
+ def check(self):
+ if self.__delta < 0:
+ raise UDFException(
+ "Parameter delta({}) should be equal to or greater than zero.".format(
+ self.__delta
+ )
+ )
+
+ if self.__display_window_begin < -9223372036854775808:
+ raise UDFException(
+ "Parameter display_window_begin({}) should be equal to or greater than -9223372036854775808.".format(
+ self.__display_window_begin
+ )
+ )
+
+ if 9223372036854775807 < self.__display_window_end:
+ raise UDFException(
+ "Parameter display_window_end({}) should be equal to or less than 9223372036854775807.".format(
+ self.__display_window_end
+ )
+ )
+
+ if self.__display_window_end < self.__display_window_begin:
+ raise UDFException(
+ "display_window_end({}) < display_window_begin({})".format(
+ self.__display_window_end, self.__display_window_begin
+ )
+ )
+
+ def get_access_strategy_type(self) -> AccessStrategyType:
+ return AccessStrategyType.STATE_WINDOW
+
+ def get_delta(self) -> float:
+ return self.__delta
+
+ def get_display_window_begin(self) -> int:
+ return self.__display_window_begin
+
+ def get_display_window_end(self) -> int:
+ return self.__display_window_end
diff --git a/udf-py/udf_api/exception/__init__.py b/udf-py/udf_api/exception/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/exception/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/exception/udf_attribute_not_provided_exception.py b/udf-py/udf_api/exception/udf_attribute_not_provided_exception.py
new file mode 100644
index 0000000000..7ffc44c181
--- /dev/null
+++ b/udf-py/udf_api/exception/udf_attribute_not_provided_exception.py
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.exception.udf_parameter_not_valid_exception import (
+ UDFParameterNotValidException,
+)
+
+
+class UDFAttributeNotProvidedException(UDFParameterNotValidException):
+ def __init__(self, required_attribute: str):
+ super().__init__(
+ "attribute {} is required but was not provided.".format(required_attribute)
+ )
diff --git a/udf-py/udf_api/exception/udf_exception.py b/udf-py/udf_api/exception/udf_exception.py
new file mode 100644
index 0000000000..50b95bae24
--- /dev/null
+++ b/udf-py/udf_api/exception/udf_exception.py
@@ -0,0 +1,36 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+class UDFException(Exception):
+ __message: str
+ __cause: Exception = None
+
+ def __init__(self, message: str, cause: Exception = None):
+ self.__message = message
+ self.__cause = cause
+
+ def get_message(self):
+ return self.__message
+
+ def get_cause(self):
+ return self.__cause
+
+ def __str__(self):
+ return "UDF exception occurred: {}, caused by: {}".format(
+ self.__message, str(self.__cause.__class__)
+ )
diff --git a/udf-py/udf_api/exception/udf_input_series_data_type_not_valid_exception.py b/udf-py/udf_api/exception/udf_input_series_data_type_not_valid_exception.py
new file mode 100644
index 0000000000..d7c4bbea1a
--- /dev/null
+++ b/udf-py/udf_api/exception/udf_input_series_data_type_not_valid_exception.py
@@ -0,0 +1,32 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from typing import List
+
+from udf_api.exception.udf_parameter_not_valid_exception import (
+ UDFParameterNotValidException,
+)
+from udf_api.type.type import Type
+
+
+class UDFInputSeriesDataTypeNotValidException(UDFParameterNotValidException):
+ def __init__(self, index: int, actual: Type, expected: List[Type]):
+ super(
+ "the data type of the input series (index: {}) is not valid. expected: {}. actual: {}.".format(
+ index, expected, actual
+ )
+ )
diff --git a/udf-py/udf_api/exception/udf_input_series_index_not_valid_exception.py b/udf-py/udf_api/exception/udf_input_series_index_not_valid_exception.py
new file mode 100644
index 0000000000..8fe059ca82
--- /dev/null
+++ b/udf-py/udf_api/exception/udf_input_series_index_not_valid_exception.py
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.exception.udf_parameter_not_valid_exception import (
+ UDFParameterNotValidException,
+)
+
+
+class UDFInputSeriesIndexNotValidException(UDFParameterNotValidException):
+ def __init__(self, provided_index: int, valid_index_upper_bound: int):
+ super().__init__(
+ "the index ({}) of the input series is not valid. valid index range: [0, {}).".format(
+ provided_index, valid_index_upper_bound
+ )
+ )
diff --git a/udf-py/udf_api/exception/udf_input_series_number_not_valid_exception.py b/udf-py/udf_api/exception/udf_input_series_number_not_valid_exception.py
new file mode 100644
index 0000000000..25287fde64
--- /dev/null
+++ b/udf-py/udf_api/exception/udf_input_series_number_not_valid_exception.py
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.exception.udf_parameter_not_valid_exception import (
+ UDFParameterNotValidException,
+)
+
+
+class UDFInputSeriesNumberNotValidException(UDFParameterNotValidException):
+ def __init__(
+ self, actual: int, expected_lower_bound: int, expected_upper_bound: int
+ ):
+ super().__init__(
+ "the number of the input series is not valid. expected: [{}, {}]. actual: {}.".format(
+ expected_lower_bound, expected_upper_bound, actual
+ )
+ if expected_lower_bound != expected_upper_bound
+ else "the number of the input series is not valid. expected: {}. actual: {}.".format(
+ expected_lower_bound, actual
+ )
+ )
diff --git a/udf-py/udf_api/exception/udf_management_exception.py b/udf-py/udf_api/exception/udf_management_exception.py
new file mode 100644
index 0000000000..cc3165a617
--- /dev/null
+++ b/udf-py/udf_api/exception/udf_management_exception.py
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.exception.udf_exception import UDFException
+
+
+class UDFManagementException(UDFException):
+ def __init__(self, message: str, cause: Exception = None):
+ super().__init__(message, cause)
diff --git a/udf-py/udf_api/exception/udf_output_series_data_type_not_valid_exception.py b/udf-py/udf_api/exception/udf_output_series_data_type_not_valid_exception.py
new file mode 100644
index 0000000000..c2ef7146a9
--- /dev/null
+++ b/udf-py/udf_api/exception/udf_output_series_data_type_not_valid_exception.py
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.exception.udf_parameter_not_valid_exception import (
+ UDFParameterNotValidException,
+)
+
+
+class UDFOutputSeriesDataTypeNotValidException(UDFParameterNotValidException):
+ def __init__(self, index: int, types: str):
+ super().__init__(
+ "the data type of the output series (index: {}) is not valid. expected: {}.".format(
+ index, types
+ )
+ )
diff --git a/udf-py/udf_api/exception/udf_parameter_not_valid_exception.py b/udf-py/udf_api/exception/udf_parameter_not_valid_exception.py
new file mode 100644
index 0000000000..69279acf90
--- /dev/null
+++ b/udf-py/udf_api/exception/udf_parameter_not_valid_exception.py
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from udf_api.exception.udf_exception import UDFException
+
+
+class UDFParameterNotValidException(UDFException):
+ def __init__(self, message: str):
+ super().__init__(message)
diff --git a/udf-py/udf_api/type/__init__.py b/udf-py/udf_api/type/__init__.py
new file mode 100644
index 0000000000..b74423fa90
--- /dev/null
+++ b/udf-py/udf_api/type/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/udf-py/udf_api/type/binary.py b/udf-py/udf_api/type/binary.py
new file mode 100644
index 0000000000..75a02d3c7b
--- /dev/null
+++ b/udf-py/udf_api/type/binary.py
@@ -0,0 +1,77 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+class Binary:
+ __values: bytes = None
+ __string_cache: str = None
+
+ @staticmethod
+ def value_of(s: str, encoding="utf-8"):
+ instance = Binary(bytes(s, encoding))
+ instance.__string_cache = s
+ return instance
+
+ def __init__(self, values: bytes = None):
+ self.__values = values
+
+ def is_null(self) -> bool:
+ return self.__values is None
+
+ def get_values(self) -> bytes:
+ return self.__values
+
+ def get_string_value(self, encoding: str = "utf-8"):
+ if self.__values is None:
+ return None
+
+ if self.__string_cache is None:
+ self.__string_cache = str(self.__values, encoding)
+ return self.__string_cache
+
+ # Get length of values. Returns -1 if values is null.
+ def __len__(self):
+ return -1 if self.__values is None else len(self.__values)
+
+ def __hash__(self):
+ return 0 if self.__values is None else self.__values.__hash__()
+
+ def __eq__(self, other):
+ return self.__values == other.__value
+
+ def __cmp__(self, other):
+ if other is None:
+ if self.__values is None:
+ return 0
+ else:
+ return 1
+
+ index = 1
+ self_length = len(self)
+ other_length = len(other)
+
+ while index < self_length and index < other_length:
+ if self.__values[index] == other.__values[index]:
+ index += 1
+ continue
+ else:
+ return self.__values[index] - other.__values[index]
+
+ return self_length - other_length
+
+ def __str__(self):
+ return self.get_string_value()
diff --git a/udf-py/udf_api/type/type.py b/udf-py/udf_api/type/type.py
new file mode 100644
index 0000000000..39fe202ea1
--- /dev/null
+++ b/udf-py/udf_api/type/type.py
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from enum import Enum
+
+
+class Type(Enum):
+ BOOLEAN = 0
+ INT32 = 1
+ INT64 = 2
+ FLOAT = 3
+ DOUBLE = 4
+ TEXT = 5
diff --git a/udf-py/udf_api/udf.py b/udf-py/udf_api/udf.py
new file mode 100644
index 0000000000..22bbaa1e25
--- /dev/null
+++ b/udf-py/udf_api/udf.py
@@ -0,0 +1,37 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from abc import ABCMeta
+
+from udf_api.customizer.parameter.udf_parameter_validator import UDFParameterValidator
+
+
+class UDF(metaclass=ABCMeta):
+ def validate(self, validator: UDFParameterValidator):
+ """
+ This method is mainly used to validate UDFParameters and it is executed before UDTF.beforeStart(UDFParameters,
+ UDTFConfigurations) is called.
+
+ :param validator: the validator used to validate UDFParameters
+ """
+ pass
+
+ def before_destroy(self):
+ """
+ This method is mainly used to release the resources used in the UDF.
+ """
+ pass
diff --git a/udf-py/udf_api/udtf.py b/udf-py/udf_api/udtf.py
new file mode 100644
index 0000000000..c4684660b8
--- /dev/null
+++ b/udf-py/udf_api/udtf.py
@@ -0,0 +1,104 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from abc import abstractmethod
+
+from udf_api.access.row import Row
+from udf_api.access.row_window import RowWindow
+from udf_api.collector.point_collector import PointCollector
+from udf_api.customizer.config.udtf_configurations import UDTFConfigurations
+from udf_api.customizer.parameter.udf_parameters import UDFParameters
+from udf_api.udf import UDF
+
+
+class UDTF(UDF):
+ """
+ User-defined Time-series Generating Function (UDTF)
+
+ New UDTF classes need to inherit from this UDTF class.
+
+ Generates a variable number of output data points for a single input row or a single input window (time-based or
+ size-based).
+
+ A complete UDTF needs to override at least the following methods:
+ * beforeStart(UDFParameters, UDTFConfigurations)
+ * transform(RowWindow, PointCollector) or transform(Row, PointCollector)
+
+ In the life cycle of a UDTF instance, the calling sequence of each method is as follows:
+ 1. validate(UDFParameterValidator)
+ 2. beforeStart(UDFParameters, UDTFConfigurations)
+ 3. transform(RowWindow, PointCollector) or transform(Row, PointCollector)
+ 4. terminate(PointCollector) 5. beforeDestroy()
+
+ The query engine will instantiate an independent UDTF instance for each udf query column, and different UDTF
+ instances will not affect each other.
+ """
+
+ @abstractmethod
+ def before_start(
+ self, parameters: UDFParameters, configurations: UDTFConfigurations
+ ):
+ """
+ This method is mainly used to customize UDTF. In this method, the user can do the following things:
+ * Use UDFParameters to get the time series paths and parse key-value pair attributes entered by the user.
+ * Set the strategy to access the original data and set the output data type in UDTFConfigurations.
+ * Create resources, such as establishing external connections, opening files, etc.
+
+ This method is called after the UDTF is instantiated and before the beginning of the transformation process.
+
+ :param parameters: used to parse the input parameters entered by the user
+ :param configurations: used to set the required properties in the UDTF
+ """
+ pass
+
+ def transform_row(self, row: Row, collector: PointCollector):
+ """
+ When the user specifies RowByRowAccessStrategy to access the original data in UDTFConfigurations, this method
+ will be called to process the transformation. In a single UDF query, this method may be called multiple times.
+
+ :param row: original input data row (aligned by time)
+ :param collector: used to collect output data points
+ """
+ pass
+
+ def transform_window(self, row_window: RowWindow, collector: PointCollector):
+ """
+ When the user specifies SlidingSizeWindowAccessStrategy or SlidingTimeWindowAccessStrategy to access the
+ original data in UDTFConfigurations, this method will be called to process the transformation. In a single UDF
+ query, this method may be called multiple times.
+
+ :param row_window: original input data window (rows inside the window are aligned by time)
+ :param collector: used to collect output data points
+ """
+
+ def map_row(self, row: Row) -> object:
+ """
+ When the user specifies MappableRowByRowAccessStrategy to access the original data in UDTFConfigurations, this
+ method will be called to process the transformation. In a single UDF query, this method may be called multiple
+ times.
+
+ :param row: original input data row (aligned by time)
+ """
+ pass
+
+ def terminate(self, collector: PointCollector):
+ """
+ This method will be called once after all calls or { UDTF#transform(RowWindow, PointCollector) calls have been
+ executed. In a single UDF query, this method will and will only be called once.
+
+ :param collector: used to collect output data points
+ """
+ pass