Повече статистика на сайта в своето малко хранилище

Анализирайки статистиката на сайта, получаваме представа за това, което се случва с него. Резултатите ги сравняваме с други знания за продукта или услугата и по този начин подобряваме нашия опит.

Когато анализът на първоначалните резултати е завършен, преминаваме през осмисляне на информацията и правим изводи, започва следващия етап. Възникват идеи: какво ще стане, ако погледнем на данните от друга гледна точка?

На този етап има ограничения в инструментите за анализ. Това е една от причините, поради които инструментът Google Analytics не ми беше достатъчен, по-специално, заради ограничената възможност да виждам своите данни и да манипулирам с тях.

Винаги съм искал бързо да заредя основните данни (главни данни), да добавя друг ниво на агрегация или по друг начин да интерпретирам наличните стойности.

Това е лесно да се направи в собственото ми малко хранилище на базата на файла access.log и за това е достатъчен езикът SQL.

И така, на какви въпроси исках да намеря отговор?

Какво и кога се е променяло на сайта

Историята на промените в главните данни винаги представлява интерес.

Повече статистика на сайта в своето малко хранилище

SQL заявка за отчет

ИЗБЕРЕТЕ
	1 като 'Стекнат бар: Актуализации на съдържание по месеци',
	strftime('%m/%Y', datetime(UPDATE_DT, 'unixepoch')) КАТО 'Ден',
	COUNT(CASE WHEN PAGE_TITLE != 'n.a.' THEN DIM_REQUEST_ID END) КАТО 'Актуализации на уеб страници',
	COUNT(CASE WHEN PAGE_DESCR = 'IMAGES' THEN DIM_REQUEST_ID END) КАТО 'Качвания на изображения',
	COUNT(CASE WHEN PAGE_DESCR = 'VIDEO' THEN DIM_REQUEST_ID END) КАТО 'Качвания на видео',
	COUNT(CASE WHEN PAGE_DESCR = 'AUDIO' THEN DIM_REQUEST_ID END) КАТО 'Качвания на аудио'
ОТ DIM_REQUEST
КЪДЕТО PAGE_TITLE != 'n.a.' ИЛИ PAGE_DESCR != 'n.a.'
ГРУПИРАЙТЕ ПО strftime('%m/%Y', datetime(UPDATE_DT, 'unixepoch'))
НАРЕДЕТЕ ПО UPDATE_DT

Например, в определен момент е извършена SEO оптимизация или е добавено ново съдържание на сайта и в следствие на това се очаква ръст в трафика.

Групи потребители

Най-простият пример за група може да бъде потребителски агент или името на операционната система.

Измерването на потребителските агенти е натрупало около хиляда записа и ми е интересно да видя динамиката на разпределението на агенти в пределите на групата.

Повече статистика на сайта в своето малко хранилище

SQL заявка за отчет

ИЗБЕРЕТЕ
	1 КАТО 'Стекнат бар: Потребителски агенти',
	AGENT_OS КАТО 'ОС',
	SUM(CASE WHEN AGENT_BOT = 'n.a.' THEN 1 ELSE 0 END ) КАТО 'Потребителски агент на потребители',
	SUM(CASE WHEN AGENT_BOT != 'n.a.' THEN 1 ELSE 0 END ) КАТО 'Потребителски агент на ботове'
ОТ DIM_USER_AGENT
КЪДЕТО DIM_USER_AGENT_ID != -1
ГРУПИРАЙТЕ ПО AGENT_OS
НАРЕДЕТЕ ПО 3 DESC

Най-много различни комбинации от агенти посещават сайта от света на Windows. Сред неопределените са включени агенти като WhatsApp, PocketImageCache, PlayStation, SmartTV и др.

Активност на групи от потребители по седмици

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

Например, потребителите на кластер Linux консумират повече трафик на сайта в сравнение с всички останали.

Повече статистика на сайта в своето малко хранилище

SQL заявка за отчет

