Загрузите большой набор данных в crossfilter/dc.js

Я построил кроссфильтр с несколькими размерами и группами для визуального отображения данных с помощью dc.js. Представленные данные представляют собой данные о поездке на велосипеде, и каждая поездка будет загружена. Сейчас имеется более 750 000 единиц данных. Файл JSON, который я использую, составляет 70 мб, и его нужно будет только увеличивать, поскольку я получаю больше данных в ближайшие месяцы.

Итак, мой вопрос: как я могу сделать данные более тонкими, чтобы он мог масштабироваться хорошо? Прямо сейчас на загрузку моего интернет-соединения требуется примерно 15 секунд, но я беспокоюсь, что это займет слишком много времени, как только у меня будет слишком много данных. Кроме того, я попытался (безуспешно) получить индикатор выполнения /spinner для отображения во время загрузки данных, но я не увенчался успехом.

Колонки, которые мне нужны для данных, start_date, start_time, usertype, gender, tripduration, meters, age. Я сократил эти поля в моем JSON до start_date, start_time, u, g, dur, m, age, поэтому файл меньше. На перекрестном фильтре в верхней строке отображается линейная диаграмма, показывающая общее количество поездок в день. Ниже приведены графики строк для дня недели (рассчитанные по данным), месяц (также рассчитанный) и круговые диаграммы для типа пользователя, пола и возраста. Ниже есть две гистограммы для start_time (округленная до часа) и триптурация (округленная до минуты).

Проект находится на GitHub: https://github.com/shaunjacobsen/divvy_explorer (набор данных находится в data2.json). Я попытался создать jsfiddle, но он не работает (вероятно, из-за данных, даже для сбора всего 1000 строк и загрузки его в HTML с тегами <pre>): http://jsfiddle.net/QLCS2/

В идеале он будет функционировать так, чтобы сначала загружать только данные для верхней диаграммы: это будет загружаться быстро, поскольку это просто количество данных в день. Однако, как только он попадает в другие диаграммы, для получения более подробных сведений требуется более подробное описание данных. Любые идеи о том, как заставить это функционировать?

Ответ 1

Я бы рекомендовал сократить все имена полей в JSON до 1 символа (включая "start_date" и "start_time" ). Это должно помочь немного. Кроме того, убедитесь, что сжатие включено на вашем сервере. Таким образом, данные, отправленные в браузер, будут автоматически сжаты в пути, что должно ускорить процесс до тонны, если он еще не включен.

Для лучшей отзывчивости я также рекомендую сначала настроить свой Crossfilter (пустой), все ваши измерения и группы и все ваши диаграммы dc.js, а затем использовать Crossfilter.add(), чтобы добавить больше данных в ваш Crossfilter в ломти. Самый простой способ сделать это - разделить ваши данные на куски размером с укусы (по несколько МБ каждый) и загрузить их поочередно. Поэтому, если вы используете d3.json, тогда начните следующую загрузку файла в обратном вызове предыдущей загрузки файла. Это приводит к набору вложенных обратных вызовов, что немного неприятно, но должно позволять пользовательскому интерфейсу реагировать во время загрузки данных.

Наконец, с такими большими данными, я считаю, что вы начнете сталкиваться с проблемами производительности в браузере, а не только при загрузке данных. Я подозреваю, что вы уже видите это, и что 15 секунд паузы вы видите, по крайней мере частично в браузере. Вы можете проверить профилирование в инструментах разработчика вашего браузера. Чтобы решить эту проблему, вам нужно будет профилировать и определить узкие места производительности, а затем попытаться их оптимизировать. Кроме того, не забудьте проверить на более медленных компьютерах, если они находятся в вашей аудитории.

Ответ 2

Рассмотрим мой класс. Он не соответствует вашим, но он иллюстрирует мои моменты.

public class MyDataModel
{
    public List<MyDatum> Data { get; set; }
}

public class MyDatum
{
    public long StartDate { get; set; }
    public long EndDate { get; set; }
    public int Duration { get; set; }
    public string Title { get; set; }
}

Датой начала и окончания являются временные метки Unix, а продолжительность - в секундах.

Сериализуется:    "{" Data ":
  [{" StartDate ": 1441256019," EndDate ": 1441257181,   " Продолжительность ": 451," Название ":" Рад - классное слово ".},...]}"

Один ряд данных - 92 символа.

Позвольте начать сжимать! Преобразование даты и времени в 60 строк. Храните все в массиве массива строк.

public class MyDataModel
{
    public List<List<string>> Data { get; set; }
}

Сериализуется:    "{" Данные ": [[" 1pCSrd "," 1pCTD1 "," 7V "," Rad - классное слово ".],...]}"

Один ряд данных теперь составляет 47 символов. moment.js - хорошая библиотека для работы с датами и временем. Он имеет встроенные функции для распаковки базового формата 60.

