use of mondrian.util.Pair in project pentaho-platform by pentaho.
the class MDXBaseComponent method getConnection.
protected IPentahoConnection getConnection() {
// first attempt to get the connection metadata from the catalog service. if that is not successful,
// get the connection using the original approach.
MdxConnectionAction connAction = (MdxConnectionAction) getActionDefinition();
String catalogName = connAction.getCatalog().getStringValue();
IMondrianCatalogService mondrianCatalogService = // $NON-NLS-1$
PentahoSystem.get(IMondrianCatalogService.class, "IMondrianCatalogService", PentahoSessionHolder.getSession());
MondrianCatalog catalog = mondrianCatalogService.getCatalog(catalogName, PentahoSessionHolder.getSession());
if (catalog == null) {
return getConnectionOrig();
}
Util.PropertyList connectProperties = Util.parseConnectString(catalog.getDataSourceInfo());
Properties properties = new Properties();
Iterator<Pair<String, String>> iter = connectProperties.iterator();
while (iter.hasNext()) {
Pair<String, String> pair = iter.next();
properties.put(pair.getKey(), pair.getValue());
}
properties.put("Catalog", catalog.getDefinition());
properties.put("Provider", "mondrian");
properties.put("PoolNeeded", "false");
properties.put(RolapConnectionProperties.Locale.name(), LocaleHelper.getLocale().toString());
debug("Mondrian Connection Properties: " + properties.toString());
MDXConnection mdxConnection = (MDXConnection) PentahoConnectionFactory.getConnection(IPentahoConnection.MDX_DATASOURCE, properties, PentahoSessionHolder.getSession(), this);
if (connAction != null) {
if ((connAction.getExtendedColumnNames() != ActionInputConstant.NULL_INPUT)) {
mdxConnection.setUseExtendedColumnNames(connAction.getExtendedColumnNames().getBooleanValue());
}
}
return mdxConnection;
}
use of mondrian.util.Pair in project pentaho-platform by pentaho.
the class MondrianModelComponent method getInitialQuery.
public static String getInitialQuery(final Properties properties, final String cubeName, IPentahoSession session) throws Throwable {
// Apply any properties for this catalog specified in datasource.xml
IMondrianCatalogService mondrianCatalogService = PentahoSystem.get(IMondrianCatalogService.class, "IMondrianCatalogService", PentahoSessionHolder.getSession());
List<MondrianCatalog> catalogs = mondrianCatalogService.listCatalogs(PentahoSessionHolder.getSession(), true);
String propCat = properties.getProperty(RolapConnectionProperties.Catalog.name());
for (MondrianCatalog cat : catalogs) {
if (cat.getDefinition().equalsIgnoreCase(propCat)) {
Util.PropertyList connectProperties = Util.parseConnectString(cat.getDataSourceInfo());
Iterator<Pair<String, String>> iter = connectProperties.iterator();
while (iter.hasNext()) {
Pair<String, String> pair = iter.next();
if (// Only set if not set already
!properties.containsKey(pair.getKey())) {
properties.put(pair.getKey(), pair.getValue());
}
}
break;
}
}
MDXConnection mdxConnection = (MDXConnection) PentahoConnectionFactory.getConnection(IPentahoConnection.MDX_DATASOURCE, properties, session, null);
// mdxConnection.setProperties( properties );
Connection connection = mdxConnection.getConnection();
if (connection == null) {
Logger.error("MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0001_INVALID_CONNECTION", // $NON-NLS-1$ //$NON-NLS-2$
properties.toString()));
return null;
}
try {
return MondrianModelComponent.getInitialQuery(connection, cubeName);
} catch (Throwable t) {
if (t instanceof MondrianException) {
// pull the cause out, otherwise it never gets logged
Throwable cause = ((MondrianException) t).getCause();
if (cause != null) {
throw cause;
} else {
throw t;
}
} else {
throw t;
}
}
}
use of mondrian.util.Pair in project mondrian by pentaho.
the class SegmentBuilder method rollup.
/**
* Given a collection of segments, all of the same dimensionality, rolls up
* to create a segment with reduced dimensionality.
*
* @param map Source segment headers and bodies
* @param keepColumns A list of column names to keep as part of
* the rolled up segment.
* @param targetBitkey The column bit key to match with the
* resulting segment.
* @param rollupAggregator The aggregator to use to rollup.
* @return Segment header and body of requested dimensionality
* @param datatype The data type to use.
*/
public static Pair<SegmentHeader, SegmentBody> rollup(Map<SegmentHeader, SegmentBody> map, Set<String> keepColumns, BitKey targetBitkey, Aggregator rollupAggregator, Datatype datatype) {
class AxisInfo {
SegmentColumn column;
SortedSet<Comparable> requestedValues;
SortedSet<Comparable> valueSet;
Comparable[] values;
boolean hasNull;
int src;
boolean lostPredicate;
}
assert allHeadersHaveSameDimensionality(map.keySet());
// store the map values in a list to assure the first header
// loaded here is consistent w/ the first segment processed below.
List<Map.Entry<SegmentHeader, SegmentBody>> segments = UnmodifiableArrayList.of(map.entrySet());
final SegmentHeader firstHeader = segments.get(0).getKey();
final List<AxisInfo> axes = new ArrayList<AxisInfo>(keepColumns.size());
int z = 0, j = 0;
List<SegmentColumn> firstHeaderConstrainedColumns = firstHeader.getConstrainedColumns();
for (SegmentColumn column : firstHeaderConstrainedColumns) {
if (keepColumns.contains(column.columnExpression)) {
final AxisInfo axisInfo = new AxisInfo();
axes.add(axisInfo);
axisInfo.src = j;
axisInfo.column = column;
axisInfo.requestedValues = column.values;
}
j++;
}
// are the intersection of the input axes.
for (Map.Entry<SegmentHeader, SegmentBody> entry : segments) {
final SegmentHeader header = entry.getKey();
for (AxisInfo axis : axes) {
final SortedSet<Comparable> values = entry.getValue().getAxisValueSets()[axis.src];
final SegmentColumn headerColumn = header.getConstrainedColumn(axis.column.columnExpression);
final boolean hasNull = entry.getValue().getNullAxisFlags()[axis.src];
final SortedSet<Comparable> requestedValues = headerColumn.getValues();
if (axis.valueSet == null) {
axis.valueSet = new TreeSet<Comparable>(values);
axis.hasNull = hasNull;
axis.requestedValues = requestedValues;
} else {
final SortedSet<Comparable> filteredValues;
final boolean filteredHasNull;
if (axis.requestedValues == null && requestedValues == null) {
// there are 2+ segments that are unconstrained for
// this axis. While unconstrained, individually
// they may not have all values present.
// Make sure we don't lose any values.
filteredValues = axis.valueSet;
filteredValues.addAll(new TreeSet<Comparable>(values));
filteredHasNull = hasNull || axis.hasNull;
} else if (axis.requestedValues == null) {
filteredValues = values;
filteredHasNull = hasNull;
axis.column = headerColumn;
} else if (requestedValues == null) {
// this axis is wildcarded
filteredValues = axis.requestedValues;
filteredHasNull = axis.hasNull;
} else {
filteredValues = Util.intersect(requestedValues, axis.requestedValues);
// SegmentColumn predicates cannot ask for the null
// value (at present).
filteredHasNull = false;
}
axis.valueSet = filteredValues;
axis.hasNull = axis.hasNull || filteredHasNull;
if (!Util.equals(axis.requestedValues, requestedValues)) {
if (axis.requestedValues == null) {
// Downgrade from wildcard to a specific list.
axis.requestedValues = requestedValues;
} else if (requestedValues != null) {
// Segment requests have incompatible predicates.
// Best we can say is "we must have asked for the
// values that came back".
axis.lostPredicate = true;
}
}
}
}
}
for (AxisInfo axis : axes) {
axis.values = axis.valueSet.toArray(new Comparable[axis.valueSet.size()]);
}
// Populate cells.
//
// (This is a rough implementation, very inefficient. It makes all
// segment types pretend to be sparse, for purposes of reading. It
// maps all axis ordinals to a value, then back to an axis ordinal,
// even if this translation were not necessary, say if the source and
// target axes had the same set of values. And it always creates a
// sparse segment.
//
// We should do really efficient rollup if the source is an array: we
// should box values (e.g double to Double and back), and we should read
// a stripe of values from the and add them up into a single cell.
final Map<CellKey, List<Object>> cellValues = new HashMap<CellKey, List<Object>>();
List<List<Comparable>> addedIntersections = new ArrayList<List<Comparable>>();
for (Map.Entry<SegmentHeader, SegmentBody> entry : map.entrySet()) {
final int[] pos = new int[axes.size()];
final Comparable[][] valueArrays = new Comparable[firstHeaderConstrainedColumns.size()][];
final SegmentBody body = entry.getValue();
// Copy source value sets into arrays. For axes that are being
// projected away, store null.
z = 0;
for (SortedSet<Comparable> set : body.getAxisValueSets()) {
valueArrays[z] = keepColumns.contains(firstHeaderConstrainedColumns.get(z).columnExpression) ? set.toArray(new Comparable[set.size()]) : null;
++z;
}
Map<CellKey, Object> v = body.getValueMap();
entryLoop: for (Map.Entry<CellKey, Object> vEntry : v.entrySet()) {
z = 0;
for (int i = 0; i < vEntry.getKey().size(); i++) {
final Comparable[] valueArray = valueArrays[i];
if (valueArray == null) {
continue;
}
final int ordinal = vEntry.getKey().getOrdinals()[i];
final int targetOrdinal;
if (axes.get(z).hasNull && ordinal == valueArray.length) {
targetOrdinal = axes.get(z).valueSet.size();
} else {
final Comparable value = valueArray[ordinal];
if (value == null) {
targetOrdinal = axes.get(z).valueSet.size();
} else {
targetOrdinal = Util.binarySearch(axes.get(z).values, 0, axes.get(z).values.length, value);
}
}
if (targetOrdinal >= 0) {
pos[z++] = targetOrdinal;
} else {
// contain the requested cell.
continue entryLoop;
}
}
final CellKey ck = CellKey.Generator.newCellKey(pos);
if (!cellValues.containsKey(ck)) {
cellValues.put(ck, new ArrayList<Object>());
}
List<Comparable> colValues = getColumnValsAtCellKey(body, vEntry.getKey());
if (!addedIntersections.contains(colValues)) {
// only add the cell value if we haven't already.
// there is a potential double add if segments overlap
cellValues.get(ck).add(vEntry.getValue());
addedIntersections.add(colValues);
}
}
}
// Build the axis list.
final List<Pair<SortedSet<Comparable>, Boolean>> axisList = new ArrayList<Pair<SortedSet<Comparable>, Boolean>>();
BigInteger bigValueCount = BigInteger.ONE;
for (AxisInfo axis : axes) {
axisList.add(Pair.of(axis.valueSet, axis.hasNull));
int size = axis.values.length;
bigValueCount = bigValueCount.multiply(BigInteger.valueOf(axis.hasNull ? size + 1 : size));
}
// The logic used here for the sparse check follows
// SegmentLoader.setAxisDataAndDecideSparseUse.
// The two methods use different data structures (AxisInfo/SegmentAxis)
// so combining logic is probably more trouble than it's worth.
final boolean sparse = bigValueCount.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0 || SegmentLoader.useSparse(bigValueCount.doubleValue(), cellValues.size());
final int[] axisMultipliers = computeAxisMultipliers(axisList);
final SegmentBody body;
// (whether to use a dense native dataset or a sparse one.
if (cellValues.size() == 0) {
// Just store the data into an empty dense object dataset.
body = new DenseObjectSegmentBody(new Object[0], axisList);
} else if (sparse) {
// The rule says we must use a sparse dataset.
// First, aggregate the values of each key.
final Map<CellKey, Object> data = new HashMap<CellKey, Object>();
for (Entry<CellKey, List<Object>> entry : cellValues.entrySet()) {
data.put(CellKey.Generator.newCellKey(entry.getKey().getOrdinals()), rollupAggregator.aggregate(entry.getValue(), datatype));
}
body = new SparseSegmentBody(data, axisList);
} else {
final BitSet nullValues;
final int valueCount = bigValueCount.intValue();
switch(datatype) {
case Integer:
final int[] ints = new int[valueCount];
nullValues = Util.bitSetBetween(0, valueCount);
for (Entry<CellKey, List<Object>> entry : cellValues.entrySet()) {
final int offset = CellKey.Generator.getOffset(entry.getKey().getOrdinals(), axisMultipliers);
final Object value = rollupAggregator.aggregate(entry.getValue(), datatype);
if (value != null) {
ints[offset] = (Integer) value;
nullValues.clear(offset);
}
}
body = new DenseIntSegmentBody(nullValues, ints, axisList);
break;
case Numeric:
final double[] doubles = new double[valueCount];
nullValues = Util.bitSetBetween(0, valueCount);
for (Entry<CellKey, List<Object>> entry : cellValues.entrySet()) {
final int offset = CellKey.Generator.getOffset(entry.getKey().getOrdinals(), axisMultipliers);
final Object value = rollupAggregator.aggregate(entry.getValue(), datatype);
if (value != null) {
doubles[offset] = (Double) value;
nullValues.clear(offset);
}
}
body = new DenseDoubleSegmentBody(nullValues, doubles, axisList);
break;
default:
final Object[] objects = new Object[valueCount];
for (Entry<CellKey, List<Object>> entry : cellValues.entrySet()) {
final int offset = CellKey.Generator.getOffset(entry.getKey().getOrdinals(), axisMultipliers);
objects[offset] = rollupAggregator.aggregate(entry.getValue(), datatype);
}
body = new DenseObjectSegmentBody(objects, axisList);
}
}
// Create header.
final List<SegmentColumn> constrainedColumns = new ArrayList<SegmentColumn>();
for (int i = 0; i < axes.size(); i++) {
AxisInfo axisInfo = axes.get(i);
constrainedColumns.add(new SegmentColumn(axisInfo.column.getColumnExpression(), axisInfo.column.getValueCount(), axisInfo.lostPredicate ? axisList.get(i).left : axisInfo.column.values));
}
final SegmentHeader header = new SegmentHeader(firstHeader.schemaName, firstHeader.schemaChecksum, firstHeader.cubeName, firstHeader.measureName, constrainedColumns, firstHeader.compoundPredicates, firstHeader.rolapStarFactTableName, targetBitkey, Collections.<SegmentColumn>emptyList());
if (LOGGER.isDebugEnabled()) {
StringBuilder builder = new StringBuilder();
builder.append("Rolling up segments with parameters: \n");
builder.append("keepColumns=" + keepColumns + "\n");
builder.append("aggregator=" + rollupAggregator + "\n");
builder.append("datatype=" + datatype + "\n");
for (Map.Entry<SegmentHeader, SegmentBody> segment : segments) {
builder.append(segment.getKey() + "\n");
}
builder.append("AxisInfos constructed:");
for (AxisInfo axis : axes) {
SortedSet<Comparable> colVals = axis.column.getValues();
builder.append(String.format("column.columnExpression=%s\n" + "column.valueCount=%s\n" + "column.values=%s\n" + "requestedValues=%s\n" + "valueSet=%s\n" + "values=%s\n" + "hasNull=%b\n" + "src=%d\n" + "lostPredicate=%b\n", axis.column.columnExpression, axis.column.getValueCount(), Arrays.toString(colVals == null ? null : colVals.toArray()), axis.requestedValues, axis.valueSet, Arrays.asList(axis.values), axis.hasNull, axis.src, axis.lostPredicate));
}
builder.append("Resulted in Segment: \n");
builder.append(header);
builder.append(body.toString());
LOGGER.debug(builder.toString());
}
return Pair.of(header, body);
}
Aggregations