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

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

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

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

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

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

3 ответов


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

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

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


рассмотрим мой дизайн класса. Он не совпадает с вашим, но иллюстрирует мои соображения.

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, а продолжительность-в секундах.

сериализует в: "{"Данные":
[{"Дата Начала": 1441256019, "Дата Окончания": 1441257181, "Продолжительность": 451, "название": "рад-классное слово."}, ...]}"

одна строка данных-92 символа.

давайте начнем сжимать! Преобразование даты и времени в базу 60 строк. Магазин все в массив массив строк.

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

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

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

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

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

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

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

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


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

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

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

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 для может сделать вас дальше