Данные в разных разрешениях

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

Если есть много пользователей, постоянно взаимодействующих с системой, будет создано множество данных, и эти таблицы будут сильно расти.

Когда я хочу посмотреть данные, я хочу видеть их почасовое или ежедневное разрешение.

Есть ли способ или наилучшая практика для непрерывного суммирования данных постепенно (по мере сбора данных) в требуемом разрешении?

Или есть ли лучший подход к этой проблеме?

PS. То, что я нашел до сих пор, это инструменты ETL, такие как Talend, могут сделать жизнь легкой.

Обновление: я использую MySQL на данный момент, но мне интересно, какие методы лучше делать независимо от БД, среды и т.д.

Ответ 1

Обычный способ сделать это в приложении с хранилищем данных с малой задержкой состоит в том, чтобы иметь секционированную таблицу с ведущим разделом, содержащим то, что может быть быстро обновлено (т.е. без необходимости пересчитывать агрегаты "на лету" ), но с завершающимися записями разделов с агрегатами. Другими словами, ведущий раздел может использовать другую схему хранения для конечных разделов.

Большинство коммерческих и некоторых платформ RDBMS с открытым исходным кодом (например, PostgreSQL) могут поддерживать секционированные таблицы, которые могут быть использованы для такого типа вещей так или иначе. Как вы заполняете базу данных из ваших журналов, остается как упражнение для читателя.

В принципе, структура этого типа системы выглядит следующим образом:

  • У вас есть таблица, разделенная на некоторые вид даты или даты-времени, разделены на час, день или что-то еще зерно кажется подходящим. Журнал записи добавляются в эту таблицу.

  • По мере того как окно времени раздел, периодические индексы работы или обобщает его и преобразует в его "замороженное" состояние. Например, работа над Oracle может создать растровое изображение индексы на этом разделе или обновить материализованное представление, включающее резюме данные для этого раздела.

  • Позже вы можете удалить старые данные, суммировать его или объединить разделы вместе.

  • С течением времени периодическое задание назад заполняется за передний край раздел. Исторические данные преобразован в формат, который предоставляет сам по себе запросов, в то время как передний край раздел легко обновляется быстро. Поскольку этот раздел не имеют так много данных, весь набор данных относительно быстро.

Точная природа этого процесса варьируется между платформами СУБД.

Например, разбиение таблиц на SQL Server не так уж и хорошо, но это можно сделать с помощью служб Analysis Services (OLAP-сервера, который Microsoft связывает с SQL Server). Это делается путем настройки ведущего раздела как чистого ROLAP (сервер OLAP просто выдает запрос на базовую базу данных), а затем перестраивает конечные разделы как MOLAP (сервер OLAP создает свои собственные специализированные структуры данных, включая постоянные сводки, известные как "скопления",). Услуги анализа могут сделать это полностью прозрачно для пользователя. Он может перестроить раздел в фоновом режиме, пока старый ROLAP файл все еще отображается пользователю. Когда сборка завершена, она заменяется на раздел; куб доступен все время без прерывания обслуживания для пользователя.

Oracle позволяет независимо настраивать структуры разделов, поэтому можно создавать индексы или раздел, построенный на материализованном представлении. С повторной записью запроса оптимизатор запросов в Oracle может решить, что совокупные показатели, рассчитанные из базовой таблицы фактов, могут быть получены из материализованного представления. Запрос будет считывать агрегированные данные из материализованного представления, где доступны разделы, и из передового раздела, где они отсутствуют.

PostgreSQL может сделать что-то подобное, но я никогда не занимался внедрением этого типа системы.

Если вы можете жить с периодическими отключениями, что-то подобное можно сделать явно, выполнив обобщение и создав представление по ведущим и конечным данным. Это позволяет проводить анализ такого типа в системе, которая не обеспечивает прозрачное разделение. Тем не менее, система будет иметь временные отключения, поскольку представление будет восстановлено, поэтому вы не могли бы сделать это в рабочее время - чаще всего было бы на ночь.

