Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DENSE_RANK aggregate function #1484

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion data/org.eclipse.birt.data.aggregation/.classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src/"/>
<classpathentry kind="output" path="target/classes"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
Expand Down Expand Up @@ -70,7 +70,7 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disa
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=11
org.eclipse.jdt.core.compiler.source=16
merks marked this conversation as resolved.
Show resolved Hide resolved
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ public interface IBuildInAggregation {
String TOTAL_CONCATENATE_FUNC = "CONCATENATE";//$NON-NLS-1$
String TOTAL_RANGE_FUNC = "RANGE";//$NON-NLS-1$

String TOTAL_DENSE__RANK_FUNC = "DENSERANK";//$NON-NLS-1$

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ TotalCount.description=function Total.COUNT()
TotalCount.displayName=COUNT
TotalCountDistinct.description=function Total.COUNTDISTINCT()
TotalCountDistinct.displayName=COUNTDISTINCT
TotalDenseRank.description=function Total.DENSE_RANK()
TotalDenseRank.displayName=DENSERANK
TotalFirst.description=function Total.FIRST()
TotalFirst.displayName=FIRST
TotalIrr.description=function Total.IRR()
Expand Down Expand Up @@ -91,7 +93,7 @@ TotalQuartile.param.quart=&Quart
TotalRank.description=function Total.RANK()
TotalRank.displayName=RANK
TotalRank.param.ascending=&Ascending
TotalConcatenate.description=funtion Total.CONCATENATE()
TotalConcatenate.description=function Total.CONCATENATE()
TotalConcatenate.displayName=CONCATENATE
TotalConcatenate.param.separator=Separat&or
TotalConcatenate.param.maxLength=Ma&x length
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Map;

import org.eclipse.birt.data.aggregation.api.IBuildInAggregation;
import org.eclipse.birt.data.aggregation.impl.rank.TotalDenseRank;
import org.eclipse.birt.data.aggregation.impl.rank.TotalIsBottomN;
import org.eclipse.birt.data.aggregation.impl.rank.TotalIsBottomNPercent;
import org.eclipse.birt.data.aggregation.impl.rank.TotalIsTopN;
Expand Down Expand Up @@ -139,6 +140,10 @@ private void populateAggregations() {
final TotalRange totalRange = new TotalRange();
aggrMap.put(IBuildInAggregation.TOTAL_RANGE_FUNC, totalRange);
aggregations.add(totalRange);

final TotalDenseRank totalDenseRank = new TotalDenseRank();
aggrMap.put(IBuildInAggregation.TOTAL_DENSE__RANK_FUNC, totalDenseRank);
aggregations.add(totalDenseRank);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package org.eclipse.birt.data.aggregation.impl.rank;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.eclipse.birt.core.data.DataType;
import org.eclipse.birt.data.aggregation.i18n.Messages;
import org.eclipse.birt.data.aggregation.impl.AggrFunction;
import org.eclipse.birt.data.aggregation.impl.Constants;
import org.eclipse.birt.data.aggregation.impl.ParameterDefn;
import org.eclipse.birt.data.aggregation.impl.RunningAccumulator;
import org.eclipse.birt.data.aggregation.impl.SupportedDataTypes;
import org.eclipse.birt.data.engine.api.aggregation.IParameterDefn;
import org.eclipse.birt.data.engine.core.DataException;

/**
* @since 3.3
*
*/
abstract class BaseTotalRank extends AggrFunction {


/*
* (non-Javadoc)
*
* @see org.eclipse.birt.data.engine.aggregation.Aggregation#getType()
*/
@Override
public int getType() {
return RUNNING_AGGR;
}

/*
* (non-Javadoc)
*
* @see org.eclipse.birt.data.engine.api.aggregation.IAggregation#getDateType()
*/
@Override
public int getDataType() {
return DataType.INTEGER_TYPE;
}

/*
* (non-Javadoc)
*
* @see org.eclipse.birt.data.engine.aggregation.Aggregation#getParameterDefn()
*/
@Override
public IParameterDefn[] getParameterDefn() {
return new IParameterDefn[] {
new ParameterDefn(Constants.EXPRESSION_NAME, Constants.EXPRESSION_DISPLAY_NAME, false, true,
SupportedDataTypes.CALCULATABLE, ""), //$NON-NLS-1$
new ParameterDefn("ascending", Messages.getString("TotalRank.param.ascending"), true, false, //$NON-NLS-1$ //$NON-NLS-2$
SupportedDataTypes.ANY, "") //$NON-NLS-1$
};
}

/*
*
*/
@Override
public int getNumberOfPasses() {
return 2;
}

static class TotalRankAccumulator extends RunningAccumulator {

private Integer sum;
private List<Object> cachedValues;
private Map<Object, Integer> rankMap;
private boolean asc;
private boolean denseRank;
private boolean hasInitialized;
private int passCount = 0;
private Comparator comparator;

/**
* @param denseRank If the dense rank algorithm should be used or not
*
*/
public TotalRankAccumulator(boolean denseRank) {
this.denseRank = denseRank;
}

@Override
public void start() {
if (passCount == 0) {
cachedValues = new ArrayList<>();
rankMap = new HashMap<>();
sum = 0;
asc = true;
hasInitialized = false;
}
passCount++;
}

/*
* (non-Javadoc)
*
* @see
* org.eclipse.birt.data.engine.aggregation.Accumulator#onRow(java.lang.Object[]
* )
*/
@Override
public void onRow(Object[] args) throws DataException {
assert (args.length > 0);
if (passCount == 1) {
if (args[0] != null) {
cachedValues.add(args[0]);
} else {
cachedValues.add(RankAggregationUtil.getNullObject());
}
if ((!hasInitialized) && args[1] != null) {
hasInitialized = true;
if (args[1].toString().equals("false")) { //$NON-NLS-1$
asc = false;
} else if (args[1] instanceof Double doubleArg && doubleArg.equals(Double.valueOf(0))) {
asc = false;
} else {
asc = true;
}

comparator = this.asc ? RankObjComparator.INSTANCE : RankObjComparator.INSTANCE.reversed();
}
} else {
Object compareValue;
if (args[0] != null) {
compareValue = args[0];
} else {
compareValue = RankAggregationUtil.getNullObject();
}

Integer calculatedRank = this.rankMap.get(compareValue);
sum = calculatedRank != null ? calculatedRank.intValue() : -1;
}
}

@Override
public void finish() throws DataException {
if (this.passCount == 1) {
Collections.sort(cachedValues, comparator);
calculateRank(cachedValues, this.denseRank);
}
}

/**
* Precondition: The parameter <code>objs</code> should be sorted acsending
* previously. Note: rank is 1-based. ex.
* <code>The following table give details:
* Value | Rank
* 20 | 4
* 10 | 5
* 30 | 2
* 30 | 2
* 40 | 1
* </code>
*
* @param key
* @return rank
*/
private void calculateRank(List<Object> sortedList, boolean useDenseRank) {

int currentRank = 1;
int currentDenseRank = 1;
Object currentValue = sortedList.get(0);

for (int i = 0; i < sortedList.size(); i++) {
Object integer = sortedList.get(i);
if (!Objects.equals(integer, currentValue)) {

rankMap.put(currentValue, useDenseRank ? currentDenseRank : currentRank);
currentValue = integer;
currentDenseRank++;
currentRank = i + 1;
}

}

// Handle the last integer in the list
rankMap.put(currentValue, useDenseRank ? currentDenseRank : currentRank);
}

/*
* (non-Javadoc)
*
* @see org.eclipse.birt.data.engine.api.aggregation.Accumulator#getValue()
*/
@Override
public Object getValue() throws DataException {
return sum;
}
}

/*
*
*/
static class RankObjComparator implements Comparator {

public static RankObjComparator INSTANCE = new RankObjComparator();

private RankObjComparator() {
// No need
}

@Override
public int compare(Object o1, Object o2) {// for efficiency, we assure o1 and o2 can be just Comparable or
// NullObject
if (o1 instanceof Comparable) {
if (o2 instanceof Comparable) {// Comparable ? Comparable
Comparable obj1 = (Comparable) o1;
Comparable obj2 = (Comparable) o2;
return obj1.compareTo(obj2);
} else {// Comparable > NullObject
return 1;
}
} else if (o2 instanceof Comparable) {// NullObject < Comparable
return -1;
} else {// NullObject == NullObject
return 0;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.eclipse.birt.data.aggregation.impl.rank;

import org.eclipse.birt.data.aggregation.api.IBuildInAggregation;
import org.eclipse.birt.data.aggregation.i18n.Messages;
import org.eclipse.birt.data.engine.api.aggregation.Accumulator;

/**
* @since 3.3
*
*/
public class TotalDenseRank extends BaseTotalRank {

/*
* (non-Javadoc)
*
* @see org.eclipse.birt.data.engine.aggregation.Aggregation#getName()
*/
@Override
public String getName() {
return IBuildInAggregation.TOTAL_DENSE__RANK_FUNC;
}

/*
* (non-Javadoc)
*
* @see org.eclipse.birt.data.engine.aggregation.Aggregation#newAccumulator()
*/
@Override
public Accumulator newAccumulator() {
return new TotalRankAccumulator(true);
}

/*
* (non-Javadoc)
*
* @see
* org.eclipse.birt.data.engine.api.aggregation.IAggrFunction#getDescription()
*/
@Override
public String getDescription() {
return Messages.getString("TotalDenseRank.description"); //$NON-NLS-1$
}

/*
* (non-Javadoc)
*
* @see
* org.eclipse.birt.data.engine.api.aggregation.IAggrFunction#getDisplayName()
*/
@Override
public String getDisplayName() {
return Messages.getString("TotalDenseRank.displayName"); //$NON-NLS-1$
}
}
Loading
Loading