From 8de7d6c4b7ca1fd3fda955da5d12af9793b73bc8 Mon Sep 17 00:00:00 2001 From: yxzhang <545952550@qq.com> Date: Fri, 20 Dec 2024 11:18:47 +0800 Subject: [PATCH] Add aggregate function count_if for relational table --- .../query/recent/IoTDBTableAggregationIT.java | 321 ++++++++++++++++++ .../aggregation/AccumulatorFactory.java | 5 + .../aggregation/CountIfAccumulator.java | 107 ++++++ .../grouped/GroupedCountIfAccumulator.java | 91 +++++ .../metadata/TableMetadataImpl.java | 2 + .../TableBuiltinAggregationFunction.java | 2 + 6 files changed, 528 insertions(+) create mode 100644 iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/CountIfAccumulator.java create mode 100644 iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/grouped/GroupedCountIfAccumulator.java diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableAggregationIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableAggregationIT.java index ce46b910e9db..9196760dcb3e 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableAggregationIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableAggregationIT.java @@ -433,6 +433,327 @@ public void countTest() { tableResultSetEqualTest("select count(*) from table1", expectedHeader, retArray, DATABASE_NAME); } + @Test + public void countIfTest() { + String[] expectedHeader = new String[] {"_col0"}; + String[] retArray = + new String[] { + "5,", + }; + tableResultSetEqualTest( + "select count_if(device_id = 'd01') from table1", expectedHeader, retArray, DATABASE_NAME); + + expectedHeader = new String[] {"_col0"}; + retArray = + new String[] { + "64,", + }; + tableResultSetEqualTest( + "select count_if(true) from table1", expectedHeader, retArray, DATABASE_NAME); + + expectedHeader = new String[] {"_col0", "end_time", "device_id", "_col3"}; + retArray = + new String[] { + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d01,1,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d01,1,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d01,1,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d01,1,", + "2024-09-24T06:15:55.000Z,2024-09-24T06:16:00.000Z,d01,1,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d02,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d02,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d02,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d03,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d03,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d03,0,", + "2024-09-24T06:15:45.000Z,2024-09-24T06:15:50.000Z,d03,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d03,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d04,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d04,0,", + "2024-09-24T06:15:55.000Z,2024-09-24T06:16:00.000Z,d04,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d05,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d05,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d05,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d05,0,", + "2024-09-24T06:15:55.000Z,2024-09-24T06:16:00.000Z,d05,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d06,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d06,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d06,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d07,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d07,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d07,0,", + "2024-09-24T06:15:45.000Z,2024-09-24T06:15:50.000Z,d07,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d07,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d08,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d08,0,", + "2024-09-24T06:15:55.000Z,2024-09-24T06:16:00.000Z,d08,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d09,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d09,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d09,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d09,0,", + "2024-09-24T06:15:55.000Z,2024-09-24T06:16:00.000Z,d09,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d10,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d10,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d10,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d11,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d11,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d11,0,", + "2024-09-24T06:15:45.000Z,2024-09-24T06:15:50.000Z,d11,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d11,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d12,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d12,0,", + "2024-09-24T06:15:55.000Z,2024-09-24T06:16:00.000Z,d12,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d13,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d13,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d13,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d13,0,", + "2024-09-24T06:15:55.000Z,2024-09-24T06:16:00.000Z,d13,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d14,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d14,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d14,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d15,0,", + "2024-09-24T06:15:35.000Z,2024-09-24T06:15:40.000Z,d15,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d15,0,", + "2024-09-24T06:15:45.000Z,2024-09-24T06:15:50.000Z,d15,0,", + "2024-09-24T06:15:50.000Z,2024-09-24T06:15:55.000Z,d15,0,", + "2024-09-24T06:15:30.000Z,2024-09-24T06:15:35.000Z,d16,0,", + "2024-09-24T06:15:40.000Z,2024-09-24T06:15:45.000Z,d16,0,", + "2024-09-24T06:15:55.000Z,2024-09-24T06:16:00.000Z,d16,0,", + }; + tableResultSetEqualTest( + "select date_bin(5s, time), (date_bin(5s, time) + 5000) as end_time, device_id, count_if(device_id = 'd01') from table1 group by 1,device_id", + expectedHeader, + retArray, + DATABASE_NAME); + + expectedHeader = new String[] {"_col0", "province", "city", "region", "device_id", "_col5"}; + retArray = + new String[] { + "2024-09-24T06:15:30.000Z,beijing,beijing,chaoyang,d09,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,chaoyang,d09,0,", + "2024-09-24T06:15:40.000Z,beijing,beijing,chaoyang,d09,0,", + "2024-09-24T06:15:50.000Z,beijing,beijing,chaoyang,d09,0,", + "2024-09-24T06:15:55.000Z,beijing,beijing,chaoyang,d09,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,chaoyang,d10,0,", + "2024-09-24T06:15:40.000Z,beijing,beijing,chaoyang,d10,0,", + "2024-09-24T06:15:50.000Z,beijing,beijing,chaoyang,d10,0,", + "2024-09-24T06:15:30.000Z,beijing,beijing,chaoyang,d11,1,", + "2024-09-24T06:15:35.000Z,beijing,beijing,chaoyang,d11,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,chaoyang,d11,1,", + "2024-09-24T06:15:45.000Z,beijing,beijing,chaoyang,d11,1,", + "2024-09-24T06:15:50.000Z,beijing,beijing,chaoyang,d11,1,", + "2024-09-24T06:15:30.000Z,beijing,beijing,chaoyang,d12,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,chaoyang,d12,1,", + "2024-09-24T06:15:55.000Z,beijing,beijing,chaoyang,d12,1,", + "2024-09-24T06:15:30.000Z,beijing,beijing,haidian,d13,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,haidian,d13,0,", + "2024-09-24T06:15:40.000Z,beijing,beijing,haidian,d13,0,", + "2024-09-24T06:15:50.000Z,beijing,beijing,haidian,d13,0,", + "2024-09-24T06:15:55.000Z,beijing,beijing,haidian,d13,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,haidian,d14,0,", + "2024-09-24T06:15:40.000Z,beijing,beijing,haidian,d14,0,", + "2024-09-24T06:15:50.000Z,beijing,beijing,haidian,d14,0,", + "2024-09-24T06:15:30.000Z,beijing,beijing,haidian,d15,1,", + "2024-09-24T06:15:35.000Z,beijing,beijing,haidian,d15,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,haidian,d15,1,", + "2024-09-24T06:15:45.000Z,beijing,beijing,haidian,d15,1,", + "2024-09-24T06:15:50.000Z,beijing,beijing,haidian,d15,1,", + "2024-09-24T06:15:30.000Z,beijing,beijing,haidian,d16,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,haidian,d16,1,", + "2024-09-24T06:15:55.000Z,beijing,beijing,haidian,d16,1,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,huangpu,d01,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,huangpu,d01,0,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,huangpu,d01,0,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,huangpu,d01,0,", + "2024-09-24T06:15:55.000Z,shanghai,shanghai,huangpu,d01,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,huangpu,d02,0,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,huangpu,d02,0,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,huangpu,d02,0,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,huangpu,d03,1,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,huangpu,d03,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,huangpu,d03,1,", + "2024-09-24T06:15:45.000Z,shanghai,shanghai,huangpu,d03,1,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,huangpu,d03,1,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,huangpu,d04,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,huangpu,d04,1,", + "2024-09-24T06:15:55.000Z,shanghai,shanghai,huangpu,d04,1,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,pudong,d05,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,pudong,d05,0,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,pudong,d05,0,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,pudong,d05,0,", + "2024-09-24T06:15:55.000Z,shanghai,shanghai,pudong,d05,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,pudong,d06,0,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,pudong,d06,0,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,pudong,d06,0,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,pudong,d07,1,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,pudong,d07,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,pudong,d07,1,", + "2024-09-24T06:15:45.000Z,shanghai,shanghai,pudong,d07,1,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,pudong,d07,1,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,pudong,d08,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,pudong,d08,1,", + "2024-09-24T06:15:55.000Z,shanghai,shanghai,pudong,d08,1,", + }; + tableResultSetEqualTest( + "select date_bin(5s, time),province,city,region,device_id,count_if(color != 'red') from table1 group by 1,2,3,4,5 order by 2,3,4,5,1", + expectedHeader, + retArray, + DATABASE_NAME); + + expectedHeader = + new String[] { + "_col0", + "province", + "city", + "region", + "device_id", + "_col5", + "_col6", + "_col7", + "_col8", + "_col9", + "_col10", + "_col11", + "_col12", + "_col13", + "_col14" + }; + retArray = + new String[] { + "2024-09-24T06:15:30.000Z,beijing,beijing,chaoyang,d09,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,chaoyang,d09,1,1,1,1,0,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,chaoyang,d09,0,0,1,0,1,0,0,1,1,0,", + "2024-09-24T06:15:50.000Z,beijing,beijing,chaoyang,d09,1,0,0,0,0,0,0,1,1,1,", + "2024-09-24T06:15:55.000Z,beijing,beijing,chaoyang,d09,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,chaoyang,d10,0,0,0,0,1,0,0,1,1,0,", + "2024-09-24T06:15:40.000Z,beijing,beijing,chaoyang,d10,0,0,0,1,0,0,0,1,1,1,", + "2024-09-24T06:15:50.000Z,beijing,beijing,chaoyang,d10,1,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:30.000Z,beijing,beijing,chaoyang,d11,1,1,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,chaoyang,d11,0,0,0,1,0,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,chaoyang,d11,0,0,1,0,0,0,0,0,1,0,", + "2024-09-24T06:15:45.000Z,beijing,beijing,chaoyang,d11,1,1,0,1,0,0,0,1,1,0,", + "2024-09-24T06:15:50.000Z,beijing,beijing,chaoyang,d11,1,0,1,0,0,0,0,1,1,0,", + "2024-09-24T06:15:30.000Z,beijing,beijing,chaoyang,d12,1,0,0,0,1,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,chaoyang,d12,1,1,0,0,0,0,0,1,1,0,", + "2024-09-24T06:15:55.000Z,beijing,beijing,chaoyang,d12,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:30.000Z,beijing,beijing,haidian,d13,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,haidian,d13,1,1,1,1,0,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,haidian,d13,0,0,1,0,1,0,0,1,1,0,", + "2024-09-24T06:15:50.000Z,beijing,beijing,haidian,d13,1,0,0,0,0,0,0,1,1,1,", + "2024-09-24T06:15:55.000Z,beijing,beijing,haidian,d13,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,haidian,d14,0,0,0,0,1,0,0,1,1,0,", + "2024-09-24T06:15:40.000Z,beijing,beijing,haidian,d14,0,0,0,1,0,0,0,1,1,1,", + "2024-09-24T06:15:50.000Z,beijing,beijing,haidian,d14,1,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:30.000Z,beijing,beijing,haidian,d15,1,1,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,beijing,beijing,haidian,d15,0,0,0,1,0,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,haidian,d15,0,0,1,0,0,0,0,0,1,0,", + "2024-09-24T06:15:45.000Z,beijing,beijing,haidian,d15,1,1,0,1,0,0,0,1,1,0,", + "2024-09-24T06:15:50.000Z,beijing,beijing,haidian,d15,1,0,1,0,0,0,0,1,1,0,", + "2024-09-24T06:15:30.000Z,beijing,beijing,haidian,d16,1,0,0,0,1,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,beijing,beijing,haidian,d16,1,1,0,0,0,0,0,1,1,0,", + "2024-09-24T06:15:55.000Z,beijing,beijing,haidian,d16,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,huangpu,d01,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,huangpu,d01,1,1,1,1,0,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,huangpu,d01,0,0,1,0,1,0,0,1,1,0,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,huangpu,d01,1,0,0,0,0,0,0,1,1,1,", + "2024-09-24T06:15:55.000Z,shanghai,shanghai,huangpu,d01,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,huangpu,d02,0,0,0,0,1,0,0,1,1,0,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,huangpu,d02,0,0,0,1,0,0,0,1,1,1,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,huangpu,d02,1,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,huangpu,d03,1,1,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,huangpu,d03,0,0,0,1,0,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,huangpu,d03,0,0,1,0,0,0,0,0,1,0,", + "2024-09-24T06:15:45.000Z,shanghai,shanghai,huangpu,d03,1,1,0,1,0,0,0,1,1,0,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,huangpu,d03,1,0,1,0,0,0,0,1,1,0,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,huangpu,d04,1,0,0,0,1,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,huangpu,d04,1,1,0,0,0,0,0,1,1,0,", + "2024-09-24T06:15:55.000Z,shanghai,shanghai,huangpu,d04,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,pudong,d05,0,0,0,0,0,1,0,0,1,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,pudong,d05,1,1,1,1,0,1,0,1,1,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,pudong,d05,0,0,1,0,1,0,0,1,1,0,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,pudong,d05,1,0,0,0,0,0,0,1,1,1,", + "2024-09-24T06:15:55.000Z,shanghai,shanghai,pudong,d05,0,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,pudong,d06,0,0,0,0,1,1,1,1,1,0,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,pudong,d06,0,0,0,1,0,0,0,1,1,1,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,pudong,d06,1,0,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,pudong,d07,1,1,0,0,0,0,0,0,1,0,", + "2024-09-24T06:15:35.000Z,shanghai,shanghai,pudong,d07,0,0,0,1,0,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,pudong,d07,0,0,1,0,0,1,0,0,1,0,", + "2024-09-24T06:15:45.000Z,shanghai,shanghai,pudong,d07,1,1,0,1,0,0,0,1,1,0,", + "2024-09-24T06:15:50.000Z,shanghai,shanghai,pudong,d07,1,0,1,0,0,1,0,1,1,0,", + "2024-09-24T06:15:30.000Z,shanghai,shanghai,pudong,d08,1,0,0,0,1,0,0,1,1,1,", + "2024-09-24T06:15:40.000Z,shanghai,shanghai,pudong,d08,1,1,0,0,0,0,0,1,1,0,", + "2024-09-24T06:15:55.000Z,shanghai,shanghai,pudong,d08,0,0,0,0,0,1,0,0,1,0,", + }; + tableResultSetEqualTest( + "select date_bin(5s, time),province,city,region,device_id, count_if(s1 is null), count_if(s2 < 50000), count_if(s3 > 30), count_if(s4 < 55), count_if(s5), count_if(s6 like '%pudong%'), count_if(s7 = 'shanghai_pudong_red_B_d06_36'), count_if(s8 is null), count(s9 is null), count_if(s10 is not null) from table1 group by 1,2,3,4,5 order by 2,3,4,5,1", + expectedHeader, retArray, DATABASE_NAME); + + expectedHeader = + new String[] { + "province", + "city", + "region", + "device_id", + "_col4", + "_col5", + "_col6", + "_col7", + "_col8", + "_col9", + "_col10", + "_col11", + "_col12", + "_col13" + }; + retArray = + new String[] { + "beijing,beijing,chaoyang,d09,2,1,2,1,1,0,0,3,5,2,", + "beijing,beijing,chaoyang,d10,1,0,0,1,1,0,0,2,3,1,", + "beijing,beijing,chaoyang,d11,3,2,2,2,0,0,0,3,5,1,", + "beijing,beijing,chaoyang,d12,2,1,0,0,1,0,0,2,3,1,", + "beijing,beijing,haidian,d13,2,1,2,1,1,0,0,3,5,2,", + "beijing,beijing,haidian,d14,1,0,0,1,1,0,0,2,3,1,", + "beijing,beijing,haidian,d15,3,2,2,2,0,0,0,3,5,1,", + "beijing,beijing,haidian,d16,2,1,0,0,1,0,0,2,3,1,", + "shanghai,shanghai,huangpu,d01,2,1,2,1,1,0,0,3,5,2,", + "shanghai,shanghai,huangpu,d02,1,0,0,1,1,0,0,2,3,1,", + "shanghai,shanghai,huangpu,d03,3,2,2,2,0,0,0,3,5,1,", + "shanghai,shanghai,huangpu,d04,2,1,0,0,1,0,0,2,3,1,", + "shanghai,shanghai,pudong,d05,2,1,2,1,1,2,0,3,5,2,", + "shanghai,shanghai,pudong,d06,1,0,0,1,1,1,1,2,3,1,", + "shanghai,shanghai,pudong,d07,3,2,2,2,0,2,0,3,5,1,", + "shanghai,shanghai,pudong,d08,2,1,0,0,1,1,0,2,3,1,", + }; + tableResultSetEqualTest( + "select province,city,region,device_id, count_if(s1 is null), count_if(s2 < 50000), count_if(s3 > 30), count_if(s4 < 55), count_if(s5), count_if(s6 like '%pudong%'), count_if(s7 = 'shanghai_pudong_red_B_d06_36'), count_if(s8 is null), count(s9 is null), count_if(s10 is not null) from table1 group by 1,2,3,4 order by 1,2,3,4", + expectedHeader, retArray, DATABASE_NAME); + + expectedHeader = new String[] {"province", "city", "region", "_col3"}; + retArray = + new String[] { + "beijing,beijing,chaoyang,5,", + "beijing,beijing,haidian,5,", + "shanghai,shanghai,huangpu,5,", + "shanghai,shanghai,pudong,5,", + }; + tableResultSetEqualTest( + "select province,city,region,count(s3 > 30 and s4 < 55) from table1 group by 1,2,3 order by 1,2,3", + expectedHeader, + retArray, + DATABASE_NAME); + + expectedHeader = new String[] {"province", "_col1"}; + retArray = + new String[] { + "beijing,6,", "shanghai,6,", + }; + tableResultSetEqualTest( + "select province,count_if(s5) from table1 group by 1 order by 1", + expectedHeader, + retArray, + DATABASE_NAME); + } + @Test public void avgTest() { String[] expectedHeader = new String[] {"device_id", "color", "type", "_col3"}; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/AccumulatorFactory.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/AccumulatorFactory.java index 7eccd33ac611..187bbb115eea 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/AccumulatorFactory.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/AccumulatorFactory.java @@ -26,6 +26,7 @@ import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedAccumulator; import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedAvgAccumulator; import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedCountAccumulator; +import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedCountIfAccumulator; import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedExtremeAccumulator; import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedFirstAccumulator; import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedFirstByAccumulator; @@ -149,6 +150,8 @@ private static GroupedAccumulator createBuiltinGroupedAccumulator( switch (aggregationType) { case COUNT: return new GroupedCountAccumulator(); + case COUNT_IF: + return new GroupedCountIfAccumulator(inputDataTypes); case AVG: return new GroupedAvgAccumulator(inputDataTypes.get(0)); case SUM: @@ -201,6 +204,8 @@ public static TableAccumulator createBuiltinAccumulator( switch (aggregationType) { case COUNT: return new CountAccumulator(); + case COUNT_IF: + return new CountIfAccumulator(inputDataTypes); case AVG: return new AvgAccumulator(inputDataTypes.get(0)); case SUM: diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/CountIfAccumulator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/CountIfAccumulator.java new file mode 100644 index 000000000000..c0739db23082 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/CountIfAccumulator.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation; + +import org.apache.tsfile.block.column.Column; +import org.apache.tsfile.block.column.ColumnBuilder; +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.file.metadata.statistics.Statistics; +import org.apache.tsfile.utils.RamUsageEstimator; + +import java.util.Collections; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.tsfile.enums.TSDataType.BOOLEAN; + +public class CountIfAccumulator implements TableAccumulator { + private static final long INSTANCE_SIZE = + RamUsageEstimator.shallowSizeOfInstance(CountIfAccumulator.class); + + private long countState = 0; + + public CountIfAccumulator(List seriesDataType) { + checkArgument( + seriesDataType.size() == 1 && seriesDataType.get(0) == BOOLEAN, + "argument of count_if should be one boolean expression"); + } + + @Override + public long getEstimatedSize() { + return INSTANCE_SIZE; + } + + @Override + public TableAccumulator copy() { + return new CountIfAccumulator(Collections.singletonList(BOOLEAN)); + } + + @Override + public void addInput(Column[] arguments) { + int count = arguments[0].getPositionCount(); + for (int i = 0; i < count; i++) { + if (arguments[0].getBoolean(i)) { + countState++; + } + } + } + + @Override + public void addIntermediate(Column argument) { + for (int i = 0; i < argument.getPositionCount(); i++) { + if (argument.isNull(i)) { + continue; + } + countState += argument.getLong(i); + } + } + + @Override + public void evaluateIntermediate(ColumnBuilder columnBuilder) { + columnBuilder.writeLong(countState); + } + + @Override + public void evaluateFinal(ColumnBuilder columnBuilder) { + columnBuilder.writeLong(countState); + } + + @Override + public boolean hasFinalResult() { + return false; + } + + @Override + public void removeInput(Column[] arguments) { + for (int i = 0; i < arguments[0].getPositionCount(); i++) { + if (arguments[0].getBoolean(i)) { + countState--; + } + } + } + + @Override + public void addStatistics(Statistics[] statistics) {} + + @Override + public void reset() { + countState = 0; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/grouped/GroupedCountIfAccumulator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/grouped/GroupedCountIfAccumulator.java new file mode 100644 index 000000000000..55e2a204da03 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/grouped/GroupedCountIfAccumulator.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped; + +import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.array.LongBigArray; + +import org.apache.tsfile.block.column.Column; +import org.apache.tsfile.block.column.ColumnBuilder; +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.utils.RamUsageEstimator; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.tsfile.enums.TSDataType.BOOLEAN; + +public class GroupedCountIfAccumulator implements GroupedAccumulator { + private final LongBigArray countValues = new LongBigArray(0L); + + private static final long INSTANCE_SIZE = + RamUsageEstimator.shallowSizeOfInstance(GroupedCountIfAccumulator.class); + + public GroupedCountIfAccumulator(List seriesDataType) { + checkArgument( + seriesDataType.size() == 1 && seriesDataType.get(0) == BOOLEAN, + "argument of count_if should be one boolean expression"); + } + + @Override + public long getEstimatedSize() { + return INSTANCE_SIZE + countValues.sizeOf(); + } + + @Override + public void setGroupCount(long groupCount) { + countValues.ensureCapacity(groupCount); + } + + @Override + public void addInput(int[] groupIds, Column[] arguments) { + for (int i = 0; i < groupIds.length; i++) { + if (arguments[0].getBoolean(i)) { + countValues.increment(groupIds[i]); + } + } + } + + @Override + public void addIntermediate(int[] groupIds, Column argument) { + for (int i = 0; i < groupIds.length; i++) { + if (!argument.isNull(i)) { + countValues.add(groupIds[i], argument.getLong(i)); + } + } + } + + @Override + public void evaluateIntermediate(int groupId, ColumnBuilder columnBuilder) { + columnBuilder.writeLong(countValues.get(groupId)); + } + + @Override + public void evaluateFinal(int groupId, ColumnBuilder columnBuilder) { + columnBuilder.writeLong(countValues.get(groupId)); + } + + @Override + public void prepareFinal() {} + + @Override + public void reset() { + countValues.reset(); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java index e544c212a28d..93ec5ee6071a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java @@ -567,6 +567,7 @@ && isIntegerNumber(argumentTypes.get(2)))) { case SqlConstant.MIN: case SqlConstant.MAX: case SqlConstant.MODE: + case SqlConstant.COUNT_IF: if (argumentTypes.size() != 1) { throw new SemanticException( String.format( @@ -615,6 +616,7 @@ && isIntegerNumber(argumentTypes.get(2)))) { // get return type switch (functionName.toLowerCase(Locale.ENGLISH)) { case SqlConstant.COUNT: + case SqlConstant.COUNT_IF: return INT64; case SqlConstant.FIRST_AGGREGATION: case SqlConstant.LAST_AGGREGATION: diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/TableBuiltinAggregationFunction.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/TableBuiltinAggregationFunction.java index 4cd046dfeb63..10aa13ed4ad9 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/TableBuiltinAggregationFunction.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/TableBuiltinAggregationFunction.java @@ -38,6 +38,7 @@ public enum TableBuiltinAggregationFunction { SUM("sum"), COUNT("count"), + COUNT_IF("count_if"), AVG("avg"), EXTREME("extreme"), MAX("max"), @@ -81,6 +82,7 @@ public static Type getIntermediateType(String name, List originalArgumentT final String functionName = name.toLowerCase(); switch (functionName) { case "count": + case "count_if": return INT64; case "sum": return DOUBLE;