Изменить: В зависимости от формата файлов журнала или того, какие параметры ведения журнала доступны для вас, существуют различные способы загрузки данных в систему. Некоторые параметры:

  • Напишите script, используя ваш любимый язык программирования, который считывает данные, анализирует соответствующие биты и вставляет их в базу данных. Это может выполняться довольно часто, но вы должны иметь какой-то способ отслеживать, где вы находитесь в файле. Будьте осторожны при блокировке, особенно в Windows. Семантика блокировки файла по умолчанию в Unix/Linux позволяет это сделать (это работает tail -f), но поведение по умолчанию в Windows отличается; обе системы должны быть написаны так, чтобы хорошо играть друг с другом.

  • В системе unix-oid вы можете записывать свои журналы в трубу и иметь процесс, аналогичный описанному выше в трубе. Это будет иметь самую низкую задержку для всех, но ошибки в читателе могут заблокировать ваше приложение.

  • Напишите интерфейс регистрации для вашего приложения, который непосредственно заполняет базу данных, а не записывает файлы журналов.

  • Используйте API для массовой загрузки для базы данных (большинство, если не все имеют доступ к этому типу API) и загружают данные регистрации в пакетах. Напишите аналогичную программу для первого варианта, но используйте API с объемной загрузкой. Это, но будет использовать меньше ресурсов, чем заполнение его по очереди, но имеет больше накладных расходов для настройки массовых нагрузок. Это было бы приемлемо для менее частых нагрузок (возможно, ежечасно или ежедневно) и уменьшало бы нагрузку на систему в целом.

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

  • Один из вариантов заключается в изменении регистратора, чтобы он начинал писать в другой файл каждый период (скажем, каждые несколько минут). Периодически запускайте свой журнал и загружайте новые файлы, которые он еще не обработал. Прочтите старые файлы. Чтобы это сработало, схема именования файлов должна основываться на времени, чтобы читатель знал, какой файл нужно забрать. Работа с файлами, которые все еще используются приложением, более затруднительна (вам нужно будет отслеживать, сколько было прочитано), поэтому вы хотели бы читать файлы только до последнего периода.

  • Другой вариант - переместить файл и прочитать его. Это лучше всего работает в файловых системах, которые ведут себя как Unix, но должны работать на NTFS. Вы перемещаете файл, затем читаете его в режиме ожидания. Однако для этого требуется, чтобы регистратор открывал файл в режиме создания/добавления, записывал на него, а затем закрывал его - не держать его открытым и заблокированным. Это, безусловно, поведение Unix - операция перемещения должна быть атомарной. В Windows вам действительно придется стоять над журналом, чтобы сделать эту работу.

Ответ 2

Взгляните на RRDTool. Это круглая база данных. Вы определяете показатели, которые хотите захватить, но также можете определить разрешение, в котором вы его сохраняете.

Например, вы можете указать в течение часа, вы сохраняете каждую секунду информации; в течение последних 24 часов - каждую минуту; за последнюю неделю, каждый час и т.д.

Он широко используется для сбора статистики в таких системах, как Ganglia и Cacti.

Ответ 3

Когда речь идет о разрезании и агрегировании данных (по времени или чему-то еще), звездная схема (звезда Кимбалла) представляет собой довольно простое, но мощное решение. Предположим, что для каждого клика мы храним время (до второго разрешения), информацию о пользователях, идентификатор кнопки и местоположение пользователя. Чтобы включить легкую нарезку и нарезку, начните с предварительно загруженных таблиц поиска для свойств объектов, которые редко меняются - так называемые таблицы размеров в мире DW.

pagevisit2_model_02

Таблица dimDate имеет одну строку для каждого дня с количеством атрибутов (полей), которые описывают определенный день. Таблица может быть предварительно загружена в течение многих лет вперед и должна обновляться один раз в день, если она содержит такие поля, как DaysAgo, WeeksAgo, MonthsAgo, YearsAgo; иначе это может быть "загрузить и забыть". dimDate позволяет легко нарезать атрибуты даты, например

WHERE [YEAR] = 2009 AND DayOfWeek = 'Sunday'

За десять лет данных таблица имеет только ~ 3650 строк.

Таблица dimGeography предварительно загружена областями географии интереса - количество строк зависит от "географического разрешения", требуемого в отчетах, оно позволяет нарезать данные, например

WHERE Continent = 'South America'

После загрузки он редко изменяется.

Для каждой кнопки сайта в таблице dimButton есть одна строка, поэтому запрос может иметь

WHERE PageURL = 'http://…/somepage.php'

Таблица dimUser имеет одну строку для зарегистрированного пользователя, она должна быть загружена с новой информацией пользователя, как только пользователь зарегистрируется, или, по крайней мере, новая информация пользователя должна быть в таблице до того, как любая другая пользовательская транзакция будет записанные на самом деле таблицы.

Для записи кликов на кнопках, добавьте таблицу factClick.

pagevisit2_model_01

