10

2 つのテーブルがあり、外部ソースからこれらのテーブルにレコードが継続的に挿入されています。これらのテーブルがユーザー インタラクションの統計を保持しているとしましょう。ユーザーがボタンをクリックすると、そのクリックの詳細 (ユーザー、クリック時刻など) がテーブルの 1 つに書き込まれます。ユーザーがそのボタンをマウスオーバーすると、レコードが詳細とともに他のテーブルに追加されます。

多くのユーザーが常にシステムと対話している場合、大量のデータが生成され、それらのテーブルが非常に大きくなります。

データを見たいときは、時間単位または日単位の解像度で見たいです。

要求された解像度で (データが収集されるにつれて) データを段階的に継続的に要約する方法またはベスト プラクティスはありますか?

または、この種の問題に対するより良いアプローチはありますか?

PS。私がこれまでに見つけたのは、Talend のような ETL ツールが生活を楽にすることができるということです。

更新:現在MySQLを使用していますが、DB、環境などに関係なくベストプラクティスが気になります.

4

6 に答える 6

8

低待機時間のデータ ウェアハウス アプリケーションでこれを行う通常の方法は、迅速に更新できる (つまり、その場で集計を再計算する必要がない) ものを含む先頭のパーティションを持つパーティション分割されたテーブルを用意し、末尾のパーティションは集計で埋め戻すことです。 . つまり、先頭のパーティションは末尾のパーティションとは異なるストレージ スキームを使用できます。

ほとんどの商用および一部のオープンソース RDBMS プラットフォーム (PostgreSQL など) は、パーティション化されたテーブルをサポートできます。これを使用して、この種のことを何らかの方法で行うことができます。ログからデータベースにデータを入力する方法は、読者の課題として残されています。

基本的に、このタイプのシステムの構造は次のようになります。

  • ある種の日付または日時の値でパーティション化されたテーブルがあり、時間、日、または適切と思われる粒度でパーティション化されています。ログ エントリはこのテーブルに追加されます。

  • タイム ウィンドウがパーティションから滑り落ちると、定期的なジョブがそれをインデックス化または要約し、「凍結」状態に変換します。たとえば、Oracle でのジョブは、そのパーティションにビットマップ インデックスを作成したり、マテリアライズド ビューを更新してそのパーティションの概要データを含めたりする場合があります。

  • 後で、古いデータを削除したり、要約したり、パーティションをマージしたりできます。

  • 時間が経つにつれて、定期的なジョブが前縁パーティションの後ろに埋め戻されます。履歴データは、パフォーマンスの高い統計クエリに適した形式に変換されますが、フロント エッジ パーティションは簡単にすばやく更新できます。このパーティションにはそれほど多くのデータがないため、データ セット全体に対するクエリは比較的高速です。

このプロセスの正確な性質は、DBMS プラットフォームによって異なります。

たとえば、SQL Server でのテーブル パーティション分割はそれほど優れたものではありませんが、Analysis Services (Microsoft が SQL Server にバンドルしている OLAP サーバー) を使用すると実行できます。これは、先頭のパーティションを純粋な ROLAP として構成し (OLAP サーバーは基になるデータベースに対してクエリを発行するだけです)、後続のパーティションを MOLAP として再構築します (OLAP サーバーは、「集計」と呼ばれる永続的な集計を含む独自の特殊なデータ構造を構築します)。 )。分析サービスは、これをユーザーに対して完全に透過的に行うことができます。古いROLAPパーティションがまだユーザーに表示されている間に、バックグラウンドでパーティションを再構築できます。ビルドが完了すると、パーティションがスワップされます。キューブは、ユーザーへのサービスを中断することなく、いつでも利用できます。

Oracle では、パーティション構造を個別に更新できるため、インデックスを作成したり、マテリアライズド ビューに基づいてパーティションを作成したりできます。Query re-write を使用すると、Oracle のクエリ オプティマイザは、ベース ファクト テーブルから計算された集計値をマテリアライズド ビューから取得できることを確認できます。クエリは、パーティションが使用可能な場合はマテリアライズド ビューから集計値を読み取り、パーティションが使用できない場合はリーディング エッジ パーティションから集計値を読み取ります。

