class MapReduceSortAggregateConverterRule extends AbstractIgniteConverterRule<LogicalAggregate> {
        /** */
        MapReduceSortAggregateConverterRule() {
            super(LogicalAggregate.class, "MapReduceSortAggregateConverterRule");
        }

        /** {@inheritDoc} */
        @Override protected PhysicalNode convert(RelOptPlanner planner, RelMetadataQuery mq,
            LogicalAggregate agg) {<FILL_FUNCTION_BODY>}
    }

            // Applicable only for GROUP BY or SELECT DISTINCT
            if (F.isEmpty(agg.getGroupSet()) || agg.getGroupSets().size() > 1)
                return null;

            if (HintUtils.isExpandDistinctAggregate(agg))
                return null;

            RelOptCluster cluster = agg.getCluster();
            RelNode input = agg.getInput();

            RelCollation collation = TraitUtils.createCollation(agg.getGroupSet().asList());

            RelTraitSet inTrait = cluster.traitSetOf(IgniteConvention.INSTANCE).replace(collation);
            RelTraitSet outTrait = cluster.traitSetOf(IgniteConvention.INSTANCE).replace(collation);

            RelNode map = new IgniteMapSortAggregate(
                cluster,
                outTrait.replace(IgniteDistributions.random()),
                convert(input, inTrait),
                agg.getGroupSet(),
                agg.getGroupSets(),
                agg.getAggCallList(),
                collation
            );

            return new IgniteReduceSortAggregate(
                cluster,
                outTrait.replace(IgniteDistributions.single()),
                convert(map, inTrait.replace(IgniteDistributions.single())),
                agg.getGroupSet(),
                agg.getGroupSets(),
                agg.getAggCallList(),
                agg.getRowType(),
                collation
            );
        
<no_super_class>