Таблица factClick имеет одну строку для каждого щелчка кнопки от определенного пользователя в определенный момент времени. Я использовал TimeStamp (второе разрешение), ButtonKey и UserKey в составном основном ключе, чтобы отфильтровать клики быстрее, чем одна секунда от конкретного пользователя. Обратите внимание на поле Hour, оно содержит часовую часть TimeStamp, целое число в диапазоне 0-23, что позволяет легко нарезать в час, например

WHERE [HOUR] BETWEEN 7 AND 9

Итак, теперь мы должны рассмотреть:

  • Как загрузить таблицу? Периодически - может быть, каждый час или каждые несколько минут - из веб-журнала с использованием инструмента ETL или решения с низкой задержкой, используя какой-то процесс потоковой передачи событий.
  • Как долго хранить информацию в таблице?

Независимо от того, хранит ли таблица информацию только за один день или несколько лет - она ​​должна быть разделена; ConcernedOfTunbridgeW объяснил разделение в его ответе, поэтому я пропустил его здесь.

Теперь несколько примеров нарезки и нарезки на разные атрибуты (включая день и час)

Для упрощения запросов Ill добавьте представление, чтобы сгладить модель:

/* To simplify queries flatten the model */ 
CREATE VIEW vClicks 
AS 
SELECT * 
FROM factClick AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimUser AS u ON u.UserKey = f.UserKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

Пример запроса

/* 
Count number of times specific users clicked any button  
today between 7 and 9 AM (7:00 - 9:59)
*/ 
SELECT  [Email] 
       ,COUNT(*) AS [Counter] 
FROM    vClicks 
WHERE   [DaysAgo] = 0 
        AND [Hour] BETWEEN 7 AND 9 
        AND [Email] IN ('[email protected]', '[email protected]') 
GROUP BY [Email] 
ORDER BY [Email]

Предположим, что меня интересуют данные для User = ALL. dimUser представляет собой большую таблицу, поэтому Ill делает вид без нее, чтобы ускорить запросы.

/* 
Because dimUser can be large table it is good 
to have a view without it, to speed-up queries 
when user info is not required 
*/ 
CREATE VIEW vClicksNoUsr 
AS 
SELECT * 
FROM factClick AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

Пример запроса

/* 
Count number of times a button was clicked on a specific page 
today and yesterday, for each hour. 
*/ 
SELECT  [FullDate] 
       ,[Hour] 
       ,COUNT(*) AS [Counter] 
FROM    vClicksNoUsr 
WHERE   [DaysAgo] IN ( 0, 1 ) 
        AND PageURL = 'http://...MyPage' 
GROUP BY [FullDate], [Hour] 
ORDER BY [FullDate] DESC, [Hour] DESC



Предположим, что для агрегаций нам не нужно сохранять определенную информацию о пользователе, но нас интересуют только дата, час, кнопка и география. Каждая строка таблицы factClickAgg имеет счетчик для каждого часа, когда была выбрана конкретная кнопка из определенной области географии.

pagevisit2_model_03

Таблица factClickAgg может загружаться ежечасно или даже в конце каждого дня - в зависимости от требований к отчетности и аналитике. Например, скажем, что таблица загружается в конце каждого дня (после полуночи), я могу использовать что-то вроде:

/* At the end of each day (after midnight) aggregate data. */ 
INSERT  INTO factClickAgg 
        SELECT  DateKey 
               ,[Hour] 
               ,ButtonKey 
               ,GeographyKey 
               ,COUNT(*) AS [ClickCount] 
        FROM    vClicksNoUsr 
        WHERE   [DaysAgo] = 1 
        GROUP BY DateKey 
               ,[Hour] 
               ,ButtonKey 
               ,GeographyKey

Чтобы упростить запросы, я создам представление, чтобы сгладить модель:

/* To simplify queries for aggregated data */ 
CREATE VIEW vClicksAggregate 
AS 
SELECT * 
FROM factClickAgg AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

Теперь я могу запросить агрегированные данные, например, днем:

/* 
Number of times a specific buttons was clicked 
in year 2009, by day 
*/ 
SELECT  FullDate 
       ,SUM(ClickCount) AS [Counter] 
FROM    vClicksAggregate 
WHERE   ButtonName = 'MyBtn_1' 
        AND [Year] = 2009 
GROUP BY FullDate 
ORDER BY FullDate

Или с еще несколькими опциями

/* 
Number of times specific buttons were clicked 
in year 2008, on Saturdays, between 9:00 and 11:59 AM 
by users from Africa 
*/ 

