chore: merge main
This commit is contained in:
commit
24882459e3
|
@ -1,19 +1,19 @@
|
||||||
name: TDengine CI Test
|
name: TDengine CI Test
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
# pull_request:
|
||||||
branches:
|
# branches:
|
||||||
- 'main'
|
# - 'main'
|
||||||
- '3.0'
|
# - '3.0'
|
||||||
- '3.1'
|
# - '3.1'
|
||||||
paths-ignore:
|
# paths-ignore:
|
||||||
- 'packaging/**'
|
# - 'packaging/**'
|
||||||
- 'docs/**'
|
# - 'docs/**'
|
||||||
repository_dispatch:
|
repository_dispatch:
|
||||||
types: [run-tests]
|
types: [run-tests]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.event.client_payload.ref}}-${{ github.event_name == 'repository_dispatch' && 'dispatch' || ''}}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
@ -65,7 +65,7 @@ jobs:
|
||||||
|
|
||||||
# check whether to run function test cases
|
# check whether to run function test cases
|
||||||
changed_files_non_tdgpt=$(git --no-pager diff --name-only FETCH_HEAD `git merge-base FETCH_HEAD $target_branch`|grep -v "^docs/en/"|grep -v "^docs/zh/"|grep -v ".md$" | grep -Ev "forecastoperator.c|anomalywindowoperator.c|tanalytics.h|tanalytics.c|tdgpt_cases.task|analytics" | tr '\n' ' ' ||:)
|
changed_files_non_tdgpt=$(git --no-pager diff --name-only FETCH_HEAD `git merge-base FETCH_HEAD $target_branch`|grep -v "^docs/en/"|grep -v "^docs/zh/"|grep -v ".md$" | grep -Ev "forecastoperator.c|anomalywindowoperator.c|tanalytics.h|tanalytics.c|tdgpt_cases.task|analytics" | tr '\n' ' ' ||:)
|
||||||
if [ $changed_files_non_tdgpt != '' ]; then
|
if [ "$changed_files_non_tdgpt" != '' ]; then
|
||||||
run_function_test="true"
|
run_function_test="true"
|
||||||
else
|
else
|
||||||
run_function_test="false"
|
run_function_test="false"
|
||||||
|
@ -88,7 +88,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
IS_TDINTERNAL: ${{ needs.fetch-parameters.outputs.tdinternal }}
|
IS_TDINTERNAL: ${{ needs.fetch-parameters.outputs.tdinternal }}
|
||||||
RUN_RUNCTION_TEST: ${{ needs.fetch-parameters.outputs.run_function_test }}
|
RUN_RUNCTION_TEST: ${{ needs.fetch-parameters.outputs.run_function_test }}
|
||||||
RUN_TDGPT_TEST: ${{ needs.fetch-parameters.outputs.run_tdgpt_tests }}
|
RUN_TDGPT_TEST: ${{ needs.fetch-parameters.outputs.run_tdgpt_test }}
|
||||||
SOURCE_BRANCH: ${{ needs.fetch-parameters.outputs.source_branch }}
|
SOURCE_BRANCH: ${{ needs.fetch-parameters.outputs.source_branch }}
|
||||||
TARGET_BRANCH: ${{ needs.fetch-parameters.outputs.target_branch }}
|
TARGET_BRANCH: ${{ needs.fetch-parameters.outputs.target_branch }}
|
||||||
PR_NUMBER: ${{ needs.fetch-parameters.outputs.pr_number }}
|
PR_NUMBER: ${{ needs.fetch-parameters.outputs.pr_number }}
|
||||||
|
@ -161,20 +161,23 @@ jobs:
|
||||||
cd ${{ env.WKC }}
|
cd ${{ env.WKC }}
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
- name: Output the 'file_no_doc_changed' information to the file
|
- name: Output the 'file_no_doc_changed' information to the file
|
||||||
if: ${{ env.IS_TDINTERNAL == 'false' }}
|
if: ${{ env.IS_TDINTERNAL == 'false' && env.TARGET_BRANCH != '3.1' }}
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ${{ env.WKDIR }}/tmp/${{ env.PR_NUMBER }}_${{ github.run_number }}
|
mkdir -p ${{ env.WKDIR }}/tmp/${{ env.PR_NUMBER }}_${{ github.run_number }}
|
||||||
changed_files_non_doc=$(git --no-pager diff --name-only FETCH_HEAD `git merge-base FETCH_HEAD ${{ env.TARGET_BRANCH }}`|grep -v "^docs/en/"|grep -v "^docs/zh/"|grep -v ".md$" | tr '\n' ' ' || :)
|
changed_files_non_doc=$(git --no-pager diff --name-only FETCH_HEAD `git merge-base FETCH_HEAD ${{ env.TARGET_BRANCH }}`|grep -v "^docs/en/"|grep -v "^docs/zh/"|grep -v ".md$" | tr '\n' ' ' || :)
|
||||||
echo $changed_files_non_doc > ${{ env.WKDIR }}/tmp/${{ env.PR_NUMBER }}_${{ github.run_number }}/docs_changed.txt
|
echo $changed_files_non_doc > ${{ env.WKDIR }}/tmp/${{ env.PR_NUMBER }}_${{ github.run_number }}/docs_changed.txt
|
||||||
- name: Check assert testing
|
- name: Check assert testing
|
||||||
|
if: ${{ env.IS_TDINTERNAL == 'false' && env.TARGET_BRANCH != '3.1' }}
|
||||||
run: |
|
run: |
|
||||||
cd ${{ env.WKC }}/tests/parallel_test
|
cd ${{ env.WKC }}/tests/parallel_test
|
||||||
./run_check_assert_container.sh -d ${{ env.WKDIR }}
|
./run_check_assert_container.sh -d ${{ env.WKDIR }}
|
||||||
- name: Check void function testing
|
- name: Check void function testing
|
||||||
|
if: ${{ env.IS_TDINTERNAL == 'false' && env.TARGET_BRANCH != '3.1' }}
|
||||||
run: |
|
run: |
|
||||||
cd ${{ env.WKC }}/tests/parallel_test
|
cd ${{ env.WKC }}/tests/parallel_test
|
||||||
./run_check_void_container.sh -d ${{ env.WKDIR }}
|
./run_check_void_container.sh -d ${{ env.WKDIR }}
|
||||||
- name: Build docker container
|
- name: Build docker container
|
||||||
|
if: ${{ env.RUN_RUNCTION_TEST == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
date
|
date
|
||||||
rm -rf ${{ env.WKC }}/debug
|
rm -rf ${{ env.WKC }}/debug
|
||||||
|
@ -204,18 +207,19 @@ jobs:
|
||||||
echo "timeout_cmd=$timeout_cmd" >> $GITHUB_OUTPUT
|
echo "timeout_cmd=$timeout_cmd" >> $GITHUB_OUTPUT
|
||||||
echo "extra_param=$extra_param" >> $GITHUB_OUTPUT
|
echo "extra_param=$extra_param" >> $GITHUB_OUTPUT
|
||||||
- name: Run function returns with a null pointer scan testing
|
- name: Run function returns with a null pointer scan testing
|
||||||
|
if: ${{ env.IS_TDINTERNAL == 'false' && env.TARGET_BRANCH != '3.1' }}
|
||||||
run: |
|
run: |
|
||||||
cd ${{ env.WKC }}/tests/parallel_test
|
cd ${{ env.WKC }}/tests/parallel_test
|
||||||
./run_scan_container.sh -d ${{ env.WKDIR }} -b ${{ env.PR_NUMBER }}_${{ github.run_number }} -f ${{ env.WKDIR }}/tmp/${{ env.PR_NUMBER }}_${{ github.run_number }}/docs_changed.txt ${{ steps.get_param.outputs.extra_param }}
|
./run_scan_container.sh -d ${{ env.WKDIR }} -b ${{ env.PR_NUMBER }}_${{ github.run_number }} -f ${{ env.WKDIR }}/tmp/${{ env.PR_NUMBER }}_${{ github.run_number }}/docs_changed.txt ${{ steps.get_param.outputs.extra_param }}
|
||||||
- name: Run tdgpt test cases
|
- name: Run tdgpt test cases
|
||||||
if: ${{ env.IS_TDINTERNAL }} == 'false' && ${{ env.RUN_TDGPT_TEST }} == 'true'
|
if: ${{ env.IS_TDINTERNAL == 'false' && env.TARGET_BRANCH != '3.1' && env.RUN_TDGPT_TEST == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
cd ${{ env.WKC }}/tests/parallel_test
|
cd ${{ env.WKC }}/tests/parallel_test
|
||||||
export DEFAULT_RETRY_TIME=2
|
export DEFAULT_RETRY_TIME=2
|
||||||
date
|
date
|
||||||
timeout 600 time ./run.sh -e -m /home/m.json -t tdgpt_cases.task -b ${{ env.PR_NUMBER }}_${{ github.run_number }} -l ${{ env.WKDIR }}/log -o 300 ${{ steps.get_param.outputs.extra_param }}
|
timeout 600 time ./run.sh -e -m /home/m.json -t tdgpt_cases.task -b ${{ env.PR_NUMBER }}_${{ github.run_number }} -l ${{ env.WKDIR }}/log -o 300 ${{ steps.get_param.outputs.extra_param }}
|
||||||
- name: Run function test cases
|
- name: Run function test cases
|
||||||
if: ${{ env.RUN_RUNCTION_TEST }} == 'true'
|
if: ${{ env.RUN_RUNCTION_TEST == 'true'}}
|
||||||
run: |
|
run: |
|
||||||
cd ${{ env.WKC }}/tests/parallel_test
|
cd ${{ env.WKC }}/tests/parallel_test
|
||||||
export DEFAULT_RETRY_TIME=2
|
export DEFAULT_RETRY_TIME=2
|
||||||
|
@ -224,7 +228,7 @@ jobs:
|
||||||
|
|
||||||
run-tests-on-mac:
|
run-tests-on-mac:
|
||||||
needs: fetch-parameters
|
needs: fetch-parameters
|
||||||
if: ${{ needs.fetch-parameters.outputs.run_function_test == 'false' }}
|
if: ${{ needs.fetch-parameters.outputs.run_function_test == 'true' }}
|
||||||
runs-on:
|
runs-on:
|
||||||
group: CI
|
group: CI
|
||||||
labels: [self-hosted, macOS, ARM64, testing]
|
labels: [self-hosted, macOS, ARM64, testing]
|
||||||
|
@ -313,3 +317,141 @@ jobs:
|
||||||
make -j10
|
make -j10
|
||||||
ctest -j10 || exit 7
|
ctest -j10 || exit 7
|
||||||
date
|
date
|
||||||
|
|
||||||
|
run-tests-on-windows:
|
||||||
|
needs: fetch-parameters
|
||||||
|
if: ${{ needs.fetch-parameters.outputs.run_function_test == 'true' }}
|
||||||
|
runs-on:
|
||||||
|
group: CI
|
||||||
|
labels: [self-hosted, Windows, X64, testing]
|
||||||
|
timeout-minutes: 126
|
||||||
|
env:
|
||||||
|
IS_TDINTERNAL: ${{ needs.fetch-parameters.outputs.tdinternal }}
|
||||||
|
SOURCE_BRANCH: ${{ needs.fetch-parameters.outputs.source_branch }}
|
||||||
|
TARGET_BRANCH: ${{ needs.fetch-parameters.outputs.target_branch }}
|
||||||
|
PR_NUMBER: ${{ needs.fetch-parameters.outputs.pr_number }}
|
||||||
|
WIN_INTERNAL_ROOT: "C:\\workspace\\0\\TDinternal"
|
||||||
|
WIN_COMMUNITY_ROOT: "C:\\workspace\\0\\TDinternal\\community"
|
||||||
|
WIN_SYSTEM_TEST_ROOT: "C:\\workspace\\0\\TDinternal\\community\\tests\\system-test"
|
||||||
|
WIN_VS_PATH: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Auxiliary\\Build\\vcvarsall.bat"
|
||||||
|
WIN_CPU_TYPE: "x64"
|
||||||
|
steps:
|
||||||
|
- name: Output the environment information
|
||||||
|
run: |
|
||||||
|
hostname
|
||||||
|
taskkill /f /t /im python.exe
|
||||||
|
taskkill /f /t /im bash.exe
|
||||||
|
taskkill /f /t /im taosd.exe
|
||||||
|
ipconfig
|
||||||
|
set
|
||||||
|
date /t
|
||||||
|
time /t
|
||||||
|
rd /s /Q "%WIN_INTERNAL_ROOT%\debug" || exit 0
|
||||||
|
shell: cmd
|
||||||
|
- name: Prepare repositories
|
||||||
|
run: |
|
||||||
|
:: Prepare internal repository
|
||||||
|
if exist "%WIN_INTERNAL_ROOT%" (
|
||||||
|
cd /d "%WIN_INTERNAL_ROOT%"
|
||||||
|
git reset --hard
|
||||||
|
git clean -f
|
||||||
|
git remote prune origin
|
||||||
|
git fetch
|
||||||
|
git checkout "%TARGET_BRANCH%"
|
||||||
|
) else (
|
||||||
|
echo Directory does not exist: "%WIN_INTERNAL_ROOT%"
|
||||||
|
exit 1
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Prepare community repository
|
||||||
|
if exist "%WIN_COMMUNITY_ROOT%" (
|
||||||
|
cd /d "%WIN_COMMUNITY_ROOT%"
|
||||||
|
git reset --hard
|
||||||
|
git clean -f
|
||||||
|
git remote prune origin
|
||||||
|
git fetch
|
||||||
|
git checkout "%TARGET_BRANCH%"
|
||||||
|
) else (
|
||||||
|
echo Directory does not exist: "%WIN_COMMUNITY_ROOT%"
|
||||||
|
exit 1
|
||||||
|
)
|
||||||
|
shell: cmd
|
||||||
|
- name: Get latest codes and logs for TDinternal PR
|
||||||
|
if: ${{ env.IS_TDINTERNAL == 'true' }}
|
||||||
|
run: |
|
||||||
|
cd %WIN_INTERNAL_ROOT%
|
||||||
|
git pull origin %TARGET_BRANCH%
|
||||||
|
git fetch origin +refs/pull/%PR_NUMBER%/merge
|
||||||
|
git checkout -qf FETCH_HEAD
|
||||||
|
cd %WIN_COMMUNITY_ROOT%
|
||||||
|
git remote prune origin
|
||||||
|
git pull
|
||||||
|
shell: cmd
|
||||||
|
- name: Get latest codes and logs for TDengine PR
|
||||||
|
if: ${{ env.IS_TDINTERNAL == 'false' }}
|
||||||
|
run: |
|
||||||
|
cd %WIN_INTERNAL_ROOT%
|
||||||
|
git pull origin %TARGET_BRANCH%
|
||||||
|
cd %WIN_COMMUNITY_ROOT%
|
||||||
|
git remote prune origin
|
||||||
|
git pull origin %TARGET_BRANCH%
|
||||||
|
git fetch origin +refs/pull/%PR_NUMBER%/merge
|
||||||
|
git checkout -qf FETCH_HEAD
|
||||||
|
shell: cmd
|
||||||
|
- name: Output branch and log information
|
||||||
|
run: |
|
||||||
|
cd %WIN_INTERNAL_ROOT%
|
||||||
|
git branch
|
||||||
|
git log -5
|
||||||
|
|
||||||
|
cd %WIN_COMMUNITY_ROOT%
|
||||||
|
git branch
|
||||||
|
git log -5
|
||||||
|
shell: cmd
|
||||||
|
- name: Update submodule
|
||||||
|
run: |
|
||||||
|
cd %WIN_COMMUNITY_ROOT%
|
||||||
|
git submodule update --init --recursive
|
||||||
|
shell: cmd
|
||||||
|
- name: Build on windows
|
||||||
|
run: |
|
||||||
|
echo "building ..."
|
||||||
|
time /t
|
||||||
|
cd %WIN_INTERNAL_ROOT%
|
||||||
|
mkdir debug
|
||||||
|
cd debug
|
||||||
|
time /t
|
||||||
|
call "%WIN_VS_PATH%" %WIN_CPU_TYPE%
|
||||||
|
set CL=/MP8
|
||||||
|
echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> cmake"
|
||||||
|
time /t
|
||||||
|
cmake .. -G "NMake Makefiles JOM" -DBUILD_TEST=true -DBUILD_TOOLS=true || exit 7
|
||||||
|
echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> jom -j 6"
|
||||||
|
time /t
|
||||||
|
jom -j 6 || exit 8
|
||||||
|
time /t
|
||||||
|
|
||||||
|
cd %WIN_COMMUNITY_ROOT%/tests/ci
|
||||||
|
pip3 install taospy==2.7.21
|
||||||
|
pip3 install taos-ws-py==0.3.8
|
||||||
|
xcopy /e/y/i/f %WIN_INTERNAL_ROOT%\\debug\\build\\lib\\taos.dll C:\\Windows\\System32
|
||||||
|
shell: cmd
|
||||||
|
- name: Run ctest
|
||||||
|
run: |
|
||||||
|
echo "windows ctest ..."
|
||||||
|
time /t
|
||||||
|
cd %WIN_INTERNAL_ROOT%\\debug
|
||||||
|
ctest -j 1 || exit 7
|
||||||
|
time /t
|
||||||
|
shell: cmd
|
||||||
|
- name: Run function test
|
||||||
|
run: |
|
||||||
|
echo "windows test ..."
|
||||||
|
xcopy /e/y/i/f "%WIN_INTERNAL_ROOT%\debug\build\lib\taos.dll" C:\Windows\System32
|
||||||
|
ls -l "C:\Windows\System32\taos.dll"
|
||||||
|
time /t
|
||||||
|
cd %WIN_SYSTEM_TEST_ROOT%
|
||||||
|
echo "testing ..."
|
||||||
|
test-all.bat ci
|
||||||
|
time /t
|
||||||
|
shell: cmd
|
||||||
|
|
|
@ -5,7 +5,6 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- 'main'
|
- 'main'
|
||||||
- '3.0'
|
- '3.0'
|
||||||
- '3.1'
|
|
||||||
paths:
|
paths:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- '*.md'
|
- '*.md'
|
||||||
|
|
|
@ -7,7 +7,7 @@ Apache Superset is a modern enterprise level business intelligence (BI) web appl
|
||||||
It is supported by the Apache Software Foundation and is an open source project with an active community and rich ecosystem.
|
It is supported by the Apache Software Foundation and is an open source project with an active community and rich ecosystem.
|
||||||
Apache Superset provides an intuitive user interface that makes creating, sharing, and visualizing data simple, while supporting multiple data sources and rich visualization options.
|
Apache Superset provides an intuitive user interface that makes creating, sharing, and visualizing data simple, while supporting multiple data sources and rich visualization options.
|
||||||
|
|
||||||
Through the Python connector of TDengine, Superset can support TDengine data sources and provide functions such as data presentation and analysis
|
Through the Python connector of TDengine, Superset can support TDengine data sources and provide functions such as data presentation and analysis.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ Tableau is a well-known business intelligence tool that supports multiple data s
|
||||||
|
|
||||||
Prepare the following environment:
|
Prepare the following environment:
|
||||||
|
|
||||||
- TDengine 3.3.5.4 and above version is installed and running normally (both Enterprise and Community versions are available)
|
- TDengine 3.3.5.8 and above version is installed and running normally (both Enterprise and Community versions are available).
|
||||||
- taosAdapter is running normally, refer to [taosAdapter Reference](../../../tdengine-reference/components/taosadapter/)
|
- taosAdapter is running normally, refer to [taosAdapter Reference](../../../tdengine-reference/components/taosadapter/).
|
||||||
- Install and run Tableau Desktop (if not installed, please download and install Windows operating system 64-bit [Download Tableau Desktop](https://www.tableau.com/products/desktop/download)). Install Tableau please refer to [Tableau Desktop](https://www.tableau.com).
|
- Install and run Tableau Desktop (if not installed, please download and install Windows operating system 64-bit [Download Tableau Desktop](https://www.tableau.com/products/desktop/download)). Install Tableau please refer to [Tableau Desktop](https://www.tableau.com).
|
||||||
- Download the latest Windows operating system X64 client driver from the TDengine official website and install it, refer to [Install ODBC Driver](../../../tdengine-reference/client-libraries/odbc/#Installation).
|
- Download the latest Windows operating system X64 client driver from the TDengine official website and install it, refer to [Install ODBC Driver](../../../tdengine-reference/client-libraries/odbc/#Installation).
|
||||||
|
|
||||||
|
@ -19,6 +19,10 @@ Prepare the following environment:
|
||||||
|
|
||||||
**Step 1**, Search and open the "ODBC Data Source (64 bit)" management tool in the Start menu of the Windows operating system and configure it, refer to [Install ODBC Driver](../../../tdengine-reference/client-libraries/odbc/#Installation).
|
**Step 1**, Search and open the "ODBC Data Source (64 bit)" management tool in the Start menu of the Windows operating system and configure it, refer to [Install ODBC Driver](../../../tdengine-reference/client-libraries/odbc/#Installation).
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
It should be noted that when configuring the ODBC data source for Tableau, the [Database] configuration item on the TDengine ODBC data source configuration page is required. You need to select a database that can be successfully connected.
|
||||||
|
:::
|
||||||
|
|
||||||
**Step 2**, Start Tableau in the Windows system environment, then search for "ODBC" on its connection page and select "Other Databases (ODBC)".
|
**Step 2**, Start Tableau in the Windows system environment, then search for "ODBC" on its connection page and select "Other Databases (ODBC)".
|
||||||
|
|
||||||
**Step 3**, Click the `DSN` radio button, then select the configured data source (MyTDengine), and click the `Connect` button. After the connection is successful, delete the content of the string attachment, and finally click the `Sign In` button.
|
**Step 3**, Click the `DSN` radio button, then select the configured data source (MyTDengine), and click the `Connect` button. After the connection is successful, delete the content of the string attachment, and finally click the `Sign In` button.
|
||||||
|
|
|
@ -10,7 +10,7 @@ toc_max_heading_level: 4
|
||||||
|
|
||||||
Prepare the following environment:
|
Prepare the following environment:
|
||||||
|
|
||||||
- TDengine 3.3.5.7 and above version is installed and running normally (both Enterprise and Community versions are available).
|
- TDengine 3.3.5.8 and above version is installed and running normally (both Enterprise and Community versions are available).
|
||||||
- taosAdapter is running normally, refer to [taosAdapter Reference](../../../tdengine-reference/components/taosadapter/).
|
- taosAdapter is running normally, refer to [taosAdapter Reference](../../../tdengine-reference/components/taosadapter/).
|
||||||
- Install and run Excel. If not installed, please download and install it. For specific instructions, please refer to Microsoft's official documentation.
|
- Install and run Excel. If not installed, please download and install it. For specific instructions, please refer to Microsoft's official documentation.
|
||||||
- Download the latest Windows operating system X64 client driver from the TDengine official website and install it, refer to [Install ODBC Driver](../../../tdengine-reference/client-libraries/odbc/#Installation).
|
- Download the latest Windows operating system X64 client driver from the TDengine official website and install it, refer to [Install ODBC Driver](../../../tdengine-reference/client-libraries/odbc/#Installation).
|
||||||
|
|
|
@ -16,7 +16,7 @@ TDengine OSS 是一个开源的高性能时序数据库,与其他时序数据
|
||||||
|
|
||||||
在 TDengine OSS 的基础上,TDengine Enterprise 提供了增强的辅助功能,包括数据的备份恢复、异地容灾、多级存储、视图、权限控制、安全加密、IP 白名单、支持 MQTT、OPC-UA、OPC-DA、PI、Wonderware、Kafka 等各种数据源。这些功能为企业提供了更为全面、安全、可靠和高效的时序数据管理解决方案。更多的细节请看 [TDengine Enterprise](https://www.taosdata.com/tdengine-pro)。
|
在 TDengine OSS 的基础上,TDengine Enterprise 提供了增强的辅助功能,包括数据的备份恢复、异地容灾、多级存储、视图、权限控制、安全加密、IP 白名单、支持 MQTT、OPC-UA、OPC-DA、PI、Wonderware、Kafka 等各种数据源。这些功能为企业提供了更为全面、安全、可靠和高效的时序数据管理解决方案。更多的细节请看 [TDengine Enterprise](https://www.taosdata.com/tdengine-pro)。
|
||||||
|
|
||||||
此外,TDengine Cloud 作为一种全托管的云服务,存储与计算分离,分开计费,为企业提供了企业级的工具和服务,彻底解决了运维难题,尤其适合中小规模的用户使用。更多的细节请看[TDengine 云服务](https://cloud.taosdata.com/?utm_source=menu&utm_medium=webcn)
|
此外,TDengine Cloud 作为一种全托管的云服务,存储与计算分离,分开计费,为企业提供了企业级的工具和服务,彻底解决了运维难题,尤其适合中小规模的用户使用。更多的细节请看 [TDengine 云服务](https://cloud.taosdata.com/?utm_source=menu&utm_medium=webcn)。
|
||||||
|
|
||||||
## TDengine 主要功能与特性
|
## TDengine 主要功能与特性
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import TabItem from "@theme/TabItem";
|
||||||
|
|
||||||
## 无模式写入行协议
|
## 无模式写入行协议
|
||||||
|
|
||||||
TDengine 的无模式写入行协议兼容 InfluxDB 的行协议、OpenTSDB 的 telnet 行协议和 OpenTSDB 的 JSON 格式协议。InfluxDB、OpenTSDB 的标准写入协议请参考各自的官方文档。
|
TDengine 的无模式写入行协议兼容 InfluxDB 的行协议、OpenTSDB 的 TELNET 行协议和 OpenTSDB 的 JSON 格式协议。InfluxDB、OpenTSDB 的标准写入协议请参考各自的官方文档。
|
||||||
|
|
||||||
下面首先以 InfluxDB 的行协议为基础,介绍 TDengine 扩展的协议内容。该协议允许用户采用更加精细的方式控制(超级表)模式。采用一个字符串来表达一个数据行,可以向写入 API 中一次传入多行字符串来实现多个数据行的批量写入,其格式约定如下。
|
下面首先以 InfluxDB 的行协议为基础,介绍 TDengine 扩展的协议内容。该协议允许用户采用更加精细的方式控制(超级表)模式。采用一个字符串来表达一个数据行,可以向写入 API 中一次传入多行字符串来实现多个数据行的批量写入,其格式约定如下。
|
||||||
|
|
||||||
|
@ -70,10 +70,9 @@ tag_set 中的所有的数据自动转化为 nchar 数据类型,并不需要
|
||||||
| 5 | i32/u32 | Int/UInt | 4 |
|
| 5 | i32/u32 | Int/UInt | 4 |
|
||||||
| 6 | i64/i/u64/u | BigInt/BigInt/UBigInt/UBigInt | 8 |
|
| 6 | i64/i/u64/u | BigInt/BigInt/UBigInt/UBigInt | 8 |
|
||||||
|
|
||||||
- t, T, true, True, TRUE, f, F, false, False 将直接作为 BOOL 型来处理。
|
- t、T、true、True、TRUE、f、F、false、False 将直接作为 BOOL 型来处理。
|
||||||
|
|
||||||
例如如下数据行表示:向名为 st 的超级表下的 t1 标签为 "3"(NCHAR)、t2 标签为 "4"(NCHAR)、t3
|
例如如下数据行表示:向名为 st 的超级表下的 t1 标签为 "3"(NCHAR)、t2 标签为 "4"(NCHAR)、t3 标签为 "t3"(NCHAR)的数据子表,写入 c1 列为 3(BIGINT)、c2 列为 false(BOOL)、c3
|
||||||
标签为 "t3"(NCHAR)的数据子表,写入 c1 列为 3(BIGINT)、c2 列为 false(BOOL)、c3
|
|
||||||
列为 "passit"(BINARY)、c4 列为 4(DOUBLE)、主键时间戳为 1626006833639000000 的一行数据。
|
列为 "passit"(BINARY)、c4 列为 4(DOUBLE)、主键时间戳为 1626006833639000000 的一行数据。
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -94,24 +93,22 @@ TDengine 提供数据写入的幂等性保证,即您可以反复调用 API 进
|
||||||
"measurement,tag_key1=tag_value1,tag_key2=tag_value2"
|
"measurement,tag_key1=tag_value1,tag_key2=tag_value2"
|
||||||
```
|
```
|
||||||
|
|
||||||
- 需要注意的是,这里的 tag_key1, tag_key2 并不是用户输入的标签的原始顺序,而是使用了标签名称按照字符串升序排列后的结果。所以,tag_key1 并不是在行协议中输入的第一个标签。
|
- 需要注意的是,这里的 tag_key1、tag_key2 并不是用户输入的标签的原始顺序,而是使用了标签名称按照字符串升序排列后的结果。所以,tag_key1 并不是在行协议中输入的第一个标签。
|
||||||
排列完成以后计算该字符串的 MD5 散列值 "md5_val"。然后将计算的结果与字符串组合生成表名:“t_md5_val”。其中的 “t_” 是固定的前缀,每个通过该映射关系自动生成的表都具有该前缀。
|
排列完成以后计算该字符串的 MD5 散列值 "md5_val"。然后将计算的结果与字符串组合生成表名:"t_md5_val"。其中的 "t_" 是固定的前缀,每个通过该映射关系自动生成的表都具有该前缀。
|
||||||
|
|
||||||
- 如果不想用自动生成的表名,有两种指定子表名的方式(第一种优先级更高)。
|
- 如果不想用自动生成的表名,有两种指定子表名的方式(第一种优先级更高)。
|
||||||
1. 通过在taos.cfg里配置 smlAutoChildTableNameDelimiter 参数来指定(`@ # 空格 回车 换行 制表符`除外)。
|
- 通过在 taos.cfg 里配置 smlAutoChildTableNameDelimiter 参数来指定(`@ # 空格 回车 换行 制表符` 除外),例如配置 smlAutoChildTableNameDelimiter=- 插入数据为 st,t0=cpu1,t1=4 c1=3 1626006833639000000 则创建的表名为 cpu1-4。
|
||||||
1. 举例如下:配置 smlAutoChildTableNameDelimiter=- 插入数据为 st,t0=cpu1,t1=4 c1=3 1626006833639000000 则创建的表名为 cpu1-4。
|
- 通过在 taos.cfg 里配置 smlChildTableName 参数来指定,例如配置 smlChildTableName=tname 插入数据为 st,tname=cpu1,t1=4 c1=3 1626006833639000000 则创建的表名为 cpu1,注意如果多行数据 tname 相同,但是后面的 tag_set 不同,则使用第一行自动建表时指定的 tag_set,其他的行会忽略。
|
||||||
2. 通过在taos.cfg里配置 smlChildTableName 参数来指定。
|
|
||||||
1. 举例如下:配置 smlChildTableName=tname 插入数据为 st,tname=cpu1,t1=4 c1=3 1626006833639000000 则创建的表名为 cpu1,注意如果多行数据 tname 相同,但是后面的 tag_set 不同,则使用第一行自动建表时指定的 tag_set,其他的行会忽略。
|
|
||||||
|
|
||||||
2. 如果解析行协议获得的超级表不存在,则会创建这个超级表(不建议手动创建超级表,不然插入数据可能异常)。
|
2. 如果解析行协议获得的超级表不存在,则会创建这个超级表(不建议手动创建超级表,不然插入数据可能异常)。
|
||||||
3. 如果解析行协议获得子表不存在,则 Schemaless 会按照步骤 1 或 2 确定的子表名来创建子表。
|
3. 如果解析行协议获得子表不存在,则 schemaless 会按照步骤 1 或 2 确定的子表名来创建子表。
|
||||||
4. 如果数据行中指定的标签列或普通列不存在,则在超级表中增加对应的标签列或普通列(只增不减)。
|
4. 如果数据行中指定的标签列或普通列不存在,则在超级表中增加对应的标签列或普通列(只增不减)。
|
||||||
5. 如果超级表中存在一些标签列或普通列未在一个数据行中被指定取值,那么这些列的值在这一行中会被置为 NULL。
|
5. 如果超级表中存在一些标签列或普通列未在一个数据行中被指定取值,那么这些列的值在这一行中会被置为 NULL。
|
||||||
6. 对 BINARY 或 NCHAR 列,如果数据行中所提供值的长度超出了列类型的限制,自动增加该列允许存储的字符长度上限(只增不减),以保证数据的完整保存。
|
6. 对 BINARY 或 NCHAR 列,如果数据行中所提供值的长度超出了列类型的限制,自动增加该列允许存储的字符长度上限(只增不减),以保证数据的完整保存。
|
||||||
7. 整个处理过程中遇到的错误会中断写入过程,并返回错误代码。
|
7. 整个处理过程中遇到的错误会中断写入过程,并返回错误代码。
|
||||||
8. 为了提高写入的效率,默认假设同一个超级表中 field_set 的顺序是一样的(第一条数据包含所有的 field,后面的数据按照这个顺序),如果顺序不一样,需要配置参数 smlDataFormat 为 false,否则,数据写入按照相同顺序写入,库中数据会异常,从 3.0.3.0 开始,自动检测顺序是否一致,该配置废弃。
|
8. 为了提高写入的效率,默认假设同一个超级表中 field_set 的顺序是一样的(第一条数据包含所有的 field,后面的数据按照这个顺序),如果顺序不一样,需要配置参数 smlDataFormat 为 false,否则,数据写入按照相同顺序写入,库中数据会异常,从 3.0.3.0 开始,自动检测顺序是否一致,该配置废弃。
|
||||||
9. 由于 sql 建表表名不支持点号(.),所以 schemaless 也对点号(.)做了处理,如果 schemaless 自动建表的表名如果有点号(.),会自动替换为下划线(\_)。如果手动指定子表名的话,子表名里有点号(.),同样转化为下划线(\_)。
|
9. 由于 sql 建表表名不支持点号(.),所以 schemaless 也对点号(.)做了处理,如果 schemaless 自动建表的表名如果有点号(.),会自动替换为下划线(\_)。如果手动指定子表名的话,子表名里有点号(.),同样转化为下划线(\_)。
|
||||||
10. taos.cfg 增加 smlTsDefaultName 配置(值为字符串),只在client端起作用,配置后,schemaless自动建表的时间列名字可以通过该配置设置。不配置的话,默认为 _ts。
|
10. taos.cfg 增加 smlTsDefaultName 配置(字符串类型),只在 client 端起作用,配置后,schemaless 自动建表的时间列名字可以通过该配置设置。不配置的话,默认为 _ts。
|
||||||
11. 无模式写入的数据超级表或子表名区分大小写。
|
11. 无模式写入的数据超级表或子表名区分大小写。
|
||||||
12. 无模式写入仍然遵循 TDengine 对数据结构的底层限制,例如每行数据的总长度不能超过 48KB(从 3.0.5.0 版本开始为 64KB),标签值的总长度不超过 16KB。
|
12. 无模式写入仍然遵循 TDengine 对数据结构的底层限制,例如每行数据的总长度不能超过 48KB(从 3.0.5.0 版本开始为 64KB),标签值的总长度不超过 16KB。
|
||||||
|
|
||||||
|
@ -147,7 +144,7 @@ InfluxDB行协议的数据将被映射成具有模式的数据,其中,measu
|
||||||
st,t1=3,t2=4,t3=t3 c1=3i64,c3="passit",c2=false,c4=4f64 1626006833639000000
|
st,t1=3,t2=4,t3=t3 c1=3i64,c3="passit",c2=false,c4=4f64 1626006833639000000
|
||||||
```
|
```
|
||||||
|
|
||||||
该行数据映射生成一个超级表: st, 其包含了 3 个类型为 nchar 的标签,分别是:t1, t2, t3。五个数据列,分别是 ts(timestamp),c1 (bigint),c3(binary),c2 (bool), c4 (bigint)。映射成为如下 SQL 语句:
|
该行数据映射生成一个超级表:st, 其包含了 3 个类型为 nchar 的标签,分别是:t1、t2、t3。五个数据列,分别是 ts(timestamp)、c1 (bigint)、c3(binary)、c2 (bool)、c4 (bigint)。映射成为如下 SQL 语句:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
create stable st (_ts timestamp, c1 bigint, c2 bool, c3 binary(6), c4 bigint) tags(t1 nchar(1), t2 nchar(1), t3 nchar(2))
|
create stable st (_ts timestamp, c1 bigint, c2 bool, c3 binary(6), c4 bigint) tags(t1 nchar(1), t2 nchar(1), t3 nchar(2))
|
||||||
|
@ -164,7 +161,7 @@ st,t1=3,t2=4,t3=t3 c1=3i64,c3="passit",c2=false,c4=4 1626006833639000000
|
||||||
st,t1=3,t2=4,t3=t3 c1=3i64,c3="passit",c2=false,c4=4i 1626006833640000000
|
st,t1=3,t2=4,t3=t3 c1=3i64,c3="passit",c2=false,c4=4i 1626006833640000000
|
||||||
```
|
```
|
||||||
|
|
||||||
第一行的数据类型映射将 c4 列定义为 Double, 但是第二行的数据又通过数值后缀方式声明该列为 BigInt, 由此会触发无模式写入的解析错误。
|
第一行的数据类型映射将 c4 列定义为 Double, 但是第二行的数据又通过数值后缀方式声明该列为 bigInt, 由此会触发无模式写入的解析错误。
|
||||||
|
|
||||||
如果列前面的行协议将数据列声明为了 binary, 后续的要求长度更长的 binary 长度,此时会触发超级表模式的变更。
|
如果列前面的行协议将数据列声明为了 binary, 后续的要求长度更长的 binary 长度,此时会触发超级表模式的变更。
|
||||||
|
|
||||||
|
@ -299,7 +296,7 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO
|
||||||
|
|
||||||
## 查询写入的数据
|
## 查询写入的数据
|
||||||
|
|
||||||
运行上节的样例代码,会在 power 数据库l中自动建表,我们可以通过 TDengine CLI 或者应用程序来查询数据。下面给出用 TDengine CLI 查询超级表和 meters 表数据的样例。
|
运行上节的样例代码,会在 power 数据库中自动建表,我们可以通过 TDengine CLI 或者应用程序来查询数据。下面给出用 TDengine CLI 查询超级表和 meters 表数据的样例。
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
taos> show power.stables;
|
taos> show power.stables;
|
||||||
|
|
|
@ -19,9 +19,9 @@ import TabItem from "@theme/TabItem";
|
||||||
我们只推荐使用下面两种形式的 SQL 进行参数绑定写入:
|
我们只推荐使用下面两种形式的 SQL 进行参数绑定写入:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
一、确定子表存在:
|
一、确定子表存在
|
||||||
1. INSERT INTO meters (tbname, ts, current, voltage, phase) VALUES(?, ?, ?, ?, ?)
|
1. INSERT INTO meters (tbname, ts, current, voltage, phase) VALUES(?, ?, ?, ?, ?)
|
||||||
二、自动建表:
|
二、自动建表
|
||||||
1. INSERT INTO meters (tbname, ts, current, voltage, phase, location, group_id) VALUES(?, ?, ?, ?, ?, ?, ?)
|
1. INSERT INTO meters (tbname, ts, current, voltage, phase, location, group_id) VALUES(?, ?, ?, ?, ?, ?, ?)
|
||||||
2. INSERT INTO ? USING meters TAGS (?, ?) VALUES (?, ?, ?, ?)
|
2. INSERT INTO ? USING meters TAGS (?, ?) VALUES (?, ?, ?, ?)
|
||||||
```
|
```
|
||||||
|
|
|
@ -16,7 +16,7 @@ TDengine 提供了类似于消息队列产品的数据订阅和消费接口。
|
||||||
|
|
||||||
**注意**
|
**注意**
|
||||||
在 TDengine 连接器实现中,对于订阅查询,有以下限制。
|
在 TDengine 连接器实现中,对于订阅查询,有以下限制。
|
||||||
- 查询语句限制:订阅查询只能使用 select 语句,并不支持其他类型的SQL,如订阅库,订阅超级表(非 select 方式),insert、update 或 delete 等。
|
- 查询语句限制:订阅查询只能使用 select 语句,并不支持其他类型的 SQL,如订阅库、订阅超级表(非 select 方式)、insert、update 或 delete 等。
|
||||||
- 原始始数据查询:订阅查询只能查询原始数据,而不能查询聚合或计算结果。
|
- 原始始数据查询:订阅查询只能查询原始数据,而不能查询聚合或计算结果。
|
||||||
- 时间顺序限制:订阅查询只能按照时间正序查询数据。
|
- 时间顺序限制:订阅查询只能按照时间正序查询数据。
|
||||||
|
|
||||||
|
@ -28,22 +28,67 @@ TDengine 消费者的概念跟 Kafka 类似,消费者通过订阅主题来接
|
||||||
### 创建参数
|
### 创建参数
|
||||||
创建消费者的参数较多,非常灵活的支持了各种连接类型、 Offset 提交方式、压缩、重连、反序列化等特性。各语言连接器都适用的通用基础配置项如下表所示:
|
创建消费者的参数较多,非常灵活的支持了各种连接类型、 Offset 提交方式、压缩、重连、反序列化等特性。各语言连接器都适用的通用基础配置项如下表所示:
|
||||||
|
|
||||||
| 参数名称 | 类型 | 参数说明 | 备注 |
|
#### td.connect.ip
|
||||||
| :-----------------------: | :-----: | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
- 说明:服务端的 FQDN
|
||||||
| `td.connect.ip` | string | 服务端的 FQDN | 可以是ip或者host name |
|
- 类型:string
|
||||||
| `td.connect.user` | string | 用户名 | |
|
- 备注:可以是 ip 或者 host name
|
||||||
| `td.connect.pass` | string | 密码 | |
|
|
||||||
| `td.connect.port` | integer | 服务端的端口号 | |
|
|
||||||
| `group.id` | string | 消费组 ID,同一消费组共享消费进度 | <br />**必填项**。最大长度:192,超长将截断。<br />每个topic最多可建立 100 个 consumer group |
|
|
||||||
| `client.id` | string | 客户端 ID | 最大长度:255,超长将截断。 |
|
|
||||||
| `auto.offset.reset` | enum | 消费组订阅的初始位置 | <br />`earliest`: default(version < 3.2.0.0);从头开始订阅; <br/>`latest`: default(version >= 3.2.0.0);仅从最新数据开始订阅; <br/>`none`: 没有提交的 offset 无法订阅 |
|
|
||||||
| `enable.auto.commit` | boolean | 是否启用消费位点自动提交,true: 自动提交,客户端应用无需commit;false:客户端应用需要自行commit | 默认值为 true |
|
|
||||||
| `auto.commit.interval.ms` | integer | 消费记录自动提交消费位点时间间隔,单位为毫秒 | 默认值为 5000 |
|
|
||||||
| `msg.with.table.name` | boolean | 是否允许从消息中解析表名, 不适用于列订阅(列订阅时可将 tbname 作为列写入 subquery 语句)(从3.2.0.0版本该参数废弃,恒为true) | 默认关闭 |
|
|
||||||
| `enable.replay` | boolean | 是否开启数据回放功能 | 默认关闭 |
|
|
||||||
| `session.timeout.ms` | integer | consumer 心跳丢失后超时时间,超时后会触发 rebalance 逻辑,成功后该 consumer 会被删除(从3.3.3.0版本开始支持) | 默认值为 12000,取值范围 [6000, 1800000] |
|
|
||||||
| `max.poll.interval.ms` | integer | consumer poll 拉取数据间隔的最长时间,超过该时间,会认为该 consumer 离线,触发rebalance 逻辑,成功后该 consumer 会被删除(从3.3.3.0版本开始支持) | 默认值为 300000,[1000,INT32_MAX] |
|
|
||||||
|
|
||||||
|
#### td.connect.user
|
||||||
|
- 说明:用户名
|
||||||
|
- 类型:string
|
||||||
|
|
||||||
|
#### td.connect.pass
|
||||||
|
- 说明:密码
|
||||||
|
- 类型:string
|
||||||
|
|
||||||
|
#### td.connect.port
|
||||||
|
- 说明:服务端的端口号
|
||||||
|
- 类型:integer
|
||||||
|
|
||||||
|
#### group.id
|
||||||
|
- 说明:消费组 ID,同一消费组共享消费进度
|
||||||
|
- 类型:string
|
||||||
|
- 备注:**必填项**。最大长度:192,超长将截断。<br />每个topic最多可建立 100 个 consumer group
|
||||||
|
|
||||||
|
#### client.id
|
||||||
|
- 说明:客户端 ID
|
||||||
|
- 类型:string
|
||||||
|
- 备注:最大长度 255,超长将截断
|
||||||
|
|
||||||
|
#### auto.offset.reset
|
||||||
|
- 说明:消费组订阅的初始位置
|
||||||
|
- 类型:enum
|
||||||
|
- 备注:<br />`earliest`:default(version < 3.2.0.0),从头开始订阅;<br/>`latest`:default(version >= 3.2.0.0),仅从最新数据开始订阅;<br/>`none`:没有提交的 offset 无法订阅。
|
||||||
|
|
||||||
|
#### enable.auto.commit
|
||||||
|
- 说明:是否启用消费位点自动提交
|
||||||
|
- 类型:boolean
|
||||||
|
- 备注:true:自动提交,客户端应用无需 commit;false:客户端应用需要自行 commit;默认值为 true。
|
||||||
|
|
||||||
|
#### auto.commit.interval.ms
|
||||||
|
- 说明:消费记录自动提交消费位点时间间隔
|
||||||
|
- 类型:integer
|
||||||
|
- 备注:单位为毫秒,默认值为 5000
|
||||||
|
|
||||||
|
#### msg.with.table.name
|
||||||
|
- 说明:是否允许从消息中解析表名
|
||||||
|
- 类型:boolean
|
||||||
|
- 备注:不适用于列订阅(列订阅时可将 tbname 作为列写入 subquery 语句),默认关闭。从 3.2.0.0 版本该参数废弃。
|
||||||
|
|
||||||
|
#### enable.replay
|
||||||
|
- 说明:是否开启数据回放功能
|
||||||
|
- 类型:boolean
|
||||||
|
- 备注:默认关闭
|
||||||
|
|
||||||
|
#### session.timeout.ms
|
||||||
|
- 说明:consumer 心跳丢失后超时时间
|
||||||
|
- 类型:integer
|
||||||
|
- 备注:超时后会触发 rebalance 逻辑,成功后该 consumer 会被删除(从 3.3.3.0 版本开始支持)。默认值为 12000,取值范围 [6000,1800000]。
|
||||||
|
|
||||||
|
#### max.poll.interval.ms
|
||||||
|
- 说明:consumer poll 拉取数据间隔的最长时间
|
||||||
|
- 类型:integer
|
||||||
|
- 备注:超过该时间,会认为该 consumer 离线,触发 rebalance 逻辑,成功后该 consumer 会被删除(从 3.3.3.0 版本开始支持)。默认值为 300000,[1000,INT32_MAX] 。
|
||||||
|
|
||||||
下面是各语言连接器创建参数:
|
下面是各语言连接器创建参数:
|
||||||
<Tabs defaultValue="java" groupId="lang">
|
<Tabs defaultValue="java" groupId="lang">
|
||||||
|
|
|
@ -323,7 +323,7 @@ def process(input: datablock) -> tuple[output_type]:
|
||||||
```
|
```
|
||||||
|
|
||||||
主要参数说明如下:
|
主要参数说明如下:
|
||||||
- input:datablock 类似二维矩阵,通过成员方法 data(row, col) 读取位于 row 行、col 列的 python 对象
|
- input:datablock 类似二维矩阵,通过成员方法 data(row, col) 读取位于 row 行、col 列的 Python 对象
|
||||||
- 返回值是一个 Python 对象元组,每个元素类型为输出类型。
|
- 返回值是一个 Python 对象元组,每个元素类型为输出类型。
|
||||||
|
|
||||||
#### 聚合函数接口
|
#### 聚合函数接口
|
||||||
|
@ -405,7 +405,7 @@ def finish(buf: bytes) -> output_type:
|
||||||
|
|
||||||
本文内容由浅入深包括 5 个示例程序,同时也包含大量实用的 debug 技巧。
|
本文内容由浅入深包括 5 个示例程序,同时也包含大量实用的 debug 技巧。
|
||||||
|
|
||||||
注意:**UDF 内无法通过 print 函数输出日志,需要自己写文件或用 python 内置的 logging 库写文件**。
|
注意:**UDF 内无法通过 print 函数输出日志,需要自己写文件或用 Python 内置的 logging 库写文件**。
|
||||||
|
|
||||||
#### 示例一
|
#### 示例一
|
||||||
|
|
||||||
|
@ -652,7 +652,7 @@ tail -20 taospyudf.log
|
||||||
2023-05-25 11:42:34.541 ERROR [1679419] [PyUdf::PyUdf@217] py udf load module failure. error ModuleNotFoundError: No module named 'moment'
|
2023-05-25 11:42:34.541 ERROR [1679419] [PyUdf::PyUdf@217] py udf load module failure. error ModuleNotFoundError: No module named 'moment'
|
||||||
```
|
```
|
||||||
|
|
||||||
这是因为 “moment” 所在位置不在 python udf 插件默认的库搜索路径中。怎么确认这一点呢?通过以下命令搜索 taospyudf.log。
|
这是因为 “moment” 所在位置不在 Python udf 插件默认的库搜索路径中。怎么确认这一点呢?通过以下命令搜索 taospyudf.log。
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
grep 'sys path' taospyudf.log | tail -1
|
grep 'sys path' taospyudf.log | tail -1
|
||||||
|
@ -664,7 +664,7 @@ grep 'sys path' taospyudf.log | tail -1
|
||||||
2023-05-25 10:58:48.554 INFO [1679419] [doPyOpen@592] python sys path: ['', '/lib/python38.zip', '/lib/python3.8', '/lib/python3.8/lib-dynload', '/lib/python3/dist-packages', '/var/lib/taos//.udf']
|
2023-05-25 10:58:48.554 INFO [1679419] [doPyOpen@592] python sys path: ['', '/lib/python38.zip', '/lib/python3.8', '/lib/python3.8/lib-dynload', '/lib/python3/dist-packages', '/var/lib/taos//.udf']
|
||||||
```
|
```
|
||||||
|
|
||||||
发现 python udf 插件默认搜索的第三方库安装路径是: /lib/python3/dist-packages,而 moment 默认安装到了 /usr/local/lib/python3.8/dist-packages。下面我们修改 python udf 插件默认的库搜索路径。
|
发现 Python udf 插件默认搜索的第三方库安装路径是: /lib/python3/dist-packages,而 moment 默认安装到了 /usr/local/lib/python3.8/dist-packages。下面我们修改 Python udf 插件默认的库搜索路径。
|
||||||
先打开 python3 命令行,查看当前的 sys.path。
|
先打开 python3 命令行,查看当前的 sys.path。
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -754,7 +754,7 @@ create or replace aggregate function myspread as '/root/udf/myspread.py' outputt
|
||||||
|
|
||||||
这个 SQL 语句与创建标量函数的 SQL 语句有两个重要区别。
|
这个 SQL 语句与创建标量函数的 SQL 语句有两个重要区别。
|
||||||
1. 增加了 aggregate 关键字
|
1. 增加了 aggregate 关键字
|
||||||
2. 增加了 bufsize 关键字,用来指定存储中间结果的内存大小,这个数值可以大于实际使用的数值。本例中间结果是两个浮点数组成的 tuple,序列化后实际占用大小只有 32 个字节,但指定的 bufsize 是128,可以用 python 命令行打印实际占用的字节数
|
2. 增加了 bufsize 关键字,用来指定存储中间结果的内存大小,这个数值可以大于实际使用的数值。本例中间结果是两个浮点数组成的 tuple,序列化后实际占用大小只有 32 个字节,但指定的 bufsize 是128,可以用 Python 命令行打印实际占用的字节数
|
||||||
|
|
||||||
```python
|
```python
|
||||||
>>> len(pickle.dumps((12345.6789, 23456789.9877)))
|
>>> len(pickle.dumps((12345.6789, 23456789.9877)))
|
||||||
|
|
|
@ -374,7 +374,7 @@ SQLWriter 类封装了拼 SQL 和写数据的逻辑。所有的表都没有提
|
||||||
- 已安装 Python3, 推荐版本 >= 3.8
|
- 已安装 Python3, 推荐版本 >= 3.8
|
||||||
- 已安装 taospy
|
- 已安装 taospy
|
||||||
|
|
||||||
2. 安装 faster-fifo 代替 python 内置的 multiprocessing.Queue
|
2. 安装 faster-fifo 代替 Python 内置的 multiprocessing.Queue
|
||||||
|
|
||||||
```
|
```
|
||||||
pip3 install faster-fifo
|
pip3 install faster-fifo
|
||||||
|
|
|
@ -36,7 +36,7 @@ taosAdapter 提供了以下功能:
|
||||||
- RESTful 接口;
|
- RESTful 接口;
|
||||||
- WebSocket 连接;
|
- WebSocket 连接;
|
||||||
- 兼容 InfluxDB v1 格式写入;
|
- 兼容 InfluxDB v1 格式写入;
|
||||||
- 兼容 OpenTSDB JSON 和 Telnet 格式写入;
|
- 兼容 OpenTSDB JSON 和 TELNET 格式写入;
|
||||||
- 无缝连接到 Telegraf;
|
- 无缝连接到 Telegraf;
|
||||||
- 无缝连接到 collectd;
|
- 无缝连接到 collectd;
|
||||||
- 无缝连接到 StatsD;
|
- 无缝连接到 StatsD;
|
||||||
|
@ -77,7 +77,7 @@ taosX Agent 是 TDengine Enterprise 数据管道功能的重要组成部分,
|
||||||
这些应用程序负责向业务集群写入、查询业务数据以及订阅数据。应用程序可以通过以下 3 种方式与业务集群进行交互。
|
这些应用程序负责向业务集群写入、查询业务数据以及订阅数据。应用程序可以通过以下 3 种方式与业务集群进行交互。
|
||||||
- 基于 taosc 的应用程序:采用原生连接的应用程序,直接连接到业务集群,默认端口为 6030。
|
- 基于 taosc 的应用程序:采用原生连接的应用程序,直接连接到业务集群,默认端口为 6030。
|
||||||
- 基于 RESTful 连接的应用程序:使用 RESTful 接口访问业务集群的应用程序,需要通过 taosAdapter 进行连接,默认端口为 6041。
|
- 基于 RESTful 连接的应用程序:使用 RESTful 接口访问业务集群的应用程序,需要通过 taosAdapter 进行连接,默认端口为 6041。
|
||||||
- 基于 WebSkcket 连接的应用程序:采用 WebSocket 连接的应用程序,同样需要通过 taosAdapter 进行连接,默认端口为 6041。
|
- 基于 WebSocket 连接的应用程序:采用 WebSocket 连接的应用程序,同样需要通过 taosAdapter 进行连接,默认端口为 6041。
|
||||||
|
|
||||||
2. 可视化/BI 工具
|
2. 可视化/BI 工具
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ toc_max_heading_level: 4
|
||||||
|
|
||||||
在这些进程中,taoskeeper、taos-explorer、taosadapter 和 taosx 的资源占用相对较少,通常不需要特别关注。此外,这些进程对存储空间的需求也较低,其占用的 CPU 和内存资源一般为 taosd 进程的十分之一到几分之一(特殊场景除外,如数据同步和历史数据迁移。在这些情况下,涛思数据的技术支持团队将提供一对一的服务)。系统管理员应定期监控这些进程的资源消耗,并及时进行相应处理。
|
在这些进程中,taoskeeper、taos-explorer、taosadapter 和 taosx 的资源占用相对较少,通常不需要特别关注。此外,这些进程对存储空间的需求也较低,其占用的 CPU 和内存资源一般为 taosd 进程的十分之一到几分之一(特殊场景除外,如数据同步和历史数据迁移。在这些情况下,涛思数据的技术支持团队将提供一对一的服务)。系统管理员应定期监控这些进程的资源消耗,并及时进行相应处理。
|
||||||
|
|
||||||
在本节中,我们将重点讨论 TDengine 数据库引擎的核心进程—taosd 的资源规划。合理的资源规划将确保 taosd 进程的高效运行,从而提高整个时序数据平台的性能和稳定性。
|
在本节中,我们将重点讨论 TDengine 数据库引擎的核心进程 taosd 的资源规划。合理的资源规划将确保 taosd 进程的高效运行,从而提高整个时序数据平台的性能和稳定性。
|
||||||
|
|
||||||
## 服务器内存需求
|
## 服务器内存需求
|
||||||
|
|
||||||
|
@ -154,9 +154,9 @@ TDengine 的多级存储功能在使用上还具备以下优点。
|
||||||
| taosKeeper | 6043 | TCP |
|
| taosKeeper | 6043 | TCP |
|
||||||
| statsd 格式写入接口 | 6044 | TCP/UDP |
|
| statsd 格式写入接口 | 6044 | TCP/UDP |
|
||||||
| collectd 格式写入接口 | 6045 | TCP/UDP |
|
| collectd 格式写入接口 | 6045 | TCP/UDP |
|
||||||
| openTSDB Telnet 格式写入接口 | 6046 | TCP |
|
| openTSDB TELNET 格式写入接口 | 6046 | TCP |
|
||||||
| collectd 使用 openTSDB Telnet 格式写入接口 | 6047 | TCP |
|
| collectd 使用 openTSDB TELNET 格式写入接口 | 6047 | TCP |
|
||||||
| icinga2 使用 openTSDB Telnet 格式写入接口 | 6048 | TCP |
|
| icinga2 使用 openTSDB TELNET 格式写入接口 | 6048 | TCP |
|
||||||
| tcollector 使用 openTSDB Telnet 格式写入接口 | 6049 | TCP |
|
| tcollector 使用 openTSDB TELNET 格式写入接口 | 6049 | TCP |
|
||||||
| taosX | 6050, 6055 | TCP |
|
| taosX | 6050, 6055 | TCP |
|
||||||
| taosExplorer | 6060 | TCP |
|
| taosExplorer | 6060 | TCP |
|
||||||
|
|
|
@ -21,7 +21,7 @@ taosd 是 TDengine 集群中最主要的服务组件,本节介绍手动部署
|
||||||
在进行 TDengine 集群部署之前,全面检查所有 dnode 以及应用程序所在物理节点的网络设置至关重要。以下是检查步骤:
|
在进行 TDengine 集群部署之前,全面检查所有 dnode 以及应用程序所在物理节点的网络设置至关重要。以下是检查步骤:
|
||||||
|
|
||||||
- 第 1 步,在每个物理节点上执行 hostname -f 命令,以查看并确认所有节点的hostname 是唯一的。对于应用程序驱动所在的节点,这一步骤可以省略。
|
- 第 1 步,在每个物理节点上执行 hostname -f 命令,以查看并确认所有节点的hostname 是唯一的。对于应用程序驱动所在的节点,这一步骤可以省略。
|
||||||
- 第 2 步,在每个物理节点上执行 ping host 命令,其中 host 是其他物理节点的 hostname。这一步骤旨在检测当前节点与其他物理节点之间的网络连通性。如果发现无法 ping 通,请立即检查网络和 DNS 设置。对于 Linux 操作系统,请检查 /etc/hosts 文件;对于 Windows 操作系统,请检查C:\Windows\system32\drivers\etc\hosts 文件。网络不通畅将导致无法组建集群,请务必解决此问题。
|
- 第 2 步,在每个物理节点上执行 ping host 命令,其中 host 是其他物理节点的 hostname。这一步骤旨在检测当前节点与其他物理节点之间的网络连通性。如果发现无法 ping 通,请立即检查网络和 DNS 设置。对于 Linux 操作系统,请检查 /etc/hosts 文件;对于 Windows 操作系统,请检查 `C:\Windows\system32\drivers\etc\hosts` 文件。网络不通畅将导致无法组建集群,请务必解决此问题。
|
||||||
- 第 3 步,在应用程序运行的物理节点上重复上述网络检测步骤。如果发现网络不通畅,应用程序将无法连接到 taosd 服务。此时,请仔细检查应用程序所在物理节点的 DNS 设置或 hosts 文件,确保其配置正确无误。
|
- 第 3 步,在应用程序运行的物理节点上重复上述网络检测步骤。如果发现网络不通畅,应用程序将无法连接到 taosd 服务。此时,请仔细检查应用程序所在物理节点的 DNS 设置或 hosts 文件,确保其配置正确无误。
|
||||||
- 第 4 步,检查端口,确保集群中所有主机在端口 6030 上的 TCP 能够互通。
|
- 第 4 步,检查端口,确保集群中所有主机在端口 6030 上的 TCP 能够互通。
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ http {
|
||||||
|
|
||||||
### 部署 taosX-Agent
|
### 部署 taosX-Agent
|
||||||
|
|
||||||
有些数据源如 Pi, OPC 等,因为网络条件和数据源访问的限制,taosX 无法直接访问数据源,这种情况下需要部署一个代理服务 taosX-Agent,关于它的详细说明和部署请参考企业版参考手册。
|
有些数据源如 PI、OPC 等,因为网络条件和数据源访问的限制,taosX 无法直接访问数据源,这种情况下需要部署一个代理服务 taosX-Agent,关于它的详细说明和部署请参考企业版参考手册。
|
||||||
|
|
||||||
### 部署 taos-Explorer
|
### 部署 taos-Explorer
|
||||||
|
|
||||||
|
@ -342,7 +342,7 @@ spec:
|
||||||
|
|
||||||
### 有状态服务 StatefulSet
|
### 有状态服务 StatefulSet
|
||||||
|
|
||||||
根据 Kubernetes 对各类部署的说明,我们将使用 StatefulSet 作为 TDengine 的部署资源类型。 创建文件 tdengine.yaml,其中 replicas 定义集群节点的数量为 3。节点时区为中国(Asia/Shanghai),每个节点分配 5G 标准(standard)存储,你也可以根据实际情况进行相应修改。
|
根据 Kubernetes 对各类部署的说明,我们将使用 StatefulSet 作为 TDengine 的部署资源类型。 创建文件 tdengine.yaml,其中 replicas 定义集群节点的数量为 3。节点时区为中国(Asia/Shanghai),每个节点分配 5GB 标准(standard)存储,你也可以根据实际情况进行相应修改。
|
||||||
|
|
||||||
请特别注意 startupProbe 的配置,在 dnode 的 Pod 掉线一段时间后,再重新启动,这个时候新上线的 dnode 会短暂不可用。如果 startupProbe 配置过小,Kubernetes 会认为该 Pod 处于不正常的状态,并尝试重启该 Pod,该 dnode 的 Pod 会频繁重启,始终无法恢复到正常状态。
|
请特别注意 startupProbe 的配置,在 dnode 的 Pod 掉线一段时间后,再重新启动,这个时候新上线的 dnode 会短暂不可用。如果 startupProbe 配置过小,Kubernetes 会认为该 Pod 处于不正常的状态,并尝试重启该 Pod,该 dnode 的 Pod 会频繁重启,始终无法恢复到正常状态。
|
||||||
|
|
||||||
|
|
|
@ -12,37 +12,37 @@ sidebar_label: 集群维护
|
||||||
|
|
||||||
## 数据重整
|
## 数据重整
|
||||||
|
|
||||||
TDengine 面向多种写入场景,而很多写入场景下,TDengine 的存储会导致数据存储的放大或数据文件的空洞等。这一方面影响数据的存储效率,另一方面也会影响查询效率。为了解决上述问题,TDengine 企业版提供了对数据的重整功能,即 DATA COMPACT 功能,将存储的数据文件重新整理,删除文件空洞和无效数据,提高数据的组织度,从而提高存储和查询的效率。数据重整功能在 3.0.3.0 版本第一次发布,此后又经过了多次迭代优化,建议使用最新版本。
|
TDengine 面向多种写入场景,而很多写入场景下,TDengine 的存储会导致数据存储的放大或数据文件的空洞等。这一方面影响数据的存储效率,另一方面也会影响查询效率。为了解决上述问题,TDengine 企业版提供了对数据的重整功能,即 data compact 功能,将存储的数据文件重新整理,删除文件空洞和无效数据,提高数据的组织度,从而提高存储和查询的效率。数据重整功能在 3.0.3.0 版本第一次发布,此后又经过了多次迭代优化,建议使用最新版本。
|
||||||
|
|
||||||
### 语法
|
### 语法
|
||||||
|
|
||||||
```SQL
|
```SQL
|
||||||
COMPACT DATABASE db_name [start with 'XXXX'] [end with 'YYYY'];
|
compact DATABASE db_name [start with 'XXXX'] [end with 'YYYY'];
|
||||||
COMPACT [db_name.]VGROUPS IN (vgroup_id1, vgroup_id2, ...) [start with 'XXXX'] [end with 'YYYY'];
|
compact [db_name.]vgroups IN (vgroup_id1, vgroup_id2, ...) [start with 'XXXX'] [end with 'YYYY'];
|
||||||
SHOW COMPACTS;
|
show compacts;
|
||||||
SHOW COMPACT compact_id;
|
show compact compact_id;
|
||||||
KILL COMPACT compact_id;
|
kill compact compact_id;
|
||||||
```
|
```
|
||||||
|
|
||||||
### 效果
|
### 效果
|
||||||
|
|
||||||
- 扫描并压缩指定的 DB 中所有 VGROUP 中 VNODE 的所有数据文件
|
- 扫描并压缩指定的 DB 中所有 vgroup 中 vnode 的所有数据文件
|
||||||
- 扫描并压缩 DB 中指定的 VGROUP 列表中 VNODE 的所有数据文件, 若 db_name 为空,则默认为当前数据库
|
- 扫描并压缩 DB 中指定的 vgroup 列表中 vnode 的所有数据文件, 若 db_name 为空,则默认为当前数据库
|
||||||
- COMPCAT 会删除被删除数据以及被删除的表的数据
|
- compact 会删除被删除数据以及被删除的表的数据
|
||||||
- COMPACT 会合并多个 STT 文件
|
- compact 会合并多个 STT 文件
|
||||||
- 可通过 start with 关键字指定 COMPACT 数据的起始时间
|
- 可通过 start with 关键字指定 compact 数据的起始时间
|
||||||
- 可通过 end with 关键字指定 COMPACT 数据的终止时间
|
- 可通过 end with 关键字指定 compact 数据的终止时间
|
||||||
- COMPACT 命令会返回 COMPACT 任务的 ID
|
- compact 命令会返回 compact 任务的 ID
|
||||||
- COMPACT 任务会在后台异步执行,可以通过 SHOW COMPACTS 命令查看 COMPACT 任务的进度
|
- compact 任务会在后台异步执行,可以通过 show compacts 命令查看 compact 任务的进度
|
||||||
- SHOW 命令会返回 COMPACT 任务的 ID,可以通过 KILL COMPACT 命令终止 COMPACT 任务
|
- show 命令会返回 compact 任务的 ID,可以通过 kill compact 命令终止 compact 任务
|
||||||
|
|
||||||
|
|
||||||
### 补充说明
|
### 补充说明
|
||||||
|
|
||||||
- COMPACT 为异步,执行 COMPACT 命令后不会等 COMPACT 结束就会返回。如果上一个 COMPACT 没有完成则再发起一个 COMPACT 任务,则会等上一个任务完成后再返回。
|
- compact 为异步,执行 compact 命令后不会等 compact 结束就会返回。如果上一个 compact 没有完成则再发起一个 compact 任务,则会等上一个任务完成后再返回。
|
||||||
- COMPACT 可能阻塞写入,尤其是在 stt_trigger = 1 的数据库中,但不阻塞查询。
|
- compact 可能阻塞写入,尤其是在 stt_trigger = 1 的数据库中,但不阻塞查询。
|
||||||
|
|
||||||
## Vgroup Leader 再平衡
|
## vgroup leader 再平衡
|
||||||
|
|
||||||
当多副本集群中的一个或多个节点因为升级或其它原因而重启后,有可能出现集群中各个 dnode 负载不均衡的现象,极端情况下会出现所有 vgroup 的 leader 都位于同一个 dnode 的情况。为了解决这个问题,可以使用下面的命令,该命令在 3.0.4.0 版本中首次发布,建议尽可能使用最新版本。
|
当多副本集群中的一个或多个节点因为升级或其它原因而重启后,有可能出现集群中各个 dnode 负载不均衡的现象,极端情况下会出现所有 vgroup 的 leader 都位于同一个 dnode 的情况。为了解决这个问题,可以使用下面的命令,该命令在 3.0.4.0 版本中首次发布,建议尽可能使用最新版本。
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ balance vgroup leader database <database_name>; # 再平衡一个 database 内
|
||||||
|
|
||||||
### 注意
|
### 注意
|
||||||
|
|
||||||
Vgroup 选举本身带有随机性,所以通过选举的重新分布产生的均匀分布也是带有一定的概率,不会完全的均匀。该命令的副作用是影响查询和写入,在vgroup重新选举时,从开始选举到选举出新的 leader 这段时间,这 个vgroup 无法写入和查询。选举过程一般在秒级完成。所有的vgroup会依次逐个重新选举。
|
vgroup 选举本身带有随机性,所以通过选举的重新分布产生的均匀分布也是带有一定的概率,不会完全的均匀。该命令的副作用是影响查询和写入,在 vgroup 重新选举时,从开始选举到选举出新的 leader 这段时间,这 个vgroup 无法写入和查询。选举过程一般在秒级完成。所有的 vgroup 会依次逐个重新选举。
|
||||||
|
|
||||||
## 恢复数据节点
|
## 恢复数据节点
|
||||||
|
|
||||||
当集群中的某个数据节点(dnode)的数据全部丢失或被破坏,比如磁盘损坏或者目录被误删除,可以通过 restore dnode 命令来恢复该数据节点上的部分或全部逻辑节点,该功能依赖多副本中的其它副本进行数据复制,所以只在集群中 dnode 数量大于等于 3 且副本数为 3 的情况下能够工作。
|
当集群中的某个数据节点(dnode)的数据全部丢失或被破坏,比如磁盘损坏或者目录被误删除,可以通过 `restore dnode` 命令来恢复该数据节点上的部分或全部逻辑节点,该功能依赖多副本中的其它副本进行数据复制,所以只在集群中 dnode 数量大于等于 3 且副本数为 3 的情况下能够工作。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
restore dnode <dnode_id>;# 恢复dnode上的mnode,所有vnode和qnode
|
restore dnode <dnode_id>;# 恢复dnode上的mnode,所有vnode和qnode
|
||||||
|
@ -78,7 +78,7 @@ restore qnode on dnode <dnode_id>;# 恢复dnode上的qnode
|
||||||
|
|
||||||
## 分裂虚拟组
|
## 分裂虚拟组
|
||||||
|
|
||||||
当一个 vgroup 因为子表数过多而导致 CPU 或 Disk 资源使用量负载过高时,增加 dnode 节点后,可通过split vgroup命令把该vgroup分裂为两个虚拟组。分裂完成后,新产生的两个 vgroup 承担原来由一个 vgroup 提供的读写服务。该命令在 3.0.6.0 版本第一次发布,建议尽可能使用最新版本。
|
当一个 vgroup 因为子表数过多而导致 CPU 或 Disk 资源使用量负载过高时,增加 dnode 节点后,可通过 `split vgroup` 命令把该 vgroup 分裂为两个虚拟组。分裂完成后,新产生的两个 vgroup 承担原来由一个 vgroup 提供的读写服务。该命令在 3.0.6.0 版本第一次发布,建议尽可能使用最新版本。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
split vgroup <vgroup_id>
|
split vgroup <vgroup_id>
|
||||||
|
@ -96,8 +96,6 @@ split vgroup <vgroup_id>
|
||||||
|
|
||||||
从 3.1.1.0 版本开始,TDengine Enterprise 支持在线热更新 `supportVnodes` 这个很重要的 dnode 配置参数。这个参数的原始配置方式是在 `taos.cfg` 配置文件中,表示该 dnode 能够支持的最大的 vnode 数量。当创建一个数据库时需要分配新的 vnode,当删除一个数据库时其 vnode 都会被销毁。
|
从 3.1.1.0 版本开始,TDengine Enterprise 支持在线热更新 `supportVnodes` 这个很重要的 dnode 配置参数。这个参数的原始配置方式是在 `taos.cfg` 配置文件中,表示该 dnode 能够支持的最大的 vnode 数量。当创建一个数据库时需要分配新的 vnode,当删除一个数据库时其 vnode 都会被销毁。
|
||||||
|
|
||||||
但在线更新 `supportVnodes` 不会产生持久化,当系统重启后,允许的最大 vnode 数量仍然由 taos.cfg 中配置的 `supportVnodes` 决定。
|
|
||||||
|
|
||||||
如果通过在线更新或配置文件方式设置的 `supportVnodes` 小于 dnode 当前已经实际存在的 vnode 数量,已经存在的 vnode 不会受影响。但当尝试创建新的 database 时,是否能够创建成功则仍然受实际生效的 `supportVnodes` 参数决定。
|
如果通过在线更新或配置文件方式设置的 `supportVnodes` 小于 dnode 当前已经实际存在的 vnode 数量,已经存在的 vnode 不会受影响。但当尝试创建新的 database 时,是否能够创建成功则仍然受实际生效的 `supportVnodes` 参数决定。
|
||||||
|
|
||||||
## 双副本
|
## 双副本
|
||||||
|
@ -106,7 +104,7 @@ split vgroup <vgroup_id>
|
||||||
|
|
||||||
### 查看 Vgroups 的状态
|
### 查看 Vgroups 的状态
|
||||||
|
|
||||||
通过以下 SQL 命令参看双副本数据库中各 Vgroup 的状态:
|
通过以下 SQL 命令参看双副本数据库中各 vgroup 的状态:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
show arbgroups;
|
show arbgroups;
|
||||||
|
@ -120,15 +118,15 @@ select * from information_schema.ins_arbgroups;
|
||||||
|
|
||||||
```
|
```
|
||||||
is_sync 有以下两种取值:
|
is_sync 有以下两种取值:
|
||||||
- 0: Vgroup 数据未达成同步。在此状态下,如果 Vgroup 中的某一 Vnode 不可访问,另一个 Vnode 无法被指定为 `AssignedLeader` role,该 Vgroup 将无法提供服务。
|
- 0: vgroup 数据未达成同步。在此状态下,如果 vgroup 中的某一 vnode 不可访问,另一个 vnode 无法被指定为 `AssignedLeader` role,该 vgroup 将无法提供服务。
|
||||||
- 1: Vgroup 数据达成同步。在此状态下,如果 Vgroup 中的某一 Vnode 不可访问,另一个 Vnode 可以被指定为 `AssignedLeader` role,该 Vgroup 可以继续提供服务。
|
- 1: vgroup 数据达成同步。在此状态下,如果 vgroup 中的某一 vnode 不可访问,另一个 vnode 可以被指定为 `AssignedLeader` role,该 vgroup 可以继续提供服务。
|
||||||
|
|
||||||
assigned_dnode:
|
assigned_dnode:
|
||||||
- 标识被指定为 AssignedLeader 的 Vnode 的 DnodeId
|
- 标识被指定为 AssignedLeader 的 vnode 的 DnodeId
|
||||||
- 未指定 AssignedLeader 时,该列显示 NULL
|
- 未指定 AssignedLeader 时,该列显示 NULL
|
||||||
|
|
||||||
assigned_token:
|
assigned_token:
|
||||||
- 标识被指定为 AssignedLeader 的 Vnode 的 Token
|
- 标识被指定为 AssignedLeader 的 vnode 的 Token
|
||||||
- 未指定 AssignedLeader时,该列显示 NULL
|
- 未指定 AssignedLeader时,该列显示 NULL
|
||||||
|
|
||||||
### 最佳实践
|
### 最佳实践
|
||||||
|
|
|
@ -40,7 +40,7 @@ taosKeeper 的配置文件默认位于 `/etc/taos/taoskeeper.toml`。 详细配
|
||||||
|
|
||||||
#### 导入仪表盘
|
#### 导入仪表盘
|
||||||
|
|
||||||
TDengine 数据源插件已提交至 Grafana 官网,如何安装 TDengine 数据源插件和配置数据源请参考:[安装 Grafana Plugin 并配置数据源](../../third-party/visual/grafana/#安装-grafana-plugin-并配置数据源)。完成插件的安装和数据源的创建后,可以进行 TDinsight 仪表盘的导入。
|
TDengine 数据源插件已提交至 Grafana 官网,如何安装 TDengine 数据源插件和配置数据源请参考 [安装 Grafana Plugin 并配置数据源](../../third-party/visual/grafana/#安装-grafana-plugin-并配置数据源)。完成插件的安装和数据源的创建后,可以进行 TDinsight 仪表盘的导入。
|
||||||
|
|
||||||
在 Grafana 的 “Home” -> “Dashboards” 页面,点击位于右上角的 “New” -> “import” 按钮,即可进入 Dashboard 的导入页面,它支持以下两种导入方式。
|
在 Grafana 的 “Home” -> “Dashboards” 页面,点击位于右上角的 “New” -> “import” 按钮,即可进入 Dashboard 的导入页面,它支持以下两种导入方式。
|
||||||
- Dashboard ID:18180。
|
- Dashboard ID:18180。
|
||||||
|
|
|
@ -4,7 +4,7 @@ title: 可视化管理工具
|
||||||
toc_max_heading_level: 4
|
toc_max_heading_level: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
为方便用户更高效地使用和管理 TDengine,TDengine 3.0 版本推出了一个全新的可视化组件—taosExplorer。这个组件旨在帮助用户在不熟悉 SQL 的情况下,也能轻松管理 TDengine 集群。通过 taosExplorer,用户可以轻松查看 TDengine 的运行状态、浏览数据、配置数据源、实现流计算和数据订阅等功能。此外,用户还可以利用taosExplorer 进行数据的备份、复制和同步操作,以及配置用户的各种访问权限。这些功能极大地简化了数据库的使用过程,提高了用户体验。
|
为方便用户更高效地使用和管理 TDengine,TDengine 3.0 版本推出了一个全新的可视化组件 taosExplorer。这个组件旨在帮助用户在不熟悉 SQL 的情况下,也能轻松管理 TDengine 集群。通过 taosExplorer,用户可以轻松查看 TDengine 的运行状态、浏览数据、配置数据源、实现流计算和数据订阅等功能。此外,用户还可以利用 taosExplorer 进行数据的备份、复制和同步操作,以及配置用户的各种访问权限。这些功能极大地简化了数据库的使用过程,提高了用户体验。
|
||||||
|
|
||||||
本节介绍可视化管理的基本功能。
|
本节介绍可视化管理的基本功能。
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ toc_max_heading_level: 4
|
||||||
|
|
||||||
下面通过创建数据库,来熟悉数据浏览器页面的功能和操作,接下来看创建数据库的两种方式:
|
下面通过创建数据库,来熟悉数据浏览器页面的功能和操作,接下来看创建数据库的两种方式:
|
||||||
|
|
||||||
1. 通过点击图中的 + 号,跳转到创建数据数库页面,点击 创建 按钮,如下图:
|
1. 通过点击图中的 + 号,跳转到创建数据数库页面,点击“创建”按钮,如下图:
|
||||||
|
|
||||||
第一步 点击 + 号;
|
第一步 点击 + 号;
|
||||||

|

|
||||||
|
@ -50,7 +50,7 @@ toc_max_heading_level: 4
|
||||||
弟三步 点击“创建”按钮之后,如下图左边出现数据库名称则创建数据库成功。
|
弟三步 点击“创建”按钮之后,如下图左边出现数据库名称则创建数据库成功。
|
||||||

|

|
||||||
|
|
||||||
2. 通过在 Sql 编辑器中数据 sql 语句,点击 执行 按钮,如下图:
|
2. 通过在 SQL 编辑器中数据 sql 语句,点击 执行 按钮,如下图:
|
||||||
|
|
||||||
第一步 输入 sql 语句;
|
第一步 输入 sql 语句;
|
||||||

|

|
||||||
|
@ -201,11 +201,11 @@ toc_max_heading_level: 4
|
||||||
## 工具
|
## 工具
|
||||||
|
|
||||||
通过 “工具” 页面,用户可以了解如下 TDengine 周边工具的使用方法。
|
通过 “工具” 页面,用户可以了解如下 TDengine 周边工具的使用方法。
|
||||||
- TDengine CLI。
|
- TDengine CLI
|
||||||
- taosBenchmark。
|
- taosBenchmark
|
||||||
- taosdump。
|
- taosdump
|
||||||
- TDengine 与 BI 工具的集成,例如 Google Data Studio、Power BI、永洪 BI 等。
|
- TDengine 与 BI 工具的集成,例如 Google Data Studio、Power BI、永洪 BI 等
|
||||||
- TDengine 与 Grafana、Seeq 的集成。
|
- TDengine 与 Grafana、Seeq 的集成
|
||||||
|
|
||||||
## 系统管理
|
## 系统管理
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,7 @@ toc_max_heading_level: 4
|
||||||
|
|
||||||
# 1. 基于 taosdump 进行数据备份恢复
|
# 1. 基于 taosdump 进行数据备份恢复
|
||||||
|
|
||||||
taosdump 是一个开源工具,用于支持从运行中的 TDengine 集群备份数据并将备份的数据恢复到相同或另一个正在运行的 TDengine
|
taosdump 是一个开源工具,用于支持从运行中的 TDengine 集群备份数据并将备份的数据恢复到相同或另一个正在运行的 TDengine 集群中。taosdump 可以将数据库作为逻辑数据单元进行备份,也可以对数据库中指定时间段内的数据记录进行备份。在使用 taosdump 时,可以指定数据备份的目录路径。如果不指定目录路径,taosdump 将默认将数据备份到当前目录。
|
||||||
集群中。taosdump 可以将数据库作为逻辑数据单元进行备份,也可以对数据库中指定时间段内的数据记录进行备份。在使用taosdump
|
|
||||||
时,可以指定数据备份的目录路径。如果不指定目录路径,taosdump 将默认将数据备份到当前目录。
|
|
||||||
|
|
||||||
以下为 taosdump 执行数据备份的使用示例。
|
以下为 taosdump 执行数据备份的使用示例。
|
||||||
|
|
||||||
|
@ -18,14 +16,11 @@ taosdump 是一个开源工具,用于支持从运行中的 TDengine 集群备
|
||||||
taosdump -h localhost -P 6030 -D dbname -o /file/path
|
taosdump -h localhost -P 6030 -D dbname -o /file/path
|
||||||
```
|
```
|
||||||
|
|
||||||
执行上述命令后,taosdump 会连接 localhost:6030 所在的 TDengine 集群,查询数据库 dbname 中的所有数据,并将数据备份到 /f
|
执行上述命令后,taosdump 会连接 localhost:6030 所在的 TDengine 集群,查询数据库 dbname 中的所有数据,并将数据备份到 /file/path 下。
|
||||||
ile/path 下。
|
|
||||||
|
|
||||||
在使用 taosdump 时,如果指定的存储路径已经包含数据文件,taosdump
|
在使用 taosdump 时,如果指定的存储路径已经包含数据文件,taosdump 会提示用户并立即退出,以避免数据被覆盖。这意味着同一存储路径只能用于一次备份。如果你看到相关提示,请谨慎操作,以免误操作导致数据丢失。
|
||||||
会提示用户并立即退出,以避免数据被覆盖。这意味着同一存储路径只能用于一次备份。如果你看到相关提示,请谨慎操作,以免误操作导致数据丢失。
|
|
||||||
|
|
||||||
要将本地指定文件路径中的数据文件恢复到正在运行的 TDengine 集群中,可以通过指定命令行参数和数据文件所在路径来执行 taosdump
|
要将本地指定文件路径中的数据文件恢复到正在运行的 TDengine 集群中,可以通过指定命令行参数和数据文件所在路径来执行 taosdump 命令。以下为 taosdump 执行数据恢复的示例代码。
|
||||||
命令。以下为 taosdump 执行数据恢复的示例代码。
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
taosdump -i /file/path -h localhost -P 6030
|
taosdump -i /file/path -h localhost -P 6030
|
||||||
|
@ -76,6 +71,17 @@ taosExplorer 服务页面中,进入“系统管理 - 备份”页面,在“
|
||||||
8. 备份文件大小:备份文件的大小限制。当备份文件大小达到此限制时,会自动创建新的备份文件。
|
8. 备份文件大小:备份文件的大小限制。当备份文件大小达到此限制时,会自动创建新的备份文件。
|
||||||
9. 文件压缩等级:备份文件的压缩等级。支持:最快速度、最佳压缩比、兼具速度和压缩比。
|
9. 文件压缩等级:备份文件的压缩等级。支持:最快速度、最佳压缩比、兼具速度和压缩比。
|
||||||
|
|
||||||
|
用户可以通过开启 S3 转储,将备份文件上传至 S3 存储服务上。开启 S3 转储,需要填写以下信息:
|
||||||
|
|
||||||
|
1. S3 节点:S3 节点的地址。
|
||||||
|
2. 访问密钥 ID:访问密钥 ID。
|
||||||
|
3. 访问密钥:访问密钥。
|
||||||
|
4. 存储桶:存储桶名称。
|
||||||
|
5. 区域:存储桶所在的区域。
|
||||||
|
6. 对象前缀:备份文件的对象前缀,类似于 S3 上的目录。
|
||||||
|
7. 本地备份文件的保留时长:本地备份的保留时间,所有早于`当前时间 - backup_retention_period`的文件都需要上传到 S3。
|
||||||
|
8. 本地备份文件的保留个数:本地备份文件的保留个数,本地只保留最新的`backup_retention_size`个备份文件。
|
||||||
|
|
||||||
创建成功后,备份计划会开始按照配置的参数运行。在“备份计划”下的列表中,可以查看已创建的备份计划。
|
创建成功后,备份计划会开始按照配置的参数运行。在“备份计划”下的列表中,可以查看已创建的备份计划。
|
||||||
|
|
||||||
备份计划支持以下操作:
|
备份计划支持以下操作:
|
||||||
|
|
|
@ -27,10 +27,8 @@ TDengine 支持 WAL 机制,实现数据的容错能力,保证数据的高可
|
||||||
|
|
||||||
- 第 3 步,访问 TDengine 集群 B,创建一个与集群 A 中数据库 db1 参数配置相同的数据库 db2。
|
- 第 3 步,访问 TDengine 集群 B,创建一个与集群 A 中数据库 db1 参数配置相同的数据库 db2。
|
||||||
|
|
||||||
- 第 4 步,通过 Web 浏览器访问集群 B 的 taosExplorer 服务,在 “数据浏览器” 页面找到 db2,在 “查看数据库配置” 选项中可以获取该数据库的 DSN,例如 taos+ws://root:taosdata@clusterB:6041/db2
|
- 第 4 步,通过 Web 浏览器访问集群 B 的 taosExplorer 服务,在 “数据浏览器” 页面找到 db2,在 “查看数据库配置” 选项中可以获取该数据库的 DSN,例如 `taos+ws://root:taosdata@clusterB:6041/db2`
|
||||||
|
|
||||||
- 第 5 步,在 taosExplorer 服务的“系统管理 - 数据同步”页面新增一个数据同步任务,在任务配置信息中填写需要同步的数据库 db1 和目标数据库 db2 的 DSN,完成创建任务后即可启动数据同步。
|
- 第 5 步,在 taosExplorer 服务的“系统管理 - 数据同步”页面新增一个数据同步任务,在任务配置信息中填写需要同步的数据库 db1 和目标数据库 db2 的 DSN,完成创建任务后即可启动数据同步。
|
||||||
|
|
||||||
- 第 6 步,访问集群 B,可以看到集群 B 中的数据库 db2 源源不断写入来自集群 A 数据库 db1 的数据,直至两个集群的数据库数据量基本保持一致。至此,一个简单的基于
|
- 第 6 步,访问集群 B,可以看到集群 B 中的数据库 db2 源源不断写入来自集群 A 数据库 db1 的数据,直至两个集群的数据库数据量基本保持一致。至此,一个简单的基于 TDengine Enterprise 的数据灾备体系搭建完成。
|
||||||
|
|
||||||
TDengine Enterprise 的数据灾备体系搭建完成。
|
|
|
@ -5,10 +5,10 @@ toc_max_heading_level: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
本节介绍 TDengine Enterprise 特有的多级存储功能,其作用是将较近的热度较高的数据存储在高速介质上,而时间久远热度很低的数据存储在低成本介质上,达成了以下目标:
|
本节介绍 TDengine Enterprise 特有的多级存储功能,其作用是将较近的热度较高的数据存储在高速介质上,而时间久远热度很低的数据存储在低成本介质上,达成了以下目标:
|
||||||
- 降低存储成本 -- 将数据分级存储后,海量极冷数据存入廉价存储介质带来显著经济性
|
- **降低存储成本**:将数据分级存储后,海量极冷数据存入廉价存储介质带来显著经济性
|
||||||
- 提升写入性能 -- 得益于每级存储可支持多个挂载点,WAL 预写日志也支持 0 级的多挂载点并行写入,极大提升写入性能(实际场景测得支持持续写入每秒 3 亿测点以上),在机械硬盘上可获得极高磁盘 IO 吞吐(实测可达 2GB/s)
|
- **提升写入性能**:得益于每级存储可支持多个挂载点,WAL 预写日志也支持 0 级的多挂载点并行写入,极大提升写入性能(实际场景测得支持持续写入每秒 3 亿测点以上),在机械硬盘上可获得极高磁盘 IO 吞吐(实测可达 2GB/s)
|
||||||
- 方便维护 -- 配置好各级存储挂载点后,系统数据迁移等工作,无需人工干预;存储扩容更灵活、方便
|
- **方便维护**:配置好各级存储挂载点后,系统数据迁移等工作,无需人工干预;存储扩容更灵活、方便
|
||||||
- 对 SQL 透明 -- 无论查询的数据是否跨级,一条 SQL 可返回所有数据,简单高效
|
- **对 SQL 透明**:无论查询的数据是否跨级,一条 SQL 可返回所有数据,简单高效
|
||||||
|
|
||||||
多级存储所涉及的各层存储介质都是本地存储设备。除了本地存储设备之外,TDengine Enterprise 还支持使用对象存储(S3),将最冷的一批数据保存在最廉价的介质上,以进一步降低存储成本,并在必要时仍然可以进行查询,且数据存储在哪里也对 SQL 透明。支持对象存储在 3.3.0.0 版本中首次发布,建议使用最新版本。
|
多级存储所涉及的各层存储介质都是本地存储设备。除了本地存储设备之外,TDengine Enterprise 还支持使用对象存储(S3),将最冷的一批数据保存在最廉价的介质上,以进一步降低存储成本,并在必要时仍然可以进行查询,且数据存储在哪里也对 SQL 透明。支持对象存储在 3.3.0.0 版本中首次发布,建议使用最新版本。
|
||||||
|
|
||||||
|
@ -26,9 +26,11 @@ dataDir [path] <level> <primary>
|
||||||
```
|
```
|
||||||
|
|
||||||
- path: 挂载点的文件夹路径。
|
- path: 挂载点的文件夹路径。
|
||||||
- level: 介质存储等级,取值为 0,1,2。 0 级存储最新的数据,1 级存储次新的数据,2 级存储最老的数据,省略默认为 0。 各级存储之间的数据流向:0 级存储 -> 1 级存储 -> 2 级存储。 同一存储等级可挂载多个硬盘,同一存储等级上的数据文件分布在该存储等级的所有硬盘上。 需要说明的是,数据在不同级别的存储介质上的移动,是由系统自动完成的,用户无需干预。
|
- level:介质存储等级,取值为 0、1、2。 0 级存储最新的数据,1 级存储次新的数据,2 级存储最老的数据,省略默认为 0。各级存储之间的数据流向:0 级存储 -> 1 级存储 -> 2 级存储。 同一存储等级可挂载多个硬盘,同一存储等级上的数据文件分布在该存储等级的所有硬盘上。需要说明的是,数据在不同级别的存储介质上的移动,是由系统自动完成的,用户无需干预。
|
||||||
- primary: 是否为主挂载点,0(否)或 1(是),省略默认为 1。
|
- primary:是否为主挂载点,0(否)或 1(是),省略默认为 1。
|
||||||
|
|
||||||
在配置中,只允许一个主挂载点的存在(level=0,primary=1),例如采用如下的配置方式:
|
在配置中,只允许一个主挂载点的存在(level=0,primary=1),例如采用如下的配置方式:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
dataDir /mnt/data1 0 1
|
dataDir /mnt/data1 0 1
|
||||||
dataDir /mnt/data2 0 0
|
dataDir /mnt/data2 0 0
|
||||||
|
@ -38,7 +40,8 @@ dataDir /mnt/data5 2 0
|
||||||
dataDir /mnt/data6 2 0
|
dataDir /mnt/data6 2 0
|
||||||
```
|
```
|
||||||
|
|
||||||
**注意** 1. 多级存储不允许跨级配置,合法的配置方案有:仅 0 级,仅 0 级+ 1 级,以及 0 级+ 1 级+ 2 级。而不允许只配置 level=0 和 level=2,而不配置 level=1。
|
**注意**
|
||||||
|
1. 多级存储不允许跨级配置,合法的配置方案有:仅 0 级、仅 0 级 + 1 级、以及 0 级 + 1 级 + 2 级。而不允许只配置 level=0 和 level=2,而不配置 level=1。
|
||||||
2. 禁止手动移除使用中的挂载盘,挂载盘目前不支持非本地的网络盘。
|
2. 禁止手动移除使用中的挂载盘,挂载盘目前不支持非本地的网络盘。
|
||||||
|
|
||||||
### 负载均衡
|
### 负载均衡
|
||||||
|
@ -74,13 +77,13 @@ dataDir /mnt/data6 2 0
|
||||||
|
|
||||||
| 参数名称 | 参数含义 |
|
| 参数名称 | 参数含义 |
|
||||||
|:---------------------|:-----------------------------------------------|
|
|:---------------------|:-----------------------------------------------|
|
||||||
| s3EndPoint | 用户所在地域的 COS 服务域名,支持 http 和 https,bucket 的区域需要与 endpoint 的保持一致,否则无法访问。 |
|
| s3EndPoint | 用户所在地域的 COS 服务域名,支持 http 和 https,bucket 的区域需要与 endpoint 的保持一致,否则无法访问 |
|
||||||
| s3AccessKey | 冒号分隔的用户 SecretId:SecretKey。例如:AKIDsQmwsfKxTo2A6nGVXZN0UlofKn6JRRSJ:lIdoy99ygEacU7iHfogaN2Xq0yumSm1E |
|
| s3AccessKey | 冒号分隔的用户 SecretId:SecretKey。例如:AKIDsQmwsfKxTo2A6nGVXZN0UlofKn6JRRSJ:lIdoy99ygEacU7iHfogaN2Xq0yumSm1E |
|
||||||
| s3BucketName | 存储桶名称,减号后面是用户注册 COS 服务的 AppId。其中 AppId 是 COS 特有,AWS 和阿里云都没有,配置时需要作为 bucket name 的一部分,使用减号分隔。参数值均为字符串类型,但不需要引号。例如:test0711-1309024725 |
|
| s3BucketName | 存储桶名称,减号后面是用户注册 COS 服务的 AppId。其中 AppId 是 COS 特有,AWS 和阿里云都没有,配置时需要作为 bucket name 的一部分,使用减号分隔。参数值均为字符串类型,但不需要引号。例如:test0711-1309024725 |
|
||||||
| s3UploadDelaySec | data 文件持续多长时间不再变动后上传至 s3,单位:秒。最小值:1;最大值:2592000(30天),默认值 60 秒 |
|
| s3UploadDelaySec | data 文件持续多长时间不再变动后上传至 s3,单位:秒。最小值:1;最大值:2592000(30天),默认值 60 秒 |
|
||||||
| s3PageCacheSize | S3 page cache 缓存页数目,单位:页。最小值:4;最大值:1024*1024*1024。 ,默认值 4096|
|
| s3PageCacheSize | S3 page cache 缓存页数目,单位:页。最小值:4;最大值:1024*1024*1024。 ,默认值 4096|
|
||||||
| s3MigrateIntervalSec | 本地数据文件自动上传 S3 的触发周期,单位为秒。最小值:600;最大值:100000。默认值 3600 |
|
| s3MigrateIntervalSec | 本地数据文件自动上传 S3 的触发周期,单位为秒。最小值:600;最大值:100000。默认值 3600 |
|
||||||
| s3MigrateEnabled | 是否自动进行 S3 迁移,默认值为 0,表示关闭自动 S3 迁移,可配置为 1。 |
|
| s3MigrateEnabled | 是否自动进行 S3 迁移,默认值为 0,表示关闭自动 S3 迁移,可配置为 1 |
|
||||||
|
|
||||||
#### 检查配置参数可用性
|
#### 检查配置参数可用性
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ alter_user_clause: {
|
||||||
- pass:修改用户密码。
|
- pass:修改用户密码。
|
||||||
- enable:是否启用用户。1 表示启用此用户,0 表示禁用此用户。
|
- enable:是否启用用户。1 表示启用此用户,0 表示禁用此用户。
|
||||||
- sysinfo :用户是否可查看系统信息。1 表示可以查看系统信息,0 表示不可以查看系统信息
|
- sysinfo :用户是否可查看系统信息。1 表示可以查看系统信息,0 表示不可以查看系统信息
|
||||||
- createdb:用户是否可创建数据库。1 表示可以创建数据库,0 表示不可以创建数据库。// 从 TDengine 企业版 3.3.2.0 开始支持
|
- createdb:用户是否可创建数据库。1 表示可以创建数据库,0 表示不可以创建数据库。从 TDengine 企业版 3.3.2.0 开始支持。
|
||||||
|
|
||||||
如下 SQL 禁用 test 用户。
|
如下 SQL 禁用 test 用户。
|
||||||
```sql
|
```sql
|
||||||
|
@ -76,7 +76,7 @@ drop user user_name
|
||||||
|
|
||||||
### 库和表的授权
|
### 库和表的授权
|
||||||
|
|
||||||
在 TDengine 中,库和表的权限分为 read (读)和 write (写)两种。这些权限可以单独授予,也可以同时授予用户。
|
在 TDengine 中,库和表的权限分为 read 和 write 两种。这些权限可以单独授予,也可以同时授予用户。
|
||||||
|
|
||||||
- read 权限:拥有 read 权限的用户仅能查询库或表中的数据,而无法对数据进行修改或删除。这种权限适用于需要访问数据但不需要对数据进行写入操作的场景,如数据分析师、报表生成器等。
|
- read 权限:拥有 read 权限的用户仅能查询库或表中的数据,而无法对数据进行修改或删除。这种权限适用于需要访问数据但不需要对数据进行写入操作的场景,如数据分析师、报表生成器等。
|
||||||
- write 权限:拥有 write 权限的用户可以向库或表中写入数据。这种权限适用于需要对数据进行写入操作的场景,如数据采集器、数据处理器等。如果只拥有 write 权限而没有 read 权限,则只能写入数据但不能查询数据。
|
- write 权限:拥有 write 权限的用户可以向库或表中写入数据。这种权限适用于需要对数据进行写入操作的场景,如数据采集器、数据处理器等。如果只拥有 write 权限而没有 read 权限,则只能写入数据但不能查询数据。
|
||||||
|
@ -101,10 +101,11 @@ resources :{
|
||||||
```
|
```
|
||||||
|
|
||||||
相关参数说明如下。
|
相关参数说明如下。
|
||||||
- resources :可以访问的库或表。. 之前为数据库名称,. 之后为表名称。dbname.tbname 的意思是名为 dbname 的数据库中的 tbname 表必须为普通表或超级表。dbname.* 的意思是名为 dbname 的数据库中的所有表。*.* 的意思是所有数据库中的所有表。
|
- resources:可以访问的库或表。`.` 之前为数据库名称,`.` 之后为表名称。`dbname.tbname` 的意思是名为 dbname 的数据库中的 tbname 表必须为普通表或超级表。`dbname.*` 的意思是名为 dbname 的数据库中的所有表。`*.*` 的意思是所有数据库中的所有表。
|
||||||
- tag_filter:超级表的过滤条件。
|
- tag_filter:超级表的过滤条件。
|
||||||
|
|
||||||
上述 SQL 既可以授权一个库、所有库,也可以授权一个库下的普通表或超级表,还可以通过 dbname.tbname 和 with 子句的组合授权符合过滤条件的一张超级表下的所有子表。
|
上述 SQL 既可以授权一个库、所有库,也可以授权一个库下的普通表或超级表,还可以通过 `dbname.tbname` 和 `with` 子句的组合授权符合过滤条件的一张超级表下的所有子表。
|
||||||
|
|
||||||
如下 SQL 将数据库 power 的 read 权限授权给用户 test。
|
如下 SQL 将数据库 power 的 read 权限授权给用户 test。
|
||||||
```sql
|
```sql
|
||||||
grant read on power to test
|
grant read on power to test
|
||||||
|
|
|
@ -28,20 +28,20 @@ ALTER USER TEST DROP HOST HOST_NAME1
|
||||||
```
|
```
|
||||||
说明
|
说明
|
||||||
- 开源版和企业版本都能添加成功,且可以查询到,但是开源版本不会对 IP 做任何限制。
|
- 开源版和企业版本都能添加成功,且可以查询到,但是开源版本不会对 IP 做任何限制。
|
||||||
- create user u_write pass 'taosdata1' host 'iprange1','iprange2', 可以一次添加多个 iprange, 服务端会做去重,去重的逻辑是需要 iprange 完全一样
|
- `create user u_write pass 'taosdata1' host 'iprange1','iprange2'`,可以一次添加多个 ip range,服务端会做去重,去重的逻辑是需要 ip range 完全一样
|
||||||
- 默认会把 127.0.0.1 添加到白名单列表,且在白名单列表可以查询
|
- 默认会把 `127.0.0.1` 添加到白名单列表,且在白名单列表可以查询
|
||||||
- 集群的节点 IP 集合会自动添加到白名单列表,但是查询不到。
|
- 集群的节点 IP 集合会自动添加到白名单列表,但是查询不到。
|
||||||
- taosadaper 和 taosd 不在一个机器的时候,需要把 taosadaper IP 手动添加到 taosd 白名单列表中
|
- taosadaper 和 taosd 不在一个机器的时候,需要把 taosadaper IP 手动添加到 taosd 白名单列表中
|
||||||
- 集群情况下,各个节点 enableWhiteList 成一样,或者全为 false,或者全为 true, 要不然集群无法启动
|
- 集群情况下,各个节点 enableWhiteList 成一样,或者全为 false,或者全为 true,要不然集群无法启动
|
||||||
- 白名单变更生效时间 1s,不超过 2s, 每次变更对收发性能有些微影响(多一次判断,可以忽略),变更完之后、影响忽略不计, 变更过程中对集群没有影响,对正在访问客户端也没有影响(假设这些客户端的 IP 包含在 white list 内)
|
- 白名单变更生效时间 1s,不超过 2s,每次变更对收发性能有些微影响(多一次判断,可以忽略),变更完之后、影响忽略不计,变更过程中对集群没有影响,对正在访问客户端也没有影响(假设这些客户端的 IP 包含在 white list 内)
|
||||||
- 如果添加两个 ip range, 192.168.1.1/16(假设为 A), 192.168.1.1/24(假设为 B), 严格来说,A 包含了 B,但是考虑情况太复杂,并不会对 A 和 B 做合并
|
- 如果添加两个 ip range,192.168.1.1/16(假设为 A),192.168.1.1/24(假设为 B),严格来说,A 包含了 B,但是考虑情况太复杂,并不会对 A 和 B 做合并
|
||||||
- 要删除的时候,必须严格匹配。 也就是如果添加的是 192.168.1.1/24, 要删除也是 192.168.1.1/24
|
- 要删除的时候,必须严格匹配。 也就是如果添加的是 192.168.1.1/24,要删除也是 192.168.1.1/24
|
||||||
- 只有 root 才有权限对其他用户增删 ip white list
|
- 只有 root 才有权限对其他用户增删 ip white list
|
||||||
- 兼容之前的版本,但是不支持从当前版本回退到之前版本
|
- 兼容之前的版本,但是不支持从当前版本回退到之前版本
|
||||||
- x.x.x.x/32 和 x.x.x.x 属于同一个 iprange, 显示为 x.x.x.x
|
- x.x.x.x/32 和 x.x.x.x 属于同一个 iprange,显示为 x.x.x.x
|
||||||
- 如果客户端拿到的 0.0.0.0/0, 说明没有开启白名单
|
- 如果客户端拿到的 0.0.0.0/0,说明没有开启白名单
|
||||||
- 如果白名单发生了改变, 客户端会在 heartbeat 里检测到。
|
- 如果白名单发生了改变, 客户端会在 heartbeat 里检测到。
|
||||||
- 针对一个 user, 添加的 IP 个数上限是 2048
|
- 针对一个 user,添加的 IP 个数上限是 2048
|
||||||
|
|
||||||
## 审计日志
|
## 审计日志
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ TDengine 先对用户操作进行记录和管理,然后将这些作为审计
|
||||||
|
|
||||||
| 参数名称 | 参数含义 |
|
| 参数名称 | 参数含义 |
|
||||||
|:-------------:|:--------------------------------------------------------:|
|
|:-------------:|:--------------------------------------------------------:|
|
||||||
|audit | 是否打开审计日志,默认值为 0。1 为开启,0 为关闭 |
|
|audit | 是否打开审计日志,1 为开启,0 为关闭,默认值为 0。 |
|
||||||
|monitorFqdn | 接收审计日志的 taosKeeper 所在服务器的 FQDN |
|
|monitorFqdn | 接收审计日志的 taosKeeper 所在服务器的 FQDN |
|
||||||
|monitorPort | 接收审计日志的 taosKeeper 服务所用端口 |
|
|monitorPort | 接收审计日志的 taosKeeper 服务所用端口 |
|
||||||
|monitorCompaction | 上报数据时是否进行压缩 |
|
|monitorCompaction | 上报数据时是否进行压缩 |
|
||||||
|
@ -64,7 +64,7 @@ TDengine 先对用户操作进行记录和管理,然后将这些作为审计
|
||||||
|
|
||||||
| 参数名称 | 参数含义 |
|
| 参数名称 | 参数含义 |
|
||||||
|:-------------:|:--------------------------------------------------------:|
|
|:-------------:|:--------------------------------------------------------:|
|
||||||
|auditDB | 用于存放审计日志的数据库的名字,默认值为 "audit" ,taosKeeper 在收到上报的审计日志后会判断该数据库是否存在,如果不存在会自动创建它 |
|
|auditDB | 用于存放审计日志的数据库的名字,默认值为 "audit",taosKeeper 在收到上报的审计日志后会判断该数据库是否存在,如果不存在会自动创建 |
|
||||||
|
|
||||||
### 数据格式
|
### 数据格式
|
||||||
|
|
||||||
|
@ -88,19 +88,19 @@ TDengine 先对用户操作进行记录和管理,然后将这些作为审计
|
||||||
taosKeeper 会依据上报的审计数据在相应的数据库中自动建立超级表用于存储数据。该超级表的定义如下
|
taosKeeper 会依据上报的审计数据在相应的数据库中自动建立超级表用于存储数据。该超级表的定义如下
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE STABLE operations(ts timestamp, details VARCHAR(64000), User VARCHAR(25), Operation VARCHAR(20), db VARCHAR(65), resource VARCHAR(193), client_add(25)) TAGS (clusterID VARCHAR(64) );
|
create stable operations(ts timestamp, details varchar(64000), user varchar(25), operation varchar(20), db varchar(65), resource varchar(193), client_add(25)) tags (clusterID varchar(64) );
|
||||||
```
|
```
|
||||||
|
|
||||||
其中:
|
其中
|
||||||
1. db 为操作涉及的 database,resource 为操作涉及的资源。
|
1. db 为操作涉及的 database,resource 为操作涉及的资源。
|
||||||
2. User 和 Operation 为数据列,表示哪个用户在该对象上进行了什么操作
|
2. user 和 operation 为数据列,表示哪个用户在该对象上进行了什么操作
|
||||||
3. timestamp 为时间戳列,表示操作发生时的时间
|
3. timestamp 为时间戳列,表示操作发生时的时间
|
||||||
4. details 为该操作的一些补充细节,在大多数操作下是所执行的操作的 SQL 语句。
|
4. details 为该操作的一些补充细节,在大多数操作下是所执行的操作的 SQL 语句。
|
||||||
5. client_add 为客户端地址,包括 ip 和端口
|
5. client_add 为客户端地址,包括 ip 和端口
|
||||||
|
|
||||||
### 操作列表
|
### 操作列表
|
||||||
|
|
||||||
目前审计日志中所记录的操作列表以及每个操作中各字段的含义如下表(注:因为每个操作的实加者即 user 字段、时间戳字段和client_add在所有操作中的含义相同,下表不包含)
|
目前审计日志中所记录的操作列表以及每个操作中各字段的含义(因为每个操作的施加者,即 user、client_add、时间戳字段在所有操作中的含义相同,下表不再描述)
|
||||||
|
|
||||||
| 操作 | Operation | DB | Resource | Details |
|
| 操作 | Operation | DB | Resource | Details |
|
||||||
| ----------------| ----------| ---------| ---------| --------|
|
| ----------------| ----------| ---------| ---------| --------|
|
||||||
|
@ -110,8 +110,8 @@ CREATE STABLE operations(ts timestamp, details VARCHAR(64000), User VARCHAR(25
|
||||||
| create stable | createStb | db name | stable name | SQL |
|
| create stable | createStb | db name | stable name | SQL |
|
||||||
| alter stable | alterStb | db name | stable name | SQL |
|
| alter stable | alterStb | db name | stable name | SQL |
|
||||||
| drop stable | dropStb | db name | stable name | SQL |
|
| drop stable | dropStb | db name | stable name | SQL |
|
||||||
| create user | createUser | NULL | 被创建的用户名 | 用户属性参数, (password除外) |
|
| create user | createUser | NULL | 被创建的用户名 | 用户属性参数, (password 除外) |
|
||||||
| alter user | alterUser | NULL | 被修改的用户名 | 修改密码操作记录的是被修改的参数和新值 (password除外) ;其他操作记录SQL |
|
| alter user | alterUser | NULL | 被修改的用户名 | 修改密码记录被修改的参数和新值 (password 除外),其他操作记录 SQL |
|
||||||
| drop user | dropUser | NULL | 被删除的用户名 | SQL |
|
| drop user | dropUser | NULL | 被删除的用户名 | SQL |
|
||||||
| create topic | createTopic | topic 所在 DB | 创建的 topic 名字 | SQL |
|
| create topic | createTopic | topic 所在 DB | 创建的 topic 名字 | SQL |
|
||||||
| drop topic | cropTopic | topic 所在 DB | 删除的 topic 名字 | SQL |
|
| drop topic | cropTopic | topic 所在 DB | 删除的 topic 名字 | SQL |
|
||||||
|
@ -123,7 +123,7 @@ CREATE STABLE operations(ts timestamp, details VARCHAR(64000), User VARCHAR(25
|
||||||
| create qnode | createQnode | NULL | dnodeId | SQL |
|
| create qnode | createQnode | NULL | dnodeId | SQL |
|
||||||
| drop qnode | dropQnode | NULL | dnodeId | SQL |
|
| drop qnode | dropQnode | NULL | dnodeId | SQL |
|
||||||
| login | login | NULL | NULL | appName |
|
| login | login | NULL | NULL | appName |
|
||||||
| create stream | createStream | NULL | 所创建的 strem 名 | SQL |
|
| create stream | createStream | NULL | 所创建的 stream 名 | SQL |
|
||||||
| drop stream | dropStream | NULL | 所删除的 stream 名 | SQL |
|
| drop stream | dropStream | NULL | 所删除的 stream 名 | SQL |
|
||||||
| grant privileges| grantPrivileges | NULL | 所授予的用户 | SQL |
|
| grant privileges| grantPrivileges | NULL | 所授予的用户 | SQL |
|
||||||
| remove privileges | revokePrivileges | NULL | 被收回权限的用户 | SQL |
|
| remove privileges | revokePrivileges | NULL | 被收回权限的用户 | SQL |
|
||||||
|
@ -171,7 +171,7 @@ database_option: {
|
||||||
```
|
```
|
||||||
|
|
||||||
主要参数说明如下。
|
主要参数说明如下。
|
||||||
encrypt_algorithm:指定数据采用的加密算法。默认是 none,即不采用加密。sm4 表示采用 SM4 加密算法
|
- encrypt_algorithm:指定数据采用的加密算法。默认是 none,即不采用加密。sm4 表示采用 SM4 加密算法
|
||||||
|
|
||||||
### 查看加密配置
|
### 查看加密配置
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ select name, `encrypt_algorithm` from ins_databases;
|
||||||
|
|
||||||
### 查看节点密钥状态
|
### 查看节点密钥状态
|
||||||
|
|
||||||
通过以下的SQL命令参看节点密钥状态:
|
通过以下的 SQL 命令参看节点密钥状态。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
show encryptions;
|
show encryptions;
|
||||||
|
@ -200,12 +200,12 @@ select * from information_schema.ins_encryptions;
|
||||||
```
|
```
|
||||||
key_status 有三种取值:
|
key_status 有三种取值:
|
||||||
- 当节点未设置密钥时,状态列显示 unset。
|
- 当节点未设置密钥时,状态列显示 unset。
|
||||||
- 当密钥被检验成功并且加载后,状态列显示 loaded.
|
- 当密钥被检验成功并且加载后,状态列显示 loaded。
|
||||||
- 当节点未启动,key的状态无法被探知时,状态列显示 unknown
|
- 当节点未启动,key 的状态无法被探知时,状态列显示 unknown。
|
||||||
|
|
||||||
### 更新密钥配置
|
### 更新密钥配置
|
||||||
|
|
||||||
当节点的硬件配置发生变更时,需要通过以下命令更新密钥,与离线配置密钥的命令相同:
|
当节点的硬件配置发生变更时,需要通过以下命令更新密钥,与离线配置密钥的命令相同。
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
taosd -y {encryptKey}
|
taosd -y {encryptKey}
|
||||||
|
|
|
@ -4,7 +4,7 @@ title: TDengine Kafka Connector
|
||||||
description: 使用 TDengine Kafka Connector 的详细指南
|
description: 使用 TDengine Kafka Connector 的详细指南
|
||||||
---
|
---
|
||||||
|
|
||||||
TDengine Kafka Connector 包含两个插件: TDengine Source Connector 和 TDengine Sink Connector。用户只需提供简单的配置文件,就可以将 Kafka 中指定 topic 的数据(批量或实时)同步到 TDengine, 或将 TDengine 中指定数据库的数据(批量或实时)同步到 Kafka。
|
TDengine Kafka Connector 包含 TDengine Source Connector 和 TDengine Sink Connector 两个插件。用户只需提供简单的配置文件,就可以将 Kafka 中指定 topic 的数据(批量或实时)同步到 TDengine,或将 TDengine 中指定数据库的数据(批量或实时)同步到 Kafka。
|
||||||
|
|
||||||
## 什么是 Kafka Connect?
|
## 什么是 Kafka Connect?
|
||||||
|
|
||||||
|
@ -346,16 +346,16 @@ curl -X DELETE http://localhost:8083/connectors/TDengineSourceConnector
|
||||||
|
|
||||||
以下配置项对 TDengine Sink Connector 和 TDengine Source Connector 均适用。
|
以下配置项对 TDengine Sink Connector 和 TDengine Source Connector 均适用。
|
||||||
|
|
||||||
1. `name`: connector 名称。
|
1. `name`:connector 名称。
|
||||||
1. `connector.class`: connector 的完整类名, 如: com.taosdata.kafka.connect.sink.TDengineSinkConnector。
|
1. `connector.class`:connector 的完整类名,例如如 com.taosdata.kafka.connect.sink.TDengineSinkConnector。
|
||||||
1. `tasks.max`: 最大任务数, 默认 1。
|
1. `tasks.max`:最大任务数, 默认 1。
|
||||||
1. `topics`: 需要同步的 topic 列表, 多个用逗号分隔, 如 `topic1,topic2`。
|
1. `topics`:需要同步的 topic 列表,多个用逗号分隔, 如 `topic1,topic2`。
|
||||||
1. `connection.url`: TDengine JDBC 连接字符串, 如 `jdbc:TAOS://127.0.0.1:6030`。
|
1. `connection.url`:TDengine JDBC 连接字符串,如 `jdbc:TAOS://127.0.0.1:6030`。
|
||||||
1. `connection.user`:TDengine 用户名,默认 root。
|
1. `connection.user`:TDengine 用户名,默认 root。
|
||||||
1. `connection.password`:TDengine 用户密码,默认 taosdata。
|
1. `connection.password`:TDengine 用户密码,默认 taosdata。
|
||||||
1. `connection.attempts`:最大尝试连接次数。默认 3。
|
1. `connection.attempts`:最大尝试连接次数。默认 3。
|
||||||
1. `connection.backoff.ms`:创建连接失败重试时间隔时间,单位为 ms。默认 5000。
|
1. `connection.backoff.ms`:创建连接失败重试时间隔时间,单位为 ms。默认 5000。
|
||||||
1. `data.precision`: 使用 InfluxDB 行协议格式时,时间戳的精度。可选值为:
|
1. `data.precision`:使用 InfluxDB 行协议格式时,时间戳的精度。可选值为:
|
||||||
1. ms:表示毫秒
|
1. ms:表示毫秒
|
||||||
1. us:表示微秒
|
1. us:表示微秒
|
||||||
1. ns:表示纳秒
|
1. ns:表示纳秒
|
||||||
|
@ -364,29 +364,29 @@ curl -X DELETE http://localhost:8083/connectors/TDengineSourceConnector
|
||||||
|
|
||||||
1. `connection.database`:目标数据库名。如果指定的数据库不存在会则自动创建。自动建库使用的时间精度为纳秒。默认值为 null。为 null 时目标数据库命名规则参考 `connection.database.prefix` 参数的说明
|
1. `connection.database`:目标数据库名。如果指定的数据库不存在会则自动创建。自动建库使用的时间精度为纳秒。默认值为 null。为 null 时目标数据库命名规则参考 `connection.database.prefix` 参数的说明
|
||||||
2. `connection.database.prefix`:当 connection.database 为 null 时, 目标数据库的前缀。可以包含占位符 '$\{topic}'。比如 kafka_$\{topic}, 对于主题 'orders' 将写入数据库 'kafka_orders'。默认 null。当为 null 时,目标数据库的名字和主题的名字是一致的。
|
2. `connection.database.prefix`:当 connection.database 为 null 时, 目标数据库的前缀。可以包含占位符 '$\{topic}'。比如 kafka_$\{topic}, 对于主题 'orders' 将写入数据库 'kafka_orders'。默认 null。当为 null 时,目标数据库的名字和主题的名字是一致的。
|
||||||
3. `batch.size`: 分批写入每批记录数。当 Sink Connector 一次接收到的数据大于这个值时将分批写入。
|
3. `batch.size`:分批写入每批记录数。当 Sink Connector 一次接收到的数据大于这个值时将分批写入。
|
||||||
4. `max.retries`: 发生错误时的最大重试次数。默认为 1。
|
4. `max.retries`:发生错误时的最大重试次数。默认为 1。
|
||||||
5. `retry.backoff.ms`: 发送错误时重试的时间间隔。单位毫秒,默认为 3000。
|
5. `retry.backoff.ms`:发送错误时重试的时间间隔。单位毫秒,默认为 3000。
|
||||||
6. `db.schemaless`: 数据格式,可选值为:
|
6. `db.schemaless`:数据格式,可选值为:
|
||||||
1. line:代表 InfluxDB 行协议格式
|
1. line:代表 InfluxDB 行协议格式
|
||||||
2. json : 代表 OpenTSDB JSON 格式
|
2. json:代表 OpenTSDB JSON 格式
|
||||||
3. telnet:代表 OpenTSDB Telnet 行协议格式
|
3. telnet:代表 OpenTSDB Telnet 行协议格式
|
||||||
|
|
||||||
### TDengine Source Connector 特有的配置
|
### TDengine Source Connector 特有的配置
|
||||||
|
|
||||||
1. `connection.database`: 源数据库名称,无缺省值。
|
1. `connection.database`:源数据库名称,无缺省值。
|
||||||
1. `topic.prefix`:数据导入 kafka 时使用的 topic 名称的前缀。默认为空字符串 ""。
|
1. `topic.prefix`:数据导入 kafka 时使用的 topic 名称的前缀。默认为空字符串 ""。
|
||||||
1. `timestamp.initial`: 数据同步起始时间。格式为'yyyy-MM-dd HH:mm:ss',若未指定则从指定 DB 中最早的一条记录开始。
|
1. `timestamp.initial`:数据同步起始时间。格式为'yyyy-MM-dd HH:mm:ss',若未指定则从指定 DB 中最早的一条记录开始。
|
||||||
1. `poll.interval.ms`: 检查是否有新建或删除的表的时间间隔,单位为 ms。默认为 1000。
|
1. `poll.interval.ms`:检查是否有新建或删除的表的时间间隔,单位为 ms。默认为 1000。
|
||||||
1. `fetch.max.rows` : 检索数据库时最大检索条数。 默认为 100。
|
1. `fetch.max.rows`:检索数据库时最大检索条数。默认为 100。
|
||||||
1. `query.interval.ms`: 从 TDengine 一次读取数据的时间跨度,需要根据表中的数据特征合理配置,避免一次查询的数据量过大或过小;在具体的环境中建议通过测试设置一个较优值,默认值为 0,即获取到当前最新时间的所有数据。
|
1. `query.interval.ms`:从 TDengine 一次读取数据的时间跨度,需要根据表中的数据特征合理配置,避免一次查询的数据量过大或过小;在具体的环境中建议通过测试设置一个较优值,默认值为 0,即获取到当前最新时间的所有数据。
|
||||||
1. `out.format` : 结果集输出格式。`line` 表示输出格式为 InfluxDB Line 协议格式,`json` 表示输出格式是 json。默认为 line。
|
1. `out.format`:结果集输出格式。`line` 表示输出格式为 InfluxDB Line 协议格式,`json` 表示输出格式是 json。默认为 line。
|
||||||
1. `topic.per.stable`: 如果设置为 true,表示一个超级表对应一个 Kafka topic,topic的命名规则 `<topic.prefix><topic.delimiter><connection.database><topic.delimiter><stable.name>`;如果设置为 false,则指定的 DB 中的所有数据进入一个 Kafka topic,topic 的命名规则为 `<topic.prefix><topic.delimiter><connection.database>`
|
1. `topic.per.stable`:如果设置为 true,表示一个超级表对应一个 Kafka topic,topic的命名规则 `<topic.prefix><topic.delimiter><connection.database><topic.delimiter><stable.name>`;如果设置为 false,则指定的 DB 中的所有数据进入一个 Kafka topic,topic 的命名规则为 `<topic.prefix><topic.delimiter><connection.database>`
|
||||||
1. `topic.ignore.db`: topic 命名规则是否包含 database 名称,true 表示规则为 `<topic.prefix><topic.delimiter><stable.name>`,false 表示规则为 `<topic.prefix><topic.delimiter><connection.database><topic.delimiter><stable.name>`,默认 false。此配置项在 `topic.per.stable` 设置为 false 时不生效。
|
1. `topic.ignore.db`:topic 命名规则是否包含 database 名称,true 表示规则为 `<topic.prefix><topic.delimiter><stable.name>`,false 表示规则为 `<topic.prefix><topic.delimiter><connection.database><topic.delimiter><stable.name>`,默认 false。此配置项在 `topic.per.stable` 设置为 false 时不生效。
|
||||||
1. `topic.delimiter`: topic 名称分割符,默认为 `-`。
|
1. `topic.delimiter`:topic 名称分割符,默认为 `-`。
|
||||||
1. `read.method`: 从 TDengine 读取数据方式,query 或是 subscription。默认为 subscription。
|
1. `read.method`:从 TDengine 读取数据方式,query 或是 subscription。默认为 subscription。
|
||||||
1. `subscription.group.id`: 指定 TDengine 数据订阅的组 id,当 `read.method` 为 subscription 时,此项为必填项。
|
1. `subscription.group.id`:指定 TDengine 数据订阅的组 id,当 `read.method` 为 subscription 时,此项为必填项。
|
||||||
1. `subscription.from`: 指定 TDengine 数据订阅起始位置,latest 或是 earliest。默认为 latest。
|
1. `subscription.from`:指定 TDengine 数据订阅起始位置,latest 或是 earliest。默认为 latest。
|
||||||
|
|
||||||
## 其他说明
|
## 其他说明
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,11 @@ TDengine连接器兼容TDengine Cloud和TDengine Server两种类型的数据源
|
||||||
- URL 和 TDengine Cloud Token,可以从 TDengine Cloud 的实例列表中获取。
|
- URL 和 TDengine Cloud Token,可以从 TDengine Cloud 的实例列表中获取。
|
||||||
- 数据库名称和超级表名称。
|
- 数据库名称和超级表名称。
|
||||||
- 查询数据的开始时间和结束时间。
|
- 查询数据的开始时间和结束时间。
|
||||||
|
|
||||||
第 2 步,Looker Studio 会根据配置自动加载所配置的 TDengine 数据库下的超级表的字段和标签。
|
第 2 步,Looker Studio 会根据配置自动加载所配置的 TDengine 数据库下的超级表的字段和标签。
|
||||||
|
|
||||||
第 3 步,点击页面右上角的 Explore 按钮,即查看从 TDengine 数据库中加载的数据。
|
第 3 步,点击页面右上角的 Explore 按钮,即查看从 TDengine 数据库中加载的数据。
|
||||||
|
|
||||||
第 4 步,根据需求,利用 Looker Studio 提供的图表,进行数据可视化的配置。
|
第 4 步,根据需求,利用 Looker Studio 提供的图表,进行数据可视化的配置。
|
||||||
|
|
||||||
**注意** 在第一次使用时,请根据页面提示,对 Looker Studio 的 TDengine 连接器进行访问授权。
|
**注意** 在第一次使用时,请根据页面提示,对 Looker Studio 的 TDengine 连接器进行访问授权。
|
|
@ -29,7 +29,7 @@ Power BI 是由 Microsoft 提供的一种商业分析工具。通过配置使用
|
||||||
### 使用说明
|
### 使用说明
|
||||||
|
|
||||||
为了充分发挥 Power BI 在分析 TDengine中 数据方面的优势,用户需要先理解维度、度量、窗口切分查询、数据切分查询、时序和相关性等核心概念,之后通过自定义的 SQL 导入数据。
|
为了充分发挥 Power BI 在分析 TDengine中 数据方面的优势,用户需要先理解维度、度量、窗口切分查询、数据切分查询、时序和相关性等核心概念,之后通过自定义的 SQL 导入数据。
|
||||||
- 维度:通常是分类(文本)数据,描述设备、测点、型号等类别信息。在 TDengine 的超级表中,使用标签列存储数据的维度信息,可以通过形如 “select distinct tbname, tag1, tag2 from supertable” 的SQL语法快速获得维度信息。
|
- 维度:通常是分类(文本)数据,描述设备、测点、型号等类别信息。在 TDengine 的超级表中,使用标签列存储数据的维度信息,可以通过形如 `select distinct tbname, tag1, tag2 from supertable` 的 SQL 语法快速获得维度信息。
|
||||||
- 度量:可以用于进行计算的定量(数值)字段,常见计算有求和、取平均值和最小值等。如果测点的采集周期为 1s,那么一年就有 3000 多万条记录,把这些数据全部导入 Power BI 会严重影响其执行效率。在 TDengine 中,用户可以使用数据切分查询、窗口切分查询等语法,结合与窗口相关的伪列,把降采样后的数据导入 Power BI 中,具体语法请参阅 TDengine 官方文档的特色查询功能部分。
|
- 度量:可以用于进行计算的定量(数值)字段,常见计算有求和、取平均值和最小值等。如果测点的采集周期为 1s,那么一年就有 3000 多万条记录,把这些数据全部导入 Power BI 会严重影响其执行效率。在 TDengine 中,用户可以使用数据切分查询、窗口切分查询等语法,结合与窗口相关的伪列,把降采样后的数据导入 Power BI 中,具体语法请参阅 TDengine 官方文档的特色查询功能部分。
|
||||||
- 窗口切分查询:比如温度传感器每秒采集一次数据,但须查询每隔 10min 的温度平均值,在这种场景下可以使用窗口子句来获得需要的降采样查询结果,对应的 SQL 形如 `select tbname, _wstart date,avg(temperature) temp from table interval(10m)`,其中,`_wstart` 是伪列,表示时间窗口起始时间,10m 表示时间窗口的持续时间,`avg(temperature)` 表示时间窗口内的聚合值。
|
- 窗口切分查询:比如温度传感器每秒采集一次数据,但须查询每隔 10min 的温度平均值,在这种场景下可以使用窗口子句来获得需要的降采样查询结果,对应的 SQL 形如 `select tbname, _wstart date,avg(temperature) temp from table interval(10m)`,其中,`_wstart` 是伪列,表示时间窗口起始时间,10m 表示时间窗口的持续时间,`avg(temperature)` 表示时间窗口内的聚合值。
|
||||||
- 数据切分查询:如果需要同时获取很多温度传感器的聚合数值,可对数据进行切分,然后在切分出的数据空间内进行一系列的计算,对应的 SQL 形如 `partition by part_list`。数据切分子句最常见的用法是在超级表查询中按标签将子表数据进行切分,将每个子表的数据独立出来,形成一条条独立的时间序列,方便针对各种时序场景的统计分析。
|
- 数据切分查询:如果需要同时获取很多温度传感器的聚合数值,可对数据进行切分,然后在切分出的数据空间内进行一系列的计算,对应的 SQL 形如 `partition by part_list`。数据切分子句最常见的用法是在超级表查询中按标签将子表数据进行切分,将每个子表的数据独立出来,形成一条条独立的时间序列,方便针对各种时序场景的统计分析。
|
||||||
|
|
|
@ -8,8 +8,8 @@ Tableau 是一款知名的商业智能工具,它支持多种数据源,可方
|
||||||
## 前置条件
|
## 前置条件
|
||||||
|
|
||||||
准备以下环境:
|
准备以下环境:
|
||||||
- TDengine 3.3.5.4 以上版本集群已部署并正常运行(企业及社区版均可)
|
- TDengine 3.3.5.8 以上版本集群已部署并正常运行(企业及社区版均可)。
|
||||||
- taosAdapter 能够正常运行。详细参考 [taosAdapter 参考手册](../../../reference/components/taosadapter)
|
- taosAdapter 能够正常运行。详细参考 [taosAdapter 参考手册](../../../reference/components/taosadapter)。
|
||||||
- Tableau 桌面版安装并运行(如未安装,请下载并安装 Windows 操作系统 64 位 [Tableau 桌面版](https://www.tableau.com/products/desktop/download) )。安装 Tableau 桌面版请参考 [官方文档](https://www.tableau.com)。
|
- Tableau 桌面版安装并运行(如未安装,请下载并安装 Windows 操作系统 64 位 [Tableau 桌面版](https://www.tableau.com/products/desktop/download) )。安装 Tableau 桌面版请参考 [官方文档](https://www.tableau.com)。
|
||||||
- 从 TDengine 官网下载最新的 Windows 操作系统 X64 客户端驱动程序,并进行安装。详细参考 [安装 ODBC 驱动](../../../reference/connector/odbc/#安装)。
|
- 从 TDengine 官网下载最新的 Windows 操作系统 X64 客户端驱动程序,并进行安装。详细参考 [安装 ODBC 驱动](../../../reference/connector/odbc/#安装)。
|
||||||
|
|
||||||
|
@ -18,7 +18,11 @@ Tableau 是一款知名的商业智能工具,它支持多种数据源,可方
|
||||||
|
|
||||||
**第 1 步**,在Windows操作系统的开始菜单中搜索并打开“ODBC数据源(64位)”管理工具并进行配置。详细参考[配置ODBC数据源](../../../reference/connector/odbc/#配置数据源)。
|
**第 1 步**,在Windows操作系统的开始菜单中搜索并打开“ODBC数据源(64位)”管理工具并进行配置。详细参考[配置ODBC数据源](../../../reference/connector/odbc/#配置数据源)。
|
||||||
|
|
||||||
**第 2 步**,在 Windows 系统环境下启动 Tableau,之后在其连接页面中搜索 “ODBC”,并选择 “其他数据库 (ODBC)”。
|
:::tip
|
||||||
|
需要注意的是,在为 Tableau 配置 ODBC 数据源时,TDengine ODBC 数据源配置页面中的【数据库】配置项为必填项,需选择一个可成功连接的数据库。
|
||||||
|
:::
|
||||||
|
|
||||||
|
**第 2 步**,在 Windows 系统环境下启动 Tableau,之后在其连接页面中搜索 “ODBC”,并选择 “其他数据库 (ODBC)”。 对于 Tableau 的使用的ODBC数据源,在其 TDengine ODBC 数据源配置页面的【数据库】的配置项为必填,需要选择可以连接的数据库。
|
||||||
|
|
||||||
**第 3 步**,点击 `DSN` 单选框,接着选择已配置好的数据源(MyTDengine),然后点击`连接`按钮。待连接成功后,删除字符串附加部分的内容,最后点击`登录`按钮即可。
|
**第 3 步**,点击 `DSN` 单选框,接着选择已配置好的数据源(MyTDengine),然后点击`连接`按钮。待连接成功后,删除字符串附加部分的内容,最后点击`登录`按钮即可。
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ title: 与 Excel 集成
|
||||||
## 前置条件
|
## 前置条件
|
||||||
|
|
||||||
准备以下环境:
|
准备以下环境:
|
||||||
- TDengine 3.3.5.7 以上版本集群已部署并正常运行(企业及社区版均可)。
|
- TDengine 3.3.5.8 以上版本集群已部署并正常运行(企业及社区版均可)。
|
||||||
- taosAdapter 能够正常运行,详细参考 [taosAdapter 参考手册](../../../reference/components/taosadapter)。
|
- taosAdapter 能够正常运行,详细参考 [taosAdapter 参考手册](../../../reference/components/taosadapter)。
|
||||||
- Excel 安装并运行, 如未安装,请下载并安装, 具体操作请参考 Microsoft 官方文档。
|
- Excel 安装并运行, 如未安装,请下载并安装, 具体操作请参考 Microsoft 官方文档。
|
||||||
- 从 TDengine 官网下载最新的 Windows 操作系统 X64 客户端驱动程序并进行安装,详细参考 [安装 ODBC 驱动](../../../reference/connector/odbc/#安装)。
|
- 从 TDengine 官网下载最新的 Windows 操作系统 X64 客户端驱动程序并进行安装,详细参考 [安装 ODBC 驱动](../../../reference/connector/odbc/#安装)。
|
||||||
|
|
|
@ -19,8 +19,7 @@ qStudio 是一款免费的多平台 SQL 数据分析工具,可以轻松浏览
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
2. 配置 TDengine 连接,填入主机地址、端口号、用户名和密码。如果 TDengine 部署在本机,可以只填用户名和密码,默认用户名为 root,默认密码为 taosdata。点击“Test”可以对连接是否可用进行测试。如果本机没有安装 TDengine Java
|
2. 配置 TDengine 连接,填入主机地址、端口号、用户名和密码。如果 TDengine 部署在本机,可以只填用户名和密码,默认用户名为 root,默认密码为 taosdata。点击 “Test” 可以对连接是否可用进行测试。如果本机没有安装 TDengine Java 连接器,qStudio 会提示下载安装。
|
||||||
连接器,qStudio 会提示下载安装。
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
|
@ -87,14 +87,14 @@ TDengine 为了解决实际应用中对不同数据采集点数据进行高效
|
||||||

|

|
||||||
|
|
||||||
具体步骤说明如下。
|
具体步骤说明如下。
|
||||||
第 1 步,taosc 从 mnode 获取库和表的元数据信息。
|
- 第 1 步,taosc 从 mnode 获取库和表的元数据信息。
|
||||||
第 2 步,mnode 返回请求的元数据信息。
|
- 第 2 步,mnode 返回请求的元数据信息。
|
||||||
第 3 步,taosc 向超级表所属的每个 vnode 发送查询请求。
|
- 第 3 步,taosc 向超级表所属的每个 vnode 发送查询请求。
|
||||||
第 4 步,vnode 启动本地查询,在获得查询结果后返回查询响应。
|
- 第 4 步,vnode 启动本地查询,在获得查询结果后返回查询响应。
|
||||||
第 5 步,taosc 向聚合节点(在本例中为 qnode)发送查询请求。
|
- 第 5 步,taosc 向聚合节点(在本例中为 qnode)发送查询请求。
|
||||||
第 6 步,qnode 向每个 vnode 节点发送数据请求消息来拉取数据。
|
- 第 6 步,qnode 向每个 vnode 节点发送数据请求消息来拉取数据。
|
||||||
第 7 步,vnode 返回本节点的查询计算结果。
|
- 第 7 步,vnode 返回本节点的查询计算结果。
|
||||||
第 8 步,qnode 完成多节点数据聚合后将最终查询结果返回给客户端。
|
- 第 8 步,qnode 完成多节点数据聚合后将最终查询结果返回给客户端。
|
||||||
|
|
||||||
TDengine 为了提升聚合计算速度,在 vnode 内实现了标签数据与时序数据的分离存储。首先,系统会在内存中过滤标签数据,以确定需要参与聚合操作的表的集合。这样做可以显著减少需要扫描的数据集,从而大幅提高聚合计算的速度。
|
TDengine 为了提升聚合计算速度,在 vnode 内实现了标签数据与时序数据的分离存储。首先,系统会在内存中过滤标签数据,以确定需要参与聚合操作的表的集合。这样做可以显著减少需要扫描的数据集,从而大幅提高聚合计算的速度。
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,11 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ANAL_FORECAST_DEFAULT_ROWS 10
|
#define ANALY_FORECAST_DEFAULT_ROWS 10
|
||||||
#define ANAL_FORECAST_DEFAULT_CONF 95
|
#define ANALY_FORECAST_DEFAULT_CONF 95
|
||||||
#define ANAL_FORECAST_DEFAULT_WNCHECK 1
|
#define ANALY_FORECAST_DEFAULT_WNCHECK 1
|
||||||
#define ANAL_FORECAST_MAX_ROWS 40000
|
#define ANALY_FORECAST_MAX_ROWS 40000
|
||||||
#define ANAL_ANOMALY_WINDOW_MAX_ROWS 40000
|
#define ANALY_ANOMALY_WINDOW_MAX_ROWS 40000
|
||||||
#define ANALY_DEFAULT_TIMEOUT 60
|
#define ANALY_DEFAULT_TIMEOUT 60
|
||||||
#define ANALY_MAX_TIMEOUT 600
|
#define ANALY_MAX_TIMEOUT 600
|
||||||
|
|
||||||
|
@ -69,28 +69,28 @@ int32_t taosAnalyticsInit();
|
||||||
void taosAnalyticsCleanup();
|
void taosAnalyticsCleanup();
|
||||||
SJson *taosAnalySendReqRetJson(const char *url, EAnalyHttpType type, SAnalyticBuf *pBuf, int64_t timeout);
|
SJson *taosAnalySendReqRetJson(const char *url, EAnalyHttpType type, SAnalyticBuf *pBuf, int64_t timeout);
|
||||||
|
|
||||||
int32_t taosAnalGetAlgoUrl(const char *algoName, EAnalAlgoType type, char *url, int32_t urlLen);
|
int32_t taosAnalyGetAlgoUrl(const char *algoName, EAnalAlgoType type, char *url, int32_t urlLen);
|
||||||
bool taosAnalGetOptStr(const char *option, const char *optName, char *optValue, int32_t optMaxLen);
|
bool taosAnalyGetOptStr(const char *option, const char *optName, char *optValue, int32_t optMaxLen);
|
||||||
bool taosAnalGetOptInt(const char *option, const char *optName, int64_t *optValue);
|
bool taosAnalyGetOptInt(const char *option, const char *optName, int64_t *optValue);
|
||||||
int64_t taosAnalGetVersion();
|
int64_t taosAnalyGetVersion();
|
||||||
void taosAnalUpdate(int64_t newVer, SHashObj *pHash);
|
void taosAnalyUpdate(int64_t newVer, SHashObj *pHash);
|
||||||
|
|
||||||
int32_t tsosAnalBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols);
|
int32_t tsosAnalyBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols);
|
||||||
int32_t taosAnalBufWriteOptStr(SAnalyticBuf *pBuf, const char *optName, const char *optVal);
|
int32_t taosAnalyBufWriteOptStr(SAnalyticBuf *pBuf, const char *optName, const char *optVal);
|
||||||
int32_t taosAnalBufWriteOptInt(SAnalyticBuf *pBuf, const char *optName, int64_t optVal);
|
int32_t taosAnalyBufWriteOptInt(SAnalyticBuf *pBuf, const char *optName, int64_t optVal);
|
||||||
int32_t taosAnalBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optName, float optVal);
|
int32_t taosAnalyBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optName, float optVal);
|
||||||
int32_t taosAnalBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, const char *colName);
|
int32_t taosAnalyBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, const char *colName);
|
||||||
int32_t taosAnalBufWriteDataBegin(SAnalyticBuf *pBuf);
|
int32_t taosAnalyBufWriteDataBegin(SAnalyticBuf *pBuf);
|
||||||
int32_t taosAnalBufWriteColBegin(SAnalyticBuf *pBuf, int32_t colIndex);
|
int32_t taosAnalyBufWriteColBegin(SAnalyticBuf *pBuf, int32_t colIndex);
|
||||||
int32_t taosAnalBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, void *colValue);
|
int32_t taosAnalyBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, void *colValue);
|
||||||
int32_t taosAnalBufWriteColEnd(SAnalyticBuf *pBuf, int32_t colIndex);
|
int32_t taosAnalyBufWriteColEnd(SAnalyticBuf *pBuf, int32_t colIndex);
|
||||||
int32_t taosAnalBufWriteDataEnd(SAnalyticBuf *pBuf);
|
int32_t taosAnalyBufWriteDataEnd(SAnalyticBuf *pBuf);
|
||||||
int32_t taosAnalBufClose(SAnalyticBuf *pBuf);
|
int32_t taosAnalyBufClose(SAnalyticBuf *pBuf);
|
||||||
void taosAnalBufDestroy(SAnalyticBuf *pBuf);
|
void taosAnalyBufDestroy(SAnalyticBuf *pBuf);
|
||||||
|
|
||||||
const char *taosAnalysisAlgoType(EAnalAlgoType algoType);
|
const char *taosAnalysisAlgoType(EAnalAlgoType algoType);
|
||||||
EAnalAlgoType taosAnalAlgoInt(const char *algoName);
|
EAnalAlgoType taosAnalyAlgoInt(const char *algoName);
|
||||||
const char *taosAnalAlgoUrlStr(EAnalAlgoType algoType);
|
const char *taosAnalyAlgoUrlStr(EAnalAlgoType algoType);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -653,9 +653,9 @@ enum { RAND_ERR_MEMORY = 1, RAND_ERR_FILE = 2, RAND_ERR_NETWORK = 4 };
|
||||||
#define AUDIT_OPERATION_LEN 20
|
#define AUDIT_OPERATION_LEN 20
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ANAL_ALGO_TYPE_ANOMALY_DETECT = 0,
|
ANALY_ALGO_TYPE_ANOMALY_DETECT = 0,
|
||||||
ANAL_ALGO_TYPE_FORECAST = 1,
|
ANALY_ALGO_TYPE_FORECAST = 1,
|
||||||
ANAL_ALGO_TYPE_END,
|
ANALY_ALGO_TYPE_END,
|
||||||
} EAnalAlgoType;
|
} EAnalAlgoType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -15,8 +15,10 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||||
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-${cpuType} /tini
|
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-${cpuType} /tini
|
||||||
RUN chmod +x /tini
|
RUN chmod +x /tini
|
||||||
|
|
||||||
RUN tar -zxf ${pkgFile} && \
|
RUN tar -zxf /root/${pkgFile} && \
|
||||||
|
cd /root/${dirName}/ && \
|
||||||
/bin/bash /root/${dirName}/install.sh -e no && \
|
/bin/bash /root/${dirName}/install.sh -e no && \
|
||||||
|
cd /root/ && \
|
||||||
rm /root/${pkgFile} && \
|
rm /root/${pkgFile} && \
|
||||||
rm -rf /root/${dirName} && \
|
rm -rf /root/${dirName} && \
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
|
|
|
@ -34,38 +34,38 @@ typedef struct {
|
||||||
} SCurlResp;
|
} SCurlResp;
|
||||||
|
|
||||||
static SAlgoMgmt tsAlgos = {0};
|
static SAlgoMgmt tsAlgos = {0};
|
||||||
static int32_t taosAnalBufGetCont(SAnalyticBuf *pBuf, char **ppCont, int64_t *pContLen);
|
static int32_t taosAnalyBufGetCont(SAnalyticBuf *pBuf, char **ppCont, int64_t *pContLen);
|
||||||
|
|
||||||
const char *taosAnalysisAlgoType(EAnalAlgoType type) {
|
const char *taosAnalysisAlgoType(EAnalAlgoType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ANAL_ALGO_TYPE_ANOMALY_DETECT:
|
case ANALY_ALGO_TYPE_ANOMALY_DETECT:
|
||||||
return "anomaly-detection";
|
return "anomaly-detection";
|
||||||
case ANAL_ALGO_TYPE_FORECAST:
|
case ANALY_ALGO_TYPE_FORECAST:
|
||||||
return "forecast";
|
return "forecast";
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *taosAnalAlgoUrlStr(EAnalAlgoType type) {
|
const char *taosAnalyAlgoUrlStr(EAnalAlgoType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ANAL_ALGO_TYPE_ANOMALY_DETECT:
|
case ANALY_ALGO_TYPE_ANOMALY_DETECT:
|
||||||
return "anomaly-detect";
|
return "anomaly-detect";
|
||||||
case ANAL_ALGO_TYPE_FORECAST:
|
case ANALY_ALGO_TYPE_FORECAST:
|
||||||
return "forecast";
|
return "forecast";
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EAnalAlgoType taosAnalAlgoInt(const char *name) {
|
EAnalAlgoType taosAnalyAlgoInt(const char *name) {
|
||||||
for (EAnalAlgoType i = 0; i < ANAL_ALGO_TYPE_END; ++i) {
|
for (EAnalAlgoType i = 0; i < ANALY_ALGO_TYPE_END; ++i) {
|
||||||
if (strcasecmp(name, taosAnalysisAlgoType(i)) == 0) {
|
if (strcasecmp(name, taosAnalysisAlgoType(i)) == 0) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ANAL_ALGO_TYPE_END;
|
return ANALY_ALGO_TYPE_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalyticsInit() {
|
int32_t taosAnalyticsInit() {
|
||||||
|
@ -90,7 +90,7 @@ int32_t taosAnalyticsInit() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void taosAnalFreeHash(SHashObj *hash) {
|
static void taosAnalyFreeHash(SHashObj *hash) {
|
||||||
void *pIter = taosHashIterate(hash, NULL);
|
void *pIter = taosHashIterate(hash, NULL);
|
||||||
while (pIter != NULL) {
|
while (pIter != NULL) {
|
||||||
SAnalyticsUrl *pUrl = (SAnalyticsUrl *)pIter;
|
SAnalyticsUrl *pUrl = (SAnalyticsUrl *)pIter;
|
||||||
|
@ -105,12 +105,12 @@ void taosAnalyticsCleanup() {
|
||||||
if (taosThreadMutexDestroy(&tsAlgos.lock) != 0) {
|
if (taosThreadMutexDestroy(&tsAlgos.lock) != 0) {
|
||||||
uError("failed to destroy anal lock");
|
uError("failed to destroy anal lock");
|
||||||
}
|
}
|
||||||
taosAnalFreeHash(tsAlgos.hash);
|
taosAnalyFreeHash(tsAlgos.hash);
|
||||||
tsAlgos.hash = NULL;
|
tsAlgos.hash = NULL;
|
||||||
uInfo("analysis env is cleaned up");
|
uInfo("analysis env is cleaned up");
|
||||||
}
|
}
|
||||||
|
|
||||||
void taosAnalUpdate(int64_t newVer, SHashObj *pHash) {
|
void taosAnalyUpdate(int64_t newVer, SHashObj *pHash) {
|
||||||
if (newVer > tsAlgos.ver) {
|
if (newVer > tsAlgos.ver) {
|
||||||
if (taosThreadMutexLock(&tsAlgos.lock) == 0) {
|
if (taosThreadMutexLock(&tsAlgos.lock) == 0) {
|
||||||
SHashObj *hash = tsAlgos.hash;
|
SHashObj *hash = tsAlgos.hash;
|
||||||
|
@ -119,14 +119,14 @@ void taosAnalUpdate(int64_t newVer, SHashObj *pHash) {
|
||||||
if (taosThreadMutexUnlock(&tsAlgos.lock) != 0) {
|
if (taosThreadMutexUnlock(&tsAlgos.lock) != 0) {
|
||||||
uError("failed to unlock hash")
|
uError("failed to unlock hash")
|
||||||
}
|
}
|
||||||
taosAnalFreeHash(hash);
|
taosAnalyFreeHash(hash);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
taosAnalFreeHash(pHash);
|
taosAnalyFreeHash(pHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool taosAnalGetOptStr(const char *option, const char *optName, char *optValue, int32_t optMaxLen) {
|
bool taosAnalyGetOptStr(const char *option, const char *optName, char *optValue, int32_t optMaxLen) {
|
||||||
char buf[TSDB_ANALYTIC_ALGO_OPTION_LEN] = {0};
|
char buf[TSDB_ANALYTIC_ALGO_OPTION_LEN] = {0};
|
||||||
char *pStart = NULL;
|
char *pStart = NULL;
|
||||||
char *pEnd = NULL;
|
char *pEnd = NULL;
|
||||||
|
@ -163,7 +163,7 @@ bool taosAnalGetOptStr(const char *option, const char *optName, char *optValue,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool taosAnalGetOptInt(const char *option, const char *optName, int64_t *optValue) {
|
bool taosAnalyGetOptInt(const char *option, const char *optName, int64_t *optValue) {
|
||||||
char buf[TSDB_ANALYTIC_ALGO_OPTION_LEN] = {0};
|
char buf[TSDB_ANALYTIC_ALGO_OPTION_LEN] = {0};
|
||||||
int32_t bufLen = tsnprintf(buf, sizeof(buf), "%s=", optName);
|
int32_t bufLen = tsnprintf(buf, sizeof(buf), "%s=", optName);
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ bool taosAnalGetOptInt(const char *option, const char *optName, int64_t *optValu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalGetAlgoUrl(const char *algoName, EAnalAlgoType type, char *url, int32_t urlLen) {
|
int32_t taosAnalyGetAlgoUrl(const char *algoName, EAnalAlgoType type, char *url, int32_t urlLen) {
|
||||||
int32_t code = 0;
|
int32_t code = 0;
|
||||||
char name[TSDB_ANALYTIC_ALGO_KEY_LEN] = {0};
|
char name[TSDB_ANALYTIC_ALGO_KEY_LEN] = {0};
|
||||||
int32_t nameLen = 1 + tsnprintf(name, sizeof(name) - 1, "%d:%s", type, algoName);
|
int32_t nameLen = 1 + tsnprintf(name, sizeof(name) - 1, "%d:%s", type, algoName);
|
||||||
|
@ -205,7 +205,7 @@ int32_t taosAnalGetAlgoUrl(const char *algoName, EAnalAlgoType type, char *url,
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t taosAnalGetVersion() { return tsAlgos.ver; }
|
int64_t taosAnalyGetVersion() { return tsAlgos.ver; }
|
||||||
|
|
||||||
static size_t taosCurlWriteData(char *pCont, size_t contLen, size_t nmemb, void *userdata) {
|
static size_t taosCurlWriteData(char *pCont, size_t contLen, size_t nmemb, void *userdata) {
|
||||||
SCurlResp *pRsp = userdata;
|
SCurlResp *pRsp = userdata;
|
||||||
|
@ -324,7 +324,7 @@ SJson *taosAnalySendReqRetJson(const char *url, EAnalyHttpType type, SAnalyticBu
|
||||||
goto _OVER;
|
goto _OVER;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
code = taosAnalBufGetCont(pBuf, &pCont, &contentLen);
|
code = taosAnalyBufGetCont(pBuf, &pCont, &contentLen);
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
terrno = code;
|
terrno = code;
|
||||||
goto _OVER;
|
goto _OVER;
|
||||||
|
@ -356,7 +356,7 @@ _OVER:
|
||||||
return pJson;
|
return pJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufGetCont(const char *fileName, char **ppCont, int64_t *pContLen) {
|
static int32_t taosAnalyJsonBufGetCont(const char *fileName, char **ppCont, int64_t *pContLen) {
|
||||||
int32_t code = 0;
|
int32_t code = 0;
|
||||||
int64_t contLen;
|
int64_t contLen;
|
||||||
char *pCont = NULL;
|
char *pCont = NULL;
|
||||||
|
@ -395,7 +395,7 @@ _OVER:
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteOptInt(SAnalyticBuf *pBuf, const char *optName, int64_t optVal) {
|
static int32_t taosAnalyJsonBufWriteOptInt(SAnalyticBuf *pBuf, const char *optName, int64_t optVal) {
|
||||||
char buf[64] = {0};
|
char buf[64] = {0};
|
||||||
int32_t bufLen = tsnprintf(buf, sizeof(buf), "\"%s\": %" PRId64 ",\n", optName, optVal);
|
int32_t bufLen = tsnprintf(buf, sizeof(buf), "\"%s\": %" PRId64 ",\n", optName, optVal);
|
||||||
if (taosWriteFile(pBuf->filePtr, buf, bufLen) != bufLen) {
|
if (taosWriteFile(pBuf->filePtr, buf, bufLen) != bufLen) {
|
||||||
|
@ -404,7 +404,7 @@ static int32_t taosAnalJsonBufWriteOptInt(SAnalyticBuf *pBuf, const char *optNam
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteOptStr(SAnalyticBuf *pBuf, const char *optName, const char *optVal) {
|
static int32_t taosAnalyJsonBufWriteOptStr(SAnalyticBuf *pBuf, const char *optName, const char *optVal) {
|
||||||
char buf[128] = {0};
|
char buf[128] = {0};
|
||||||
int32_t bufLen = tsnprintf(buf, sizeof(buf), "\"%s\": \"%s\",\n", optName, optVal);
|
int32_t bufLen = tsnprintf(buf, sizeof(buf), "\"%s\": \"%s\",\n", optName, optVal);
|
||||||
if (taosWriteFile(pBuf->filePtr, buf, bufLen) != bufLen) {
|
if (taosWriteFile(pBuf->filePtr, buf, bufLen) != bufLen) {
|
||||||
|
@ -413,7 +413,7 @@ static int32_t taosAnalJsonBufWriteOptStr(SAnalyticBuf *pBuf, const char *optNam
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optName, float optVal) {
|
static int32_t taosAnalyJsonBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optName, float optVal) {
|
||||||
char buf[128] = {0};
|
char buf[128] = {0};
|
||||||
int32_t bufLen = tsnprintf(buf, sizeof(buf), "\"%s\": %f,\n", optName, optVal);
|
int32_t bufLen = tsnprintf(buf, sizeof(buf), "\"%s\": %f,\n", optName, optVal);
|
||||||
if (taosWriteFile(pBuf->filePtr, buf, bufLen) != bufLen) {
|
if (taosWriteFile(pBuf->filePtr, buf, bufLen) != bufLen) {
|
||||||
|
@ -422,7 +422,7 @@ static int32_t taosAnalJsonBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optN
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteStr(SAnalyticBuf *pBuf, const char *buf, int32_t bufLen) {
|
static int32_t taosAnalyJsonBufWriteStr(SAnalyticBuf *pBuf, const char *buf, int32_t bufLen) {
|
||||||
if (bufLen <= 0) {
|
if (bufLen <= 0) {
|
||||||
bufLen = strlen(buf);
|
bufLen = strlen(buf);
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,7 @@ static int32_t taosAnalJsonBufWriteStr(SAnalyticBuf *pBuf, const char *buf, int3
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteStart(SAnalyticBuf *pBuf) { return taosAnalJsonBufWriteStr(pBuf, "{\n", 0); }
|
static int32_t taosAnalyJsonBufWriteStart(SAnalyticBuf *pBuf) { return taosAnalyJsonBufWriteStr(pBuf, "{\n", 0); }
|
||||||
|
|
||||||
static int32_t tsosAnalJsonBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) {
|
static int32_t tsosAnalJsonBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) {
|
||||||
pBuf->filePtr = taosOpenFile(pBuf->fileName, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_WRITE_THROUGH);
|
pBuf->filePtr = taosOpenFile(pBuf->fileName, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_WRITE_THROUGH);
|
||||||
|
@ -445,7 +445,7 @@ static int32_t tsosAnalJsonBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) {
|
||||||
pBuf->numOfCols = numOfCols;
|
pBuf->numOfCols = numOfCols;
|
||||||
|
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON) {
|
||||||
return taosAnalJsonBufWriteStart(pBuf);
|
return taosAnalyJsonBufWriteStart(pBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32_t i = 0; i < numOfCols; ++i) {
|
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||||
|
@ -458,16 +458,16 @@ static int32_t tsosAnalJsonBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return taosAnalJsonBufWriteStart(pBuf);
|
return taosAnalyJsonBufWriteStart(pBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, const char *colName) {
|
static int32_t taosAnalyJsonBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, const char *colName) {
|
||||||
char buf[128] = {0};
|
char buf[128] = {0};
|
||||||
bool first = (colIndex == 0);
|
bool first = (colIndex == 0);
|
||||||
bool last = (colIndex == pBuf->numOfCols - 1);
|
bool last = (colIndex == pBuf->numOfCols - 1);
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
if (taosAnalJsonBufWriteStr(pBuf, "\"schema\": [\n", 0) != 0) {
|
if (taosAnalyJsonBufWriteStr(pBuf, "\"schema\": [\n", 0) != 0) {
|
||||||
return terrno;
|
return terrno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,7 +479,7 @@ static int32_t taosAnalJsonBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last) {
|
if (last) {
|
||||||
if (taosAnalJsonBufWriteStr(pBuf, "],\n", 0) != 0) {
|
if (taosAnalyJsonBufWriteStr(pBuf, "],\n", 0) != 0) {
|
||||||
return terrno;
|
return terrno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,11 +487,11 @@ static int32_t taosAnalJsonBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteDataBegin(SAnalyticBuf *pBuf) {
|
static int32_t taosAnalyJsonBufWriteDataBegin(SAnalyticBuf *pBuf) {
|
||||||
return taosAnalJsonBufWriteStr(pBuf, "\"data\": [\n", 0);
|
return taosAnalyJsonBufWriteStr(pBuf, "\"data\": [\n", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteStrUseCol(SAnalyticBuf *pBuf, const char *buf, int32_t bufLen, int32_t colIndex) {
|
static int32_t taosAnalyJsonBufWriteStrUseCol(SAnalyticBuf *pBuf, const char *buf, int32_t bufLen, int32_t colIndex) {
|
||||||
if (bufLen <= 0) {
|
if (bufLen <= 0) {
|
||||||
bufLen = strlen(buf);
|
bufLen = strlen(buf);
|
||||||
}
|
}
|
||||||
|
@ -511,20 +511,20 @@ static int32_t taosAnalJsonBufWriteStrUseCol(SAnalyticBuf *pBuf, const char *buf
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteColBegin(SAnalyticBuf *pBuf, int32_t colIndex) {
|
static int32_t taosAnalyJsonBufWriteColBegin(SAnalyticBuf *pBuf, int32_t colIndex) {
|
||||||
return taosAnalJsonBufWriteStrUseCol(pBuf, "[\n", 0, colIndex);
|
return taosAnalyJsonBufWriteStrUseCol(pBuf, "[\n", 0, colIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteColEnd(SAnalyticBuf *pBuf, int32_t colIndex) {
|
static int32_t taosAnalyJsonBufWriteColEnd(SAnalyticBuf *pBuf, int32_t colIndex) {
|
||||||
if (colIndex == pBuf->numOfCols - 1) {
|
if (colIndex == pBuf->numOfCols - 1) {
|
||||||
return taosAnalJsonBufWriteStrUseCol(pBuf, "\n]\n", 0, colIndex);
|
return taosAnalyJsonBufWriteStrUseCol(pBuf, "\n]\n", 0, colIndex);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return taosAnalJsonBufWriteStrUseCol(pBuf, "\n],\n", 0, colIndex);
|
return taosAnalyJsonBufWriteStrUseCol(pBuf, "\n],\n", 0, colIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, void *colValue) {
|
static int32_t taosAnalyJsonBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, void *colValue) {
|
||||||
char buf[64];
|
char buf[64];
|
||||||
int32_t bufLen = 0;
|
int32_t bufLen = 0;
|
||||||
|
|
||||||
|
@ -575,10 +575,10 @@ static int32_t taosAnalJsonBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
pBuf->pCols[colIndex].numOfRows++;
|
pBuf->pCols[colIndex].numOfRows++;
|
||||||
return taosAnalJsonBufWriteStrUseCol(pBuf, buf, bufLen, colIndex);
|
return taosAnalyJsonBufWriteStrUseCol(pBuf, buf, bufLen, colIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteDataEnd(SAnalyticBuf *pBuf) {
|
static int32_t taosAnalyJsonBufWriteDataEnd(SAnalyticBuf *pBuf) {
|
||||||
int32_t code = 0;
|
int32_t code = 0;
|
||||||
char *pCont = NULL;
|
char *pCont = NULL;
|
||||||
int64_t contLen = 0;
|
int64_t contLen = 0;
|
||||||
|
@ -593,10 +593,10 @@ static int32_t taosAnalJsonBufWriteDataEnd(SAnalyticBuf *pBuf) {
|
||||||
code = taosCloseFile(&pCol->filePtr);
|
code = taosCloseFile(&pCol->filePtr);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
code = taosAnalJsonBufGetCont(pBuf->pCols[i].fileName, &pCont, &contLen);
|
code = taosAnalyJsonBufGetCont(pBuf->pCols[i].fileName, &pCont, &contLen);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
code = taosAnalJsonBufWriteStr(pBuf, pCont, contLen);
|
code = taosAnalyJsonBufWriteStr(pBuf, pCont, contLen);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
taosMemoryFreeClear(pCont);
|
taosMemoryFreeClear(pCont);
|
||||||
|
@ -604,18 +604,18 @@ static int32_t taosAnalJsonBufWriteDataEnd(SAnalyticBuf *pBuf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return taosAnalJsonBufWriteStr(pBuf, "],\n", 0);
|
return taosAnalyJsonBufWriteStr(pBuf, "],\n", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalJsonBufWriteEnd(SAnalyticBuf *pBuf) {
|
static int32_t taosAnalyJsonBufWriteEnd(SAnalyticBuf *pBuf) {
|
||||||
int32_t code = taosAnalJsonBufWriteOptInt(pBuf, "rows", pBuf->pCols[0].numOfRows);
|
int32_t code = taosAnalyJsonBufWriteOptInt(pBuf, "rows", pBuf->pCols[0].numOfRows);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
return taosAnalJsonBufWriteStr(pBuf, "\"protocol\": 1.0\n}", 0);
|
return taosAnalyJsonBufWriteStr(pBuf, "\"protocol\": 1.0\n}", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalJsonBufClose(SAnalyticBuf *pBuf) {
|
int32_t taosAnalJsonBufClose(SAnalyticBuf *pBuf) {
|
||||||
int32_t code = taosAnalJsonBufWriteEnd(pBuf);
|
int32_t code = taosAnalyJsonBufWriteEnd(pBuf);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
if (pBuf->filePtr != NULL) {
|
if (pBuf->filePtr != NULL) {
|
||||||
|
@ -640,7 +640,7 @@ int32_t taosAnalJsonBufClose(SAnalyticBuf *pBuf) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void taosAnalBufDestroy(SAnalyticBuf *pBuf) {
|
void taosAnalyBufDestroy(SAnalyticBuf *pBuf) {
|
||||||
if (pBuf->fileName[0] != 0) {
|
if (pBuf->fileName[0] != 0) {
|
||||||
if (pBuf->filePtr != NULL) (void)taosCloseFile(&pBuf->filePtr);
|
if (pBuf->filePtr != NULL) (void)taosCloseFile(&pBuf->filePtr);
|
||||||
// taosRemoveFile(pBuf->fileName);
|
// taosRemoveFile(pBuf->fileName);
|
||||||
|
@ -664,7 +664,7 @@ void taosAnalBufDestroy(SAnalyticBuf *pBuf) {
|
||||||
pBuf->numOfCols = 0;
|
pBuf->numOfCols = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tsosAnalBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) {
|
int32_t tsosAnalyBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return tsosAnalJsonBufOpen(pBuf, numOfCols);
|
return tsosAnalJsonBufOpen(pBuf, numOfCols);
|
||||||
} else {
|
} else {
|
||||||
|
@ -672,79 +672,79 @@ int32_t tsosAnalBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteOptStr(SAnalyticBuf *pBuf, const char *optName, const char *optVal) {
|
int32_t taosAnalyBufWriteOptStr(SAnalyticBuf *pBuf, const char *optName, const char *optVal) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteOptStr(pBuf, optName, optVal);
|
return taosAnalyJsonBufWriteOptStr(pBuf, optName, optVal);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteOptInt(SAnalyticBuf *pBuf, const char *optName, int64_t optVal) {
|
int32_t taosAnalyBufWriteOptInt(SAnalyticBuf *pBuf, const char *optName, int64_t optVal) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteOptInt(pBuf, optName, optVal);
|
return taosAnalyJsonBufWriteOptInt(pBuf, optName, optVal);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optName, float optVal) {
|
int32_t taosAnalyBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optName, float optVal) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteOptFloat(pBuf, optName, optVal);
|
return taosAnalyJsonBufWriteOptFloat(pBuf, optName, optVal);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, const char *colName) {
|
int32_t taosAnalyBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, const char *colName) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteColMeta(pBuf, colIndex, colType, colName);
|
return taosAnalyJsonBufWriteColMeta(pBuf, colIndex, colType, colName);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteDataBegin(SAnalyticBuf *pBuf) {
|
int32_t taosAnalyBufWriteDataBegin(SAnalyticBuf *pBuf) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteDataBegin(pBuf);
|
return taosAnalyJsonBufWriteDataBegin(pBuf);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteColBegin(SAnalyticBuf *pBuf, int32_t colIndex) {
|
int32_t taosAnalyBufWriteColBegin(SAnalyticBuf *pBuf, int32_t colIndex) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteColBegin(pBuf, colIndex);
|
return taosAnalyJsonBufWriteColBegin(pBuf, colIndex);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, void *colValue) {
|
int32_t taosAnalyBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, void *colValue) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteColData(pBuf, colIndex, colType, colValue);
|
return taosAnalyJsonBufWriteColData(pBuf, colIndex, colType, colValue);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteColEnd(SAnalyticBuf *pBuf, int32_t colIndex) {
|
int32_t taosAnalyBufWriteColEnd(SAnalyticBuf *pBuf, int32_t colIndex) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteColEnd(pBuf, colIndex);
|
return taosAnalyJsonBufWriteColEnd(pBuf, colIndex);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufWriteDataEnd(SAnalyticBuf *pBuf) {
|
int32_t taosAnalyBufWriteDataEnd(SAnalyticBuf *pBuf) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufWriteDataEnd(pBuf);
|
return taosAnalyJsonBufWriteDataEnd(pBuf);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosAnalBufClose(SAnalyticBuf *pBuf) {
|
int32_t taosAnalyBufClose(SAnalyticBuf *pBuf) {
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufClose(pBuf);
|
return taosAnalJsonBufClose(pBuf);
|
||||||
} else {
|
} else {
|
||||||
|
@ -752,12 +752,12 @@ int32_t taosAnalBufClose(SAnalyticBuf *pBuf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t taosAnalBufGetCont(SAnalyticBuf *pBuf, char **ppCont, int64_t *pContLen) {
|
static int32_t taosAnalyBufGetCont(SAnalyticBuf *pBuf, char **ppCont, int64_t *pContLen) {
|
||||||
*ppCont = NULL;
|
*ppCont = NULL;
|
||||||
*pContLen = 0;
|
*pContLen = 0;
|
||||||
|
|
||||||
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
if (pBuf->bufType == ANALYTICS_BUF_TYPE_JSON || pBuf->bufType == ANALYTICS_BUF_TYPE_JSON_COL) {
|
||||||
return taosAnalJsonBufGetCont(pBuf->fileName, ppCont, pContLen);
|
return taosAnalyJsonBufGetCont(pBuf->fileName, ppCont, pContLen);
|
||||||
} else {
|
} else {
|
||||||
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
return TSDB_CODE_ANA_BUF_INVALID_TYPE;
|
||||||
}
|
}
|
||||||
|
@ -769,26 +769,26 @@ int32_t taosAnalyticsInit() { return 0; }
|
||||||
void taosAnalyticsCleanup() {}
|
void taosAnalyticsCleanup() {}
|
||||||
SJson *taosAnalySendReqRetJson(const char *url, EAnalyHttpType type, SAnalyticBuf *pBuf, int64_t timeout) { return NULL; }
|
SJson *taosAnalySendReqRetJson(const char *url, EAnalyHttpType type, SAnalyticBuf *pBuf, int64_t timeout) { return NULL; }
|
||||||
|
|
||||||
int32_t taosAnalGetAlgoUrl(const char *algoName, EAnalAlgoType type, char *url, int32_t urlLen) { return 0; }
|
int32_t taosAnalyGetAlgoUrl(const char *algoName, EAnalAlgoType type, char *url, int32_t urlLen) { return 0; }
|
||||||
bool taosAnalGetOptStr(const char *option, const char *optName, char *optValue, int32_t optMaxLen) { return true; }
|
bool taosAnalyGetOptStr(const char *option, const char *optName, char *optValue, int32_t optMaxLen) { return true; }
|
||||||
bool taosAnalGetOptInt(const char *option, const char *optName, int64_t *optValue) { return true; }
|
bool taosAnalyGetOptInt(const char *option, const char *optName, int64_t *optValue) { return true; }
|
||||||
int64_t taosAnalGetVersion() { return 0; }
|
int64_t taosAnalyGetVersion() { return 0; }
|
||||||
void taosAnalUpdate(int64_t newVer, SHashObj *pHash) {}
|
void taosAnalyUpdate(int64_t newVer, SHashObj *pHash) {}
|
||||||
|
|
||||||
int32_t tsosAnalBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) { return 0; }
|
int32_t tsosAnalyBufOpen(SAnalyticBuf *pBuf, int32_t numOfCols) { return 0; }
|
||||||
int32_t taosAnalBufWriteOptStr(SAnalyticBuf *pBuf, const char *optName, const char *optVal) { return 0; }
|
int32_t taosAnalyBufWriteOptStr(SAnalyticBuf *pBuf, const char *optName, const char *optVal) { return 0; }
|
||||||
int32_t taosAnalBufWriteOptInt(SAnalyticBuf *pBuf, const char *optName, int64_t optVal) { return 0; }
|
int32_t taosAnalyBufWriteOptInt(SAnalyticBuf *pBuf, const char *optName, int64_t optVal) { return 0; }
|
||||||
int32_t taosAnalBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optName, float optVal) { return 0; }
|
int32_t taosAnalyBufWriteOptFloat(SAnalyticBuf *pBuf, const char *optName, float optVal) { return 0; }
|
||||||
int32_t taosAnalBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, const char *colName) {
|
int32_t taosAnalyBufWriteColMeta(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, const char *colName) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int32_t taosAnalBufWriteDataBegin(SAnalyticBuf *pBuf) { return 0; }
|
int32_t taosAnalyBufWriteDataBegin(SAnalyticBuf *pBuf) { return 0; }
|
||||||
int32_t taosAnalBufWriteColBegin(SAnalyticBuf *pBuf, int32_t colIndex) { return 0; }
|
int32_t taosAnalyBufWriteColBegin(SAnalyticBuf *pBuf, int32_t colIndex) { return 0; }
|
||||||
int32_t taosAnalBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, void *colValue) { return 0; }
|
int32_t taosAnalyBufWriteColData(SAnalyticBuf *pBuf, int32_t colIndex, int32_t colType, void *colValue) { return 0; }
|
||||||
int32_t taosAnalBufWriteColEnd(SAnalyticBuf *pBuf, int32_t colIndex) { return 0; }
|
int32_t taosAnalyBufWriteColEnd(SAnalyticBuf *pBuf, int32_t colIndex) { return 0; }
|
||||||
int32_t taosAnalBufWriteDataEnd(SAnalyticBuf *pBuf) { return 0; }
|
int32_t taosAnalyBufWriteDataEnd(SAnalyticBuf *pBuf) { return 0; }
|
||||||
int32_t taosAnalBufClose(SAnalyticBuf *pBuf) { return 0; }
|
int32_t taosAnalyBufClose(SAnalyticBuf *pBuf) { return 0; }
|
||||||
void taosAnalBufDestroy(SAnalyticBuf *pBuf) {}
|
void taosAnalyBufDestroy(SAnalyticBuf *pBuf) {}
|
||||||
|
|
||||||
const char *taosAnalysisAlgoType(EAnalAlgoType algoType) { return 0; }
|
const char *taosAnalysisAlgoType(EAnalAlgoType algoType) { return 0; }
|
||||||
EAnalAlgoType taosAnalAlgoInt(const char *algoName) { return 0; }
|
EAnalAlgoType taosAnalAlgoInt(const char *algoName) { return 0; }
|
||||||
|
|
|
@ -94,7 +94,7 @@ static void dmMayShouldUpdateIpWhiteList(SDnodeMgmt *pMgmt, int64_t ver) {
|
||||||
|
|
||||||
static void dmMayShouldUpdateAnalFunc(SDnodeMgmt *pMgmt, int64_t newVer) {
|
static void dmMayShouldUpdateAnalFunc(SDnodeMgmt *pMgmt, int64_t newVer) {
|
||||||
int32_t code = 0;
|
int32_t code = 0;
|
||||||
int64_t oldVer = taosAnalGetVersion();
|
int64_t oldVer = taosAnalyGetVersion();
|
||||||
if (oldVer == newVer) return;
|
if (oldVer == newVer) return;
|
||||||
dDebug("analysis on dnode ver:%" PRId64 ", status ver:%" PRId64, oldVer, newVer);
|
dDebug("analysis on dnode ver:%" PRId64 ", status ver:%" PRId64, oldVer, newVer);
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ void dmSendStatusReq(SDnodeMgmt *pMgmt) {
|
||||||
|
|
||||||
req.statusSeq = pMgmt->statusSeq;
|
req.statusSeq = pMgmt->statusSeq;
|
||||||
req.ipWhiteVer = pMgmt->pData->ipWhiteVer;
|
req.ipWhiteVer = pMgmt->pData->ipWhiteVer;
|
||||||
req.analVer = taosAnalGetVersion();
|
req.analVer = taosAnalyGetVersion();
|
||||||
|
|
||||||
int32_t contLen = tSerializeSStatusReq(NULL, 0, &req);
|
int32_t contLen = tSerializeSStatusReq(NULL, 0, &req);
|
||||||
if (contLen < 0) {
|
if (contLen < 0) {
|
||||||
|
|
|
@ -119,7 +119,7 @@ static bool dmIsForbiddenIp(int8_t forbidden, char *user, uint32_t clientIp) {
|
||||||
static void dmUpdateAnalFunc(SDnodeData *pData, void *pTrans, SRpcMsg *pRpc) {
|
static void dmUpdateAnalFunc(SDnodeData *pData, void *pTrans, SRpcMsg *pRpc) {
|
||||||
SRetrieveAnalAlgoRsp rsp = {0};
|
SRetrieveAnalAlgoRsp rsp = {0};
|
||||||
if (tDeserializeRetrieveAnalAlgoRsp(pRpc->pCont, pRpc->contLen, &rsp) == 0) {
|
if (tDeserializeRetrieveAnalAlgoRsp(pRpc->pCont, pRpc->contLen, &rsp) == 0) {
|
||||||
taosAnalUpdate(rsp.ver, rsp.hash);
|
taosAnalyUpdate(rsp.ver, rsp.hash);
|
||||||
rsp.hash = NULL;
|
rsp.hash = NULL;
|
||||||
}
|
}
|
||||||
tFreeRetrieveAnalAlgoRsp(&rsp);
|
tFreeRetrieveAnalAlgoRsp(&rsp);
|
||||||
|
|
|
@ -649,16 +649,16 @@ void mndRetrieveAlgoList(SMnode* pMnode, SArray* pFc, SArray* pAd) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pObj->numOfAlgos >= ANAL_ALGO_TYPE_END) {
|
if (pObj->numOfAlgos >= ANALY_ALGO_TYPE_END) {
|
||||||
if (pObj->algos[ANAL_ALGO_TYPE_ANOMALY_DETECT] != NULL) {
|
if (pObj->algos[ANALY_ALGO_TYPE_ANOMALY_DETECT] != NULL) {
|
||||||
void* p = taosArrayAddAll(pAd, pObj->algos[ANAL_ALGO_TYPE_ANOMALY_DETECT]);
|
void* p = taosArrayAddAll(pAd, pObj->algos[ANALY_ALGO_TYPE_ANOMALY_DETECT]);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
mError("failed to add retrieved anomaly-detection algorithms, code:%s", tstrerror(terrno));
|
mError("failed to add retrieved anomaly-detection algorithms, code:%s", tstrerror(terrno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pObj->algos[ANAL_ALGO_TYPE_FORECAST] != NULL) {
|
if (pObj->algos[ANALY_ALGO_TYPE_FORECAST] != NULL) {
|
||||||
void* p = taosArrayAddAll(pFc, pObj->algos[ANAL_ALGO_TYPE_FORECAST]);
|
void* p = taosArrayAddAll(pFc, pObj->algos[ANALY_ALGO_TYPE_FORECAST]);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
mError("failed to add retrieved forecast algorithms, code:%s", tstrerror(terrno));
|
mError("failed to add retrieved forecast algorithms, code:%s", tstrerror(terrno));
|
||||||
}
|
}
|
||||||
|
@ -744,11 +744,11 @@ static int32_t mndDecodeAlgoList(SJson *pJson, SAnodeObj *pObj) {
|
||||||
if (details == NULL) return TSDB_CODE_INVALID_JSON_FORMAT;
|
if (details == NULL) return TSDB_CODE_INVALID_JSON_FORMAT;
|
||||||
int32_t numOfDetails = tjsonGetArraySize(details);
|
int32_t numOfDetails = tjsonGetArraySize(details);
|
||||||
|
|
||||||
pObj->algos = taosMemoryCalloc(ANAL_ALGO_TYPE_END, sizeof(SArray *));
|
pObj->algos = taosMemoryCalloc(ANALY_ALGO_TYPE_END, sizeof(SArray *));
|
||||||
if (pObj->algos == NULL) return TSDB_CODE_OUT_OF_MEMORY;
|
if (pObj->algos == NULL) return TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
pObj->numOfAlgos = ANAL_ALGO_TYPE_END;
|
pObj->numOfAlgos = ANALY_ALGO_TYPE_END;
|
||||||
for (int32_t i = 0; i < ANAL_ALGO_TYPE_END; ++i) {
|
for (int32_t i = 0; i < ANALY_ALGO_TYPE_END; ++i) {
|
||||||
pObj->algos[i] = taosArrayInit(4, sizeof(SAnodeAlgo));
|
pObj->algos[i] = taosArrayInit(4, sizeof(SAnodeAlgo));
|
||||||
if (pObj->algos[i] == NULL) return TSDB_CODE_OUT_OF_MEMORY;
|
if (pObj->algos[i] == NULL) return TSDB_CODE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
@ -759,8 +759,8 @@ static int32_t mndDecodeAlgoList(SJson *pJson, SAnodeObj *pObj) {
|
||||||
|
|
||||||
code = tjsonGetStringValue2(detail, "type", buf, sizeof(buf));
|
code = tjsonGetStringValue2(detail, "type", buf, sizeof(buf));
|
||||||
if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
|
if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
|
||||||
EAnalAlgoType type = taosAnalAlgoInt(buf);
|
EAnalAlgoType type = taosAnalyAlgoInt(buf);
|
||||||
if (type < 0 || type >= ANAL_ALGO_TYPE_END) return TSDB_CODE_MND_ANODE_INVALID_ALGO_TYPE;
|
if (type < 0 || type >= ANALY_ALGO_TYPE_END) return TSDB_CODE_MND_ANODE_INVALID_ALGO_TYPE;
|
||||||
|
|
||||||
SJson *algos = tjsonGetObjectItem(detail, "algo");
|
SJson *algos = tjsonGetObjectItem(detail, "algo");
|
||||||
if (algos == NULL) return TSDB_CODE_INVALID_JSON_FORMAT;
|
if (algos == NULL) return TSDB_CODE_INVALID_JSON_FORMAT;
|
||||||
|
@ -887,7 +887,7 @@ static int32_t mndProcessAnalAlgoReq(SRpcMsg *pReq) {
|
||||||
}
|
}
|
||||||
|
|
||||||
url.urlLen = 1 + tsnprintf(url.url, TSDB_ANALYTIC_ANODE_URL_LEN + TSDB_ANALYTIC_ALGO_TYPE_LEN, "%s/%s", pAnode->url,
|
url.urlLen = 1 + tsnprintf(url.url, TSDB_ANALYTIC_ANODE_URL_LEN + TSDB_ANALYTIC_ALGO_TYPE_LEN, "%s/%s", pAnode->url,
|
||||||
taosAnalAlgoUrlStr(url.type));
|
taosAnalyAlgoUrlStr(url.type));
|
||||||
if (taosHashPut(rsp.hash, name, nameLen, &url, sizeof(SAnalyticsUrl)) != 0) {
|
if (taosHashPut(rsp.hash, name, nameLen, &url, sizeof(SAnalyticsUrl)) != 0) {
|
||||||
taosMemoryFree(url.url);
|
taosMemoryFree(url.url);
|
||||||
sdbRelease(pSdb, pAnode);
|
sdbRelease(pSdb, pAnode);
|
||||||
|
|
|
@ -78,19 +78,19 @@ int32_t createAnomalywindowOperatorInfo(SOperatorInfo* downstream, SPhysiNode* p
|
||||||
goto _error;
|
goto _error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!taosAnalGetOptStr(pAnomalyNode->anomalyOpt, "algo", pInfo->algoName, sizeof(pInfo->algoName))) {
|
if (!taosAnalyGetOptStr(pAnomalyNode->anomalyOpt, "algo", pInfo->algoName, sizeof(pInfo->algoName))) {
|
||||||
qError("%s failed to get anomaly_window algorithm name from %s", id, pAnomalyNode->anomalyOpt);
|
qError("%s failed to get anomaly_window algorithm name from %s", id, pAnomalyNode->anomalyOpt);
|
||||||
code = TSDB_CODE_ANA_ALGO_NOT_FOUND;
|
code = TSDB_CODE_ANA_ALGO_NOT_FOUND;
|
||||||
goto _error;
|
goto _error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taosAnalGetAlgoUrl(pInfo->algoName, ANAL_ALGO_TYPE_ANOMALY_DETECT, pInfo->algoUrl, sizeof(pInfo->algoUrl)) != 0) {
|
if (taosAnalyGetAlgoUrl(pInfo->algoName, ANALY_ALGO_TYPE_ANOMALY_DETECT, pInfo->algoUrl, sizeof(pInfo->algoUrl)) != 0) {
|
||||||
qError("%s failed to get anomaly_window algorithm url from %s", id, pInfo->algoName);
|
qError("%s failed to get anomaly_window algorithm url from %s", id, pInfo->algoName);
|
||||||
code = TSDB_CODE_ANA_ALGO_NOT_LOAD;
|
code = TSDB_CODE_ANA_ALGO_NOT_LOAD;
|
||||||
goto _error;
|
goto _error;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasTimeout = taosAnalGetOptInt(pAnomalyNode->anomalyOpt, "timeout", &pInfo->timeout);
|
bool hasTimeout = taosAnalyGetOptInt(pAnomalyNode->anomalyOpt, "timeout", &pInfo->timeout);
|
||||||
if (!hasTimeout) {
|
if (!hasTimeout) {
|
||||||
qDebug("not set the timeout val, set default:%d", ANALY_DEFAULT_TIMEOUT);
|
qDebug("not set the timeout val, set default:%d", ANALY_DEFAULT_TIMEOUT);
|
||||||
pInfo->timeout = ANALY_DEFAULT_TIMEOUT;
|
pInfo->timeout = ANALY_DEFAULT_TIMEOUT;
|
||||||
|
@ -280,7 +280,7 @@ static void anomalyDestroyOperatorInfo(void* param) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t anomalyCacheBlock(SAnomalyWindowOperatorInfo* pInfo, SSDataBlock* pSrc) {
|
static int32_t anomalyCacheBlock(SAnomalyWindowOperatorInfo* pInfo, SSDataBlock* pSrc) {
|
||||||
if (pInfo->anomalySup.cachedRows > ANAL_ANOMALY_WINDOW_MAX_ROWS) {
|
if (pInfo->anomalySup.cachedRows > ANALY_ANOMALY_WINDOW_MAX_ROWS) {
|
||||||
return TSDB_CODE_ANA_ANODE_TOO_MANY_ROWS;
|
return TSDB_CODE_ANA_ANODE_TOO_MANY_ROWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,35 +379,35 @@ static int32_t anomalyAnalysisWindow(SOperatorInfo* pOperator) {
|
||||||
SAnomalyWindowOperatorInfo* pInfo = pOperator->info;
|
SAnomalyWindowOperatorInfo* pInfo = pOperator->info;
|
||||||
SAnomalyWindowSupp* pSupp = &pInfo->anomalySup;
|
SAnomalyWindowSupp* pSupp = &pInfo->anomalySup;
|
||||||
SJson* pJson = NULL;
|
SJson* pJson = NULL;
|
||||||
SAnalyticBuf analBuf = {.bufType = ANALYTICS_BUF_TYPE_JSON};
|
SAnalyticBuf analyBuf = {.bufType = ANALYTICS_BUF_TYPE_JSON};
|
||||||
char dataBuf[64] = {0};
|
char dataBuf[64] = {0};
|
||||||
int32_t code = 0;
|
int32_t code = 0;
|
||||||
int64_t ts = 0;
|
int64_t ts = 0;
|
||||||
int32_t lino = 0;
|
int32_t lino = 0;
|
||||||
const char* pId = GET_TASKID(pOperator->pTaskInfo);
|
const char* pId = GET_TASKID(pOperator->pTaskInfo);
|
||||||
|
|
||||||
snprintf(analBuf.fileName, sizeof(analBuf.fileName), "%s/tdengine-anomaly-%" PRId64 "-%" PRId64, tsTempDir, ts,
|
snprintf(analyBuf.fileName, sizeof(analyBuf.fileName), "%s/tdengine-anomaly-%" PRId64 "-%" PRId64, tsTempDir, ts,
|
||||||
pSupp->groupId);
|
pSupp->groupId);
|
||||||
code = tsosAnalBufOpen(&analBuf, 2);
|
code = tsosAnalyBufOpen(&analyBuf, 2);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
const char* prec = TSDB_TIME_PRECISION_MILLI_STR;
|
const char* prec = TSDB_TIME_PRECISION_MILLI_STR;
|
||||||
if (pInfo->anomalyCol.precision == TSDB_TIME_PRECISION_MICRO) prec = TSDB_TIME_PRECISION_MICRO_STR;
|
if (pInfo->anomalyCol.precision == TSDB_TIME_PRECISION_MICRO) prec = TSDB_TIME_PRECISION_MICRO_STR;
|
||||||
if (pInfo->anomalyCol.precision == TSDB_TIME_PRECISION_NANO) prec = TSDB_TIME_PRECISION_NANO_STR;
|
if (pInfo->anomalyCol.precision == TSDB_TIME_PRECISION_NANO) prec = TSDB_TIME_PRECISION_NANO_STR;
|
||||||
|
|
||||||
code = taosAnalBufWriteColMeta(&analBuf, 0, TSDB_DATA_TYPE_TIMESTAMP, "ts");
|
code = taosAnalyBufWriteColMeta(&analyBuf, 0, TSDB_DATA_TYPE_TIMESTAMP, "ts");
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
code = taosAnalBufWriteColMeta(&analBuf, 1, pInfo->anomalyCol.type, "val");
|
code = taosAnalyBufWriteColMeta(&analyBuf, 1, pInfo->anomalyCol.type, "val");
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
code = taosAnalBufWriteDataBegin(&analBuf);
|
code = taosAnalyBufWriteDataBegin(&analyBuf);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
int32_t numOfBlocks = (int32_t)taosArrayGetSize(pSupp->blocks);
|
int32_t numOfBlocks = (int32_t)taosArrayGetSize(pSupp->blocks);
|
||||||
|
|
||||||
// timestamp
|
// timestamp
|
||||||
code = taosAnalBufWriteColBegin(&analBuf, 0);
|
code = taosAnalyBufWriteColBegin(&analyBuf, 0);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
for (int32_t i = 0; i < numOfBlocks; ++i) {
|
for (int32_t i = 0; i < numOfBlocks; ++i) {
|
||||||
|
@ -416,16 +416,16 @@ static int32_t anomalyAnalysisWindow(SOperatorInfo* pOperator) {
|
||||||
SColumnInfoData* pTsCol = taosArrayGet(pBlock->pDataBlock, pInfo->tsSlotId);
|
SColumnInfoData* pTsCol = taosArrayGet(pBlock->pDataBlock, pInfo->tsSlotId);
|
||||||
if (pTsCol == NULL) break;
|
if (pTsCol == NULL) break;
|
||||||
for (int32_t j = 0; j < pBlock->info.rows; ++j) {
|
for (int32_t j = 0; j < pBlock->info.rows; ++j) {
|
||||||
code = taosAnalBufWriteColData(&analBuf, 0, TSDB_DATA_TYPE_TIMESTAMP, &((TSKEY*)pTsCol->pData)[j]);
|
code = taosAnalyBufWriteColData(&analyBuf, 0, TSDB_DATA_TYPE_TIMESTAMP, &((TSKEY*)pTsCol->pData)[j]);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
code = taosAnalBufWriteColEnd(&analBuf, 0);
|
code = taosAnalyBufWriteColEnd(&analyBuf, 0);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
// data
|
// data
|
||||||
code = taosAnalBufWriteColBegin(&analBuf, 1);
|
code = taosAnalyBufWriteColBegin(&analyBuf, 1);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
for (int32_t i = 0; i < numOfBlocks; ++i) {
|
for (int32_t i = 0; i < numOfBlocks; ++i) {
|
||||||
|
@ -435,38 +435,38 @@ static int32_t anomalyAnalysisWindow(SOperatorInfo* pOperator) {
|
||||||
if (pValCol == NULL) break;
|
if (pValCol == NULL) break;
|
||||||
|
|
||||||
for (int32_t j = 0; j < pBlock->info.rows; ++j) {
|
for (int32_t j = 0; j < pBlock->info.rows; ++j) {
|
||||||
code = taosAnalBufWriteColData(&analBuf, 1, pValCol->info.type, colDataGetData(pValCol, j));
|
code = taosAnalyBufWriteColData(&analyBuf, 1, pValCol->info.type, colDataGetData(pValCol, j));
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code = taosAnalBufWriteColEnd(&analBuf, 1);
|
code = taosAnalyBufWriteColEnd(&analyBuf, 1);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
code = taosAnalBufWriteDataEnd(&analBuf);
|
code = taosAnalyBufWriteDataEnd(&analyBuf);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
code = taosAnalBufWriteOptStr(&analBuf, "option", pInfo->anomalyOpt);
|
code = taosAnalyBufWriteOptStr(&analyBuf, "option", pInfo->anomalyOpt);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
code = taosAnalBufWriteOptStr(&analBuf, "algo", pInfo->algoName);
|
code = taosAnalyBufWriteOptStr(&analyBuf, "algo", pInfo->algoName);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
code = taosAnalBufWriteOptStr(&analBuf, "prec", prec);
|
code = taosAnalyBufWriteOptStr(&analyBuf, "prec", prec);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
int64_t wncheck = ANAL_FORECAST_DEFAULT_WNCHECK;
|
int64_t wncheck = ANALY_FORECAST_DEFAULT_WNCHECK;
|
||||||
bool hasWncheck = taosAnalGetOptInt(pInfo->anomalyOpt, "wncheck", &wncheck);
|
bool hasWncheck = taosAnalyGetOptInt(pInfo->anomalyOpt, "wncheck", &wncheck);
|
||||||
if (!hasWncheck) {
|
if (!hasWncheck) {
|
||||||
qDebug("anomaly_window wncheck not found from %s, use default:%" PRId64, pInfo->anomalyOpt, wncheck);
|
qDebug("anomaly_window wncheck not found from %s, use default:%" PRId64, pInfo->anomalyOpt, wncheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
code = taosAnalBufWriteOptInt(&analBuf, "wncheck", wncheck);
|
code = taosAnalyBufWriteOptInt(&analyBuf, "wncheck", wncheck);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
code = taosAnalBufClose(&analBuf);
|
code = taosAnalyBufClose(&analyBuf);
|
||||||
QUERY_CHECK_CODE(code, lino, _OVER);
|
QUERY_CHECK_CODE(code, lino, _OVER);
|
||||||
|
|
||||||
pJson = taosAnalySendReqRetJson(pInfo->algoUrl, ANALYTICS_HTTP_TYPE_POST, &analBuf, pInfo->timeout * 1000);
|
pJson = taosAnalySendReqRetJson(pInfo->algoUrl, ANALYTICS_HTTP_TYPE_POST, &analyBuf, pInfo->timeout * 1000);
|
||||||
if (pJson == NULL) {
|
if (pJson == NULL) {
|
||||||
code = terrno;
|
code = terrno;
|
||||||
goto _OVER;
|
goto _OVER;
|
||||||
|
@ -479,7 +479,7 @@ _OVER:
|
||||||
qError("%s failed to analysis window since %s, lino:%d", pId, tstrerror(code), lino);
|
qError("%s failed to analysis window since %s, lino:%d", pId, tstrerror(code), lino);
|
||||||
}
|
}
|
||||||
|
|
||||||
taosAnalBufDestroy(&analBuf);
|
taosAnalyBufDestroy(&analyBuf);
|
||||||
if (pJson != NULL) tjsonDelete(pJson);
|
if (pJson != NULL) tjsonDelete(pJson);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ typedef struct {
|
||||||
int16_t inputValSlot;
|
int16_t inputValSlot;
|
||||||
int8_t inputValType;
|
int8_t inputValType;
|
||||||
int8_t inputPrecision;
|
int8_t inputPrecision;
|
||||||
SAnalyticBuf analBuf;
|
SAnalyticBuf analyBuf;
|
||||||
} SForecastSupp;
|
} SForecastSupp;
|
||||||
|
|
||||||
typedef struct SForecastOperatorInfo {
|
typedef struct SForecastOperatorInfo {
|
||||||
|
@ -75,12 +75,12 @@ static FORCE_INLINE int32_t forecastEnsureBlockCapacity(SSDataBlock* pBlock, int
|
||||||
static int32_t forecastCacheBlock(SForecastSupp* pSupp, SSDataBlock* pBlock, const char* id) {
|
static int32_t forecastCacheBlock(SForecastSupp* pSupp, SSDataBlock* pBlock, const char* id) {
|
||||||
int32_t code = TSDB_CODE_SUCCESS;
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
int32_t lino = 0;
|
int32_t lino = 0;
|
||||||
SAnalyticBuf* pBuf = &pSupp->analBuf;
|
SAnalyticBuf* pBuf = &pSupp->analyBuf;
|
||||||
|
|
||||||
if (pSupp->cachedRows > ANAL_FORECAST_MAX_ROWS) {
|
if (pSupp->cachedRows > ANALY_FORECAST_MAX_ROWS) {
|
||||||
code = TSDB_CODE_ANA_ANODE_TOO_MANY_ROWS;
|
code = TSDB_CODE_ANA_ANODE_TOO_MANY_ROWS;
|
||||||
qError("%s rows:%" PRId64 " for forecast cache, error happens, code:%s, upper limit:%d", id, pSupp->cachedRows,
|
qError("%s rows:%" PRId64 " for forecast cache, error happens, code:%s, upper limit:%d", id, pSupp->cachedRows,
|
||||||
tstrerror(code), ANAL_FORECAST_MAX_ROWS);
|
tstrerror(code), ANALY_FORECAST_MAX_ROWS);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,13 +100,13 @@ static int32_t forecastCacheBlock(SForecastSupp* pSupp, SSDataBlock* pBlock, con
|
||||||
pSupp->maxTs = MAX(pSupp->maxTs, ts);
|
pSupp->maxTs = MAX(pSupp->maxTs, ts);
|
||||||
pSupp->numOfRows++;
|
pSupp->numOfRows++;
|
||||||
|
|
||||||
code = taosAnalBufWriteColData(pBuf, 0, TSDB_DATA_TYPE_TIMESTAMP, &ts);
|
code = taosAnalyBufWriteColData(pBuf, 0, TSDB_DATA_TYPE_TIMESTAMP, &ts);
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
qError("%s failed to write ts in buf, code:%s", id, tstrerror(code));
|
qError("%s failed to write ts in buf, code:%s", id, tstrerror(code));
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
code = taosAnalBufWriteColData(pBuf, 1, valType, val);
|
code = taosAnalyBufWriteColData(pBuf, 1, valType, val);
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
qError("%s failed to write val in buf, code:%s", id, tstrerror(code));
|
qError("%s failed to write val in buf, code:%s", id, tstrerror(code));
|
||||||
return code;
|
return code;
|
||||||
|
@ -116,81 +116,88 @@ static int32_t forecastCacheBlock(SForecastSupp* pSupp, SSDataBlock* pBlock, con
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t forecastCloseBuf(SForecastSupp* pSupp) {
|
static int32_t forecastCloseBuf(SForecastSupp* pSupp, const char* id) {
|
||||||
SAnalyticBuf* pBuf = &pSupp->analBuf;
|
SAnalyticBuf* pBuf = &pSupp->analyBuf;
|
||||||
int32_t code = 0;
|
int32_t code = 0;
|
||||||
|
|
||||||
for (int32_t i = 0; i < 2; ++i) {
|
for (int32_t i = 0; i < 2; ++i) {
|
||||||
code = taosAnalBufWriteColEnd(pBuf, i);
|
code = taosAnalyBufWriteColEnd(pBuf, i);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
code = taosAnalBufWriteDataEnd(pBuf);
|
code = taosAnalyBufWriteDataEnd(pBuf);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
code = taosAnalBufWriteOptStr(pBuf, "option", pSupp->algoOpt);
|
code = taosAnalyBufWriteOptStr(pBuf, "option", pSupp->algoOpt);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
code = taosAnalBufWriteOptStr(pBuf, "algo", pSupp->algoName);
|
code = taosAnalyBufWriteOptStr(pBuf, "algo", pSupp->algoName);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
const char* prec = TSDB_TIME_PRECISION_MILLI_STR;
|
const char* prec = TSDB_TIME_PRECISION_MILLI_STR;
|
||||||
if (pSupp->inputPrecision == TSDB_TIME_PRECISION_MICRO) prec = TSDB_TIME_PRECISION_MICRO_STR;
|
if (pSupp->inputPrecision == TSDB_TIME_PRECISION_MICRO) prec = TSDB_TIME_PRECISION_MICRO_STR;
|
||||||
if (pSupp->inputPrecision == TSDB_TIME_PRECISION_NANO) prec = TSDB_TIME_PRECISION_NANO_STR;
|
if (pSupp->inputPrecision == TSDB_TIME_PRECISION_NANO) prec = TSDB_TIME_PRECISION_NANO_STR;
|
||||||
code = taosAnalBufWriteOptStr(pBuf, "prec", prec);
|
code = taosAnalyBufWriteOptStr(pBuf, "prec", prec);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
int64_t wncheck = ANAL_FORECAST_DEFAULT_WNCHECK;
|
int64_t wncheck = ANALY_FORECAST_DEFAULT_WNCHECK;
|
||||||
bool hasWncheck = taosAnalGetOptInt(pSupp->algoOpt, "wncheck", &wncheck);
|
bool hasWncheck = taosAnalyGetOptInt(pSupp->algoOpt, "wncheck", &wncheck);
|
||||||
if (!hasWncheck) {
|
if (!hasWncheck) {
|
||||||
qDebug("forecast wncheck not found from %s, use default:%" PRId64, pSupp->algoOpt, wncheck);
|
qDebug("%s forecast wncheck not found from %s, use default:%" PRId64, id, pSupp->algoOpt, wncheck);
|
||||||
}
|
}
|
||||||
code = taosAnalBufWriteOptInt(pBuf, "wncheck", wncheck);
|
code = taosAnalyBufWriteOptInt(pBuf, "wncheck", wncheck);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
bool noConf = (pSupp->resHighSlot == -1 && pSupp->resLowSlot == -1);
|
bool noConf = (pSupp->resHighSlot == -1 && pSupp->resLowSlot == -1);
|
||||||
code = taosAnalBufWriteOptInt(pBuf, "return_conf", !noConf);
|
code = taosAnalyBufWriteOptInt(pBuf, "return_conf", !noConf);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
pSupp->optRows = ANAL_FORECAST_DEFAULT_ROWS;
|
pSupp->optRows = ANALY_FORECAST_DEFAULT_ROWS;
|
||||||
bool hasRows = taosAnalGetOptInt(pSupp->algoOpt, "rows", &pSupp->optRows);
|
bool hasRows = taosAnalyGetOptInt(pSupp->algoOpt, "rows", &pSupp->optRows);
|
||||||
if (!hasRows) {
|
if (!hasRows) {
|
||||||
qDebug("forecast rows not found from %s, use default:%" PRId64, pSupp->algoOpt, pSupp->optRows);
|
qDebug("%s forecast rows not found from %s, use default:%" PRId64, id, pSupp->algoOpt, pSupp->optRows);
|
||||||
}
|
}
|
||||||
code = taosAnalBufWriteOptInt(pBuf, "forecast_rows", pSupp->optRows);
|
|
||||||
|
if (pSupp->optRows > ANALY_FORECAST_MAX_ROWS) {
|
||||||
|
qError("%s required too many forecast rows, max allowed:%d, required:%" PRId64, id, ANALY_FORECAST_MAX_ROWS,
|
||||||
|
pSupp->optRows);
|
||||||
|
return TSDB_CODE_ANA_ANODE_TOO_MANY_ROWS;
|
||||||
|
}
|
||||||
|
|
||||||
|
code = taosAnalyBufWriteOptInt(pBuf, "forecast_rows", pSupp->optRows);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
int64_t conf = ANAL_FORECAST_DEFAULT_CONF;
|
int64_t conf = ANALY_FORECAST_DEFAULT_CONF;
|
||||||
bool hasConf = taosAnalGetOptInt(pSupp->algoOpt, "conf", &conf);
|
bool hasConf = taosAnalyGetOptInt(pSupp->algoOpt, "conf", &conf);
|
||||||
if (!hasConf) {
|
if (!hasConf) {
|
||||||
qDebug("forecast conf not found from %s, use default:%" PRId64, pSupp->algoOpt, conf);
|
qDebug("%s forecast conf not found from %s, use default:%" PRId64, id, pSupp->algoOpt, conf);
|
||||||
}
|
}
|
||||||
code = taosAnalBufWriteOptInt(pBuf, "conf", conf);
|
code = taosAnalyBufWriteOptInt(pBuf, "conf", conf);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
int32_t len = strlen(pSupp->algoOpt);
|
int32_t len = strlen(pSupp->algoOpt);
|
||||||
int64_t every = (pSupp->maxTs - pSupp->minTs) / (pSupp->numOfRows - 1);
|
int64_t every = (pSupp->maxTs - pSupp->minTs) / (pSupp->numOfRows - 1);
|
||||||
int64_t start = pSupp->maxTs + every;
|
int64_t start = pSupp->maxTs + every;
|
||||||
bool hasStart = taosAnalGetOptInt(pSupp->algoOpt, "start", &start);
|
bool hasStart = taosAnalyGetOptInt(pSupp->algoOpt, "start", &start);
|
||||||
if (!hasStart) {
|
if (!hasStart) {
|
||||||
qDebug("forecast start not found from %s, use %" PRId64, pSupp->algoOpt, start);
|
qDebug("%s forecast start not found from %s, use %" PRId64, id, pSupp->algoOpt, start);
|
||||||
}
|
}
|
||||||
code = taosAnalBufWriteOptInt(pBuf, "start", start);
|
code = taosAnalyBufWriteOptInt(pBuf, "start", start);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
bool hasEvery = taosAnalGetOptInt(pSupp->algoOpt, "every", &every);
|
bool hasEvery = taosAnalyGetOptInt(pSupp->algoOpt, "every", &every);
|
||||||
if (!hasEvery) {
|
if (!hasEvery) {
|
||||||
qDebug("forecast every not found from %s, use %" PRId64, pSupp->algoOpt, every);
|
qDebug("%s forecast every not found from %s, use %" PRId64, id, pSupp->algoOpt, every);
|
||||||
}
|
}
|
||||||
code = taosAnalBufWriteOptInt(pBuf, "every", every);
|
code = taosAnalyBufWriteOptInt(pBuf, "every", every);
|
||||||
if (code != 0) return code;
|
if (code != 0) return code;
|
||||||
|
|
||||||
code = taosAnalBufClose(pBuf);
|
code = taosAnalyBufClose(pBuf);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t forecastAnalysis(SForecastSupp* pSupp, SSDataBlock* pBlock, const char* pId) {
|
static int32_t forecastAnalysis(SForecastSupp* pSupp, SSDataBlock* pBlock, const char* pId) {
|
||||||
SAnalyticBuf* pBuf = &pSupp->analBuf;
|
SAnalyticBuf* pBuf = &pSupp->analyBuf;
|
||||||
int32_t resCurRow = pBlock->info.rows;
|
int32_t resCurRow = pBlock->info.rows;
|
||||||
int8_t tmpI8 = 0;
|
int8_t tmpI8 = 0;
|
||||||
int16_t tmpI16 = 0;
|
int16_t tmpI16 = 0;
|
||||||
|
@ -358,9 +365,9 @@ _OVER:
|
||||||
static int32_t forecastAggregateBlocks(SForecastSupp* pSupp, SSDataBlock* pResBlock, const char* pId) {
|
static int32_t forecastAggregateBlocks(SForecastSupp* pSupp, SSDataBlock* pResBlock, const char* pId) {
|
||||||
int32_t code = TSDB_CODE_SUCCESS;
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
int32_t lino = 0;
|
int32_t lino = 0;
|
||||||
SAnalyticBuf* pBuf = &pSupp->analBuf;
|
SAnalyticBuf* pBuf = &pSupp->analyBuf;
|
||||||
|
|
||||||
code = forecastCloseBuf(pSupp);
|
code = forecastCloseBuf(pSupp, pId);
|
||||||
QUERY_CHECK_CODE(code, lino, _end);
|
QUERY_CHECK_CODE(code, lino, _end);
|
||||||
|
|
||||||
code = forecastEnsureBlockCapacity(pResBlock, 1);
|
code = forecastEnsureBlockCapacity(pResBlock, 1);
|
||||||
|
@ -373,7 +380,7 @@ static int32_t forecastAggregateBlocks(SForecastSupp* pSupp, SSDataBlock* pResBl
|
||||||
|
|
||||||
_end:
|
_end:
|
||||||
pSupp->numOfBlocks = 0;
|
pSupp->numOfBlocks = 0;
|
||||||
taosAnalBufDestroy(&pSupp->analBuf);
|
taosAnalyBufDestroy(&pSupp->analyBuf);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +391,7 @@ static int32_t forecastNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
|
||||||
SForecastOperatorInfo* pInfo = pOperator->info;
|
SForecastOperatorInfo* pInfo = pOperator->info;
|
||||||
SSDataBlock* pResBlock = pInfo->pRes;
|
SSDataBlock* pResBlock = pInfo->pRes;
|
||||||
SForecastSupp* pSupp = &pInfo->forecastSupp;
|
SForecastSupp* pSupp = &pInfo->forecastSupp;
|
||||||
SAnalyticBuf* pBuf = &pSupp->analBuf;
|
SAnalyticBuf* pBuf = &pSupp->analyBuf;
|
||||||
int64_t st = taosGetTimestampUs();
|
int64_t st = taosGetTimestampUs();
|
||||||
int32_t numOfBlocks = pSupp->numOfBlocks;
|
int32_t numOfBlocks = pSupp->numOfBlocks;
|
||||||
const char* pId = GET_TASKID(pOperator->pTaskInfo);
|
const char* pId = GET_TASKID(pOperator->pTaskInfo);
|
||||||
|
@ -527,12 +534,12 @@ static int32_t forecastParseAlgo(SForecastSupp* pSupp, const char* id) {
|
||||||
pSupp->minTs = INT64_MAX;
|
pSupp->minTs = INT64_MAX;
|
||||||
pSupp->numOfRows = 0;
|
pSupp->numOfRows = 0;
|
||||||
|
|
||||||
if (!taosAnalGetOptStr(pSupp->algoOpt, "algo", pSupp->algoName, sizeof(pSupp->algoName))) {
|
if (!taosAnalyGetOptStr(pSupp->algoOpt, "algo", pSupp->algoName, sizeof(pSupp->algoName))) {
|
||||||
qError("%s failed to get forecast algorithm name from %s", id, pSupp->algoOpt);
|
qError("%s failed to get forecast algorithm name from %s", id, pSupp->algoOpt);
|
||||||
return TSDB_CODE_ANA_ALGO_NOT_FOUND;
|
return TSDB_CODE_ANA_ALGO_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasTimeout = taosAnalGetOptInt(pSupp->algoOpt, "timeout", &pSupp->timeout);
|
bool hasTimeout = taosAnalyGetOptInt(pSupp->algoOpt, "timeout", &pSupp->timeout);
|
||||||
if (!hasTimeout) {
|
if (!hasTimeout) {
|
||||||
qDebug("%s not set the timeout val, set default:%d", id, ANALY_DEFAULT_TIMEOUT);
|
qDebug("%s not set the timeout val, set default:%d", id, ANALY_DEFAULT_TIMEOUT);
|
||||||
pSupp->timeout = ANALY_DEFAULT_TIMEOUT;
|
pSupp->timeout = ANALY_DEFAULT_TIMEOUT;
|
||||||
|
@ -546,7 +553,7 @@ static int32_t forecastParseAlgo(SForecastSupp* pSupp, const char* id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taosAnalGetAlgoUrl(pSupp->algoName, ANAL_ALGO_TYPE_FORECAST, pSupp->algoUrl, sizeof(pSupp->algoUrl)) != 0) {
|
if (taosAnalyGetAlgoUrl(pSupp->algoName, ANALY_ALGO_TYPE_FORECAST, pSupp->algoUrl, sizeof(pSupp->algoUrl)) != 0) {
|
||||||
qError("%s failed to get forecast algorithm url from %s", id, pSupp->algoName);
|
qError("%s failed to get forecast algorithm url from %s", id, pSupp->algoName);
|
||||||
return TSDB_CODE_ANA_ALGO_NOT_LOAD;
|
return TSDB_CODE_ANA_ALGO_NOT_LOAD;
|
||||||
}
|
}
|
||||||
|
@ -555,32 +562,32 @@ static int32_t forecastParseAlgo(SForecastSupp* pSupp, const char* id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t forecastCreateBuf(SForecastSupp* pSupp) {
|
static int32_t forecastCreateBuf(SForecastSupp* pSupp) {
|
||||||
SAnalyticBuf* pBuf = &pSupp->analBuf;
|
SAnalyticBuf* pBuf = &pSupp->analyBuf;
|
||||||
int64_t ts = 0; // taosGetTimestampMs();
|
int64_t ts = 0; // taosGetTimestampMs();
|
||||||
|
|
||||||
pBuf->bufType = ANALYTICS_BUF_TYPE_JSON_COL;
|
pBuf->bufType = ANALYTICS_BUF_TYPE_JSON_COL;
|
||||||
snprintf(pBuf->fileName, sizeof(pBuf->fileName), "%s/tdengine-forecast-%" PRId64, tsTempDir, ts);
|
snprintf(pBuf->fileName, sizeof(pBuf->fileName), "%s/tdengine-forecast-%" PRId64, tsTempDir, ts);
|
||||||
int32_t code = tsosAnalBufOpen(pBuf, 2);
|
int32_t code = tsosAnalyBufOpen(pBuf, 2);
|
||||||
if (code != 0) goto _OVER;
|
if (code != 0) goto _OVER;
|
||||||
|
|
||||||
code = taosAnalBufWriteColMeta(pBuf, 0, TSDB_DATA_TYPE_TIMESTAMP, "ts");
|
code = taosAnalyBufWriteColMeta(pBuf, 0, TSDB_DATA_TYPE_TIMESTAMP, "ts");
|
||||||
if (code != 0) goto _OVER;
|
if (code != 0) goto _OVER;
|
||||||
|
|
||||||
code = taosAnalBufWriteColMeta(pBuf, 1, pSupp->inputValType, "val");
|
code = taosAnalyBufWriteColMeta(pBuf, 1, pSupp->inputValType, "val");
|
||||||
if (code != 0) goto _OVER;
|
if (code != 0) goto _OVER;
|
||||||
|
|
||||||
code = taosAnalBufWriteDataBegin(pBuf);
|
code = taosAnalyBufWriteDataBegin(pBuf);
|
||||||
if (code != 0) goto _OVER;
|
if (code != 0) goto _OVER;
|
||||||
|
|
||||||
for (int32_t i = 0; i < 2; ++i) {
|
for (int32_t i = 0; i < 2; ++i) {
|
||||||
code = taosAnalBufWriteColBegin(pBuf, i);
|
code = taosAnalyBufWriteColBegin(pBuf, i);
|
||||||
if (code != 0) goto _OVER;
|
if (code != 0) goto _OVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
_OVER:
|
_OVER:
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
(void)taosAnalBufClose(pBuf);
|
(void)taosAnalyBufClose(pBuf);
|
||||||
taosAnalBufDestroy(pBuf);
|
taosAnalyBufDestroy(pBuf);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -673,7 +680,7 @@ static void destroyForecastInfo(void* param) {
|
||||||
blockDataDestroy(pInfo->pRes);
|
blockDataDestroy(pInfo->pRes);
|
||||||
pInfo->pRes = NULL;
|
pInfo->pRes = NULL;
|
||||||
cleanupExprSupp(&pInfo->scalarSup);
|
cleanupExprSupp(&pInfo->scalarSup);
|
||||||
taosAnalBufDestroy(&pInfo->forecastSupp.analBuf);
|
taosAnalyBufDestroy(&pInfo->forecastSupp.analyBuf);
|
||||||
taosMemoryFreeClear(param);
|
taosMemoryFreeClear(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1223,7 +1223,7 @@ static int32_t translateForecast(SFunctionNode* pFunc, char* pErrBuf, int32_t le
|
||||||
}
|
}
|
||||||
|
|
||||||
SValueNode* pValue = (SValueNode*)pOption;
|
SValueNode* pValue = (SValueNode*)pOption;
|
||||||
if (!taosAnalGetOptStr(pValue->literal, "algo", NULL, 0) != 0) {
|
if (!taosAnalyGetOptStr(pValue->literal, "algo", NULL, 0) != 0) {
|
||||||
return invaildFuncParaValueErrMsg(pErrBuf, len, "FORECAST option should include algo field");
|
return invaildFuncParaValueErrMsg(pErrBuf, len, "FORECAST option should include algo field");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -425,8 +425,8 @@ static int32_t tlvDecodeValueU64(STlvDecoder* pDecoder, uint64_t* pValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t tlvDecodeDouble(STlv* pTlv, double* pValue) {
|
static int32_t tlvDecodeDouble(STlv* pTlv, double* pValue) {
|
||||||
int64_t temp = 0;
|
volatile int64_t temp = 0;
|
||||||
int32_t code = tlvDecodeI64(pTlv, &temp);
|
int32_t code = tlvDecodeI64(pTlv, (int64_t*)&temp);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
*pValue = *(double*)&temp;
|
*pValue = *(double*)&temp;
|
||||||
}
|
}
|
||||||
|
@ -434,8 +434,8 @@ static int32_t tlvDecodeDouble(STlv* pTlv, double* pValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t tlvDecodeValueDouble(STlvDecoder* pDecoder, double* pValue) {
|
static int32_t tlvDecodeValueDouble(STlvDecoder* pDecoder, double* pValue) {
|
||||||
int64_t temp = 0;
|
volatile int64_t temp = 0;
|
||||||
int32_t code = tlvDecodeValueI64(pDecoder, &temp);
|
int32_t code = tlvDecodeValueI64(pDecoder, (int64_t*)&temp);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
*pValue = *(double*)&temp;
|
*pValue = *(double*)&temp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6110,7 +6110,7 @@ static int32_t translateAnomalyWindow(STranslateContext* pCxt, SSelectStmt* pSel
|
||||||
SAnomalyWindowNode* pAnomaly = (SAnomalyWindowNode*)pSelect->pWindow;
|
SAnomalyWindowNode* pAnomaly = (SAnomalyWindowNode*)pSelect->pWindow;
|
||||||
int32_t code = checkAnomalyExpr(pCxt, pAnomaly->pExpr);
|
int32_t code = checkAnomalyExpr(pCxt, pAnomaly->pExpr);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
if (!taosAnalGetOptStr(pAnomaly->anomalyOpt, "algo", NULL, 0) != 0) {
|
if (!taosAnalyGetOptStr(pAnomaly->anomalyOpt, "algo", NULL, 0) != 0) {
|
||||||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ANOMALY_WIN_OPT,
|
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ANOMALY_WIN_OPT,
|
||||||
"ANOMALY_WINDOW option should include algo field");
|
"ANOMALY_WINDOW option should include algo field");
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,9 @@ if $data00 != 1 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
|
print ================= too many rows error
|
||||||
|
sql_error select forecast(c6, 'algo=holtwinters, rows=1025') from ct1;
|
||||||
|
|
||||||
print ================= try every loaded anomaly detection algorithm
|
print ================= try every loaded anomaly detection algorithm
|
||||||
sql select count(*) from ct1 anomaly_window(c1, 'algo=iqr');
|
sql select count(*) from ct1 anomaly_window(c1, 'algo=iqr');
|
||||||
sql select count(*) from ct1 anomaly_window(c1, 'algo=ksigma');
|
sql select count(*) from ct1 anomaly_window(c1, 'algo=ksigma');
|
||||||
|
|
Loading…
Reference in New Issue