Search in sources :

Example 1 with MapValue

use of io.questdb.cairo.map.MapValue in project questdb by bluestreak01.

the class SampleByInterpolateRecordCursorFactory method getCursor.

@Override
public RecordCursor getCursor(SqlExecutionContext executionContext) throws SqlException {
    recordKeyMap.clear();
    dataMap.clear();
    final RecordCursor baseCursor = base.getCursor(executionContext);
    final Record baseRecord = baseCursor.getRecord();
    final SqlExecutionInterruptor interruptor = executionContext.getSqlExecutionInterruptor();
    try {
        // init all record function for this cursor, in case functions require metadata and/or symbol tables
        Function.init(recordFunctions, baseCursor, executionContext);
        // At the same time check if cursor has data
        while (baseCursor.hasNext()) {
            interruptor.checkInterrupted();
            final MapKey key = recordKeyMap.withKey();
            mapSink.copy(baseRecord, key);
            key.createValue();
        }
        // no data, nothing to do
        if (recordKeyMap.size() == 0) {
            baseCursor.close();
            return EmptyTableRandomRecordCursor.INSTANCE;
        }
        // topTop() is guaranteeing that we get
        // the same data as previous while() loop
        // there is no data
        baseCursor.toTop();
        // Evaluate group-by functions.
        // On every change of timestamp sample value we
        // check group for gaps and fill them with placeholder
        // entries. Values for these entries will be interpolated later
        // we have data in cursor, so we can grab first value
        final boolean good = baseCursor.hasNext();
        assert good;
        long timestamp = baseRecord.getTimestamp(timestampIndex);
        sampler.setStart(timestamp);
        long prevSample = sampler.round(timestamp);
        // the lowest timestamp value
        long loSample = prevSample;
        long hiSample;
        do {
            // this seems inefficient, but we only double-sample
            // very first record and nothing else
            long sample = sampler.round(baseRecord.getTimestamp(timestampIndex));
            if (sample != prevSample) {
                // before we continue with next interval
                // we need to fill gaps in current interval
                // we will go over unique keys and attempt to
                // find them in data map with current timestamp
                fillGaps(prevSample, sample);
                prevSample = sample;
                GroupByUtils.toTop(groupByFunctions);
            }
            // same data group - evaluate group-by functions
            MapKey key = dataMap.withKey();
            mapSink.copy(baseRecord, key);
            key.putLong(sample);
            MapValue value = key.createValue();
            if (value.isNew()) {
                // not a gap
                value.putByte(0, (byte) 0);
                for (int i = 0; i < groupByFunctionCount; i++) {
                    groupByFunctions.getQuick(i).computeFirst(value, baseRecord);
                }
            } else {
                for (int i = 0; i < groupByFunctionCount; i++) {
                    groupByFunctions.getQuick(i).computeNext(value, baseRecord);
                }
            }
            if (!baseCursor.hasNext()) {
                hiSample = sampler.nextTimestamp(prevSample);
                break;
            }
            interruptor.checkInterrupted();
        } while (true);
        // fill gaps if any at end of base cursor
        fillGaps(prevSample, hiSample);
        if (groupByTwoPointFunctionCount > 0) {
            final RecordCursor mapCursor = recordKeyMap.getCursor();
            final Record mapRecord = mapCursor.getRecord();
            while (mapCursor.hasNext()) {
                MapValue value = findDataMapValue(mapRecord, loSample);
                if (value.getByte(0) == 0) {
                    // we have at least 1 data point
                    long x1 = loSample;
                    long x2 = x1;
                    while (true) {
                        // to timestamp after 'sample' to begin with
                        x2 = sampler.nextTimestamp(x2);
                        if (x2 < hiSample) {
                            value = findDataMapValue(mapRecord, x2);
                            if (value.getByte(0) == 0) {
                                interpolateBoundaryRange(x1, x2, mapRecord);
                                x1 = x2;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        // find gaps by checking each of the unique keys against every sample
        long sample;
        for (sample = prevSample = loSample; sample < hiSample; prevSample = sample, sample = sampler.nextTimestamp(sample)) {
            final RecordCursor mapCursor = recordKeyMap.getCursor();
            final Record mapRecord = mapCursor.getRecord();
            while (mapCursor.hasNext()) {
                // locate first gap
                MapValue value = findDataMapValue(mapRecord, sample);
                if (value.getByte(0) == 1) {
                    // gap is at 'sample', so potential X-value is at 'prevSample'
                    // now we need to find Y-value
                    long current = sample;
                    while (true) {
                        // to timestamp after 'sample' to begin with
                        long x2 = sampler.nextTimestamp(current);
                        // is this timestamp within range?
                        if (x2 < hiSample) {
                            value = findDataMapValue(mapRecord, x2);
                            if (value.getByte(0) == 1) {
                                // gap
                                current = x2;
                            } else {
                                // do we really have X-value?
                                if (sample == loSample) {
                                    // prevSample does not exist
                                    // find first valid value from 'x2+1' onwards
                                    long x1 = x2;
                                    while (true) {
                                        x2 = sampler.nextTimestamp(x2);
                                        if (x2 < hiSample) {
                                            final MapValue x2value = findDataMapValue(mapRecord, x2);
                                            if (x2value.getByte(0) == 0) {
                                                // non-gap
                                                // found value at 'x2' - this is our Y-value
                                                // the X-value it at 'x1'
                                                // compute slope and go back down all the way to start
                                                // computing values in records
                                                // this has to be a loop that would store y1 and y2 values for each
                                                // group-by function
                                                // use current 'value' for record
                                                MapValue x1Value = findDataMapValue2(mapRecord, x1);
                                                interpolate(loSample, x1, mapRecord, x1, x2, x1Value, x2value);
                                                break;
                                            }
                                        } else {
                                            // we only have a single value at 'x1' - cannot interpolate
                                            // make all values before and after 'x1' NULL
                                            nullifyRange(loSample, x1, mapRecord);
                                            nullifyRange(sampler.nextTimestamp(x1), hiSample, mapRecord);
                                            break;
                                        }
                                    }
                                } else {
                                    // calculate slope between 'preSample' and 'x2'
                                    // yep, that's right, and go all the way back down
                                    // to 'sample' calculating interpolated values
                                    MapValue x1Value = findDataMapValue2(mapRecord, prevSample);
                                    interpolate(sampler.nextTimestamp(prevSample), x2, mapRecord, prevSample, x2, x1Value, value);
                                }
                                break;
                            }
                        } else {
                            // try using first two values
                            // we had X-value at 'prevSample'
                            // it will become Y-value and X is at 'prevSample-1'
                            // and calculate interpolated value all the way to 'hiSample'
                            long x1 = sampler.previousTimestamp(prevSample);
                            if (x1 < loSample) {
                                // not enough data points
                                // fill all data points from 'sample' down with null
                                nullifyRange(sample, hiSample, mapRecord);
                            } else {
                                MapValue x1Value = findDataMapValue2(mapRecord, x1);
                                MapValue x2value = findDataMapValue(mapRecord, prevSample);
                                interpolate(sampler.nextTimestamp(prevSample), hiSample, mapRecord, x1, prevSample, x1Value, x2value);
                            }
                            break;
                        }
                    }
                }
            }
        }
        cursor.of(baseCursor, dataMap.getCursor());
        return cursor;
    } catch (Throwable e) {
        baseCursor.close();
        throw e;
    }
}
Also used : EmptyTableRandomRecordCursor(io.questdb.griffin.engine.EmptyTableRandomRecordCursor) MapKey(io.questdb.cairo.map.MapKey) SqlExecutionInterruptor(io.questdb.griffin.SqlExecutionInterruptor) MapValue(io.questdb.cairo.map.MapValue)

Example 2 with MapValue

use of io.questdb.cairo.map.MapValue in project questdb by bluestreak01.

the class SampleByInterpolateRecordCursorFactory method interpolate.

private void interpolate(long lo, long hi, Record mapRecord, long x1, long x2, MapValue x1Value, MapValue x2value) {
    computeYPoints(x1Value, x2value);
    for (long x = lo; x < hi; x = sampler.nextTimestamp(x)) {
        final MapValue result = findDataMapValue3(mapRecord, x);
        assert result != null && result.getByte(0) == 1;
        for (int i = 0; i < groupByTwoPointFunctionCount; i++) {
            GroupByFunction function = groupByTwoPointFunctions.getQuick(i);
            InterpolationUtil.interpolateGap(function, result, sampler.getBucketSize(), x1Value, x2value);
        }
        for (int i = 0; i < groupByScalarFunctionCount; i++) {
            GroupByFunction function = groupByScalarFunctions.getQuick(i);
            interpolatorFunctions.getQuick(i).interpolateAndStore(function, result, x, x1, x2, yData + i * 16L, yData + i * 16L + 8);
        }
        // fill the value, change flag from 'gap' to 'fill'
        result.putByte(0, (byte) 0);
    }
}
Also used : GroupByFunction(io.questdb.griffin.engine.functions.GroupByFunction) MapValue(io.questdb.cairo.map.MapValue)

Example 3 with MapValue

use of io.questdb.cairo.map.MapValue in project questdb by bluestreak01.

the class SampleByInterpolateRecordCursorFactory method nullifyRange.

private void nullifyRange(long lo, long hi, Record record) {
    for (long x = lo; x < hi; x = sampler.nextTimestamp(x)) {
        final MapKey key = dataMap.withKey();
        mapSink2.copy(record, key);
        key.putLong(x);
        MapValue value = key.findValue();
        // expect  'gap' flag
        assert value != null && value.getByte(0) == 1;
        // fill the value, change flag from 'gap' to 'fill'
        value.putByte(0, (byte) 0);
        for (int i = 0; i < groupByFunctionCount; i++) {
            groupByFunctions.getQuick(i).setNull(value);
        }
    }
}
Also used : MapKey(io.questdb.cairo.map.MapKey) MapValue(io.questdb.cairo.map.MapValue)

Example 4 with MapValue

use of io.questdb.cairo.map.MapValue in project questdb by bluestreak01.

the class SampleByInterpolateRecordCursorFactory method fillGaps.

private void fillGaps(long lo, long hi) {
    final RecordCursor keyCursor = recordKeyMap.getCursor();
    final Record record = keyCursor.getRecord();
    long timestamp = lo;
    while (timestamp < hi) {
        while (keyCursor.hasNext()) {
            MapKey key = dataMap.withKey();
            mapSink2.copy(record, key);
            key.putLong(timestamp);
            MapValue value = key.createValue();
            if (value.isNew()) {
                // this is gap
                value.putByte(0, (byte) 1);
            }
        }
        timestamp = sampler.nextTimestamp(timestamp);
        keyCursor.toTop();
    }
}
Also used : EmptyTableRandomRecordCursor(io.questdb.griffin.engine.EmptyTableRandomRecordCursor) MapKey(io.questdb.cairo.map.MapKey) MapValue(io.questdb.cairo.map.MapValue)

Example 5 with MapValue

use of io.questdb.cairo.map.MapValue in project questdb by bluestreak01.

the class GroupByRecordCursorFactory method getCursor.

@Override
public RecordCursor getCursor(SqlExecutionContext executionContext) throws SqlException {
    dataMap.clear();
    final RecordCursor baseCursor = base.getCursor(executionContext);
    try {
        Function.init(recordFunctions, baseCursor, executionContext);
        final Record baseRecord = baseCursor.getRecord();
        final int n = groupByFunctions.size();
        while (baseCursor.hasNext()) {
            executionContext.getSqlExecutionInterruptor().checkInterrupted();
            final MapKey key = dataMap.withKey();
            mapSink.copy(baseRecord, key);
            MapValue value = key.createValue();
            GroupByUtils.updateFunctions(groupByFunctions, n, value, baseRecord);
        }
        cursor.of(baseCursor, dataMap.getCursor());
        // init all record function for this cursor, in case functions require metadata and/or symbol tables
        return cursor;
    } catch (Throwable e) {
        baseCursor.close();
        throw e;
    }
}
Also used : MapKey(io.questdb.cairo.map.MapKey) MapValue(io.questdb.cairo.map.MapValue)

Aggregations

MapValue (io.questdb.cairo.map.MapValue)23 MapKey (io.questdb.cairo.map.MapKey)17 MapRecord (io.questdb.cairo.map.MapRecord)2 RecordCursor (io.questdb.cairo.sql.RecordCursor)2 SqlExecutionInterruptor (io.questdb.griffin.SqlExecutionInterruptor)2 EmptyTableRandomRecordCursor (io.questdb.griffin.engine.EmptyTableRandomRecordCursor)2 GroupByFunction (io.questdb.griffin.engine.functions.GroupByFunction)2 Function (io.questdb.cairo.sql.Function)1 Record (io.questdb.cairo.sql.Record)1 EmptyTableNoSizeRecordCursor (io.questdb.griffin.engine.EmptyTableNoSizeRecordCursor)1