SELECT  SUM(ClickCount) AS [Counter] 
FROM    vClicksAggregate 
WHERE   [Year] = 2008 
        AND [DayOfWeek] = 'Saturday' 
        AND [Hour] BETWEEN 9 AND 11 
        AND Continent = 'Africa' 
        AND ButtonName IN ( 'MyBtn_1', 'MyBtn_2', 'MyBtn_3' )

Ответ 4

Вы можете использовать исторический db, такой как PI или Historian. Это может быть больше денег, чем вы хотите потратить на этот проект, поэтому вам может понадобиться найти одну из бесплатных альтернатив, например пакет базы данных Realtime и History.

Ответ 5

Быстрые n грязные предложения.

[Предполагая, что вы не можете изменить базовые таблицы, чтобы эти таблицы уже записывали строки времени/даты, и у вас есть разрешение на создание объектов в БД].

  • Создайте VIEW (или пару VIEWS), на котором есть логическое поле, которое генерирует уникальный "номер слота" путем измельчения даты в таблицах. Что-то вроде:

CREATE VIEW view AS SELECT a, b, c, SUBSTR (date_field, x, y) slot_number   ИЗ         Таблица;

Приведенный выше пример упрощен, вы, вероятно, захотите добавить больше элементов с даты + времени.

[например, say date '2010-01-01 10: 20: 23,111', вы могли бы сгенерировать ключ как '2010-01-01 10:00': так что ваше разрешение составляет один час].

  1. Дополнительно: используйте VIEW для создания реальной таблицы, например:

    CREATE TABLE frozen_data   В ВИДЕ   SELECT * FROM VIEW   ГДЕ   Slot_Number = 'ххх;

Зачем беспокоиться о шаге 1? Вам фактически не нужно: просто использование VIEW может сделать вещи немного проще (с точки зрения SQL).

Зачем беспокоиться о шаге 2? Просто способ (возможно) уменьшения нагрузки на уже загруженные таблицы: если вы можете динамически генерировать DDL, тогда вы можете создавать отдельные таблицы с копиями "слотов" данных: с ними вы можете работать.

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

Ежедневно вы должны reset эти таблицы: если вы не можете генерировать таблицы в своем триггере на своей БД. [вряд ли я думаю].

Ответ 6

Предложение, которое не было дано (до сих пор), могло бы заключаться в использовании couchDB или аналогичных концепций баз данных, которые касаются неструктурированных данных.

Подождите! Прежде чем вскочить на меня в ужасе, позвольте мне закончить.

CouchDB собирает неструктурированные данные (JSON & c); цитируя технический обзор с веб-сайта,

Чтобы решить эту проблему добавления вернуться к неструктурированным и полуструктурированные данные, CouchDB объединяет модель представления. Представления метод агрегирования и отчетности по документы в базе данных и построенный по требованию для объединения, присоединения и отчет по документам базы данных. Просмотры динамически создаются и не влияют базовый документ, вы можете иметь как много различных представлений представлений из тех же данных, что вам нравится.

Просмотр определений строго виртуальных и отображать только документы из текущий экземпляр базы данных, они отделены от данных, которые они отображение и совместимость с Репликация. Представления CouchDB определены внутри специальных проектных документов и может реплицироваться через базу данных таких как обычные документы, поэтому что не только данные воспроизводятся в CouchDB, но все приложение также повторяются проекты.

Из ваших требований, я могу сказать вам, что вам нужно

  • для сбора большого количества данных надежным способом.
  • приоритет заключается в скорости/надежности, а не при структурировании данных, как только он попадает в систему, ни при сохранении/проверке структурных свойств того, что вы собираете (даже если вы пропустите 1 мс пользовательских данных, это может быть не такое большая проблема)
  • вам нужны структурированные данные, когда он приходит out из DB

Лично я бы сделал что-то вроде:

  • кеш собрал данные на клиентах и ​​сохранил их в пакетах на couchdb
  • в зависимости от рабочей нагрузки, сохраняйте кластер db (опять же, для этого был разработан couchdb), синхронизируя между собой
  • каждый интервал имеет сервер, генерирующий представление о необходимых вещах (т.е. каждый час и т.д.), в то время как другие продолжают собирать данные.
  • сохранить такие (теперь структурированные) представления в правильную базу данных для манипуляций и воспроизведения с помощью инструментов SQL или любого другого

Последний пример - только пример. Я понятия не имею, что вы собираетесь с этим делать.