Charts: Improve dataset caching

This commit is contained in:
Aysam Guerler
2014-04-11 20:38:53 -04:00
parent 01cd002652
commit 641663dc1f
5 changed files with 185 additions and 78 deletions
File diff suppressed because one or more lines are too long
@@ -7,7 +7,7 @@ return {
columns : {
label : {
title : 'Labels',
any_type : true
is_label : true
},
y : {
title : 'Values'
@@ -7,6 +7,9 @@ return Backbone.Collection.extend(
// list of datasets
list: {},
// cache for datablocks
cache: {},
// initialize
initialize: function(app, options)
{
@@ -18,23 +21,23 @@ return Backbone.Collection.extend(
},
// wait
request: function(options, success, error) {
request: function(request_dictionary, success, error) {
// link this
var self = this;
// check if column data is requested
if (options.groups) {
this._fetch(options, success);
if (request_dictionary.groups) {
this._get(request_dictionary, success);
} else {
// check if dataset is available from cache
var dataset = this.list[options.id];
var dataset = this.list[request_dictionary.id];
if (dataset) {
success(dataset);
return;
}
// request dataset
Utils.request('GET', config.root + 'api/datasets/' + options.id, {}, function(dataset) {
Utils.request('GET', config.root + 'api/datasets/' + request_dictionary.id, {}, function(dataset) {
switch (dataset.state) {
case 'error':
if (error) {
@@ -42,110 +45,207 @@ return Backbone.Collection.extend(
}
break;
default:
self.list[options.id] = dataset;
self.list[request_dictionary.id] = dataset;
success(dataset);
}
});
}
},
// get block id
_block_id: function (options, column) {
return options.id + '_' + options.start + '_' + options.end + '_' + column;
},
// fills request dictionary with data from cache/response
_get: function(request_dictionary, callback) {
// set start/end
if (!request_dictionary.start) {
request_dictionary.start = 0;
}
if (!request_dictionary.end) {
request_dictionary.end = this.app.config.get('query_limit');
}
// get column indices
var column_list = [];
var column_map = {};
var column_count = 0;
for (var i in request_dictionary.groups) {
var group = request_dictionary.groups[i];
for (var key in group.columns) {
// identify column
var column = group.columns[key].index;
// check if column is in cache
var block_id = this._block_id(request_dictionary, column);
if (this.cache[block_id]) {
continue;
}
// add to dictionary
if (!column_map[column]) {
column_map[column] = column_count;
column_list.push(column);
column_count++;
}
}
}
// check length
if (column_list.length == 0) {
// fill dictionary from cache
this._fill_from_cache(request_dictionary);
// parse requested data
callback(request_dictionary);
// return
return;
}
// configure dataset request dictionary
var dataset_request = {
dataset_id : request_dictionary.id,
start : request_dictionary.start,
end : request_dictionary.end,
columns : column_list
}
// fetch data
var self = this;
this._fetch(dataset_request, function(results) {
// add results to cache
for (var i in results) {
var column = column_list[i];
var block_id = self._block_id(request_dictionary, column);
self.cache[block_id] = results[i];
}
// fill dictionary from cache
self._fill_from_cache(request_dictionary);
// trigger callback
callback(request_dictionary);
});
},
// convert
_fill_from_cache: function(request_dictionary) {
// log
console.debug('Datasets::_fill_from_cache() - Filling request from cache.');
// collect all data into the defined groups
for (var i in request_dictionary.groups) {
// get group
var group = request_dictionary.groups[i];
// create array for values
group.values = [];
// fill value
for (var key in group.columns) {
// get column
var column = group.columns[key];
// get block
var block_id = this._block_id(request_dictionary, column.index);
var column_data = this.cache[block_id];
// go through column
for (k in column_data) {
// initialize value
var value = group.values[k];
if (value === undefined) {
// create new value field
value = {
x : parseInt(k) + request_dictionary.start
}
// add to group
group.values[k] = value;
};
// get/fix value
var v = column_data[k];
if (isNaN(v) && !column.is_label) {
v = 0;
}
// add to dict
value[key] = v;
}
}
}
},
// fetch data columns into dataset object
_fetch: function(options, callback) {
_fetch: function(dataset_request, callback) {
// set offset
var offset = options.start ? options.start : 0;
var offset = dataset_request.start ? dataset_request.start : 0;
// set limit
var limit = Math.abs(options.end - options.start);
var limit = Math.abs(dataset_request.end - dataset_request.start);
var query_limit = this.app.config.get('query_limit');
if (!limit || limit > query_limit) {
limit = query_limit;
}
// check length
var n_columns = 0;
if (dataset_request.columns) {
n_columns = dataset_request.columns.length;
console.debug('Datasets::_fetch() - Fetching ' + n_columns + ' column(s)');
}
if (n_columns == 0) {
console.debug('Datasets::_fetch() - No columns requested');
}
// get column indices
var index_string = '';
var index_map = {};
var index_count = 0;
for (var i in options.groups) {
var group = options.groups[i];
for (var key in group.columns) {
var column = group.columns[key];
// add to index string
index_string += column + ',';
// add to dictionary
index_map[column] = index_count;
// increase counter
index_count++;
}
}
if (index_count == 0) {
callback({});
return;
}
index_string = index_string.substring(0, index_string.length - 1);
// initialize result dictionary
var result = options.groups;
for (var i in result) {
result[i].values = [];
var column_string = '';
for (var i in dataset_request.columns) {
column_string += dataset_request.columns[i] + ',';
}
column_string = column_string.substring(0, column_string.length - 1);
// make request
var self = this;
Utils.request('GET', config.root + 'api/datasets/' + options.id, {
Utils.request('GET', config.root + 'api/datasets/' + dataset_request.dataset_id, {
data_type : 'raw_data',
provider : 'dataset-column',
limit : limit,
offset : offset,
indeces : index_string
indeces : column_string
}, function(response) {
// initialize result dictionary
var result = new Array(n_columns);
for (var i = 0; i < n_columns; i++) {
result[i] = [];
}
// loop through rows
for (var i in response.data) {
// get row
var row = response.data[i];
// collect all data into the defined groups
for (var j in options.groups) {
for (var j in row) {
// get group
var group = options.groups[j];
// initialize value
var value = {
x : parseInt(i) + offset
};
// fill value
var skip = false;
for (var key in group.columns) {
// get column
var column = group.columns[key];
// identify column
var index = index_map[column];
// read value from row
var v = row[index];
if(isNaN(v)) {
skip = true;
}
// add value to dictionary
value[key] = v;
}
// add to result
if (!skip) {
result[j].values.push(value);
var v = row[j];
if (v !== undefined) {
// add to result
result[j].push(v);
}
}
}
// log
console.debug('Datasets::_fetch() - Fetching complete.');
// callback
callback(options);
});
callback(result);
}
);
}
});
@@ -122,14 +122,14 @@ return Backbone.View.extend(
for (var id in list) {
// is a numeric number required
var any_type = chart_settings.columns[id].any_type;
var is_label = chart_settings.columns[id].is_label;
// configure columns
var columns = [];
var meta = dataset.metadata_column_types;
for (var key in meta) {
// check type
if (meta[key] == 'int' || meta[key] == 'float' || any_type) {
if ((!is_label && (meta[key] == 'int' || meta[key] == 'float')) || is_label) {
// add to selection
columns.push({
'label' : 'Column: ' + (parseInt(key) + 1) + ' [' + meta[key] + ']',
@@ -215,7 +215,14 @@ return Backbone.View.extend({
// add columns
var columns = {};
for (var key in self.chart_settings.columns) {
columns[key] = group.get(key);
// get settings for column
var column_settings = self.chart_settings.columns[key];
// add to columns
columns[key] = {
index : group.get(key),
is_label : column_settings.is_label
}
}
// add group data