28

私は私たちのサイトのアクティビティ ストリームを構築しており、かなりうまく機能するものでかなりの前進を遂げています。

次の 2 つのテーブルを使用します。

ストリーム:

  • id- 一意のストリーム アイテム ID
  • user_id- ストリーム アイテムを作成したユーザーの ID
  • object_type- オブジェクトのタイプ (現在は「販売者」または「製品」)
  • object_id- オブジェクトの内部 ID (現在、販売者 ID または製品 ID)
  • action_name- オブジェクトに対して実行されたアクション (現在は「購入」または「ハート」のいずれか)
  • stream_date- アクションが作成されたタイムスタンプ。
  • hidden- ユーザーが項目を非表示にすることを選択した場合のブール値。

次のとおりです。

  • id- 独自のフォローID
  • user_id- 「フォロー」アクションを開始したユーザーの ID。
  • following_user- フォローされているユーザーの ID。
  • followed- フォロー アクションが実行されたタイムスタンプ。

現在、次のクエリを使用してデータベースからコンテンツを取得しています。

クエリ:

SELECT stream.*,
   COUNT(stream.id) AS rows_in_group,
   GROUP_CONCAT(stream.id) AS in_collection
FROM stream
INNER JOIN follows ON stream.user_id = follows.following_user
WHERE follows.user_id = '1'
  AND stream.hidden = '0'
GROUP BY stream.user_id,
     stream.action_name,
     stream.object_type,
     date(stream.stream_date)
ORDER BY stream.stream_date DESC;

このクエリは実際には非常にうまく機能し、小さな PHP を使用して MySQL が返すデータを解析し、同じユーザーによる同じタイプのアクションをグループ化して、アクション間の時間があまり長くない場合に適切なアクティビティ ストリームを作成できます。 (以下の例を参照)。

現在のストリームの出力例

私の質問は、これをよりスマートにするにはどうすればよいですか? 現在、MySQL がそれらをグループ化することを認識している特定の時間枠内に特定のユーザーによる複数のアイテムがある場合、「ユーザー」アクティビティという 1 つの軸でグループ化されます。

これをさらにスマートにして、「object_id」などの別の軸でグループ化するにはどうすればよいですか。同じオブジェクトに対して複数のアクションが順番にある場合、これらのアイテムはグループ化されますが、ユーザーごとにアクション/オブジェクトをグループ化するために現在持っているグループ化ロジックを維持します. そして、データの重複なしにこれを実装しますか?

複数のオブジェクトが連続して表示される例:

連続して現れる複数のオブジェクト

このような問題の解決策が非常に複雑になり、非常に迅速になる可能性があることは理解していますが、これに対するエレガントでかなり単純な解決策が (できれば) MySQL にあるかどうか疑問に思っています。

4

4 に答える 4

17

希望する結果に関するいくつかの観察:

一部のアイテムは集約されており (Jack Sprat は 7 人のセラーを心に留めています)、他のアイテムはアイテム化されています (Lord Nelson が Golden Hind をチャーターしました)。おそらく、2 つの別個のサブクエリからこれら 2 つのクラスの項目をまとめるクエリに UNION を含める必要があります。

かなり大雑把なタイムスタンプ近似関数を使用して、アイテムをグループ化します... DATE(). より洗練された微調整可能なスキームを使用したい場合があります...このように、多分

  GROUP BY TIMESTAMPDIFF(HOUR,CURRENT_TIME(),stream_date) DIV hourchunk

これにより、年齢ごとにグループ化できます。たとえば、48 を使用するとhourchunk、0 ~ 48 時間前のものをまとめてグループ化できます。システムにトラフィックとアクションを追加すると、値を減らしたい場合がありhourchunkます。

于 2012-12-22T17:37:43.977 に答える
14

私の印象では、あなたと同じようにユーザーごとにグループ化する必要がありますが、そのグループ化の後、アクションごとにもグループ化する必要があります。

次のようなサブクエリが必要なようです。

SELECT *, -- or whatever columns
   SUM(actions_in_group) AS total_rows_in_group,
   GROUP_CONCAT(in_collection) AS complete_collection
   FROM
     ( SELECT stream.*, -- or whatever columns
          COUNT(stream.id) AS actions_in_user_group,
          GROUP_CONCAT(stream.id) AS actions_in_user_collection
       FROM stream
       INNER JOIN follows
       ON stream.user_id = follows.following_user
       WHERE follows.user_id = '1'
         AND stream.hidden = '0'
       GROUP BY stream.user_id,
            date(stream.stream_date)
     )
   GROUP BY object_id,
            date(stream.stream_date)
   ORDER BY stream.stream_date DESC;

最初のクエリ (現在は内側のクエリ) はユーザーごとにグループ化されますが、ユーザー グループは同じアクションによって再グループ化されます。

于 2013-01-05T10:43:29.733 に答える
6

Fashiolista では、フィード システムを構築するアプローチをオープンソース化しました。 https://github.com/tschellenbach/Feedly 現在、この問題の解決を目的とした最大のオープン ソース ライブラリです。(ただしPythonで書かれています)

Feedly を構築したのと同じチームが、複雑さを処理するホスト型 API も提供しています。getstream.ioをご覧ください。PHP 、Node、Ruby、および Python 用のクライアントがあります。 https://github.com/tbarbugli/stream-php また、探しているカスタム定義の集計もサポートしています。

さらに、この高スケーラビリティの投稿を見て、関連する設計上の決定事項のいくつかを説明しました: http://highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic- feeds.html

このチュートリアルは、Redis を使用して Pinterest のフィードのようなシステムをセットアップするのに役立ちます。始めるのはとても簡単です。

フィードの設計についてさらに学ぶには、Feedly の元になった次の記事を読むことを強くお勧めします。

于 2014-05-30T12:59:50.780 に答える