1

検索クエリに基づいて特定の方法で並べ替える必要がある大量のデータがありますが、最適な方法がわかりません。

並べ替えようとしているデータは、学校ごとにグループ化されたコースのリストです。各コースは 1 つの学校によって教えられます。各学校は、複数の学校間の関係を表す任意の数の「パートナーシップ」に属することができます。ユーザーは、コース名で任意の数のコースを検索できます。

次のようにデータを並べ替える必要があります。

  • コースは学校ごとにグループ化されており、1 ページに 10 の学校が表示されます。

  • ユーザーが検索したすべてのコースを提供できる学校がリストの最初に表示されます。

  • これらの結果の後に、ユーザーが検索したすべてのコースに対応できるパートナーシップに属する学校が並んで表示されます。

次に例を示します。

  • Aは歴史、フランス語、英語のコースを教えています。
  • Bはフランス語と数学を教えています。
  • Cは歴史を教えています。
  • BCはパートナーシップを結んでいます。
  • Dは歴史を教えています。

  • ユーザーは「歴史」と「フランス語」を検索します。

  • Aは、ユーザーが探している両方のコースを提供できるため、歴史とフランス語のコースと共に結果に最初に表示されます。

  • Bに続いてCが次に表示され、その後に関連するコースがリストされます。これは、パートナーシップがユーザーの必須コースの両方を提供できるためです。

  • D関連するコースが 1 つしかないため、次に表示されます。

データは、いくつかのテーブルにわたって Microsoft SQL Server データベースに保存されます。簡略化したスキーマを次に示します。

コース:

  • 整数 ID
  • varchar 名
  • int スクール ID

学校:

  • 整数 ID
  • varchar 名

パートナーシップ:

  • 整数 ID
  • varchar パートナーシップ名

学校パートナーシップ:

  • 整数 ID
  • int スクール ID
  • int パートナーシップ ID

100000 以上のコースと約 300 の学校があります。SQLで指定されたコースをソートする方法がわかりません。これが私の最大の問題だと思います。ページごとに 10 個の結果を表示するだけで済みますが、SQL クエリで並べ替えを行うことができないため、結果セットを 10 個の結果に切り詰める前に、結果セット全体を抽出して PHP で手動で並べ替える必要があります。

私は現在、Doctrine 2 を使用して複数の結合を使用して単一のクエリで必要なデータを抽出し、結果を配列として水和しています。次に、PHP でこの膨大なレコードの配列を操作して、正しい順序にする予定です。この配列のサイズが原因で、この並べ替えプロセスが非常に遅くなるのではないかと心配しているので、次のいずれかの方法でこれをより速くする方法についてアドバイスを探しています。

  • SQL クエリでの並べ替えの処理。
  • 説明されているようなアルゴリズムを Solr などの検索エンジンに実装する方法を提案します (これの基本については少し経験がありますが、複雑な並べ替えは実​​行していません)。
  • 他の 2 つのオプションが実行できない場合に、PHP でソートを実行する最善の方法に関する提案。

編集:

私はこれについていくつかの良い進歩を遂げました、ありがとう(特に@Neil)。これまでの進捗状況の一部を含む別の質問 (サブクエリの Groupwise MAX() ) を開きました。

4

3 に答える 3

0

サイトのページでも同様の問題が発生しました。サブクエリや結合なしで検索を実行するために、すべてのパラメータを使用して特別な非正規化検索テーブルを作成しました。すべてのデータが複製されたため、何かが変更された場合は、すべての非正規化データを更新します。データの同期にはバックグラウンドタスクを使用したため、検索結果がしばらくの間実際のものではなかった可能性があります。

複雑に思えるかもしれませんが、それはデータとリクエストが大きくなる場合にのみ有効です。

于 2013-02-10T14:14:25.823 に答える
0

一致するコースの数で学校を見つけるのは簡単です。

SELECT schoolId, COUNT(*) AS schoolCount
  FROM Courses
  WHERE name IN ('History', 'French')
  GROUP BY schoolId

これだけあれば、好きなORDER BY schoolCount DESC順序で取得できます。

コースが一致するパートナーシップを見つけるには、まず少なくとも 1 つの学校でコースを持つパートナーシップを見つける必要があります。

SELECT partnershipId, COUNT(DISTINCT name) AS partnershipCount
  FROM SchoolPartnership
  INNER JOIN Courses ON Course.schoolId = SchoolPartnership.schoolId
  WHERE name IN ('History', 'French')
  GROUP BY partnershipId

DISTINCTパートナーシップ内のいくつの学校がそのコースを持っているかは気にしないため、 が必要であることに注意してください。持っていない場合はDISTINCT、代わりに副選択を使用できます。

SELECT partnershipId, COUNT(*) AS partnershipCount
  FROM (
    SELECT DISTINCT partnershipId, name
      FROM SchoolPartnership
      INNER JOIN Courses ON Course.schoolId = SchoolPartnership.schoolId
      WHERE name IN ('History', 'French'))
  GROUP BY partnershipId

上記の最初と最後のクエリを SchoolPartnership との結合のサブセレクトとして使用して、partnershipMatches と schoolMatches の降順で学校を並べ替えることができます。(すべての学校が少なくとも 1 つの学校と提携していると仮定していることに注意してください。) 最終的なクエリは次のようになると思います。

SELECT SchoolMatches.schoolID
  FROM (
    SELECT schoolId, COUNT(*) AS schoolCount
      FROM Courses
      WHERE name IN ('History', 'French')
      GROUP BY schoolId
  ) SchoolMatches
  JOIN SchoolPartnership ON SchoolMatches.schoolID = SchoolPartnership.schoolID
  JOIN (
    SELECT partnershipId, COUNT(DISTINCT name) AS partnershipCount
      FROM SchoolPartnership
      INNER JOIN Courses ON Course.schoolId = SchoolPartnership.schoolId
      WHERE name IN ('History', 'French')
      GROUP BY partnershipId
   ) PartnershipMatches ON SchoolPartnership.schoolId = PartnershipMatches.schoolId
   ORDER BY PartnershipMatches.partnershipCount DESC, SchoolMatches.SchoolCount DESC
于 2013-02-09T20:56:49.767 に答える
-2
filter_var('sgamgee@example.com', FILTER_VALIDATE_EMAIL); // Returns "sgamgee@example.com"

これは有効な電子メール アドレスです。

于 2013-12-17T11:59:12.793 に答える