diff --git a/be/src/exprs/bitmap_function.cpp b/be/src/exprs/bitmap_function.cpp index e1a1362a54..834d283a29 100644 --- a/be/src/exprs/bitmap_function.cpp +++ b/be/src/exprs/bitmap_function.cpp @@ -117,6 +117,19 @@ void BitmapFunctions::bitmap_intersect(FunctionContext* ctx, const StringVal& sr } } +void BitmapFunctions::group_bitmap_xor(FunctionContext* ctx, const StringVal& src, StringVal* dst) { + if (src.is_null) { + return; + } + auto dst_bitmap = reinterpret_cast(dst->ptr); + // zero size means the src input is a agg object + if (src.len == 0) { + (*dst_bitmap) ^= *reinterpret_cast(src.ptr); + } else { + (*dst_bitmap) ^= BitmapValue((char*)src.ptr); + } +} + BigIntVal BitmapFunctions::bitmap_count(FunctionContext* ctx, const StringVal& src) { if (src.is_null) { return 0; diff --git a/be/src/exprs/bitmap_function.h b/be/src/exprs/bitmap_function.h index 0ace3589c8..15e164eef1 100644 --- a/be/src/exprs/bitmap_function.h +++ b/be/src/exprs/bitmap_function.h @@ -53,6 +53,7 @@ public: // the dst value could be null static void nullable_bitmap_init(FunctionContext* ctx, StringVal* dst); static void bitmap_intersect(FunctionContext* ctx, const StringVal& src, StringVal* dst); + static void group_bitmap_xor(FunctionContext* ctx, const StringVal& src, StringVal* dst); static BigIntVal bitmap_count(FunctionContext* ctx, const StringVal& src); static BigIntVal bitmap_and_not_count(FunctionContext* ctx, const StringVal& src, const StringVal& dst); diff --git a/be/src/vec/aggregate_functions/aggregate_function_bitmap.cpp b/be/src/vec/aggregate_functions/aggregate_function_bitmap.cpp index abe445fb0f..fe52a1bdfb 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_bitmap.cpp +++ b/be/src/vec/aggregate_functions/aggregate_function_bitmap.cpp @@ -59,6 +59,14 @@ AggregateFunctionPtr create_aggregate_function_bitmap_intersect(const std::strin argument_types); } +AggregateFunctionPtr create_aggregate_function_group_bitmap_xor(const std::string& name, + const DataTypes& argument_types, + const Array& parameters, + const bool result_is_nullable) { + return std::make_shared>( + argument_types); +} + AggregateFunctionPtr create_aggregate_function_bitmap_union_count(const std::string& name, const DataTypes& argument_types, const Array& parameters, @@ -88,6 +96,7 @@ AggregateFunctionPtr create_aggregate_function_bitmap_union_int(const std::strin void register_aggregate_function_bitmap(AggregateFunctionSimpleFactory& factory) { factory.register_function("bitmap_union", create_aggregate_function_bitmap_union); factory.register_function("bitmap_intersect", create_aggregate_function_bitmap_intersect); + factory.register_function("group_bitmap_xor", create_aggregate_function_group_bitmap_xor); factory.register_function("bitmap_union_count", create_aggregate_function_bitmap_union_count); factory.register_function("bitmap_union_count", create_aggregate_function_bitmap_union_count, true); diff --git a/be/src/vec/aggregate_functions/aggregate_function_bitmap.h b/be/src/vec/aggregate_functions/aggregate_function_bitmap.h index 3b7022e51a..aabc6efb62 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_bitmap.h +++ b/be/src/vec/aggregate_functions/aggregate_function_bitmap.h @@ -84,6 +84,28 @@ struct AggregateFunctionBitmapIntersectOp { } }; +struct AggregateFunctionGroupBitmapXorOp { + static constexpr auto name = "group_bitmap_xor"; + + static void add(BitmapValue& res, const BitmapValue& data, bool& is_first) { + if (UNLIKELY(is_first)) { + res = data; + is_first = false; + } else { + res ^= data; + } + } + + static void merge(BitmapValue& res, const BitmapValue& data, bool& is_first) { + if (UNLIKELY(is_first)) { + res = data; + is_first = false; + } else { + res ^= data; + } + } +}; + template struct AggregateFunctionBitmapData { BitmapValue value; diff --git a/docs/en/docs/sql-manual/sql-functions/aggregate-functions/group_bitmap_xor.md b/docs/en/docs/sql-manual/sql-functions/aggregate-functions/group_bitmap_xor.md new file mode 100644 index 0000000000..c7165920e2 --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/aggregate-functions/group_bitmap_xor.md @@ -0,0 +1,57 @@ +--- +{ + "title": "group_bitmap_xor", + "language": "en" +} +--- + + + +## group_bitmap_xor +### description +#### Syntax + +`BITMAP GROUP_BITMAP_XOR(expr)` + +Perform an xor calculation on expr, and return a new bitmap. + +### example + +``` +mysql> select page, bitmap_to_string(user_id) from pv_bitmap; ++------+-----------------------------+ +| page | bitmap_to_string(`user_id`) | ++------+-----------------------------+ +| m | 4,7,8 | +| m | 1,3,6,15 | +| m | 4,7 | ++------+-----------------------------+ + +mysql> select page, bitmap_to_string(group_bitmap_xor(user_id)) from pv_bitmap group by page; ++------+-----------------------------------------------+ +| page | bitmap_to_string(group_bitmap_xor(`user_id`)) | ++------+-----------------------------------------------+ +| m | 1,3,6,8,15 | ++------+-----------------------------------------------+ +``` + +### keywords + + GROUP_BITMAP_XOR,BITMAP diff --git a/docs/sidebars.json b/docs/sidebars.json index 97f7348ffb..8c7cb3a277 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -420,6 +420,7 @@ "sql-manual/sql-functions/aggregate-functions/sum", "sql-manual/sql-functions/aggregate-functions/max_by", "sql-manual/sql-functions/aggregate-functions/bitmap_union", + "sql-manual/sql-functions/aggregate-functions/group_bitmap_xor", "sql-manual/sql-functions/aggregate-functions/percentile_approx", "sql-manual/sql-functions/aggregate-functions/stddev", "sql-manual/sql-functions/aggregate-functions/group_concat", diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/aggregate-functions/group_bitmap_xor.md b/docs/zh-CN/docs/sql-manual/sql-functions/aggregate-functions/group_bitmap_xor.md new file mode 100644 index 0000000000..653f6b5ef3 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/aggregate-functions/group_bitmap_xor.md @@ -0,0 +1,57 @@ +--- +{ + "title": "group_bitmap_xor", + "language": "zh-CN" +} +--- + + + +## group_bitmap_xor +### description +#### Syntax + +`BITMAP GROUP_BITMAP_XOR(expr)` + +对expr进行 xor 计算, 返回新的bitmap。 + +### example + +``` +mysql> select page, bitmap_to_string(user_id) from pv_bitmap; ++------+-----------------------------+ +| page | bitmap_to_string(`user_id`) | ++------+-----------------------------+ +| m | 4,7,8 | +| m | 1,3,6,15 | +| m | 4,7 | ++------+-----------------------------+ + +mysql> select page, bitmap_to_string(group_bitmap_xor(user_id)) from pv_bitmap group by page; ++------+-----------------------------------------------+ +| page | bitmap_to_string(group_bitmap_xor(`user_id`)) | ++------+-----------------------------------------------+ +| m | 1,3,6,8,15 | ++------+-----------------------------------------------+ +``` + +### keywords + + GROUP_BITMAP_XOR,BITMAP diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java index 9be288b4ce..a2d5ba356a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java @@ -2364,6 +2364,25 @@ public class FunctionSet { "", "", true, false, true, true)); + + addBuiltin(AggregateFunction.createBuiltin("group_bitmap_xor", Lists.newArrayList(Type.BITMAP), + Type.BITMAP, Type.VARCHAR, + "_ZN5doris15BitmapFunctions11bitmap_initEPN9doris_udf15FunctionContextEPNS1_9StringValE", + "_ZN5doris15BitmapFunctions16group_bitmap_xorEPN9doris_udf15FunctionContextERKNS1_9StringValEPS4_", + "_ZN5doris15BitmapFunctions16group_bitmap_xorEPN9doris_udf15FunctionContextERKNS1_9StringValEPS4_", + "_ZN5doris15BitmapFunctions16bitmap_serializeEPN9doris_udf15FunctionContextERKNS1_9StringValE", + "_ZN5doris15BitmapFunctions16bitmap_serializeEPN9doris_udf15FunctionContextERKNS1_9StringValE", + true, false, true)); + + // vec group_bitmap_xor + addBuiltin(AggregateFunction.createBuiltin("group_bitmap_xor", Lists.newArrayList(Type.BITMAP), + Type.BITMAP, Type.BITMAP, + "", + "", + "", + "", + "", + true, false, true, true)); //quantile_state addBuiltin(AggregateFunction.createBuiltin(QUANTILE_UNION, Lists.newArrayList(Type.QUANTILE_STATE), Type.QUANTILE_STATE, diff --git a/regression-test/data/query_p0/sql_functions/aggregate_functions/test_aggregate_all_functions.out b/regression-test/data/query_p0/sql_functions/aggregate_functions/test_aggregate_all_functions.out index 51f9bb3aab..41a9dda202 100644 --- a/regression-test/data/query_p0/sql_functions/aggregate_functions/test_aggregate_all_functions.out +++ b/regression-test/data/query_p0/sql_functions/aggregate_functions/test_aggregate_all_functions.out @@ -27,6 +27,11 @@ xian 100.0 -- !select5 -- 3 +-- !group_bitmap_xor -- +20220201 10000 +20220202 10001 +20220203 10000,10001 + -- !select6 -- beijing 3 xian 3 diff --git a/regression-test/suites/query_p0/sql_functions/aggregate_functions/test_aggregate_all_functions.groovy b/regression-test/suites/query_p0/sql_functions/aggregate_functions/test_aggregate_all_functions.groovy index 1dbe4cff2b..08ba780f17 100644 --- a/regression-test/suites/query_p0/sql_functions/aggregate_functions/test_aggregate_all_functions.groovy +++ b/regression-test/suites/query_p0/sql_functions/aggregate_functions/test_aggregate_all_functions.groovy @@ -59,7 +59,7 @@ suite("test_aggregate_all_functions") { - // BITMAP_UNION + // BITMAP_UNION group_bitmap_xor def tableName_03 = "pv_bitmap" def tableName_04 = "bitmap_base" sql "DROP TABLE IF EXISTS ${tableName_03}" @@ -112,6 +112,8 @@ suite("test_aggregate_all_functions") { qt_select4 "select bitmap_union_count(user_id) from ${tableName_03}" qt_select5 "select bitmap_count(bitmap_union(user_id)) FROM ${tableName_03}" + qt_group_bitmap_xor "select dt, bitmap_to_string(group_bitmap_xor(user_id_bitmap)) from ${tableName_04} group by dt order by dt" + sql "DROP TABLE IF EXISTS ${tableName_03}" sql "DROP TABLE IF EXISTS ${tableName_04}"