Работа с массивом массивов сделает ваш код менее читаемым, поэтому добавьте комментарии для документирования кода.

Загрузите только последние 90 дней. Увеличить до 30 дней. Когда пользователь перетаскивает кисть на диаграмме диапазона, вы можете начать получать больше данных в кусках по 90 дней, пока пользователь не перестанет перетаскивать. Добавьте данные в существующий кроссфильтр, используя метод добавления.

По мере того, как вы добавляете все больше и больше данных, вы заметите, что ваши диаграммы становятся все менее и менее отзывчивыми. Это потому, что вы предоставили сотни или даже тысячи элементов в вашем svg. Браузер раздавлен. Используйте функцию квантования d3 для группировки точек данных в ведра. Уменьшите отображаемые данные до 50 ковшей.

Квантование стоит усилий и является единственным способом создания масштабируемого графика с постоянно растущим набором данных.

Другой вариант - отказаться от диаграммы дальности и группировать данные за месяц, день за днем ​​и час за час. Затем добавьте подборщик диапазонов дат. Поскольку ваши данные будут сгруппированы по месяцам, дням и часам, вы обнаружите, что даже если вы ездили на велосипеде каждый час дня, у вас никогда не было бы результата, большего, чем 8766 строк.

Ответ 3

Я наблюдал подобные проблемы с данными (работающими в корпоративной компании), я нашел пару идей, которые стоит попробовать.

  • ваши данные имеют регулярную структуру, поэтому вы можете поместить ключи в первую строку, а только данные в следующих строках - имитировать CSV (сначала заголовок, данные следуют)
  • Дата Время может быть изменено на номер эпохи (и вы можете перенести начало эпохи на 01/01/2015 и вычислить при получении
  • используйте oboe.js при получении ответа от сервера (http://oboejs.com/), поскольку набор данных будет большим, подумайте об использовании гобоя. падение во время загрузки
  • визуализация обновления с помощью таймера JavaScript

образец таймера

var datacnt=0;
var timerId=setInterval(function () {
    // body...
    d3.select("#count-data-current").text(datacnt);
    //update visualization should go here, something like dc.redrawAll()...
},300);

oboe("relative-or-absolute path to your data(ajax)")
.node('CNT',function (count,path) {
    // body...
    d3.select("#count-data-all").text("Expecting " + count + " records");
    return oboe.drop;
})
.node('data.*', function (record, path) {
    // body...
    datacnt++;
    return oboe.drop;
})
.node('done', function (item, path) {
    // body...
    d3.select("#progress-data").text("all data loaded");
    clearTimeout(timerId);
    d3.select("#count-data-current").text(datacnt);
});

образец данных

{"CNT":107498, 
 "keys": "DATACENTER","FQDN","VALUE","CONSISTENCY_RESULT","FIRST_REC_DATE","LAST_REC_DATE","ACTIVE","OBJECT_ID","OBJECT_TYPE","CONSISTENCY_MESSAGE","ID_PARAMETER"], 
 "data": [[22,202,"4.9.416.2",0,1449655898,1453867824,-1,"","",0,45],[22,570,"4.9.416.2",0,1449655912,1453867884,-1,"","",0,45],[14,377,"2.102.453.0",-1,1449654863,1468208273,-1,"","",0,45],[14,406,"2.102.453.0",-1,1449654943,1468208477,-1,"","",0,45],[22,202,"10.2.293.0",0,1449655898,1453867824,-1,"","",0,8],[22,381,"10.2.293.0",0,1449655906,1453867875,-1,"","",0,8],[22,570,"10.2.293.0",0,1449655912,1453867884,-1,"","",0,8],[22,381,"1.80",0,1449655906,1453867875,-1,"","",0,41],[22,570,"1.80",0,1449655912,1453867885,-1,"","",0,41],[22,202,"4",0,1449655898,1453867824,-1,"","",0,60],[22,381,"4",0,1449655906,1453867875,-1,"","",0,60],[22,570,"4",0,1449655913,1453867885,-1,"","",0,60],[22,202,"A20",0,1449655898,1453867824,-1,"","",0,52],[22,381,"A20",0,1449655906,1453867875,-1,"","",0,52],[22,570,"A20",0,1449655912,1453867884,-1,"","",0,52],[22,202,"20140201",2,1449655898,1453867824,-1,"","",0,40],[22,381,"20140201",2,1449655906,1453867875,-1,"","",0,40],[22,570,"20140201",2,1449655912,1453867884,-1,"","",0,40],[22,202,"16",-4,1449655898,1453867824,-1,"","",0,58],[22,381,"16",-4,1449655906,1453867875,-1,"","",0,58],[22,570,"16",-4,1449655913,1453867885,-1,"","",0,58],[22,202,"512",0,1449655898,1453867824,-1,"","",0,57],[22,381,"512",0,1449655906,1453867875,-1,"","",0,57],[22,570,"512",0,1449655913,1453867885,-1,"","",0,57],[22,930,"I32",0,1449656143,1461122271,-1,"","",0,66],[22,930,"20140803",-4,1449656143,1461122271,-1,"","",0,64],[14,1359,"10.2.340.19",0,1449655203,1468209257,-1,"","",0,131],[14,567,"10.2.340.19",0,1449655185,1468209111,-1,"","",0,131],[22,930,"4.9.416.0",-1,1449656143,1461122271,-1,"","",0,131],[14,1359,"10.2.293.0",0,1449655203,1468209258,-1,"","",0,13],[14,567,"10.2.293.0",0,1449655185,1468209112,-1,"","",0,13],[22,930,"4.9.288.0",-1,1449656143,1461122271,-1,"","",0,13],[22,930,"4",0,1449656143,1461122271,-1,"","",0,76],[22,930,"96",0,1449656143,1461122271,-1,"","",0,77],[22,930,"4",0,1449656143,1461122271,-1,"","",0,74],[22,930,"VMware ESXi 5.1.0 build-2323236",0,1449656143,1461122271,-1,"","",0,17],[21,616,"A20",0,1449073850,1449073850,-1,"","",0,135],[21,616,"4",0,1449073850,1449073850,-1,"","",0,139],[21,616,"12",0,1449073850,1449073850,-1,"","",0,138],[21,616,"4",0,1449073850,1449073850,-1,"","",0,140],[21,616,"2",0,1449073850,1449073850,-1,"","",0,136],[21,616,"512",0,1449073850,1449073850,-1,"","",0,141],[21,616,"Microsoft Windows Server 2012 R2 Datacenter",0,1449073850,1449073850,-1,"","",0,109],[21,616,"4.4.5.100",0,1449073850,1449073850,-1,"","",0,97],[21,616,"3.2.7895.0",-1,1449073850,1449073850,-1,"","",0,56],[9,2029,"10.7.220.6",-4,1470362743,1478315637,1,"vmnic0","",1,8],[9,1918,"10.7.220.6",-4,1470362728,1478315616,1,"vmnic3","",1,8],[9,1918,"10.7.220.6",-4,1470362727,1478315616,1,"vmnic2","",1,8],[9,1918,"10.7.220.6",-4,1470362727,1478315615,1,"vmnic1","",1,8],[9,1918,"10.7.220.6",-4,1470362727,1478315615,1,"vmnic0","",1,8],[14,205,"934.5.45.0-1vmw",-50,1465996556,1468209226,-1,"","",0,47],[14,1155,"934.5.45.0-1vmw",-50,1465996090,1468208653,-1,"","",0,14],[14,963,"934.5.45.0-1vmw",-50,1465995972,1468208526,-1,"","",0,14],
 "done" : true}

образец смены ключей сначала на полный массив объектов

    //function to convert main data to array of objects
    function convertToArrayOfObjects(data) {
        var keys = data.shift(),
            i = 0, k = 0,
            obj = null,
            output = [];

        for (i = 0; i < data.length; i++) {
            obj = {};

            for (k = 0; k < keys.length; k++) {
                obj[keys[k]] = data[i][k];
            }

            output.push(obj);
        }

        return output;
    }

эта функция выше работает с измененной версией данных образец здесь

   [["ID1","ID2","TEXT1","STATE1","DATE1","DATE2","STATE2","TEXT2","TEXT3","ID3"],
    [14,377,"2.102.453.0",-1,1449654863,1468208273,-1,"","",0,45],
    [14,406,"2.102.453.0",-1,1449654943,1468208477,-1,"","",0,45],
    [22,202,"10.2.293.0",0,1449655898,1453867824,-1,"","",0,8],
    [22,381,"10.2.293.0",0,1449655906,1453867875,-1,"","",0,8],
    [22,570,"10.2.293.0",0,1449655912,1453867884,-1,"","",0,8],
    [22,381,"1.80",0,1449655906,1453867875,-1,"","",0,41],
    [22,570,"1.80",0,1449655912,1453867885,-1,"","",0,41],
    [22,202,"4",0,1449655898,1453867824,-1,"","",0,60],
    [22,381,"4",0,1449655906,1453867875,-1,"","",0,60],
    [22,570,"4",0,1449655913,1453867885,-1,"","",0,60],
    [22,202,"A20",0,1449655898,1453867824,-1,"","",0,52]]

Также рассмотрите использование memcached https://memcached.org/ или redis https://redis.io/ для кэширования данных на стороне сервера, в соответствии с размером данных, redis может помочь вам в дальнейшем