2

月/日ごとに集計されたコレクションのメトリックをインデックス化するためのベスト プラクティスがあるかどうかに興味がありました。

ドキュメントの例:

{
  track: {
    2012: { # year
      1: { # month
        page_views: ...,
        clicks: ...,
        visits: ...
      },
      5: {
        page_views: ...,
        clicks: ...,
        visits: ...
      },
      ...
  }
}

編集:

ドキュメントを改善する方法と、それを分割するためのいくつかの提案 (私が検討したもの) についての議論が行われているためです。要件がそのようになっている理由を更新します。ドキュメントは、ユーザーを追跡するためのものです。ページビュー、訪問などを経時的に追跡します。ユーザーはドキュメントに他のデータを持っています。たとえば、registation_date があります。目標は、「X 日に登録し、A と B のトラッキング日の間に Z ページ ビューを超えたユーザーを表示する」のようなことを言うことができるようにすることでした。これを容易にする埋め込みなしのスキーマを思い付くことができませんでした。

更新されたドキュメントの例:

{
  registration_date: ...,
  email: ...,
  track: {
    2012: { # year
      1: { # month
        page_views: ...,
        clicks: ...,
        visits: ...
      },
      5: {
        page_views: ...,
        clicks: ...,
        visits: ...
      },
      ...
  }
}
4

3 に答える 3

3

残念ながら、データベーススキーマは非常にインデックス作成に適していません。そのようなオブジェクトをネストする場合、唯一のオプションは、可能なすべての年/月の組み合わせでインデックスを作成することです。また、クエリを実行するのは非常に困難です。たとえば、降順で最高の3か月を取得したい場合、データベースでそれを実行するのは困難です。

より良いオプションは、年と月の両方をオブジェクトに入れ、オブジェクトを配列に入れ(インデックスは配列のルックアップに使用できるため)、年、月、および周囲のドキュメントの一意のフィールドにわたって一意の複合インデックスを作成することです。 。

{
    name: "Some Unique Name",
    tracking:    [
        {year: 2011, month: 11, page_views: 235, clicks: 132, visits: 87 },
        {year: 2011, month: 12, page_views: 176, clicks: 122, visits: 67 },
        {year: 2012, month: 1, page_views: 53, clicks: 32, visits: 17 },
        {year: 2012, month: 2, page_views: 89, clicks: 72, visits: 67 },
        {year: 2012, month: 3, page_views: 99, clicks: 82, visits: 72 }
    ]
}

ensureIndex({name:1, tracking.year:1, tracking.month:1});

個々の日、月、または年の累積統計に頻繁にアクセスする必要がある場合は、これらのメトリックを個々のサブドキュメントに保存できます。

    tracking_daily: [
        ...
        {year: 2012, month: 3, day: 1, ...  }, 
        {year: 2012, month: 3, day: 2, ...  }, 
        {year: 2012, month: 3, day: 3, ...  }, 
        {year: 2012, month: 3, day: 4, ...  }, 
        {year: 2012, month: 3, day: 5, ...  }, 
        {year: 2012, month: 3, day: 6, ...  }, 
        {year: 2012, month: 3, day: 7, ...  }, 
        {year: 2012, month: 3, day: 8, ...  }, 
        ...
    ],
    tracking_monthly: [
        ...
        {year: 2011, month: 11, ... },
        {year: 2011, month: 12, ... },
        {year: 2012, month: 1, ...  },
        {year: 2012, month: 2, ...  },
        {year: 2012, month: 3, ...  } 
        ...
    ],
    tracking_yearly:    [
        ...
        {year: 2011, ...  },
        {year: 2012, ...  }
    ]
于 2012-12-04T21:28:15.080 に答える
1

これについてもう少し考えた後、スキーマを提案するかもしれません。

個人的には、メトリクスにサブドキュメントをまったく使用しません。メトリクスの期間にわたって日付クエリが存在すると想像できるからです。

また、サブドキュメント、特に、何年にもわたってクライアント側で膨大な処理が簡単に発生する可能性のあるサブドキュメントからメトリックを抽出するには、少なくとも集約フレームワークが必要になることを考慮する必要があります。それでも、あなたが満足するのに十分な速さで真の分析クエリを実行できるかどうかはわかりません.

サブドキュメントを省略するもう 1 つの理由は、ルート ドキュメントのサイズとの将来の互換性です。前の段落で、時間の経過とともにサブドキュメントがかなり大きくなる可能性があることを述べて、これについて少し触れました。

したがって、一般的に、将来の互換性とクエリの速度のために、サブドキュメントを広範囲に使用することはありません。

通常、私自身の個人的な経験とそのようなスキーマに関する多くの議論からわかったように、追跡分布を実際に時間バケット コレクションに分割することは良い方法です。合計 3 つのコレクションを作成します。

個人的には、この場合、適切に最適化されたインデックス全体で線形範囲のクエリを確実にするために、比較的フラットなドキュメントが必要ですが、ネストは常に悪い考えではありません。毎日の統計に使用できるドキュメントの例を挙げましょう。

{
    hours: [
        {views: 2, unique: 1} // This is actually index 0 which denotes hour 0 of the day
    ],
    pageviews: 1000,
    unique_visitors: 4,
    visitors: 67,
    clicks: 5
}

クエリを簡単にするために、1 日の時間をサブドキュメントに配置した方法がわかります。つまり、その日の統計をクエリするには、1 回往復するだけで済みますが、複雑なクエリで 2 日間の時間サブドキュメントを使用する可能性はほとんどないため、実際の分析能力を失うことはありません。

そうです、私は個人的に私のコメントに注意を払い、あなたのデータを少し非正規化しようとします. MongoDB atm で正規化しすぎていると考えています。

于 2012-12-04T21:53:30.143 に答える
0

ユーザーレベルで追跡データを集約することは本当に価値がありますか?このようなタイムスタンプを処理するのはどうですか。

{
 userId: 1234,
 registered: ISODate(""),
 visits: [ 
   ISODate(""), 
   ISODate(""),
   ISODate("")
 ],
 clicks: [
   ISODate(""),
   ISODate("")
 ]
}

次に、登録日で照合し、たとえば訪問数をカウントするための集計フレームワークだけです。

ユーザーコレクションで追加のルックアップを実行する余裕がある場合は、代わりにオブジェクトベースで追跡データを保存することをお勧めします。

visits_collection
{
  {userId: 1234, time: ISODate(""), registration: ISODate("")},
  {userId: 1234, time: ISODate(""), registration: ISODate("")},
  {userId: 1234, time: ISODate(""), registration: ISODate("")},
}

再度クエリを実行するには、集計フレームワークを使用します。これは上限付きのコレクションであり、必要に応じて登録フィールドにインデックスを付けることもできます。また、後で訪問期間などのフィールドを追加できるため、柔軟性が高くなります。

于 2012-12-05T09:48:03.527 に答える