PostgreSQL も同様のことができるかもしれませんが、このタイプのシステムを PostgreSQL に実装することを検討したことはありません。

定期的な停止に耐えることができる場合は、要約を実行し、先行データと後続データのビューを設定することで、同様のことを明示的に行うことができます。これにより、透過的なパーティショニングをサポートしていないシステムでこの種の分析を実行できます。ただし、ビューが再構築されると、システムが一時的に停止するため、実際には営業時間中にこれを行うことはできません。ほとんどの場合、夜間になります。

編集:ログ ファイルの形式または利用可能なログ オプションに応じて、データをシステムにロードするさまざまな方法があります。いくつかのオプションは次のとおりです。

  • お気に入りのプログラミング言語を使用して、データを読み取り、関連する部分を解析してデータベースに挿入するスクリプトを作成します。これはかなり頻繁に実行される可能性がありますが、ファイル内のどこにいるかを追跡する何らかの方法が必要です。特に Windows では、ロックに注意してください。Unix/Linux ではデフォルトのファイル ロック セマンティクスでこれを行うことができますが (これが機能tail -fします)、Windows でのデフォルトの動作は異なります。両方のシステムは、互いにうまく機能するように作成する必要があります。

  • unix-oid システムでは、ログをパイプに書き込み、上記のパイプからの読み取りと同様のプロセスを実行できます。これにより、レイテンシーが最も低くなりますが、リーダーで障害が発生すると、アプリケーションがブロックされる可能性があります。

  • ログ ファイルを書き出すのではなく、データベースに直接入力するアプリケーションのログ インターフェイスを作成します。

  • データベースにバルク ロード API を使用し (ほとんどの場合、このタイプの API を使用できるわけではありません)、ロギング データをバッチでロードします。最初のオプションと同様のプログラムを作成しますが、一括読み込み API を使用します。これは、行ごとに入力するよりも使用するリソースが少なくなりますが、一括読み込みを設定するためのオーバーヘッドが大きくなります。これは負荷の頻度が低い場合 (おそらく毎時間または毎日) に適しており、システム全体への負担が少なくなります。

これらのシナリオのほとんどでは、どこに行ったかを追跡することが問題になります。ファイルをポーリングして変更を見つけるのは実行不可能なほどコストがかかる可能性があるため、ログ リーダーとうまく連携するようにロガーを設定する必要がある場合があります。

  • 1 つのオプションは、ロガーを変更して、一定期間ごと (数分ごとなど) に別のファイルへの書き込みを開始することです。ログ リーダーを定期的に起動し、まだ処理されていない新しいファイルを読み込みます。古いファイルを読みます。これが機能するためには、ファイルの命名スキームは時間に基づいている必要があります。これにより、リーダーはどのファイルを選択するかがわかります。アプリケーションでまだ使用中のファイルを処理するのは面倒なので (どのくらい読み取ったかを追跡する必要があります)、最後の期間までのファイルのみを読み取る必要があります。

  • 別のオプションは、ファイルを移動してから読み取ることです。これは、Unix のように動作するファイルシステムで最適に機能しますが、NTFS でも機能するはずです。ファイルを移動してから、気楽に読みます。ただし、ロガーはファイルを作成/追加モードで開き、書き込みを行ってから閉じる必要があります。開いたままロックしたままにしないでください。これは間違いなく Unix の動作です。移動操作はアトミックでなければなりません。Windows では、これを機能させるためにロガーの上に立たなければならない場合があります。

于 2010-01-14T21:36:02.493 に答える
2

RRDToolを見てください。ラウンドロビンデータベースです。キャプチャするメトリックを定義しますが、それを保存する解像度を定義することもできます。

たとえば、1秒ごとに価値のある情報を保持するように指定できます。過去24時間-毎分; 過去1週間、1時間ごとなど。

これは、 GangliaCactiなどのシステムで統計を収集するために広く使用されています。

于 2010-01-07T17:02:34.643 に答える
2

データのスライスと集計 (時間別など) に関して言えば、スター スキーマ (Kimball スター) は非常にシンプルですが、強力なソリューションです。クリックごとに、時間 (2 番目の解像度まで)、ユーザー情報、ボタン ID、およびユーザーの場所を保存するとします。スライスとダイシングを簡単に行えるようにするために、ほとんど変更されないオブジェクトのプロパティ用に事前に読み込まれたルックアップ テーブル (DW の世界ではディメンション テーブルと呼ばれる) から始めます。 テーブルには、特定の日を説明する属性 (フィールド) の数を含む、日ごとに 1 つの行があります 。テーブルは何年も前から事前に読み込むことができ、次のようなフィールドが含まれている場合は 1 日 1 回更新する必要があります。それ以外の場合は、「ロード アンド フォーゲット」になる可能性があります。は、次のような日付属性ごとに簡単にスライスできます

pagevisit2_model_02

dimDateDaysAgo, WeeksAgo, MonthsAgo, YearsAgodimDate

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

10 年間のデータの場合、テーブルには最大 3650 行しかありません。

dimGeographyテーブルには、関心のある地域がプリロードされています。行数は、レポートで必要な「地理的解像度」に応じて異なり、次のようなデータ スライスが可能です 。

WHERE Continent = 'South America'

一度読み込まれると、めったに変更されません。

サイトのボタンごとに、dimButton テーブルに 1 つの行があるため、クエリで

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

テーブルには登録ユーザーごとに 1 つの行があり、ユーザーが登録するとすぐに新しいユーザー情報がこのdimUser行に読み込まれるか、少なくとも他のユーザー トランザクションがファクト テーブルに記録される前に、新しいユーザー情報がテーブルに含まれている必要があります。

ボタンのクリックを記録するために、factClickテーブルを追加します。 テーブルには、ある時点で特定のユーザーがボタンをクリックするたびに 1 つの行があります 。私は(2番目の解決策)を使用し、特定のユーザーからのクリックを1秒あたり1回よりも速く除外するために、複合主キーで使用しました。フィールドに注意してください.

pagevisit2_model_01

factClickTimeStampButtonKeyUserKeyHourTimeStamp

WHERE [HOUR] BETWEEN 7 AND 9

したがって、次のことを考慮する必要があります。

  • テーブルをロードする方法は?ETL ツールを使用して Weblog から定期的に (1 時間ごとまたは数分ごとに)、または何らかのイベント ストリーミング プロセスを使用した低遅延ソリューションを使用します。
  • テーブル内の情報を保持する期間は?

テーブルが情報を 1 日だけ保持するか、数年間保持するかに関係なく、分割する必要があります。ConcernedOfTunbridgeWは彼の回答でパーティショニングについて説明しているので、ここではスキップします。

ここで、さまざまな属性 (日と時間を含む) ごとのスライスとダイシングの例をいくつか示します。

クエリを簡素化するために、モデルをフラット化するビューを追加します。

/* 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 ('dude45@somemail.com', 'bob46@bobmail.com') 
GROUP BY [Email] 
ORDER BY [Email]

のデータに興味があるとしますUser = ALL。はdimUser大きなテーブルなので、クエリを高速化するために、テーブルなしでビューを作成します。

/* 
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レポートと分析の要件に応じて、1 時間ごとに、または 1 日の終わりに読み込むことができます。たとえば、テーブルが毎日の終わり (真夜中以降) にロードされるとしましょう。次のようなものを使用できます。

/* 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' )
于 2010-01-16T18:26:39.547 に答える
0

(これまでのところ)提供されていない提案は、非構造化データを処理するcouchDBまたは同様のデータベースの概念を使用することかもしれません。

待って!恐怖で私に飛びつく前に、私を終わらせてください。

CouchDBは非構造化データ(JSON&c)を収集します。ウェブサイトから技術概要を引用し、

非構造化データと半構造化データに構造を追加するというこの問題に対処するために、CouchDBはビューモデルを統合します。ビューは、データベース内のドキュメントを集約およびレポートする方法であり、データベースドキュメントを集約、結合、およびレポートするためにオンデマンドで構築されます。ビューは動的に構築され、基になるドキュメントには影響しません。同じデータのさまざまなビュー表現を好きなだけ持つことができます。

ビュー定義は厳密に仮想化されており、現在のデータベースインスタンスのドキュメントのみを表示するため、表示するデータとは別に、レプリケーションと互換性があります。CouchDBビューは、特別な設計ドキュメント内で定義され、通常のドキュメントのようにデータベースインスタンス間で複製できるため、CouchDBでデータが複製されるだけでなく、アプリケーション設計全体も複製されます。

あなたの要件から、私はあなたが必要だと言うことができます

  • 信頼できる方法で大量のデータを収集する
  • 優先順位は速度/信頼性であり、システムに入るとすぐにデータを構造化することや、収集したものの構造的特性を維持/チェックすることではありません(1msのユーザーデータを見逃しても、それほど大きな問題ではないかもしれません)
  • DBから出力されるときに構造化データが必要です

個人的に、私は次のようなことをします:

  • 収集したデータをクライアントにキャッシュし、バーストでcouchdbに保存します
  • ワークロードに応じて、dbのクラスター(ここでも、couchdbはそのために設計されています)を相互に同期させます
  • 間隔ごとに、サーバーが必要なもののビューを生成し(つまり、1時間ごとなど)、他のサーバーはデータを収集し続けます
  • このような(現在は構造化された)ビューを適切なデータベースに保存して、SQLツールなどを操作したり操作したりできます。

最後のポイントは単なる例です。私はあなたがそれで何をするつもりなのか分かりません。

于 2010-01-15T11:29:30.100 に答える
0

クイック&ダーティな提案。

[基礎となるテーブルを変更できないと仮定すると、これらのテーブルには行が追加された時刻/日付が既に記録されており、DB にオブジェクトを作成する権限があることが前提です]。

  1. テーブル内の日付を切り刻むことによって一意の「スロット番号」を生成する論理フィールドを持つ VIEW (またはいくつかの VIEW) を作成します。何かのようなもの:

CREATE VIEW ビュー AS SELECT a、b、c、SUBSTR(date_field、x、y) slot_number FROM TABLE;

上記の例は簡略化されています。おそらく、日付と時刻の要素をさらに追加する必要があります。

[たとえば、日付が '2010-01-01 10:20:23,111' の場合、おそらく '2010-01-01 10:00' としてキーを生成できます。つまり、解像度は 1 時間です]。

  1. オプション: VIEW を使用して、次のような実際のテーブルを生成します。

    CREATE TABLE frozen_data AS SELECT * FROM VIEW WHERE slot_number='xxx;

なぜステップ 1 を気にするのですか? 実際にそうする必要はありません: VIEW を使用するだけで、(SQL の観点から) 少し簡単になる場合があります。

なぜステップ 2 を気にするのですか? すでにビジーなテーブルの負荷を (おそらく) 軽減する方法: DDL を動的に生成できる場合は、データの「スロット」のコピーを使用して別のテーブルを作成できます。これを使用して作業できます。

または、テーブルのグループを設定することもできます: 1 日の 1 時間ごとに 1 つ。セカンダリ テーブルにデータを入力するトリガーを作成します。トリガーのロジックは、どのテーブルに書き込まれるかを分離できます。

DB のトリガーでテーブルを生成できない限り、これらのテーブルを毎日リセットする必要があります。[ありそうもない]。

于 2010-01-14T21:04:39.793 に答える
0

PI や Historian などの履歴データベースを使用できます。これらは、このプロジェクトに費やす金額よりも多くの費用がかかる可能性があるため、Realtime and History Database Packageなどのフリーウェアの代替品を調べてください。

于 2010-01-14T18:58:07.320 に答える