SELECT
1 as 'StackedBar: Обем на трафика по потребителска ОС и по седмица',
strftime('%W week', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Седмица',
SUM(CASE WHEN USG.AGENT_OS IN ('Android', 'Linux') THEN FCT.BYTES ELSE 0 END) / 1000 AS 'Потребители на Android/Linux',
SUM(CASE WHEN USG.AGENT_OS IN ('Windows') THEN FCT.BYTES ELSE 0 END) / 1000 AS 'Потребители на Windows',
SUM(CASE WHEN USG.AGENT_OS IN ('Macintosh', 'iOS') THEN FCT.BYTES ELSE 0 END) / 1000 AS 'Потребители на Mac/iOS',
SUM(CASE WHEN USG.AGENT_OS IN ('n.a.', 'BlackBerry') THEN FCT.BYTES ELSE 0 END) / 1000 AS 'Други'
FROM
  FCT_ACCESS_USER_AGENT_DD FCT,
  DIM_USER_AGENT USG,
  DIM_HTTP_STATUS HST
WHERE FCT.DIM_USER_AGENT_ID = USG.DIM_USER_AGENT_ID
  AND FCT.DIM_HTTP_STATUS_ID = HST.DIM_HTTP_STATUS_ID
  AND USG.AGENT_BOT = 'n.a.' /* само потребители */
  AND HST.STATUS_GROUP IN ('Успешни') /* добри страници */
  AND datetime(FCT.EVENT_DT, 'unixepoch') > date('now', '-3 month')
GROUP BY strftime('%W week', datetime(FCT.EVENT_DT, 'unixepoch'))
ORDER BY FCT.EVENT_DT

Интензивна консумация на трафик

От таблицата става видно кои са най-активните групи потребители и кой ден е техният връх на активност.
Най-активните принадлежат на кластер Linux.

Повече статистика на сайта в своето малко хранилище

SQL заявка за отчет

ИЗБЕРИ
1 AS 'Таблица: Потребителски агент с висока употреба',
strftime('%d.%m.%Y', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Ден',
ROUND(1.0*SUM(FCT.BYTES) / 1000000, 1) AS 'Трафик MB',
ROUND(1.0*SUM(FCT.IP_CNT) / SUM(1), 1) AS 'IPs',
ROUND(1.0*SUM(FCT.REQUEST_CNT) / SUM(1), 1) AS 'Заявки',
USA.DIM_USER_AGENT_ID AS 'ID',
MAX(USA.USER_AGENT_NK) AS 'Потребителски агент',
MAX(USA.AGENT_BOT) AS 'Бот'
ОТ
FCT_ACCESS_USER_AGENT_DD FCT,
DIM_USER_AGENT USA
КЪДЕ
FCT.DIM_USER_AGENT_ID = USA.DIM_USER_AGENT_ID
  И datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-30 day')
ГРУПИРАЙ ПО USA.DIM_USER_AGENT_ID, strftime('%d.%m.%Y', datetime(FCT.EVENT_DT, 'unixepoch')) 
НАРЕДИ ПО SUM(FCT.BYTES) DESC, FCT.EVENT_DT
LIMIT 10

Използвайки атрибутите ден и ID на агента, бързо можете да намерите и проследите статистиката по дни на отделни групи потребители. При необходимост, може да се намери и подробна информация в таблицата на етапа.

Как да получите информация?

Информацията от файла access.log може да стане още по-ефективна, ако интегрирате допълнителни източници на данни, въведете нови нива на агрегация и групиране.

Основни данни и същности

К основните данни спада информацията за същностите: уеб страници, изображения, видео и аудио съдържание, а в случай на магазин — продукти.

Същността сама по себе си изпълнява ролята на измерение, а процесът на запазване на промените в атрибутите се нарича историзация. В базата данни този процес често се реализира под формата на бавно променящи се измерения (SCD).

Източникът на основните данни може да бъде от най-различни системи, затова почти винаги е необходимо те да се интегрират.

Бавно променящо се измерение

Измерението DIM_REQUEST ще съдържа информация за заявките на сайта в историческа форма.

Таблица SCD2

CREATE TABLE DIM_REQUEST ( 
  DIM_REQUEST_ID      INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  DIM_REQUEST_ID_HIST INTEGER NOT NULL DEFAULT -1,
  REQUEST_NK          TEXT NOT NULL DEFAULT 'n.a.', 
  PAGE_TITLE          TEXT NOT NULL DEFAULT 'n.a.',
  PAGE_DESCR          TEXT NOT NULL DEFAULT 'n.a.',
  PAGE_KEYWORDS       TEXT NOT NULL DEFAULT 'n.a.',
  DELETE_FLAG         INTEGER NOT NULL DEFAULT 0,
  UPDATE_DT           INTEGER NOT NULL DEFAULT 0,
  UNIQUE (REQUEST_NK, DIM_REQUEST_ID_HIST)
);
INSERT INTO DIM_REQUEST (DIM_REQUEST_ID) VALUES (-1);

В допълнение ще създадем и едно представление, което винаги показва всички записи в последното им състояние. Необходимо е за зареждането на самото измерение.

Повече статистика на сайта в своето малко хранилище

Актуално представление SCD2

/* Content: actual view on scd table */
SELECT HI.DIM_REQUEST_ID,
  HI.DIM_REQUEST_ID_HIST,
  HI.REQUEST_NK,
  HI.PAGE_TITLE,
  HI.PAGE_DESCR,
  HI.PAGE_KEYWORDS,
  NK.CNT AS HIST_CNT,
  HI.DELETE_FLAG,
  strftime('%d.%m.%Y %H:%M', datetime(HI.UPDATE_DT, 'unixepoch')) AS UPDATE_DT
FROM
  ( SELECT REQUEST_NK, MAX(DIM_REQUEST_ID) AS DIM_REQUEST_ID, SUM(1) AS CNT
    FROM DIM_REQUEST
    GROUP BY REQUEST_NK
  ) NK,
  DIM_REQUEST HI
WHERE 1 = 1
  AND NK.REQUEST_NK = HI.REQUEST_NK
  AND NK.DIM_REQUEST_ID = HI.DIM_REQUEST_ID;

И представление, в което за всяка запись е събрана историческа информация. Необходимо е за изграждане на исторически точна връзка с фактите.

Повече статистика на сайта в своето малко хранилище

Историческо представяне на SCD2

/* Content: actual view on scd table */
SELECT SCD.DIM_REQUEST_ID,
  SCD.DIM_REQUEST_ID_HIST,
  SCD.REQUEST_NK,
  SCD.PAGE_TITLE,
  SCD.PAGE_DESCR,
  SCD.PAGE_KEYWORDS,
  SCD.DELETE_FLAG,
  CASE
    WHEN HIS.UPDATE_DT IS NULL
    THEN 1
    ELSE 0 END ACTIVE_FLAG,
  SCD.DIM_REQUEST_ID_HIST AS ID_FROM,
  SCD.DIM_REQUEST_ID AS ID_TO,
  CASE
    WHEN SCD.DIM_REQUEST_ID_HIST=-1
    THEN 3600
    ELSE IFNULL(SCD.UPDATE_DT,3600)
  END AS TIME_FROM,
  CASE
    WHEN HIS.UPDATE_DT IS NULL
    THEN 253370764800
    ELSE HIS.UPDATE_DT
  END AS TIME_TO,
  CASE
    WHEN SCD.DIM_REQUEST_ID_HIST=-1
    THEN STRFTIME('%d.%m.%Y %H:%M', DATETIME(3600, 'unixepoch'))
    ELSE STRFTIME('%d.%m.%Y %H:%M', DATETIME(IFNULL(SCD.UPDATE_DT,3600), 'unixepoch'))
  END AS ACTIVE_FROM,
  CASE
    WHEN HIS.UPDATE_DT IS NULL
    THEN STRFTIME('%d.%m.%Y %H:%M', DATETIME(253370764800, 'unixepoch'))
    ELSE STRFTIME('%d.%m.%Y %H:%M', DATETIME(HIS.UPDATE_DT, 'unixepoch'))
  END AS ACTIVE_TO
FROM
  DIM_REQUEST SCD
  LEFT OUTER JOIN DIM_REQUEST HIS
  ON SCD.REQUEST_NK = HIS.REQUEST_NK AND SCD.DIM_REQUEST_ID = HIS.DIM_REQUEST_ID_HIST;

Агреация на данни

Стискането (агреацията) позволява оценка на данните на по-високо ниво и откриване на аномалии и тенденции, които не се виждат в подробните отчети.

Например, в измерението с кодовете на статуса на заявките DIM_HTTP_STATUS ще добавим група:

STATUS / GROUP
0xx / n.a.
1xx / Информационен
2xx / Успешен
3xx / Пренасочване
4xx / Клиентска грешка
5xx / Серверна грешка

Измерението на потребителските агенти DIM_USER_AGENT ще съдържа атрибутите AGENT_OS и AGENT_BOT, отговорни за групите. Те могат да бъдат попълвани в процеса на ETL:

Зареждане на DIM_USER_AGENT

/* Propagate the user agent from access log */
INSERT INTO DIM_USER_AGENT (USER_AGENT_NK, AGENT_OS, AGENT_ENGINE, AGENT_DEVICE, AGENT_BOT, UPDATE_DT)
WITH CLS AS (
	SELECT BROWSER
	FROM STG_ACCESS_LOG WHERE LENGTH(BROWSER)>1
	GROUP BY BROWSER
)
SELECT
	CLS.BROWSER AS USER_AGENT_NK,
	CASE
	WHEN INSTR(CLS.BROWSER,'Macintosh')>0
		THEN 'Macintosh'
	WHEN INSTR(CLS.BROWSER,'iPhone')>0
			 OR INSTR(CLS.BROWSER,'iPad')>0
			 OR INSTR(CLS.BROWSER,'iPod')>0
			 OR INSTR(CLS.BROWSER,'Apple TV')>0
			 OR INSTR(CLS.BROWSER,'Darwin')>0
		THEN 'iOS'
	WHEN INSTR(CLS.BROWSER,'Android')>0
		THEN 'Android'
	WHEN INSTR(CLS.BROWSER,'X11;')>0 OR INSTR(CLS.BROWSER,'Wayland;')>0 OR INSTR(CLS.BROWSER,'linux-gnu')>0
		THEN 'Linux'
	WHEN INSTR(CLS.BROWSER,'BB10;')>0 OR INSTR(CLS.BROWSER,'BlackBerry')>0
		THEN 'BlackBerry'
	WHEN INSTR(CLS.BROWSER,'Windows')>0
		THEN 'Windows'
	ELSE 'n.a.' END AS AGENT_OS, -- OS
	CASE
	WHEN INSTR(CLS.BROWSER,'AppleCoreMedia')>0
		THEN 'AppleWebKit'
	WHEN INSTR(CLS.BROWSER,') ')>1 AND LENGTH(CLS.BROWSER)>INSTR(CLS.BROWSER,') ')
		THEN COALESCE(SUBSTR(CLS.BROWSER, INSTR(CLS.BROWSER,') ')+2, LENGTH(CLS.BROWSER) - INSTR(CLS.BROWSER,') ')-1), 'N/A')
	ELSE 'n.a.' END AS AGENT_ENGINE, -- Engine
	CASE
	WHEN INSTR(CLS.BROWSER,'iPhone')>0
		THEN 'iPhone'
	WHEN INSTR(CLS.BROWSER,'iPad')>0
		THEN 'iPad'
	WHEN INSTR(CLS.BROWSER,'iPod')>0
		THEN 'iPod'
	WHEN INSTR(CLS.BROWSER,'Apple TV')>0
		THEN 'Apple TV'
	WHEN INSTR(CLS.BROWSER,'Android ')>0 AND INSTR(CLS.BROWSER,'Build')>0
		THEN COALESCE(SUBSTR(CLS.BROWSER, INSTR(CLS.BROWSER,'Android '), INSTR(CLS.BROWSER,'Build')-INSTR(CLS.BROWSER,'Android ')), 'n.a.')
	WHEN INSTR(CLS.BROWSER,'Android ')>0 AND INSTR(CLS.BROWSER,'MIUI')>0
		THEN COALESCE(SUBSTR(CLS.BROWSER, INSTR(CLS.BROWSER,'Android '), INSTR(CLS.BROWSER,'MIUI')-INSTR(CLS.BROWSER,'Android ')), 'n.a.')
	ELSE 'n.a.' END AS AGENT_DEVICE, -- Device
	CASE
	WHEN INSTR(LOWER(CLS.BROWSER),'yandex.com')>0
		THEN 'yandex'
	WHEN INSTR(LOWER(CLS.BROWSER),'googlebot')>0
		THEN 'google'
	WHEN INSTR(LOWER(CLS.BROWSER),'bingbot')>0
		THEN 'microsoft'
	WHEN INSTR(LOWER(CLS.BROWSER),'ahrefsbot')>0
		THEN 'ahrefs'
	WHEN INSTR(LOWER(CLS.BROWSER),'jobboersebot')>0 OR INSTR(LOWER(CLS.BROWSER),'jobkicks')>0
		THEN 'job.de'
	WHEN INSTR(LOWER(CLS.BROWSER),'mail.ru')>0
		THEN 'mail.ru'
	WHEN INSTR(LOWER(CLS.BROWSER),'baiduspider')>0
		THEN 'baidu'
	WHEN INSTR(LOWER(CLS.BROWSER),'mj12bot')>0
		THEN 'majestic-12'
	WHEN INSTR(LOWER(CLS.BROWSER),'duckduckgo')>0
		THEN 'duckduckgo'
	WHEN INSTR(LOWER(CLS.BROWSER),'bytespider')>0
		THEN 'bytespider'
	WHEN INSTR(LOWER(CLS.BROWSER),'360spider')>0
		THEN 'so.360.cn'
	WHEN INSTR(LOWER(CLS.BROWSER),'compatible')>0 OR INSTR(LOWER(CLS.BROWSER),'http')>0
		OR INSTR(LOWER(CLS.BROWSER),'libwww')>0 OR INSTR(LOWER(CLS.BROWSER),'spider')>0
		OR INSTR(LOWER(CLS.BROWSER),'java')>0 OR INSTR(LOWER(CLS.BROWSER),'python')>0
		OR INSTR(LOWER(CLS.BROWSER),'robot')>0 OR INSTR(LOWER(CLS.BROWSER),'curl')>0 OR INSTR(LOWER(CLS.BROWSER),'wget')>0
		THEN 'other'
	ELSE 'n.a.' END AS AGENT_BOT, -- Bot
	STRFTIME('%s','now') AS UPDATE_DT
FROM CLS
LEFT OUTER JOIN DIM_USER_AGENT TRG
ON CLS.BROWSER = TRG.USER_AGENT_NK
WHERE TRG.DIM_USER_AGENT_ID IS NULL

Интеграция на данни

Включва организирането на прехвърлянето на данни от операционната система в отчетна. За това е необходимо да се създаде стейдж таблица със структура, подобна на източника.

В стейдж информацията за уеб страниците попада от резервно копие на CMS под формата на заявки за вмъкване.

Зареждането на историческата таблица DIM_REQUEST с основни данни се извършва в три стъпки: зареждане на нови ключове и атрибути, обновяване на съществуващите и фиксиране на изтритите записи.

Зареждане на нови записи SCD2

/* Load request table SCD from master data */
INSERT INTO DIM_REQUEST (DIM_REQUEST_ID_HIST, REQUEST_NK, PAGE_TITLE, PAGE_DESCR, PAGE_KEYWORDS, DELETE_FLAG, UPDATE_DT)
WITH CLS  AS ( -- prepare keys
	SELECT
	'/' || NAME AS REQUEST_NK,
	TITLE       AS PAGE_TITLE,
	CASE WHEN DESCRIPTION = '' OR DESCRIPTION IS NULL
	     THEN 'n.a.' ELSE DESCRIPTION
	END AS PAGE_DESCR,
	CASE WHEN KEYWORDS = '' OR KEYWORDS IS NULL
	     THEN 'n.a.' ELSE KEYWORDS
	END AS PAGE_KEYWORDS
	FROM STG_CMS_MENU
	WHERE CONTENT_TYPE != 'folder' -- only web pages
	  AND PAGE_TITLE != 'n.a.' -- master data which make sense
)
/* new records from stage: CLS */
SELECT
	-1 AS DIM_REQUEST_ID_HIST,
	CLS.REQUEST_NK,
	CLS.PAGE_TITLE,
	CLS.PAGE_DESCR,
	CLS.PAGE_KEYWORDS,
	0 AS DELETE_FLAG,
	STRFTIME('%s','now') AS UPDATE_DT
FROM CLS
LEFT OUTER JOIN
 (
	SELECT
	DIM_REQUEST_ID,
	REQUEST_NK,
	PAGE_TITLE,
	PAGE_DESCR,
	PAGE_KEYWORDS
	FROM DIM_REQUEST_V_ACT
) TRG ON CLS.REQUEST_NK = TRG.REQUEST_NK
WHERE TRG.REQUEST_NK IS NULL -- no such record in data mart

Обновяване на атрибутите SCD2

/* Load request table SCD from master data */
INSERT INTO DIM_REQUEST (DIM_REQUEST_ID_HIST, REQUEST_NK, PAGE_TITLE, PAGE_DESCR, PAGE_KEYWORDS, DELETE_FLAG, UPDATE_DT)
WITH CLS  AS ( -- prepare keys
	SELECT
	'/' || NAME AS REQUEST_NK,
	TITLE       AS PAGE_TITLE,
	CASE WHEN DESCRIPTION = '' OR DESCRIPTION IS NULL
	     THEN 'n.a.' ELSE DESCRIPTION
	END AS PAGE_DESCR,
	CASE WHEN KEYWORDS = '' OR KEYWORDS IS NULL
	     THEN 'n.a.' ELSE KEYWORDS
	END AS PAGE_KEYWORDS
	FROM STG_CMS_MENU
	WHERE CONTENT_TYPE != 'folder' -- only web pages
	  AND PAGE_TITLE != 'n.a.' -- master data which make sense
)
/* updated records from stage: CLS and build reference to history: HIST */
SELECT
	HIST.DIM_REQUEST_ID AS DIM_REQUEST_ID_HIST,
	HIST.REQUEST_NK,
	CLS.PAGE_TITLE,
	CLS.PAGE_DESCR,
	CLS.PAGE_KEYWORDS,
	0 AS DELETE_FLAG,
	STRFTIME('%s','now') AS UPDATE_DT
FROM CLS,
     DIM_REQUEST_V_ACT TRG,
     DIM_REQUEST HIST
WHERE CLS.REQUEST_NK = TRG.REQUEST_NK
  AND TRG.DIM_REQUEST_ID = HIST.DIM_REQUEST_ID
  AND ( CLS.PAGE_TITLE != HIST.PAGE_TITLE /* changes only */
     OR CLS.PAGE_DESCR != HIST.PAGE_DESCR
     OR CLS.PAGE_KEYWORDS != HIST.PAGE_KEYWORDS )

Изтрити записи SCD2

/* Load request table SCD from master data */
INSERT INTO DIM_REQUEST (DIM_REQUEST_ID_HIST, REQUEST_NK, PAGE_TITLE, PAGE_DESCR, PAGE_KEYWORDS, DELETE_FLAG, UPDATE_DT)
WITH CLS  AS ( -- prepare keys
	SELECT
	'/' || NAME AS REQUEST_NK,
	TITLE       AS PAGE_TITLE
	FROM STG_CMS_MENU
	WHERE CONTENT_TYPE != 'folder' -- only web pages
	  AND PAGE_TITLE != 'n.a.' -- master data which make sense
)
/*  deleted records in data mart: TRG */
SELECT
	TRG.DIM_REQUEST_ID AS DIM_REQUEST_ID_HIST,
	TRG.REQUEST_NK,
	TRG.PAGE_TITLE,
	TRG.PAGE_DESCR,
	TRG.PAGE_KEYWORDS,
	1 AS DELETE_FLAG,
	STRFTIME('%s','now') AS UPDATE_DT
FROM (
	SELECT
	DIM_REQUEST_ID,
	REQUEST_NK,
	PAGE_TITLE,
	PAGE_DESCR,
	PAGE_KEYWORDS
	FROM DIM_REQUEST_V_ACT
	WHERE PAGE_TITLE != 'n.a.' -- track master data only
	  AND DELETE_FLAG = 0 -- not already deleted
) TRG
LEFT OUTER JOIN CLS ON TRG.REQUEST_NK = CLS.REQUEST_NK
WHERE CLS.REQUEST_NK IS NULL -- no such record in stage

Всеки източник на данни трябва да бъде придружен от формално описание, например, в файла readme.txt:

Получател на данни формално/технически: име, електронен адрес
Доставчик на данни формално/технически: име, електронен адрес
Източник на данни: път до файла, имена на услугите
Информация за достъп до данни: потребители и пароли

Схема на движението на данни ще помогне в процеса на поддръжка и актуализация, например, в текстов вид:

Прехвърляне на файл. Източник: ftp.domain.net:/logs/access.log Цел: /var/www/access.log
Четене в стейдж. Цел: STG_ACCESS_LOG
Зареждане и трансформация. Цел: FCT_ACCESS_REQUEST_REF_HH
Зареждане и трансформация. Цел: FCT_ACCESS_USER_AGENT_DD
Доклад. Цел: /var/www/report.html

Извод

Така, статията описва механизми като интеграция на основни данни и въвеждане на нови нива на агрегиране. Те са необходими при изграждането на хранилища за данни с цел получаване на допълнителни знания и подобряване на качеството на информацията.

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster